From 8db04e4ccc4c460a14887daba257a0a835acba62 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Tue, 11 Jun 2013 09:29:07 +0530 Subject: ASoC: dwc: debug message correction. Debug message correction. Signed-off-by: Rajeev Kumar Signed-off-by: Mark Brown (cherry picked from commit 5e83c160d83070152a595f57a6ca7c5bb1ce16b3) Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 489a9abf112b..0ba94856ed6e 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -410,7 +410,7 @@ static int dw_i2s_probe(struct platform_device *pdev) } if (cap & DWC_I2S_PLAY) { - dev_dbg(&pdev->dev, " SPEAr: play supported\n"); + dev_dbg(&pdev->dev, " designware: play supported\n"); dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->playback.channels_max = pdata->channel; dw_i2s_dai->playback.formats = pdata->snd_fmts; @@ -418,7 +418,7 @@ static int dw_i2s_probe(struct platform_device *pdev) } if (cap & DWC_I2S_RECORD) { - dev_dbg(&pdev->dev, "SPEAr: record supported\n"); + dev_dbg(&pdev->dev, "designware: record supported\n"); dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->capture.channels_max = pdata->channel; dw_i2s_dai->capture.formats = pdata->snd_fmts; -- cgit v1.2.3 From bfadef40cc84a86e7f1e41114cd9da95272f5a4a Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Tue, 11 Jun 2013 09:29:08 +0530 Subject: ASoC: dwc: Folder path correction in file header. Folder path correction in file header. Signed-off-by: Rajeev Kumar Signed-off-by: Mark Brown (cherry picked from commit 22a4adf25826d1128d116dd4a313f66175c703bd) Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 0ba94856ed6e..9dfdbf470b27 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -1,7 +1,7 @@ /* * ALSA SoC Synopsys I2S Audio Layer * - * sound/soc/spear/designware_i2s.c + * sound/soc/dwc/designware_i2s.c * * Copyright (C) 2010 ST Microelectronics * Rajeev Kumar -- cgit v1.2.3 From d832d830d532e87e5e1ac810ef867a3b815ace2f Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 16 May 2013 14:08:07 +0800 Subject: ASoC: omap-hdmi-codec: make the driver common for other SoCs to support HDMI on CSR SiRFprimaII and atlasVI, we need one more HDMI pseudo codec, rather than add a new driver, we can make omap HDMI codec common for other SoCs as well. then the omap-hdmi codec becomes a generic HDMI pseudo- codec as HDMI audio features depend on HDMI specification not on SoCs. Signed-off-by: Barry Song Signed-off-by: Mark Brown (cherry picked from commit bf7c6e6ccbde22c96c5c1e5cec08740c31229df1) Signed-off-by: Jon Medhurst --- sound/soc/codecs/Kconfig | 4 +-- sound/soc/codecs/Makefile | 4 +-- sound/soc/codecs/hdmi.c | 69 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/omap-hdmi.c | 69 ----------------------------------------- sound/soc/omap/omap-hdmi-card.c | 2 +- 5 files changed, 74 insertions(+), 74 deletions(-) create mode 100644 sound/soc/codecs/hdmi.c delete mode 100644 sound/soc/codecs/omap-hdmi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2f45f00e31b0..d8c4f3dcf4a1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -53,7 +53,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C - select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI + select SND_SOC_HDMI_CODEC select SND_SOC_PCM3008 select SND_SOC_RT5631 if I2C select SND_SOC_SGTL5000 if I2C @@ -287,7 +287,7 @@ config SND_SOC_MAX98095 config SND_SOC_MAX9850 tristate -config SND_SOC_OMAP_HDMI_CODEC +config SND_SOC_HDMI_CODEC tristate config SND_SOC_PCM3008 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b9e41c9a1f4c..49ff12718bed 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -41,7 +41,7 @@ snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o -snd-soc-omap-hdmi-codec-objs := omap-hdmi.o +snd-soc-hdmi-codec-objs := hdmi.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-rt5631-objs := rt5631.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -168,7 +168,7 @@ obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o -obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o +obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c new file mode 100644 index 000000000000..2bcae2b40c92 --- /dev/null +++ b/sound/soc/codecs/hdmi.c @@ -0,0 +1,69 @@ +/* + * ALSA SoC codec driver for HDMI audio codecs. + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Ricardo Neri + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include + +#define DRV_NAME "hdmi-audio-codec" + +static struct snd_soc_codec_driver hdmi_codec; + +static struct snd_soc_dai_driver hdmi_codec_dai = { + .name = "hdmi-hifi", + .playback = { + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}; + +static int hdmi_codec_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &hdmi_codec, + &hdmi_codec_dai, 1); +} + +static int hdmi_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver hdmi_codec_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + + .probe = hdmi_codec_probe, + .remove = hdmi_codec_remove, +}; + +module_platform_driver(hdmi_codec_driver); + +MODULE_AUTHOR("Ricardo Neri "); +MODULE_DESCRIPTION("ASoC generic HDMI codec driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c deleted file mode 100644 index 529d06444c54..000000000000 --- a/sound/soc/codecs/omap-hdmi.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ALSA SoC codec driver for HDMI audio on OMAP processors. - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include -#include - -#define DRV_NAME "hdmi-audio-codec" - -static struct snd_soc_codec_driver omap_hdmi_codec; - -static struct snd_soc_dai_driver omap_hdmi_codec_dai = { - .name = "omap-hdmi-hifi", - .playback = { - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}; - -static int omap_hdmi_codec_probe(struct platform_device *pdev) -{ - return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec, - &omap_hdmi_codec_dai, 1); -} - -static int omap_hdmi_codec_remove(struct platform_device *pdev) -{ - snd_soc_unregister_codec(&pdev->dev); - return 0; -} - -static struct platform_driver omap_hdmi_codec_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - - .probe = omap_hdmi_codec_probe, - .remove = omap_hdmi_codec_remove, -}; - -module_platform_driver(omap_hdmi_codec_driver); - -MODULE_AUTHOR("Ricardo Neri "); -MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c index d4eaa92e518e..7e66e9cba5a8 100644 --- a/sound/soc/omap/omap-hdmi-card.c +++ b/sound/soc/omap/omap-hdmi-card.c @@ -35,7 +35,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = { .cpu_dai_name = "omap-hdmi-audio-dai", .platform_name = "omap-pcm-audio", .codec_name = "hdmi-audio-codec", - .codec_dai_name = "omap-hdmi-hifi", + .codec_dai_name = "hdmi-hifi", }; static struct snd_soc_card snd_soc_omap_hdmi = { -- cgit v1.2.3 From ca33bfa3d8fa4de1b45f666a385a56c3e3089b39 Mon Sep 17 00:00:00 2001 From: Rongjun Ying Date: Wed, 17 Jul 2013 14:12:16 +0800 Subject: ASoC: hdmi-codec: let the driver support HDMI sink Devices like mobilephones, computers are typically used as HDMI sources, but devices like TV, navigators will be HDMI sinks. for auto scenerios, In-Vehicle Infotainment(IVI) can be HDMI sink to display movies from mobilephones. Signed-off-by: Rongjun Ying Signed-off-by: Barry Song Signed-off-by: Mark Brown (cherry picked from commit c6c0925ea32d37696da7d71631a4a0c999f2094f) Signed-off-by: Jon Medhurst --- sound/soc/codecs/hdmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 2bcae2b40c92..f0986b9f1939 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -37,6 +37,17 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + }; static int hdmi_codec_probe(struct platform_device *pdev) -- cgit v1.2.3 From 2425529ef0a6645fefc75320930e48534d2bb88b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 19 Aug 2013 12:17:36 +0100 Subject: ASoC: hdmi: Provide stub DAPM integration Ensure continued operation with DAPM being mandatory. Signed-off-by: Mark Brown (cherry picked from commit c34e51b12751c3e81c752b385f02a97bf3f862da) Signed-off-by: Jon Medhurst --- sound/soc/codecs/hdmi.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index f0986b9f1939..68342b121c96 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -23,11 +23,20 @@ #define DRV_NAME "hdmi-audio-codec" -static struct snd_soc_codec_driver hdmi_codec; +static const struct snd_soc_dapm_widget hdmi_widgets[] = { + SND_SOC_DAPM_INPUT("RX"), + SND_SOC_DAPM_OUTPUT("TX"), +}; + +static const struct snd_soc_dapm_route hdmi_routes[] = { + { "Capture", NULL, "RX" }, + { "TX", NULL, "Playback" }, +}; static struct snd_soc_dai_driver hdmi_codec_dai = { .name = "hdmi-hifi", .playback = { + .stream_name = "Playback", .channels_min = 2, .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | @@ -38,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { SNDRV_PCM_FMTBIT_S24_LE, }, .capture = { + .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_32000 | @@ -50,6 +60,13 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { }; +static struct snd_soc_codec_driver hdmi_codec = { + .dapm_widgets = hdmi_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), + .dapm_routes = hdmi_routes, + .num_dapm_routes = ARRAY_SIZE(hdmi_routes), +}; + static int hdmi_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &hdmi_codec, -- cgit v1.2.3 From 1cdefdb9dc8b45ba81958300be8e539018aa92bd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 23 Aug 2013 14:35:17 -0300 Subject: ASoC: simple-card: Provide owner and MODULE_ALIAS() Add .owner field and also MODULE_ALIAS(), so that auto module loading can work. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown (cherry picked from commit c445be35956b0cefe85db75d1e7994af5cecf16a) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6cf8355a8542..8c49147db84c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -105,6 +105,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev) static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", + .owner = THIS_MODULE, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove, @@ -112,6 +113,7 @@ static struct platform_driver asoc_simple_card = { module_platform_driver(asoc_simple_card); +MODULE_ALIAS("platform:asoc-simple-card"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ASoC Simple Sound Card"); MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v1.2.3 From 9af34ac75a53368de1071ffabc3ee3750d204190 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 26 Aug 2013 09:25:15 -0300 Subject: ASoC: designware_i2s: Remove unnecessary dev_set_drvdata() Driver core clears the driver data to NULL after device_release or on probe failure, so just remove it from here. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown (cherry picked from commit e925a6b1b6e7ddb43a71b31c0afa12ca9a6ec118) Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 9dfdbf470b27..2f6357578616 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -435,13 +435,11 @@ static int dw_i2s_probe(struct platform_device *pdev) dw_i2s_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); - goto err_set_drvdata; + goto err_clk_disable; } return 0; -err_set_drvdata: - dev_set_drvdata(&pdev->dev, NULL); err_clk_disable: clk_disable(dev->clk); err_clk_put: @@ -454,7 +452,6 @@ static int dw_i2s_remove(struct platform_device *pdev) struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - dev_set_drvdata(&pdev->dev, NULL); clk_put(dev->clk); -- cgit v1.2.3 From dd791b3f43aaf9e9a8b9016b8279b16f15a16c12 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2013 19:39:03 -0700 Subject: ASoC: snd_soc_codec includes snd_soc_component Codec includes component by this patch, and component moved to upside of codec to avoid extra declaration. Codec dai will be registered via component by this patch. Current component register function is used for cpu, and it is using dai/dais functions properly to keep existing cpu dai name. And now, it will be used from codec also. But codec driver had been used dais function only even though it was single dai. This patch adds new flag which can selects dai/dais function on component register function to keep existing codec dai name. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit d191bd8de8c61619563f2b19f1fdcc0944ff1a72) Signed-off-by: Jon Medhurst --- include/sound/soc.h | 33 +++++---- sound/soc/soc-core.c | 202 ++++++++++++++++++++++++++++----------------------- 2 files changed, 131 insertions(+), 104 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 5bbdc653a826..09834a57954a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -668,6 +668,21 @@ struct snd_soc_cache_ops { int (*sync)(struct snd_soc_codec *codec); }; +/* component interface */ +struct snd_soc_component_driver { + const char *name; +}; + +struct snd_soc_component { + const char *name; + int id; + int num_dai; + struct device *dev; + struct list_head list; + + const struct snd_soc_component_driver *driver; +}; + /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; @@ -715,6 +730,9 @@ struct snd_soc_codec { struct mutex cache_rw_mutex; int val_bytes; + /* component */ + struct snd_soc_component component; + /* dapm */ struct snd_soc_dapm_context dapm; unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ @@ -734,6 +752,7 @@ struct snd_soc_codec_driver { int (*remove)(struct snd_soc_codec *); int (*suspend)(struct snd_soc_codec *); int (*resume)(struct snd_soc_codec *); + struct snd_soc_component_driver component_driver; /* Default control and setup, added after probe() is run */ const struct snd_kcontrol_new *controls; @@ -851,20 +870,6 @@ struct snd_soc_platform { #endif }; -struct snd_soc_component_driver { - const char *name; -}; - -struct snd_soc_component { - const char *name; - int id; - int num_dai; - struct device *dev; - struct list_head list; - - const struct snd_soc_component_driver *driver; -}; - struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d56bbea6e75e..14f80c15d769 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3899,6 +3899,112 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count) snd_soc_unregister_dai(dev); } +/** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +static int +__snd_soc_register_component(struct device *dev, + struct snd_soc_component *cmpnt, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai, bool allow_single_dai) +{ + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to connecting component\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->num_dai = num_dai; + + /* + * snd_soc_register_dai() uses fmt_single_name(), and + * snd_soc_register_dais() uses fmt_multiple_name() + * for dai->name which is used for name based matching + * + * this function is used from cpu/codec. + * allow_single_dai flag can ignore "codec" driver reworking + * since it had been used snd_soc_register_dais(), + */ + if ((1 == num_dai) && allow_single_dai) + ret = snd_soc_register_dai(dev, dai_drv); + else + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} + +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, + dai_drv, num_dai, true); +} +EXPORT_SYMBOL_GPL(snd_soc_register_component); + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ + struct snd_soc_component *cmpnt; + + list_for_each_entry(cmpnt, &component_list, list) { + if (dev == cmpnt->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); + /** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform @@ -4123,10 +4229,12 @@ int snd_soc_register_codec(struct device *dev, list_add(&codec->list, &codec_list); mutex_unlock(&client_mutex); - /* register any DAIs */ - ret = snd_soc_register_dais(dev, dai_drv, num_dai); + /* register component */ + ret = __snd_soc_register_component(dev, &codec->component, + &codec_drv->component_driver, + dai_drv, num_dai, false); if (ret < 0) { - dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); goto fail_codec_name; } @@ -4161,7 +4269,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - snd_soc_unregister_dais(dev, codec->num_dai); + snd_soc_unregister_component(dev); mutex_lock(&client_mutex); list_del(&codec->list); @@ -4176,92 +4284,6 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); - -/** - * snd_soc_register_component - Register a component with the ASoC core - * - */ -int snd_soc_register_component(struct device *dev, - const struct snd_soc_component_driver *cmpnt_drv, - struct snd_soc_dai_driver *dai_drv, - int num_dai) -{ - struct snd_soc_component *cmpnt; - int ret; - - dev_dbg(dev, "component register %s\n", dev_name(dev)); - - cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); - if (!cmpnt) { - dev_err(dev, "ASoC: Failed to allocate memory\n"); - return -ENOMEM; - } - - cmpnt->name = fmt_single_name(dev, &cmpnt->id); - if (!cmpnt->name) { - dev_err(dev, "ASoC: Failed to simplifying name\n"); - return -ENOMEM; - } - - cmpnt->dev = dev; - cmpnt->driver = cmpnt_drv; - cmpnt->num_dai = num_dai; - - /* - * snd_soc_register_dai() uses fmt_single_name(), and - * snd_soc_register_dais() uses fmt_multiple_name() - * for dai->name which is used for name based matching - */ - if (1 == num_dai) - ret = snd_soc_register_dai(dev, dai_drv); - else - ret = snd_soc_register_dais(dev, dai_drv, num_dai); - if (ret < 0) { - dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); - goto error_component_name; - } - - mutex_lock(&client_mutex); - list_add(&cmpnt->list, &component_list); - mutex_unlock(&client_mutex); - - dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); - - return ret; - -error_component_name: - kfree(cmpnt->name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_component); - -/** - * snd_soc_unregister_component - Unregister a component from the ASoC core - * - */ -void snd_soc_unregister_component(struct device *dev) -{ - struct snd_soc_component *cmpnt; - - list_for_each_entry(cmpnt, &component_list, list) { - if (dev == cmpnt->dev) - goto found; - } - return; - -found: - snd_soc_unregister_dais(dev, cmpnt->num_dai); - - mutex_lock(&client_mutex); - list_del(&cmpnt->list); - mutex_unlock(&client_mutex); - - dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); - kfree(cmpnt->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_component); - /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) -- cgit v1.2.3 From 9c0c9e3310104f8f540e8d19a0db1417d0d962a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Sep 2013 17:39:56 -0700 Subject: ASoC: add .of_xlate_dai_name on snd_soc_component_driver ASoC sound driver requires CPU/CODEC drivers for probing, and each CPU/CODEC has some DAI on it. Then, "dai name matching" have been used to identify CPU-CODEC DAI pair on ASoC. But, the "dai port number matching" is now required from DeviceTree. The solution of this issue is to replace the dai port number into dai name. Now, CPU/CODEC are based on struct snd_soc_component, and it can care above as common issue. This patch adds .of_xlate_dai_name callback interface on struct snd_soc_component_driver, and snd_soc_of_get_dai_name() which is using .of_xlate_dai_name. Then, #sound-dai-cells which enables DAI specifier is required on CPU/CODEC device tree properties. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit cb470087669a3fab1958fec79dd7db280b33f178) Signed-off-by: Jon Medhurst --- include/sound/soc.h | 8 ++++++++ sound/soc/soc-core.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 09834a57954a..9eba47ed72e7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -13,6 +13,7 @@ #ifndef __LINUX_SND_SOC_H #define __LINUX_SND_SOC_H +#include #include #include #include @@ -671,6 +672,11 @@ struct snd_soc_cache_ops { /* component interface */ struct snd_soc_component_driver { const char *name; + + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); }; struct snd_soc_component { @@ -1202,6 +1208,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name); #include diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 14f80c15d769..92957852cf56 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4470,6 +4470,41 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name) +{ + struct snd_soc_component *pos; + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(of_node, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + ret = -EPROBE_DEFER; + + mutex_lock(&client_mutex); + list_for_each_entry(pos, &component_list, list) { + if (pos->dev->of_node != args.np) + continue; + + if (!pos->driver->of_xlate_dai_name) { + ret = -ENOSYS; + break; + } + + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + break; + } + mutex_unlock(&client_mutex); + + of_node_put(args.np); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From d1e55f50f9ac285373a2e24c2b01ac37b74717b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 16 Oct 2013 22:05:26 -0700 Subject: ASoC: add snd_soc_of_get_dai_name() default of_xlate Current snd_soc_of_get_dai_name() needs .of_xlate_dai_name() callback on each component drivers. But required behavior on almost all these drivers is just returns its indexed driver's name. This patch adds this feature as default behavior. .of_xlate_dai_name() can overwrite it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 6833c452c2fb47353566aa705d68541c6045c796) Signed-off-by: Jon Medhurst --- include/sound/soc.h | 4 +++- sound/soc/soc-core.c | 28 ++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 9eba47ed72e7..408118aad524 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -682,10 +682,12 @@ struct snd_soc_component_driver { struct snd_soc_component { const char *name; int id; - int num_dai; struct device *dev; struct list_head list; + struct snd_soc_dai_driver *dai_drv; + int num_dai; + const struct snd_soc_component_driver *driver; }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 92957852cf56..e2ca10345597 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3927,6 +3927,7 @@ __snd_soc_register_component(struct device *dev, cmpnt->dev = dev; cmpnt->driver = cmpnt_drv; + cmpnt->dai_drv = dai_drv; cmpnt->num_dai = num_dai; /* @@ -4489,12 +4490,31 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, if (pos->dev->of_node != args.np) continue; - if (!pos->driver->of_xlate_dai_name) { - ret = -ENOSYS; - break; + if (pos->driver->of_xlate_dai_name) { + ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + } else { + int id = -1; + + switch (args.args_count) { + case 0: + id = 0; /* same as dai_drv[0] */ + break; + case 1: + id = args.args[0]; + break; + default: + /* not supported */ + break; + } + + if (id < 0 || id >= pos->num_dai) { + ret = -EINVAL; + } else { + *dai_name = pos->dai_drv[id].name; + ret = 0; + } } - ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); break; } mutex_unlock(&client_mutex); -- cgit v1.2.3 From 9089e2a9a6eb4794c6bd0affb16df2c06b2a7eba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Sep 2013 20:37:34 +0100 Subject: ASoC: core: Implement devm_snd_soc_register_component() Since with the wider use of devres many drivers are now only calling snd_soc_unregister_component() in their remove functions providing a managed version will save a reasonable amount of code. Signed-off-by: Mark Brown (cherry picked from commit a0b03a616b08cf9d709812ff5cf7e9c0958d6807) Signed-off-by: Jon Medhurst --- include/sound/soc.h | 3 +++ sound/soc/Makefile | 2 +- sound/soc/soc-devres.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 sound/soc/soc-devres.c diff --git a/include/sound/soc.h b/include/sound/soc.h index 408118aad524..c4d48b5563e2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -387,6 +387,9 @@ void snd_soc_unregister_codec(struct device *dev); int snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_component(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 197b6ae54c8d..e85fb6df689d 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o +snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) snd-soc-core-objs += soc-dmaengine-pcm.o diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c new file mode 100644 index 000000000000..13fe86f7c9a8 --- /dev/null +++ b/sound/soc/soc-devres.c @@ -0,0 +1,52 @@ +/* + * soc-devres.c -- ALSA SoC Audio Layer devres functions + * + * Copyright (C) 2013 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +static void devm_component_release(struct device *dev, void *res) +{ + snd_soc_unregister_component(*(struct device **)res); +} + +/** + * devm_snd_soc_register_component - resource managed component registration + * @dev: Device used to manage component + * @cmpnt_drv: Component driver + * @dai_drv: DAI driver + * @num_dai: Number of DAIs to register + * + * Register a component with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); -- cgit v1.2.3 From d914eea7352a6882d91948504fc1b530857b7e9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 16 Sep 2013 18:02:05 +0100 Subject: ASoC: core: Add devm_snd_soc_register_card() Simplify error handling and remove repetitive (and rarely executed) code for unregistration by providing a devm_snd_soc_register() card. Signed-off-by: Mark Brown Acked-by: Liam Girdwood (cherry picked from commit 0e4ff5c806263bf40ee5409ac283b776f0c11e41) Signed-off-by: Jon Medhurst --- include/sound/soc.h | 1 + sound/soc/soc-devres.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index c4d48b5563e2..929f793de318 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -370,6 +370,7 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, int snd_soc_register_card(struct snd_soc_card *card); int snd_soc_unregister_card(struct snd_soc_card *card); +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card); int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 13fe86f7c9a8..b1d732255c02 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -50,3 +50,37 @@ int devm_snd_soc_register_component(struct device *dev, return ret; } EXPORT_SYMBOL_GPL(devm_snd_soc_register_component); + +static void devm_card_release(struct device *dev, void *res) +{ + snd_soc_unregister_card(*(struct snd_soc_card **)res); +} + +/** + * devm_snd_soc_register_card - resource managed card registration + * @dev: Device used to manage card + * @card: Card to register + * + * Register a card with automatic unregistration when the device is + * unregistered. + */ +int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_register_card(card); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); -- cgit v1.2.3 From 129ce7287179ce07b7736b29848bf04fe6bdf9b9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 29 Aug 2014 15:05:00 +0100 Subject: ASoC: dwc: Allocate resources with platform_get_resource Reorder allocations and use updated interface, platform_get_resource, to allocate IO mapping. Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 46 +++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 2f6357578616..08bd53b1418f 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -352,31 +352,34 @@ static int dw_i2s_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no i2s resource defined\n"); - return -ENODEV; - } - - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "i2s region already claimed\n"); - return -EBUSY; - } - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_warn(&pdev->dev, "kzalloc fail\n"); return -ENOMEM; } - dev->i2s_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!dev->i2s_base) { - dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); + dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); + if (!dw_i2s_dai) { + dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); return -ENOMEM; } + dw_i2s_dai->ops = &dw_i2s_dai_ops; + dw_i2s_dai->suspend = dw_i2s_suspend; + dw_i2s_dai->resume = dw_i2s_resume; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no i2s resource defined\n"); + return -ENODEV; + } + + dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dev->i2s_base)) { + dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); + return PTR_ERR(dev->i2s_base); + } + cap = pdata->cap; dev->capability = cap; dev->i2s_clk_cfg = pdata->i2s_clk_cfg; @@ -402,13 +405,6 @@ static int dw_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_put; - dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); - if (!dw_i2s_dai) { - dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); - ret = -ENOMEM; - goto err_clk_disable; - } - if (cap & DWC_I2S_PLAY) { dev_dbg(&pdev->dev, " designware: play supported\n"); dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; @@ -425,10 +421,6 @@ static int dw_i2s_probe(struct platform_device *pdev) dw_i2s_dai->capture.rates = pdata->snd_rates; } - dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->suspend = dw_i2s_suspend; - dw_i2s_dai->resume = dw_i2s_resume; - dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, -- cgit v1.2.3 From 99de002da7b4fd071310448b7846a82580a5f438 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 29 Aug 2014 15:02:38 +0100 Subject: ASoC: dwc: Don't allow negative use counts Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 08bd53b1418f..c2c5b4335029 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -293,7 +293,8 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dev->active--; + if (dev->active > 0) + dev->active--; i2s_stop(dev, substream); break; default: -- cgit v1.2.3 From 40123cb4084e6e94df8cf66d7229093be6efc1af Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 29 Aug 2014 15:00:00 +0100 Subject: ASoC: dwc: Iterate over all channels On the Designware core, the channels are independent and not combined in higher registers. So as more channels are added, more registers need to be updated. Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index c2c5b4335029..2cde4924fd9c 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -227,19 +227,25 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, i2s_disable_channels(dev, substream->stream); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution); - i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); - } else { - i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution); - i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); - } + /* Iterate over set of channels - independently controlled. + */ + do { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TCR(ch_reg), + xfer_resolution); + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); + i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); + } else { + i2s_write_reg(dev->i2s_base, RCR(ch_reg), + xfer_resolution); + i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); + i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); + } + } while (ch_reg-- > 0); i2s_write_reg(dev->i2s_base, CCR, ccr); -- cgit v1.2.3 From 820493db4ec4a175dd92b3184c1d07d666e96274 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 29 Aug 2014 15:09:40 +0100 Subject: ASoC: dwc: Add devicetree support for Designware I2S Convert to driver to use either platform_data or device-tree for configuration of the device. When using device-tree, the I2S block's configuration is read from the relevant registers: this reduces the amount of information required in the device tree. Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- sound/soc/dwc/Kconfig | 1 + sound/soc/dwc/designware_i2s.c | 262 +++++++++++++++++++++++++++++++++-------- 2 files changed, 216 insertions(+), 47 deletions(-) diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig index e334900cf0b8..d50e08517dce 100644 --- a/sound/soc/dwc/Kconfig +++ b/sound/soc/dwc/Kconfig @@ -1,6 +1,7 @@ config SND_DESIGNWARE_I2S tristate "Synopsys I2S Device Driver" depends on CLKDEV_LOOKUP + select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S driver for Synopsys desigwnware I2S device. The device supports upto diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 2cde4924fd9c..0923b79c093f 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -22,6 +22,7 @@ #include #include #include +#include /* common register for all channel */ #define IER 0x000 @@ -54,19 +55,46 @@ #define I2S_COMP_VERSION 0x01F8 #define I2S_COMP_TYPE 0x01FC +/* + * Component parameter register fields - define the I2S block's + * configuration. + */ +#define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25) +#define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22) +#define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19) +#define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16) +#define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9) +#define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7) +#define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6) +#define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5) +#define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4) +#define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2) +#define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0) + +#define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10) +#define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7) +#define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3) +#define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0) + #define MAX_CHANNEL_NUM 8 #define MIN_CHANNEL_NUM 2 +union snd_dma_data { + struct i2s_dma_data pd; + struct snd_dmaengine_dai_dma_data dt; +}; + struct dw_i2s_dev { void __iomem *i2s_base; struct clk *clk; int active; unsigned int capability; struct device *dev; + bool using_pd; /* data related to DMA transfers b/w i2s and DMAC */ - struct i2s_dma_data play_dma_data; - struct i2s_dma_data capture_dma_data; + union snd_dma_data play_dma_data; + union snd_dma_data capture_dma_data; struct i2s_clk_config_data config; int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); }; @@ -153,7 +181,7 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - struct i2s_dma_data *dma_data = NULL; + union snd_dma_data *dma_data = NULL; if (!(dev->capability & DWC_I2S_RECORD) && (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) @@ -251,13 +279,18 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, config->sample_rate = params_rate(params); - if (!dev->i2s_clk_cfg) - return -EINVAL; + if (dev->using_pd) { + ret = dev->i2s_clk_cfg(config); + if (ret < 0) { + dev_err(dev->dev, "runtime audio clk config fail\n"); + return ret; + } + } else { + u32 bitclk; - ret = dev->i2s_clk_cfg(config); - if (ret < 0) { - dev_err(dev->dev, "runtime audio clk config fail\n"); - return ret; + /* TODO: Validate sample rate against permissible set */ + bitclk = config->sample_rate * config->data_width * 2; + clk_set_rate(dev->clk, bitclk); } return 0; @@ -345,6 +378,61 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) #define dw_i2s_resume NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id dw_i2s_of_match[] = { + { .compatible = "snps,i2s", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dw_i2s_of_match); +#endif + +/* Maximum resolution of a channel - not uniformly spaced */ +static const u32 fifo_width [] = { + 12, 16, 20, 24, 32, 0, 0, 0 +}; + +/* Width of (DMA) bus */ +static const u32 bus_widths [] = { + DMA_SLAVE_BUSWIDTH_1_BYTE, + DMA_SLAVE_BUSWIDTH_2_BYTES, + DMA_SLAVE_BUSWIDTH_4_BYTES, + DMA_SLAVE_BUSWIDTH_UNDEFINED +}; + +/* PCM format to support channel resolution */ +static const u32 formats [] = { + SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S32_LE, + 0, + 0, + 0 +}; + +/* Find the DMA channel ID allocated for playback or record */ +static int find_dma_channel(struct platform_device *pdev, const char *name, + u32 *channel) +{ + int ret; + struct of_phandle_args dma_spec; + + ret = of_property_match_string(pdev->dev.of_node, "dma-names", name); + if (ret < 0) + return ret; + + ret = of_parse_phandle_with_args(pdev->dev.of_node, + "dmas", "#dma-cells", ret, + &dma_spec); + if (ret < 0) + return ret; + + *channel = dma_spec.args[0]; + return 0; +} + static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; @@ -354,11 +442,6 @@ static int dw_i2s_probe(struct platform_device *pdev) unsigned int cap; struct snd_soc_dai_driver *dw_i2s_dai; - if (!pdata) { - dev_err(&pdev->dev, "Invalid platform data\n"); - return -EINVAL; - } - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_warn(&pdev->dev, "kzalloc fail\n"); @@ -387,47 +470,120 @@ static int dw_i2s_probe(struct platform_device *pdev) return PTR_ERR(dev->i2s_base); } - cap = pdata->cap; - dev->capability = cap; - dev->i2s_clk_cfg = pdata->i2s_clk_cfg; + if (pdata) { + dev->using_pd = true; + cap = pdata->cap; + dev->capability = cap; + dev->i2s_clk_cfg = pdata->i2s_clk_cfg; + if (!dev->i2s_clk_cfg) { + dev_err(&pdev->dev, "no clock device\n"); + return -ENODEV; + } - /* Set DMA slaves info */ + /* Set DMA slaves info */ + + dev->play_dma_data.pd.data = pdata->play_dma_data; + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; + dev->play_dma_data.pd.max_burst = 16; + dev->capture_dma_data.pd.max_burst = 16; + dev->play_dma_data.pd.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + dev->capture_dma_data.pd.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + dev->play_dma_data.pd.filter = pdata->filter; + dev->capture_dma_data.pd.filter = pdata->filter; + + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + + if (cap & DWC_I2S_PLAY) { + dev_dbg(&pdev->dev, " designware: play supported\n"); + dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->playback.channels_max = pdata->channel; + dw_i2s_dai->playback.formats = pdata->snd_fmts; + dw_i2s_dai->playback.rates = pdata->snd_rates; + } - dev->play_dma_data.data = pdata->play_dma_data; - dev->capture_dma_data.data = pdata->capture_dma_data; - dev->play_dma_data.addr = res->start + I2S_TXDMA; - dev->capture_dma_data.addr = res->start + I2S_RXDMA; - dev->play_dma_data.max_burst = 16; - dev->capture_dma_data.max_burst = 16; - dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - dev->play_dma_data.filter = pdata->filter; - dev->capture_dma_data.filter = pdata->filter; + if (cap & DWC_I2S_RECORD) { + dev_dbg(&pdev->dev, "designware: record supported\n"); + dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->capture.channels_max = pdata->channel; + dw_i2s_dai->capture.formats = pdata->snd_fmts; + dw_i2s_dai->capture.rates = pdata->snd_rates; + } + } else { + /* Read component parameter registers to extract + * the I2S block's configuration. + */ + u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 bus_width = bus_widths [COMP1_APB_DATA_WIDTH(comp1)]; + u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); + u32 max_size; + u32 slave_id; + + dev->using_pd = false; + + dev->clk = devm_clk_get(&pdev->dev, "i2sclk"); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + + /* Code presumes all channels are configured with the same + * word size. + */ + if (COMP1_TX_ENABLED(comp1)) { + dev_dbg(&pdev->dev, "playback capable\n"); + + ret = find_dma_channel(pdev, "tx", &slave_id); + if (ret < 0) + return ret; + dev->capability |= DWC_I2S_PLAY; + max_size = COMP1_TX_WORDSIZE_0(comp1); + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.addr_width = bus_width; + dev->play_dma_data.dt.chan_name = "TX"; + dev->play_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[max_size]) >> 8; + dev->play_dma_data.dt.maxburst = 16; + dev->play_dma_data.dt.slave_id = slave_id; + dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->playback.channels_max = + 1 << (COMP1_TX_CHANNELS(comp1) + 1); + dw_i2s_dai->playback.formats = formats[max_size]; + dw_i2s_dai->playback.rates = SNDRV_PCM_RATE_8000_192000; + } + if (COMP1_RX_ENABLED(comp1)) { + dev_dbg(&pdev->dev, "record capable\n"); + + ret = find_dma_channel(pdev, "rx", &slave_id); + if (ret < 0) + return ret; + dev->capability |= DWC_I2S_RECORD; + max_size = COMP2_RX_WORDSIZE_0(comp2); + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.addr_width = bus_width; + dev->capture_dma_data.dt.chan_name = "RX"; + dev->capture_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[max_size] >> 8); + dev->capture_dma_data.dt.maxburst = 16; + dev->capture_dma_data.dt.slave_id = slave_id; + dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; + dw_i2s_dai->capture.channels_max = + 1 << (COMP1_RX_CHANNELS(comp1) + 1); + dw_i2s_dai->capture.formats = formats[max_size]; + dw_i2s_dai->capture.rates = SNDRV_PCM_RATE_8000_192000; + } + } - dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) - return PTR_ERR(dev->clk); + ret = clk_prepare(dev->clk); + if (ret < 0) + goto err_clk_put; ret = clk_enable(dev->clk); if (ret < 0) goto err_clk_put; - if (cap & DWC_I2S_PLAY) { - dev_dbg(&pdev->dev, " designware: play supported\n"); - dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->playback.channels_max = pdata->channel; - dw_i2s_dai->playback.formats = pdata->snd_fmts; - dw_i2s_dai->playback.rates = pdata->snd_rates; - } - - if (cap & DWC_I2S_RECORD) { - dev_dbg(&pdev->dev, "designware: record supported\n"); - dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; - dw_i2s_dai->capture.channels_max = pdata->channel; - dw_i2s_dai->capture.formats = pdata->snd_fmts; - dw_i2s_dai->capture.rates = pdata->snd_rates; - } - dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, @@ -437,6 +593,15 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } + if (!dev->using_pd) { + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, + "Could not register PCM: %d\n", ret); + return ret; + } + } + return 0; err_clk_disable: @@ -463,6 +628,9 @@ static struct platform_driver dw_i2s_driver = { .driver = { .name = "designware-i2s", .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = dw_i2s_of_match, +#endif }, }; -- cgit v1.2.3 From d3072fa863cef08e37eea5524f1e7fe41d6ec5e1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 3 Oct 2014 09:29:01 +0100 Subject: ASoC: dwc: Ensure FIFOs are flushed to prevent channel swap If the FIFOs aren't flushed, the left/right channels may be swapped: this may occur if the FIFOs are not empty when the streams start. Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 0923b79c093f..e9a7667ea49a 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -259,6 +259,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, */ do { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TXFFR, 1); i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution); i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); @@ -266,6 +267,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); } else { + i2s_write_reg(dev->i2s_base, RXFFR, 1); i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution); i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); -- cgit v1.2.3 From 7934a7e615a0b373f52c3a2c85f9425445cfa940 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 8 Oct 2013 15:07:59 +0200 Subject: ASoC: dmaengine-pcm: Add support for querying DMA capabilities Currently each platform making use the the generic dmaengine PCM driver still needs to provide a custom snd_pcm_hardware struct which specifies the capabilities of the DMA controller, e.g. the maximum period size that can be supported. This patch adds code which uses the newly introduced dma_get_slave_caps() API to query this information from the dmaengine driver. The new code path will only be taken if the 'pcm_hardware' field of the snd_dmaengine_pcm_config struct is NULL. The patch also introduces a new 'fifo_size' field to the snd_dmaengine_dai_dma_data struct which is used to initialize the snd_pcm_hardware 'fifo_size' field and needs to be set by the DAI driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown (cherry picked from commit c0de42bf595238e9dd593405ebc2992cc8470732) Signed-off-by: Jon Medhurst --- include/sound/dmaengine_pcm.h | 2 ++ sound/soc/soc-generic-dmaengine-pcm.c | 55 ++++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f11c35cd5532..83b2c3e95a1a 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -61,6 +61,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. + * @fifo_size: FIFO size of the DAI controller in bytes */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; @@ -68,6 +69,7 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; + unsigned int fifo_size; }; void snd_dmaengine_pcm_set_config_from_dai_data( diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index e29ec3cd84b1..c39e19e84c8a 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -36,6 +36,15 @@ static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) return container_of(p, struct dmaengine_pcm, platform); } +static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, + struct snd_pcm_substream *substream) +{ + if (!pcm->chan[substream->stream]) + return NULL; + + return pcm->chan[substream->stream]->device->dev; +} + /** * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback * @substream: PCM substream @@ -92,28 +101,54 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int dmaengine_pcm_open(struct snd_pcm_substream *substream) +static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + 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; int ret; - ret = snd_soc_set_runtime_hwparams(substream, + if (pcm->config->pcm_hardware) + return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); - if (ret) - return ret; - return snd_dmaengine_pcm_open(substream, chan); + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + memset(&hw, 0, sizeof(hw)); + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = UINT_MAX; + hw.period_bytes_min = 256; + hw.period_bytes_max = dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = SIZE_MAX; + hw.fifo_size = dma_data->fifo_size; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause) + hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + } + + return snd_soc_set_runtime_hwparams(substream, &hw); } -static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, - struct snd_pcm_substream *substream) +static int dmaengine_pcm_open(struct snd_pcm_substream *substream) { - if (!pcm->chan[substream->stream]) - return NULL; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct dma_chan *chan = pcm->chan[substream->stream]; + int ret; - return pcm->chan[substream->stream]->device->dev; + ret = dmaengine_pcm_set_runtime_hwparams(substream); + if (ret) + return ret; + + return snd_dmaengine_pcm_open(substream, chan); } static void dmaengine_pcm_free(struct snd_pcm *pcm) -- cgit v1.2.3 From 66a0181dfd59bfe8a88731104817c8b7c497a1b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 8 Oct 2013 15:08:00 +0200 Subject: ASoC: dmaengine-pcm: Provide default config This patch adds some default settings for the generic dmaengine PCM driver for the case that no config has been supplied. The following defaults are used: * Use snd_dmaengine_pcm_prepare_slave_config for preparing the DMA slave config. * 512kB for the prealloc buffer size. This value has been chosen based on 'feels about right' and is not backed up by any scientific facts. We may need to come up with something smarter in the future but it should work fine for now. With this infrastructure in place we can finally write DAI drivers which are independent of the DMA controller they are connected to. This is e.g. useful if the DAI IP core is reused across different SoCs, but the SoCs uses different DMA controllers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown (cherry picked from commit fa654e085300e9c222ef931bc0702a9df2542666) Signed-off-by: Jon Medhurst --- sound/soc/soc-generic-dmaengine-pcm.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index c39e19e84c8a..99f9495c1c40 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -84,12 +84,19 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + int (*prepare_slave_config)(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config); struct dma_slave_config slave_config; int ret; - if (pcm->config->prepare_slave_config) { - ret = pcm->config->prepare_slave_config(substream, params, - &slave_config); + if (!pcm->config) + prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; + else + prepare_slave_config = pcm->config->prepare_slave_config; + + if (prepare_slave_config) { + ret = prepare_slave_config(substream, params, &slave_config); if (ret) return ret; @@ -112,7 +119,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea struct snd_pcm_hardware hw; int ret; - if (pcm->config->pcm_hardware) + if (pcm->config && pcm->config->pcm_hardware) return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); @@ -177,9 +184,20 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; struct snd_pcm_substream *substream; + size_t prealloc_buffer_size; + size_t max_buffer_size; unsigned int i; int ret; + if (config && config->prealloc_buffer_size) { + prealloc_buffer_size = config->prealloc_buffer_size; + max_buffer_size = config->pcm_hardware->buffer_bytes_max; + } else { + prealloc_buffer_size = 512 * 1024; + max_buffer_size = SIZE_MAX; + } + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { substream = rtd->pcm->streams[i].substream; if (!substream) @@ -200,8 +218,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) ret = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, dmaengine_dma_dev(pcm, substream), - config->prealloc_buffer_size, - config->pcm_hardware->buffer_bytes_max); + prealloc_buffer_size, + max_buffer_size); if (ret) goto err_free; } -- cgit v1.2.3 From 5b29d3645b1630000740631fc24d99b26d2d8074 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Oct 2013 21:13:19 +0100 Subject: ASoC: dai: Provide interface for setting DMA data at probe time Allow DMA data to be set at probe time for devices that can do that, avoiding the need to do it every time we start a stream and supporting non-DT dmaengine users using the helpers. Signed-off-by: Mark Brown (cherry picked from commit ecfc0c04f236f1e2a95094792ec10cf27be39f7c) Signed-off-by: Jon Medhurst --- include/sound/soc-dai.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ae9a227d35d3..97943fd397cc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -276,6 +276,13 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai, dai->capture_dma_data = data; } +static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, + void *playback, void *capture) +{ + dai->playback_dma_data = playback; + dai->capture_dma_data = capture; +} + static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai, void *data) { -- cgit v1.2.3 From 5b648ee1cf154c7af9b6390490860accd05b74d6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 17:43:51 +0100 Subject: ASoC: dmaengine: Support custom channel names Some devices have more than just simple TX and RX DMA channels, for example modern Samsung I2S IPs support a secondary transmit DMA stream which is mixed into the primary stream during playback. Allow such devices to specify the names of the channels to be requested in their dma_data. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen (cherry picked from commit ea73b7ddf13548afd666373dc5e26ee7c812a3fe) Signed-off-by: Jon Medhurst --- include/sound/dmaengine_pcm.h | 6 ++++++ sound/soc/soc-generic-dmaengine-pcm.c | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 83b2c3e95a1a..15017311f2e9 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -61,6 +61,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. + * @chan_name: Custom channel name to use when requesting DMA channel. * @fifo_size: FIFO size of the DAI controller in bytes */ struct snd_dmaengine_dai_dma_data { @@ -69,6 +70,7 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; + const char *chan_name; unsigned int fifo_size; }; @@ -98,6 +100,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) +/* + * The PCM streams have custom channel names specified. + */ +#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 99f9495c1c40..793cd6c246f6 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -183,6 +183,8 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; + struct device *dev = rtd->platform->dev; + struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -203,6 +205,13 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + if (!pcm->chan[i] && + (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + pcm->chan[i] = dma_request_slave_channel(dev, + dma_data->chan_name); + if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); @@ -275,7 +284,9 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, { unsigned int i; - if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node) + if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | + SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || + !dev->of_node) return; if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { -- cgit v1.2.3 From 90e68583d12351575b2b16a9e0646d97f2e751c4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 19 Oct 2013 21:38:26 +0100 Subject: ASoC: dmaengine: Use filter_data rather than dma_data for compat requests When using the legacy filter function channel requests we currently pass the audio specific struct snd_dmaengine_dai_dma_data which isn't likely to be helpful for actual filtering. Since there's already a field in the structure called filter_data clearly intended for use here convert the driver to use that. All existing users of plain filter functions have been converted to use an explicit compat function to override this behaviour except i.MX which is working around this issue in its filter function and is updated to just use filter_data directly here. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen (cherry picked from commit 90130d2e8f75c7181cef514e8a1491925f386a16) Signed-off-by: Jon Medhurst --- sound/soc/fsl/imx-pcm-dma.c | 4 +--- sound/soc/soc-generic-dmaengine-pcm.c | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index c246fb514930..9e410ecab613 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -24,12 +24,10 @@ static bool filter(struct dma_chan *chan, void *param) { - struct snd_dmaengine_dai_dma_data *dma_data = param; - if (!imx_dma_is_general_purpose(chan)) return false; - chan->private = dma_data->filter_data; + chan->private = param; return true; } diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 793cd6c246f6..0c469cbbe881 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -168,6 +168,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( struct snd_pcm_substream *substream) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct snd_dmaengine_dai_dma_data *dma_data; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0]) return pcm->chan[0]; @@ -176,7 +179,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( return pcm->config->compat_request_channel(rtd, substream); return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn, - snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); + dma_data->filter_data); } static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) -- cgit v1.2.3 From 1cdfac190cedd6b5b64384a442f7a97d1dd665a7 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 6 Oct 2014 15:36:26 +0100 Subject: ASoC: dwc: Add missing include for of.h Signed-off-by: Jon Medhurst --- sound/soc/dwc/designware_i2s.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index e9a7667ea49a..e83a7b359d59 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From bb581905857aba0d5f28d87c0ec4af1e56cbe675 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Oct 2013 22:46:49 -0700 Subject: ASoC: simple-card: un-implemented set_fmt is not error Current simple-card returns error if DAI doesn't support .set_fmt callback. But the error is -ENOTSUPP (= not supported), and it is not error. This patch avoids such case Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit e244bb9bc1883547d44642c99f483c2e57e2a940) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 8c49147db84c..b2fbb7075a6c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -27,6 +27,11 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, if (!ret && daifmt) ret = snd_soc_dai_set_fmt(dai, daifmt); + if (ret == -ENOTSUPP) { + dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n"); + ret = 0; + } + if (!ret && set->sysclk) ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); -- cgit v1.2.3 From 01a75638344a220c601c529da0739147396bc9bb Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 20 Dec 2013 14:39:51 +0800 Subject: ASoC: core: Fix the DAI name getting. From "ASoC: make snd_soc_dai_link more symmetrical", can we see that the name of CPU DAI maybe omitted. If the DAI name is omitted, try to use the component name instead. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit e41975edc73d2c16d0784e5fa87a6162e2fcab80) Signed-off-by: Jon Medhurst --- sound/soc/soc-core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e2ca10345597..c02c721baf79 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4509,10 +4509,14 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, if (id < 0 || id >= pos->num_dai) { ret = -EINVAL; - } else { - *dai_name = pos->dai_drv[id].name; - ret = 0; + break; } + + ret = 0; + + *dai_name = pos->dai_drv[id].name; + if (!*dai_name) + *dai_name = pos->name; } break; -- cgit v1.2.3 From c1050403925500519377ada8ff72c7abdf3059cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 28 Nov 2013 08:50:32 +0100 Subject: ASoC: Add resource managed snd_dmaengine_pcm_register() For many drivers using the generic dmaengine PCM driver one of the few (or the only) things left to do in the drivers remove function is to unregister the PCM device. This patch adds a resource managed version of snd_dmaengine_pcm_register() which makes it possible to simplify the remove function as well as the error path in the probe function for those drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown (cherry picked from commit 21585ee848078b12d0d1a513e93936bf96b444a0) Signed-off-by: Jon Medhurst --- include/sound/dmaengine_pcm.h | 4 ++++ sound/soc/soc-devres.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 15017311f2e9..4ef986cab182 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -140,6 +140,10 @@ int snd_dmaengine_pcm_register(struct device *dev, unsigned int flags); void snd_dmaengine_pcm_unregister(struct device *dev); +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, + unsigned int flags); + int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index b1d732255c02..999861942d28 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -12,6 +12,7 @@ #include #include #include +#include static void devm_component_release(struct device *dev, void *res) { @@ -84,3 +85,43 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) return ret; } EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); + +#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM + +static void devm_dmaengine_pcm_release(struct device *dev, void *res) +{ + snd_dmaengine_pcm_unregister(*(struct device **)res); +} + +/** + * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration + * @dev: The parent device for the PCM device + * @config: Platform specific PCM configuration + * @flags: Platform specific quirks + * + * Register a dmaengine based PCM device with automatic unregistration when the + * device is unregistered. + */ +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, unsigned int flags) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_dmaengine_pcm_register(dev, config, flags); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register); + +#endif -- cgit v1.2.3 From 2e472ceac1d894c4cc8840999689ac3d3893cd83 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Nov 2013 15:25:02 +0900 Subject: ASoC: simple-card: add Device Tree support Support for loading the simple-card module via DeviceTree. It requests CPU/CODEC information. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit fa558c2801fc173758c742d836f3cc4621851557) Signed-off-by: Jon Medhurst --- .../devicetree/bindings/sound/simple-card.txt | 68 +++++++++ sound/soc/generic/simple-card.c | 156 ++++++++++++++++++++- 2 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 000000000000..769a346f890c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,68 @@ +Simple-Card: + +Simple-Card specifies audio DAI connection of SoC <-> codec. + +Required properties: + +- compatible : "simple-audio-card" + +Optional properties: + +- simple-audio-card,format : CPU/CODEC common audio format. + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +Required subnodes: + +- simple-audio-card,cpu : CPU sub-node +- simple-audio-card,codec : CODEC sub-node + +Required CPU/CODEC subnodes properties: + +- sound-dai : phandle and port of CPU/CODEC + +Optional CPU/CODEC subnodes properties: + +- format : CPU/CODEC specific audio format if needed. + see simple-audio-card,format +- frame-master : bool property. add this if subnode is frame master +- bitclock-master : bool property. add this if subnode is bitclock master +- bitclock-inversion : bool property. add this if subnode has clock inversion +- frame-inversion : bool property. add this if subnode has frame inversion +- clocks / system-clock-frequency : specify subnode's clock if needed. + it can be specified via "clocks" if system has + clock node (= common clock), or "system-clock-frequency" + (if system doens't support common clock) + +Example: + +sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "left_j"; + + simple-audio-card,cpu { + sound-dai = <&sh_fsi2 0>; + }; + + simple-audio-card,codec { + sound-dai = <&ak4648>; + bitclock-master; + frame-master; + clocks = <&osc>; + }; +}; + +&i2c0 { + ak4648: ak4648@12 { + #sound-dai-cells = <0>; + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@ec230000 { + #sound-dai-cells = <1>; + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b2fbb7075a6c..7a9b6b4898c0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -8,7 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include +#include #include #include #include @@ -57,11 +58,144 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int +asoc_simple_card_sub_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + struct device_node **node) +{ + struct clk *clk; + int ret; + + /* + * get node via "sound-dai = <&phandle port>" + * it will be used as xxx_of_node on soc_bind_dai_link() + */ + *node = of_parse_phandle(np, "sound-dai", 0); + if (!*node) + return -ENODEV; + + /* get dai->name */ + ret = snd_soc_of_get_dai_name(np, &dai->name); + if (ret < 0) + goto parse_error; + + /* + * bitclock-inversion, frame-inversion + * bitclock-master, frame-master + * and specific "format" if it has + */ + dai->fmt = snd_soc_of_parse_daifmt(np, NULL); + + /* + * dai->sysclk come from + * "clocks = <&xxx>" (if system has common clock) + * or "system-clock-frequency = " + */ + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) + of_property_read_u32(np, + "system-clock-frequency", + &dai->sysclk); + else + dai->sysclk = clk_get_rate(clk); + + ret = 0; + +parse_error: + of_node_put(*node); + + return ret; +} + +static int asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct device_node *np; + char *name; + int ret = 0; + + /* get CPU/CODEC common format via simple-audio-card,format */ + info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + /* CPU sub-node */ + ret = -EINVAL; + np = of_get_child_by_name(node, "simple-audio-card,cpu"); + if (np) + ret = asoc_simple_card_sub_parse_of(np, + &info->cpu_dai, + of_cpu); + if (ret < 0) + return ret; + + /* CODEC sub-node */ + ret = -EINVAL; + np = of_get_child_by_name(node, "simple-audio-card,codec"); + if (np) + ret = asoc_simple_card_sub_parse_of(np, + &info->codec_dai, + of_codec); + if (ret < 0) + return ret; + + /* card name is created from CPU/CODEC dai name */ + name = devm_kzalloc(dev, + strlen(info->cpu_dai.name) + + strlen(info->codec_dai.name) + 2, + GFP_KERNEL); + sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name); + info->name = info->card = name; + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x\n", info->daifmt); + dev_dbg(dev, "cpu : %s / %04x / %d\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk); + dev_dbg(dev, "codec : %s / %04x / %d\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk); + + return 0; +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev; + cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) { + int ret; + ret = asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + return ret; + } + } + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -69,10 +203,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -86,6 +220,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init; /* @@ -107,10 +244,17 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); } +static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio-card", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .owner = THIS_MODULE, + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove, -- cgit v1.2.3 From 67222eb537e1adbddcdef2d7ced79544884cc04f Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 20 Dec 2013 14:39:50 +0800 Subject: ASoC: simple-card: Add cpu_dai and codec_dai names NULL check The name of cpu DAI maybe omitted, and then strlen() will lead kernel panic. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit dd41e0c4e35abc5a5679762ab108a6fcd9a0ead9) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 7a9b6b4898c0..be7c1db5388f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -142,6 +142,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (ret < 0) return ret; + if (!info->cpu_dai.name || !info->codec_dai.name) + return -EINVAL; + /* card name is created from CPU/CODEC dai name */ name = devm_kzalloc(dev, strlen(info->cpu_dai.name) + -- cgit v1.2.3 From c30c41fae71337844f022c22c4a07bca10047260 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 19 Dec 2013 11:59:54 +0800 Subject: ASoC: simple-card: Use devm_snd_soc_register_card() Makes the code slightly shorter. Signed-off-by: Xiubo Li Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit e1acb40a3addc9aceb4600f04c9c86b50770b9b8) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index be7c1db5388f..1d87db823a51 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -237,14 +237,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_card.num_links = 1; cinfo->snd_card.dev = &pdev->dev; - return snd_soc_register_card(&cinfo->snd_card); -} - -static int asoc_simple_card_remove(struct platform_device *pdev) -{ - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; - - return snd_soc_unregister_card(&cinfo->snd_card); + return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card); } static const struct of_device_id asoc_simple_of_match[] = { @@ -260,7 +253,6 @@ static struct platform_driver asoc_simple_card = { .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, }; module_platform_driver(asoc_simple_card); -- cgit v1.2.3 From 98cd2b063020123f19b14884f4a67ed5f1146699 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 23 Dec 2013 12:57:01 +0800 Subject: ASoC: simple-card: Add DAPM routes parse from device tree Parses a simple DAPM route table from device tree. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit d4c22094b256a7327346738721b89a78d4680b08) Signed-off-by: Jon Medhurst --- Documentation/devicetree/bindings/sound/simple-card.txt | 13 +++++++++++-- sound/soc/generic/simple-card.c | 11 +++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 769a346f890c..2ee80c76ca64 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -9,8 +9,13 @@ Required properties: Optional properties: - simple-audio-card,format : CPU/CODEC common audio format. - "i2s", "right_j", "left_j" , "dsp_a" - "dsp_b", "ac97", "pdm", "msb", "lsb" + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +- simple-audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. + Required subnodes: - simple-audio-card,cpu : CPU sub-node @@ -38,6 +43,10 @@ Example: sound { compatible = "simple-audio-card"; simple-audio-card,format = "left_j"; + simple-audio-routing = + "MIC_IN", "Mic Jack", + "Headphone Jack", "HP_OUT", + "Ext Spk", "LINE_OUT"; simple-audio-card,cpu { sound-dai = <&sh_fsi2 0>; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 1d87db823a51..643c9edd47b0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -116,12 +116,18 @@ static int asoc_simple_card_parse_of(struct device_node *node, { struct device_node *np; char *name; - int ret = 0; + int ret; /* get CPU/CODEC common format via simple-audio-card,format */ info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + /* DAPM routes */ + ret = snd_soc_of_parse_audio_routing(&info->snd_card, + "simple-audio-routing"); + if (ret) + return ret; + /* CPU sub-node */ ret = -EINVAL; np = of_get_child_by_name(node, "simple-audio-card,cpu"); @@ -185,6 +191,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); if (cinfo) { int ret; + cinfo->snd_card.dev = &pdev->dev; ret = asoc_simple_card_parse_of(np, cinfo, dev, &of_cpu, &of_codec, @@ -196,6 +203,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } } } else { + cinfo->snd_card.dev = &pdev->dev; cinfo = pdev->dev.platform_data; } @@ -235,7 +243,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_card.owner = THIS_MODULE; cinfo->snd_card.dai_link = &cinfo->snd_link; cinfo->snd_card.num_links = 1; - cinfo->snd_card.dev = &pdev->dev; return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card); } -- cgit v1.2.3 From d4548d1e8187dd659c23049f0faa8d8cc6b09988 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 23 Dec 2013 13:24:59 +0800 Subject: ASoC: simple-card: Cleanup __asoc_simple_card_dai_init() ret check The ret parameter is always equal to zero till here. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit e874ddead38996ec40c6a6be2347a69fac520126) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 643c9edd47b0..6ce9745bf847 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -25,7 +25,7 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, daifmt |= set->fmt; - if (!ret && daifmt) + if (daifmt) ret = snd_soc_dai_set_fmt(dai, daifmt); if (ret == -ENOTSUPP) { -- cgit v1.2.3 From 6b3a8b3310115d434dd3a08448af1a9875b18799 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 23 Dec 2013 15:25:38 +0800 Subject: ASoC: simple-card: Add device's module clock selection. Try to get the device's module clock if the dt has no clocks and system-clock-frequency properties. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit 71467e46414d3bab220de77d3d085be0c0aa03e1) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6ce9745bf847..c0d928138c88 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -90,14 +90,29 @@ asoc_simple_card_sub_parse_of(struct device_node *np, * dai->sysclk come from * "clocks = <&xxx>" (if system has common clock) * or "system-clock-frequency = " + * or device's module clock. */ - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) + if (of_property_read_bool(np, "clocks")) { + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto parse_error; + } + + dai->sysclk = clk_get_rate(clk); + } else if (of_property_read_bool(np, "system-clock-frequency")) { of_property_read_u32(np, "system-clock-frequency", &dai->sysclk); - else + } else { + clk = of_clk_get(*node, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto parse_error; + } + dai->sysclk = clk_get_rate(clk); + } ret = 0; -- cgit v1.2.3 From 8d54389ff5a97ceec2472c792426c239157f43d2 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 19 Nov 2013 14:12:25 +0200 Subject: ASoC: hdmi-codec: Add SNDRV_PCM_FMTBIT_32_LE playback format The new playback format is needed for tda998x HDMI audio support. At the moment the only other user of this codec is omap-hdmi-audio. This change should not break anything because omap-hdmi-audio-dai, the cpu-dai of omap-hdmi-audio, enforces sufficient constraints to available sample formats. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown (cherry picked from commit c600e95360dac3a3b88f0a2106214dff8e5f56be) Signed-off-by: Jon Medhurst --- sound/soc/codecs/hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 68342b121c96..32797a8e4ee9 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -44,7 +44,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { .stream_name = "Capture", -- cgit v1.2.3 From cafa79a25083aaeb31de44005ab42cf973d060e1 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 20 Dec 2013 12:40:16 +0200 Subject: ASoC: hdmi-codec: Add devicetree binding with documentation Signed-off-by: Jyri Sarha cc: bcousson@baylibre.com Signed-off-by: Mark Brown (cherry picked from commit 0f7f3d1f17c2e4d73e449e6acb2007b13813c58e) Signed-off-by: Jon Medhurst --- Documentation/devicetree/bindings/sound/hdmi.txt | 17 +++++++++++++++++ sound/soc/codecs/hdmi.c | 10 ++++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/hdmi.txt diff --git a/Documentation/devicetree/bindings/sound/hdmi.txt b/Documentation/devicetree/bindings/sound/hdmi.txt new file mode 100644 index 000000000000..31af7bca3099 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/hdmi.txt @@ -0,0 +1,17 @@ +Device-Tree bindings for dummy HDMI codec + +Required properties: + - compatible: should be "linux,hdmi-audio". + +CODEC output pins: + * TX + +CODEC input pins: + * RX + +Example node: + + hdmi_audio: hdmi_audio@0 { + compatible = "linux,hdmi-audio"; + status = "okay"; + }; diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 32797a8e4ee9..9cb1c7d3e1dc 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -20,6 +20,7 @@ */ #include #include +#include #define DRV_NAME "hdmi-audio-codec" @@ -60,6 +61,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { }; +#ifdef CONFIG_OF +static const struct of_device_id hdmi_audio_codec_ids[] = { + { .compatible = "linux,hdmi-audio", }, + { } +}; +MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids); +#endif + static struct snd_soc_codec_driver hdmi_codec = { .dapm_widgets = hdmi_widgets, .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), @@ -83,6 +92,7 @@ static struct platform_driver hdmi_codec_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(hdmi_audio_codec_ids), }, .probe = hdmi_codec_probe, -- cgit v1.2.3 From 8be12663c639a43d2d8a91d1eda0a6605fd1c80d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Jan 2014 19:04:19 +0000 Subject: ASoC: core: Return -ENOTSUPP from set_sysclk() if no operation provided Make it easier for generic code to work with set_sysclk() by distinguishing between the operation not being supported and an error as is done for other operations like set_dai_fmt() Signed-off-by: Mark Brown (cherry picked from commit 1104a9c822f0e9f5e57a236f20a142166dd8f91e) Signed-off-by: Jon Medhurst --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c02c721baf79..1f0f4a7c5657 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3372,7 +3372,7 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0, freq, dir); else - return -EINVAL; + return -ENOTSUPP; } EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); @@ -3393,7 +3393,7 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, return codec->driver->set_sysclk(codec, clk_id, source, freq, dir); else - return -EINVAL; + return -ENOTSUPP; } EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk); -- cgit v1.2.3 From e56de6be9d5845e1bb02c80270a442c8972b3f60 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Jan 2014 14:02:18 +0100 Subject: ASoC: generic-dmaengine-pcm: Check NO_RESIDUE flag at runtime Currently we have two different snd_soc_platform_driver structs in the generic dmaengine PCM driver. One for dmaengine drivers that support residue reporting and one for those which do not. When registering the PCM component we check whether the NO_RESIDUE flag is set or not and use the corresponding snd_soc_platform_driver. This patch modifies the driver to only have one snd_soc_platform_driver struct where the pointer() callback checks the NO_RESIDUE flag at runtime. This allows us to set the NO_RESIDUE flag after the PCM component has been registered. This becomes necessary when querying whether the dmaengine driver supports residue reporting from the dmaengine driver itself since the DMA channel might only be requested after the PCM component has been registered. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown (cherry picked from commit 93b943edfc5e439f7b843535e0bb0f7d2371f67f) Signed-off-by: Jon Medhurst --- sound/soc/soc-generic-dmaengine-pcm.c | 39 ++++++++++++++--------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 0c469cbbe881..60f8163b0e6c 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -243,6 +243,18 @@ err_free: return ret; } +static snd_pcm_uframes_t dmaengine_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) + return snd_dmaengine_pcm_pointer_no_residue(substream); + else + return snd_dmaengine_pcm_pointer(substream); +} + static const struct snd_pcm_ops dmaengine_pcm_ops = { .open = dmaengine_pcm_open, .close = snd_dmaengine_pcm_close, @@ -250,7 +262,7 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { .hw_params = dmaengine_pcm_hw_params, .hw_free = snd_pcm_lib_free_pages, .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer, + .pointer = dmaengine_pcm_pointer, }; static const struct snd_soc_platform_driver dmaengine_pcm_platform = { @@ -260,23 +272,6 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = { .probe_order = SND_SOC_COMP_ORDER_LATE, }; -static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = { - .open = dmaengine_pcm_open, - .close = snd_dmaengine_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = dmaengine_pcm_hw_params, - .hw_free = snd_pcm_lib_free_pages, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer_no_residue, -}; - -static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = { - .ops = &dmaengine_no_residue_pcm_ops, - .pcm_new = dmaengine_pcm_new, - .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, -}; - static const char * const dmaengine_pcm_dma_channel_names[] = { [SNDRV_PCM_STREAM_PLAYBACK] = "tx", [SNDRV_PCM_STREAM_CAPTURE] = "rx", @@ -323,12 +318,8 @@ int snd_dmaengine_pcm_register(struct device *dev, dmaengine_pcm_request_chan_of(pcm, dev); - if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) - return snd_soc_add_platform(dev, &pcm->platform, - &dmaengine_no_residue_pcm_platform); - else - return snd_soc_add_platform(dev, &pcm->platform, - &dmaengine_pcm_platform); + return snd_soc_add_platform(dev, &pcm->platform, + &dmaengine_pcm_platform); } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register); -- cgit v1.2.3 From a942da4393e177da5d6ef77c3259f2b05bac9e3d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Jan 2014 14:02:19 +0100 Subject: ASoC: generic-dmaengine-pcm: Check DMA residue granularity The dmaengine framework now exposes the granularity with which it is able to report the transfer residue for a certain DMA channel. Check the granularity in the generic dmaengine PCM driver and a) Set the SNDRV_PCM_INFO_BATCH if the granularity is per period or worse. b) Fallback to the (race condition prone) period counting if the driver does not support any residue reporting. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown (cherry picked from commit 478028e088d6a94666d8a776be2cd2291faf3bbd) Signed-off-by: Jon Medhurst --- sound/soc/soc-generic-dmaengine-pcm.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 60f8163b0e6c..36f6f1b67fab 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -139,6 +139,8 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea if (ret == 0) { if (dma_caps.cmd_pause) 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; } return snd_soc_set_runtime_hwparams(substream, &hw); @@ -182,6 +184,21 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( dma_data->filter_data); } +static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan) +{ + struct dma_slave_caps dma_caps; + int ret; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret != 0) + return true; + + if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) + return false; + + return true; +} + static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); @@ -234,6 +251,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) max_buffer_size); if (ret) goto err_free; + + /* + * This will only return false if we know for sure that at least + * one channel does not support residue reporting. If the DMA + * driver does not implement the slave_caps API we rely having + * the NO_RESIDUE flag set manually in case residue reporting is + * not supported. + */ + if (!dmaengine_pcm_can_report_residue(pcm->chan[i])) + pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; } return 0; -- cgit v1.2.3 From 2a7b6b0e8d38b1f5911607aa7cd712f985df7390 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 6 Jan 2014 12:34:36 +0800 Subject: ASoC: simple-card: Fix the sysclk selection. For spdif there is no need to do the sysclk setting. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit e2a19ac6c5b27ac93fe744c0ff0823cde52c9cbb) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index c0d928138c88..670dbbe9054c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -106,12 +106,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np, &dai->sysclk); } else { clk = of_clk_get(*node, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto parse_error; - } - - dai->sysclk = clk_get_rate(clk); + if (!IS_ERR(clk)) + dai->sysclk = clk_get_rate(clk); } ret = 0; -- cgit v1.2.3 From f964fca02180dcadc525962733afad6ada94a2e3 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 7 Jan 2014 09:13:42 +0800 Subject: ASoC: simple-card: fix the DAPM routes map parsing The simple-card's DAPM route maping is optional. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit f87a3e825cb0f7d4d51556ece147f1a6299ac1af) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 670dbbe9054c..5addb1accc6a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -134,10 +134,12 @@ static int asoc_simple_card_parse_of(struct device_node *node, (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); /* DAPM routes */ - ret = snd_soc_of_parse_audio_routing(&info->snd_card, + if (of_property_read_bool(node, "simple-audio-routing")) { + ret = snd_soc_of_parse_audio_routing(&info->snd_card, "simple-audio-routing"); - if (ret) - return ret; + if (ret) + return ret; + } /* CPU sub-node */ ret = -EINVAL; -- cgit v1.2.3 From 6e60dba276b216e9c540b82ad57681cc85460d91 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 7 Jan 2014 09:15:16 +0800 Subject: ASoC: simple-card: keep the property's name the same pattern Even though we might not have rigor rule for the simple card property names, according to the existing ones, they are all in a same pattern: [simple-audio-card,]XXX; Rename simple-audio-routing to simple-audio-card,routing, and make the simple card's properties has one unified name. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit 8c0b8230b2d9708eed5b50f9f8442aaa879a3c57) Signed-off-by: Jon Medhurst --- Documentation/devicetree/bindings/sound/simple-card.txt | 2 +- sound/soc/generic/simple-card.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 2ee80c76ca64..e9e20ec67d62 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -11,7 +11,7 @@ Optional properties: - simple-audio-card,format : CPU/CODEC common audio format. "i2s", "right_j", "left_j" , "dsp_a" "dsp_b", "ac97", "pdm", "msb", "lsb" -- simple-audio-routing : A list of the connections between audio components. +- simple-audio-card,routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, the second being the connection's source. diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 5addb1accc6a..e473dc9537e5 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -134,9 +134,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); /* DAPM routes */ - if (of_property_read_bool(node, "simple-audio-routing")) { + if (of_property_read_bool(node, "simple-audio-card,routing")) { ret = snd_soc_of_parse_audio_routing(&info->snd_card, - "simple-audio-routing"); + "simple-audio-card,routing"); if (ret) return ret; } -- cgit v1.2.3 From 5f68060f2e739d4e8396896fdb07fd3ec877d330 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 9 Jan 2014 17:19:08 +0800 Subject: ASoC: simple-card: fix a bug where cinfo will be NULL before using it If the dt is not used, the cinfo will be always NULL before using it. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit 708ec0241c56b85176937e79314430f4f71e40c6) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e473dc9537e5..ea278470acf3 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -216,8 +216,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } } } else { - cinfo->snd_card.dev = &pdev->dev; cinfo = pdev->dev.platform_data; + cinfo->snd_card.dev = &pdev->dev; } if (!cinfo) { -- cgit v1.2.3 From ecf633b9bda0b7335e033dbd6e2fd6711d86b2db Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 9 Jan 2014 17:49:40 +0800 Subject: ASoC: simple-card: fix the cinfo error check If the dt is used and the cinfo is NULL, the -ENOMEM should be return. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit 34787d0a258ebb3686676fb37a9e8717cbdd835a) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index ea278470acf3..b7dc63ed28c4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -214,15 +214,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dev_err(dev, "parse error %d\n", ret); return ret; } + } else { + return -ENOMEM; } } else { cinfo = pdev->dev.platform_data; - cinfo->snd_card.dev = &pdev->dev; - } + if (!cinfo) { + dev_err(dev, "no info for asoc-simple-card\n"); + return -EINVAL; + } - if (!cinfo) { - dev_err(dev, "no info for asoc-simple-card\n"); - return -EINVAL; + cinfo->snd_card.dev = &pdev->dev; } if (!cinfo->name || -- cgit v1.2.3 From 730201cbd00375b881f5e8b053db22b641ade786 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 13 Jan 2014 17:08:08 +0800 Subject: ASoC: simple-card: use snd_soc_card_set/get_drvdata Remove asoc_simple_get_card_info macro and use snd_soc_card_set_drvdata and snd_soc_card_get_drvdata instead. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit ba194a4de5c81ee200b6af88743b26f7b69aa659) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b7dc63ed28c4..79dcac778d67 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -14,9 +14,6 @@ #include #include -#define asoc_simple_get_card_info(p) \ - container_of(p->dai_link, struct asoc_simple_card_info, snd_link) - static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, struct asoc_simple_dai *set, unsigned int daifmt) @@ -41,7 +38,8 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd); + struct asoc_simple_card_info *info = + snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; unsigned int daifmt = info->daifmt; @@ -259,6 +257,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_card.dai_link = &cinfo->snd_link; cinfo->snd_card.num_links = 1; + snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo); + return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card); } -- cgit v1.2.3 From c0c1f5d198de721a77186c5b9aaf2a2f851bc155 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 14 Jan 2014 12:35:32 +0800 Subject: ASoC: simple-card: fix one bug to writing to the platform data It's a bug that writing to the platform data directly, for it should be constant. So just copy it before writing. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit ca919fe4b972b9428ab42bead11b04a4ebf0f632) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 79dcac778d67..2a1b1b5b5221 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,9 +9,10 @@ * published by the Free Software Foundation. */ #include +#include #include #include -#include +#include #include static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, @@ -193,36 +194,37 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev; + int ret; cinfo = NULL; of_cpu = NULL; of_codec = NULL; of_platform = NULL; + + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + if (np && of_device_is_available(np)) { - cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); - if (cinfo) { - int ret; - cinfo->snd_card.dev = &pdev->dev; - ret = asoc_simple_card_parse_of(np, cinfo, dev, - &of_cpu, - &of_codec, - &of_platform); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - return ret; - } - } else { - return -ENOMEM; + cinfo->snd_card.dev = dev; + + ret = asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + return ret; } } else { - cinfo = pdev->dev.platform_data; - if (!cinfo) { + if (!dev->platform_data) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; } - cinfo->snd_card.dev = &pdev->dev; + memcpy(cinfo, dev->platform_data, sizeof(*cinfo)); + cinfo->snd_card.dev = dev; } if (!cinfo->name || -- cgit v1.2.3 From f08b3dcc99a73d1b11f498f6eb9f8ba2a049d8b0 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 24 Jan 2014 15:43:00 +0800 Subject: ASoC: simple-card: fix __asoc_simple_card_dai_init If the CPU/CODEC DAI set_sysclk() is not support, the -ENOTSUPP will returnd. Here do the check like set_fmt(). Signed-off-by: Xiubo Li Signed-off-by: Mark Brown (cherry picked from commit 4763ebe226156db985fe75bfe930c4069d1f4207) Signed-off-by: Jon Medhurst --- sound/soc/generic/simple-card.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2a1b1b5b5221..b193265cf47a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -19,21 +19,29 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, struct asoc_simple_dai *set, unsigned int daifmt) { - int ret = 0; + int ret; daifmt |= set->fmt; - if (daifmt) + if (daifmt) { ret = snd_soc_dai_set_fmt(dai, daifmt); - - if (ret == -ENOTSUPP) { - dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n"); - ret = 0; + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "simple-card: set_fmt error\n"); + goto err; + } } - if (!ret && set->sysclk) + if (set->sysclk) { ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "simple-card: set_sysclk error\n"); + goto err; + } + } + + ret = 0; +err: return ret; } -- cgit v1.2.3 From 2a076955d1cbf04018767dd343492c02f0fca574 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 29 Aug 2014 16:00:29 +0100 Subject: Juno: Add I2S and TDA998x audio CODEC support. Signed-off-by: Andrew Jackson Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/juno.dts | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/juno.dts b/arch/arm64/boot/dts/juno.dts index b8baba186b1e..4ca32bf78374 100644 --- a/arch/arm64/boot/dts/juno.dts +++ b/arch/arm64/boot/dts/juno.dts @@ -142,7 +142,14 @@ /include/ "juno-clocks.dtsi" - dma@7ff00000 { + soc_i2sclk: clki2s { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2116800>; + clock-output-names = "i2sclk"; + }; + + dma0: dma@7ff00000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x0 0x7ff00000 0 0x1000>; #dma-cells = <1>; @@ -181,11 +188,17 @@ dvi0: dvi-transmitter@70 { compatible = "nxp,tda998x"; reg = <0x70>; + audio-ports = <0x03>, <0x04>; + audio-port-names = "i2s", "spdif"; + #sound-dai-cells = <1>; }; dvi1: dvi-transmitter@71 { compatible = "nxp,tda998x"; reg = <0x71>; + audio-ports = <0x03>, <0x04>; + audio-port-names = "i2s", "spdif"; + #sound-dai-cells = <1>; }; }; @@ -226,6 +239,37 @@ interrupt-names = "JOB", "MMU", "GPU"; }; + soc_i2s: i2s@7ff90000 { + compatible = "snps,i2s"; + reg = <0x0 0x7ff90000 0x0 0x1000>; + clocks = <&audio_clk 0>, <&soc_refclk100mhz>; + clock-names = "i2sclk", "apb_pclk"; + #sound-dai-cells = <0>; + dmas = <&dma0 5>; + dma-names = "tx"; + }; + + hdmi_audio: hdmi_audio@0 { + compatible = "linux,hdmi-audio"; + #sound-dai-cells = <0>; + status = "okay"; + }; + + sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "i2s"; + + simple-audio-card,cpu { + sound-dai = <&soc_i2s>; + }; + + simple-audio-card,codec { + sound-dai = <&dvi0 0>; + }; + + }; + smb { compatible = "simple-bus"; #address-cells = <2>; -- cgit v1.2.3 From 872bca20c960a1f145442d1ffbf15f55a996d85f Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 6 Oct 2014 13:49:05 +0100 Subject: juno: Add sound configs Signed-off-by: Jon Medhurst --- linaro/configs/vexpress64.conf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/linaro/configs/vexpress64.conf b/linaro/configs/vexpress64.conf index c9b66a198586..fc368ad830c1 100644 --- a/linaro/configs/vexpress64.conf +++ b/linaro/configs/vexpress64.conf @@ -53,3 +53,16 @@ CONFIG_ARM_BIG_LITTLE_CPUFREQ=y CONFIG_ARM_DT_BL_CPUFREQ=y CONFIG_ARM64_CPUIDLE=y CONFIG_ARM64_CRYPTO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SEQUENCER=y +CONFIG_SND_SEQ_DUMMY=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_DESIGNWARE_I2S=y +CONFIG_SND_SOC_HDMI_CODEC=y +CONFIG_SND_SOC_SPDIF=y +CONFIG_SND_SIMPLE_CARD=y -- cgit v1.2.3 From 90a59173ce59c546009067399c7c42df29d58730 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 6 Oct 2014 16:25:40 +0100 Subject: juno: Enable CONFIG_SND_SOC_ALL_CODECS We only want two codecs (SND_SOC_HDMI_CODEC and SND_SOC_SPDIF), unfortunately, codecs aren't individually user selectable which means merge_config.sh won't let us select them. Signed-off-by: Jon Medhurst --- linaro/configs/vexpress64.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/linaro/configs/vexpress64.conf b/linaro/configs/vexpress64.conf index fc368ad830c1..029b6e0baa1f 100644 --- a/linaro/configs/vexpress64.conf +++ b/linaro/configs/vexpress64.conf @@ -63,6 +63,7 @@ CONFIG_SND_SEQUENCER_OSS=y # CONFIG_SND_USB is not set CONFIG_SND_SOC=y CONFIG_SND_DESIGNWARE_I2S=y +CONFIG_SND_SOC_ALL_CODECS=y CONFIG_SND_SOC_HDMI_CODEC=y CONFIG_SND_SOC_SPDIF=y CONFIG_SND_SIMPLE_CARD=y -- cgit v1.2.3