From 648722155dc081b019ab0ef548bbebde760a2b83 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 24 Apr 2014 19:42:00 +0300 Subject: ASoC: simple-card: is_top_level_node parameter to simple_card_dai_link_of() Restore correct parsing of dai-link subnodes with more explicit implementation for applying the "simple-audio-card,"-prefix to dai-link property and subnode names. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 98f97e5..06fe0e2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -144,7 +144,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np, static int simple_card_dai_link_of(struct device_node *node, struct device *dev, struct snd_soc_dai_link *dai_link, - struct simple_dai_props *dai_props) + struct simple_dai_props *dai_props, + bool is_top_level_node) { struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; @@ -155,7 +156,8 @@ static int simple_card_dai_link_of(struct device_node *node, char *prefix = ""; int ret; - prefix = "simple-audio-card,"; + if (is_top_level_node) + prefix = "simple-audio-card,"; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); @@ -307,14 +309,15 @@ static int asoc_simple_card_parse_of(struct device_node *node, for (i = 0; (np = of_get_next_child(node, np)); i++) { dev_dbg(dev, "\tlink %d:\n", i); ret = simple_card_dai_link_of(np, dev, dai_link + i, - dai_props + i); + dai_props + i, false); if (ret < 0) { of_node_put(np); return ret; } } } else { - ret = simple_card_dai_link_of(node, dev, dai_link, dai_props); + ret = simple_card_dai_link_of(node, dev, dai_link, dai_props, + true); if (ret < 0) return ret; } -- cgit v0.10.2 From a6aba536ab60274e8f46ae3a5966b81c35f845fa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 22 May 2014 12:10:52 +0200 Subject: ASoC: samsung: Handle errors when getting the op_clk clock Ensure i2s->op_clk is not used when clk_get() for this clock fails. This prevents working with an incorrectly configured clock in some conditions. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 07ff3e7..043d986 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -488,7 +488,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, clk_id = 1; if (!any_active(i2s)) { - if (i2s->op_clk) { + if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || (!clk_id && (mod & MOD_IMS_SYSMUX))) { clk_disable_unprepare(i2s->op_clk); @@ -506,6 +506,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, else i2s->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk0"); + + if (WARN_ON(IS_ERR(i2s->op_clk))) + return PTR_ERR(i2s->op_clk); + clk_prepare_enable(i2s->op_clk); i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); -- cgit v0.10.2 From b20e53a826a7adc3bfd2772bd49a83b6f21b4cce Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 23 May 2014 02:38:56 -0300 Subject: ASoC: fsl_ssi: Add suspend/resume support Doing a suspend/resume sequence while playing an audio track in the backgroung causes broken audio right after resume: root@freescale /$ aplay clarinet.wav & root@freescale /home$ Playing WAVE 'clarinet.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono root@freescale /home$ echo mem > /sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.002 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done. Suspending console(s) (use no_console_suspend to debug) PM: suspend of devices complete after 37.082 msecs PM: suspend devices took 0.040 seconds PM: late suspend of devices complete after 4.234 msecs PM: noirq suspend of devices complete after 4.618 msecs Disabling non-boot CPUs ... PM: noirq resume of devices complete after 4.013 msecs PM: early resume of devices complete after 4.000 msecs PM: resume of devices complete after 68.907 msecs PM: resume devices took 0.070 seconds Restarting tasks ... Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. Suspended. Trying resume. Failed. Restarting stream. Done. .... Add SNDRV_PCM_TRIGGER_RESUME/SUSPEND cases so that we can gracefully handle system suspend/resume. Signed-off-by: Fabio Estevam Acked-by: Shawn Guo Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e5d8819..ef50425 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -873,6 +873,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fsl_ssi_tx_config(ssi_private, true); @@ -881,6 +882,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fsl_ssi_tx_config(ssi_private, false); -- cgit v0.10.2 From 2c81a10ae6c6aaef68f8b92b4fc8037d1dfe0d9e Mon Sep 17 00:00:00 2001 From: Chen Zhen Date: Thu, 22 May 2014 13:21:43 +0200 Subject: ASoC: max98090: Add NI/MI values for user pclk 19.2 MHz This patch adds the clock divisor and multiplier NI, MI values for audio sampling frequencies 44100 and 48000 Hz and PCLK 19.2 MHz. This is useful for the Odroid X2/U2 boards when the codec works in master mode and its MCLK clock is fed from the I2S CDCLK output. Signed-off-by: Chen Zhen [s.nawrocki@samsung.com: edited the commit description] Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index c88bf82..4ee1f88 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1545,19 +1545,19 @@ static const int lrclk_rates[] = { }; static const int user_pclk_rates[] = { - 13000000, 13000000 + 13000000, 13000000, 19200000, 19200000, }; static const int user_lrclk_rates[] = { - 44100, 48000 + 44100, 48000, 44100, 48000, }; static const unsigned long long ni_value[] = { - 3528, 768 + 3528, 768, 441, 8 }; static const unsigned long long mi_value[] = { - 8125, 1625 + 8125, 1625, 1500, 25 }; static void max98090_configure_bclk(struct snd_soc_codec *codec) -- cgit v0.10.2 From 2942a0e285c46587a1025f12597df63ec04d08c6 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 22 May 2014 17:31:49 +0200 Subject: ASoC: simple-card: Support setting mclk via a fixed factor Some platforms require that the codecs mclk is a fixed multiplication factor of the audio stream rate. Add a optional property to the binding to hold this factor and implement a hw_params() function to make use of it. Signed-off-by: Andrew Lunn Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 9b9df14..c2e9841 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -15,6 +15,9 @@ Optional properties: Each entry is a pair of strings, the first being the connection's sink, the second being the connection's source. +- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec + mclk. + Optional subnodes: - simple-audio-card,dai-link : Container for dai-link level diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 06fe0e2..03a7fdc 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -24,9 +24,32 @@ struct simple_card_data { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; } *dai_props; + unsigned int mclk_fs; struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; +static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + unsigned int mclk; + int ret = 0; + + if (priv->mclk_fs) { + mclk = params_rate(params) * priv->mclk_fs; + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + } + + return ret; +} + +static struct snd_soc_ops asoc_simple_card_ops = { + .hw_params = asoc_simple_card_hw_params, +}; + static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, struct asoc_simple_dai *set) { @@ -251,6 +274,7 @@ static int simple_card_dai_link_of(struct device_node *node, sprintf(name, "%s-%s", dai_link->cpu_dai_name, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; + dai_link->ops = &asoc_simple_card_ops; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %04x / %d\n", @@ -300,6 +324,10 @@ static int asoc_simple_card_parse_of(struct device_node *node, return ret; } + /* Factor to mclk, used in hw_params() */ + of_property_read_u32(node, "simple-audio-card,mclk-fs", + &priv->mclk_fs); + dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? priv->snd_card.name : ""); -- cgit v0.10.2 From 35386320898ec01f922929877a723fe1d4ddf04b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 May 2014 11:43:55 -0700 Subject: ASoC: Intel: avoid format string leak to thread name This makes sure a format string can never get processed into the worker thread name from the device name. Signed-off-by: Kees Cook Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 7c1ec00..18273d2 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -892,7 +892,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) /* start the IPC message thread */ init_kthread_worker(&byt->kworker); byt->tx_thread = kthread_run(kthread_worker_fn, - &byt->kworker, + &byt->kworker, "%s", dev_name(byt->dev)); if (IS_ERR(byt->tx_thread)) { err = PTR_ERR(byt->tx_thread); diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index e7996b3..a8fd60c 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1735,7 +1735,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) /* start the IPC message thread */ init_kthread_worker(&hsw->kworker); hsw->tx_thread = kthread_run(kthread_worker_fn, - &hsw->kworker, + &hsw->kworker, "%s", dev_name(hsw->dev)); if (IS_ERR(hsw->tx_thread)) { ret = PTR_ERR(hsw->tx_thread); -- cgit v0.10.2 From fb6b8e71448aef58628eb9da007c30e731925260 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 22 May 2014 16:14:53 -0600 Subject: ASoC: tegra: free jack GPIOs before the sound card is freed snd_soc_jack_add_gpios() schedules a work queue item to poll the GPIO to generate an initial jack status report. If sound card initialization fails, that work item needs to be cancelled, so it doesn't run after the card has been freed. Specifically, freeing the card calls snd_jack_dev_free() which calls snd_jack_dev_disconnect() which sets jack->input_dev = NULL, and input_dev is used by snd_jack_report(), which is called from the work queue item. snd_soc_jack_free_gpios() cancels the work item. The Tegra ASoC machine drivers do call this function in the platform driver remove() callback. However, this happens after the sound card is freed, at least when the card is freed due to errors late during snd_soc_instantiate_card(). This leaves a window where the work item can execute after the card is freed. In next-20140522, sound card initialization does fail for unrelated reasons, and hits the problem described above. To solve this, fix the Tegra ASoC machine drivers to clean up the Jack GPIOs during the snd_soc_card's .remove() callback, which is executed before the overall card object is freed. also, gGuard the cleanup call based on whether we actually setup up the GPIOs in the first place. Ideally, we'd do the cleanup in a struct snd_soc_dai_link .fini/remove function to match where the GPIOs get set up. However, there is no such callback. This change fixes all Tegra machine drivers. By code inspection, I believe some non-Tegra machine drivers have the same issue. I'll send a patch for that separately, once this is reviewed. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index c61ea3a..02734bd 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -125,6 +125,18 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int tegra_alc5632_card_remove(struct snd_soc_card *card) +{ + struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1, + &tegra_alc5632_hp_jack_gpio); + } + + return 0; +} + static struct snd_soc_dai_link tegra_alc5632_dai = { .name = "ALC5632", .stream_name = "ALC5632 PCM", @@ -139,6 +151,7 @@ static struct snd_soc_dai_link tegra_alc5632_dai = { static struct snd_soc_card snd_soc_tegra_alc5632 = { .name = "tegra-alc5632", .owner = THIS_MODULE, + .remove = tegra_alc5632_card_remove, .dai_link = &tegra_alc5632_dai, .num_links = 1, .controls = tegra_alc5632_controls, @@ -223,9 +236,6 @@ static int tegra_alc5632_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); - snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1, - &tegra_alc5632_hp_jack_gpio); - snd_soc_unregister_card(card); tegra_asoc_utils_fini(&machine->util_data); diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 0283cfb..ce73e1f 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -145,6 +145,18 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int tegra_max98090_card_remove(struct snd_soc_card *card) +{ + struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1, + &tegra_max98090_hp_jack_gpio); + } + + return 0; +} + static struct snd_soc_dai_link tegra_max98090_dai = { .name = "max98090", .stream_name = "max98090 PCM", @@ -158,6 +170,7 @@ static struct snd_soc_dai_link tegra_max98090_dai = { static struct snd_soc_card snd_soc_tegra_max98090 = { .name = "tegra-max98090", .owner = THIS_MODULE, + .remove = tegra_max98090_card_remove, .dai_link = &tegra_max98090_dai, .num_links = 1, .controls = tegra_max98090_controls, @@ -241,9 +254,6 @@ static int tegra_max98090_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); - snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1, - &tegra_max98090_hp_jack_gpio); - snd_soc_unregister_card(card); tegra_asoc_utils_fini(&machine->util_data); diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 4511c5a..4feb16a 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -128,6 +128,18 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int tegra_rt5640_card_remove(struct snd_soc_card *card) +{ + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1, + &tegra_rt5640_hp_jack_gpio); + } + + return 0; +} + static struct snd_soc_dai_link tegra_rt5640_dai = { .name = "RT5640", .stream_name = "RT5640 PCM", @@ -141,6 +153,7 @@ static struct snd_soc_dai_link tegra_rt5640_dai = { static struct snd_soc_card snd_soc_tegra_rt5640 = { .name = "tegra-rt5640", .owner = THIS_MODULE, + .remove = tegra_rt5640_card_remove, .dai_link = &tegra_rt5640_dai, .num_links = 1, .controls = tegra_rt5640_controls, @@ -224,9 +237,6 @@ static int tegra_rt5640_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1, - &tegra_rt5640_hp_jack_gpio); - snd_soc_unregister_card(card); tegra_asoc_utils_fini(&machine->util_data); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 4ac7373..0939661 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -206,6 +206,12 @@ static int tegra_wm8903_remove(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]); struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1, + &tegra_wm8903_hp_jack_gpio); + } wm8903_mic_detect(codec, NULL, 0, 0); @@ -228,9 +234,7 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = { .owner = THIS_MODULE, .dai_link = &tegra_wm8903_dai, .num_links = 1, - .remove = tegra_wm8903_remove, - .controls = tegra_wm8903_controls, .num_controls = ARRAY_SIZE(tegra_wm8903_controls), .dapm_widgets = tegra_wm8903_dapm_widgets, @@ -368,9 +372,6 @@ static int tegra_wm8903_driver_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1, - &tegra_wm8903_hp_jack_gpio); - snd_soc_unregister_card(card); tegra_asoc_utils_fini(&machine->util_data); -- cgit v0.10.2 From f451e48d8e1cae07d55b4a5b558c008cd4dc9a73 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:24:59 -0700 Subject: ASoC: rsnd: DT node clean up by using the of_node_put() Driver needs to call of_node_put() after of_get_chile_by_name() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 7da87cd..61009c4 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -598,18 +598,21 @@ static void rsnd_of_parse_src(struct platform_device *pdev, nr = of_get_child_count(src_node); if (!nr) - return; + goto rsnd_of_parse_src_end; src_info = devm_kzalloc(dev, sizeof(struct rsnd_src_platform_info) * nr, GFP_KERNEL); if (!src_info) { dev_err(dev, "src info allocation error\n"); - return; + goto rsnd_of_parse_src_end; } info->src_info = src_info; info->src_info_nr = nr; + +rsnd_of_parse_src_end: + of_node_put(src_node); } int rsnd_src_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b13edb..ea8d4e7 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -554,14 +554,14 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, nr = of_get_child_count(node); if (!nr) - return; + goto rsnd_of_parse_ssi_end; ssi_info = devm_kzalloc(dev, sizeof(struct rsnd_ssi_platform_info) * nr, GFP_KERNEL); if (!ssi_info) { dev_err(dev, "ssi info allocation error\n"); - return; + goto rsnd_of_parse_ssi_end; } info->ssi_info = ssi_info; @@ -584,6 +584,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, */ ssi_info->pio_irq = irq_of_parse_and_map(np, 0); } + +rsnd_of_parse_ssi_end: + of_node_put(node); } int rsnd_ssi_probe(struct platform_device *pdev, -- cgit v0.10.2 From 9f464f8e076e6fcc8d249e76d84f4fb99c1fecff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:25:30 -0700 Subject: ASoC: rsnd: save platform_device instead of device DT DMA support needs struct platform_device pointer, and it can get struct device pointer from platform_device. Save platform_device instead of device. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1f6981a..073a293 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -957,7 +957,7 @@ static int rsnd_probe(struct platform_device *pdev) return -ENODEV; } - priv->dev = dev; + priv->pdev = pdev; priv->info = info; spin_lock_init(&priv->lock); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5aa7901..344f941 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -317,7 +317,7 @@ struct rsnd_of_data { struct rsnd_priv { - struct device *dev; + struct platform_device *pdev; struct rcar_snd_info *info; spinlock_t lock; @@ -357,7 +357,8 @@ struct rsnd_priv { int rdai_nr; }; -#define rsnd_priv_to_dev(priv) ((priv)->dev) +#define rsnd_priv_to_pdev(priv) ((priv)->pdev) +#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) #define rsnd_priv_to_info(priv) ((priv)->info) #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) -- cgit v0.10.2 From 033e7ed85b8513db4efacbdf0f22db2bed4ff405 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:25:37 -0700 Subject: ASoC: rsnd: remove rsnd_src_non_ops Renesas sound driver is supporting Gen1/Gen2. SRC probe can return error if it was unknown generation. Now, rsnd_src_non_ops is not needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 61009c4..c5ddbcc 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -268,10 +268,6 @@ static int rsnd_src_stop(struct rsnd_mod *mod, return 0; } -static struct rsnd_mod_ops rsnd_src_non_ops = { - .name = "src (non)", -}; - /* * Gen1 functions */ @@ -627,6 +623,16 @@ int rsnd_src_probe(struct platform_device *pdev, char name[RSND_SRC_NAME_SIZE]; int i, nr; + ops = NULL; + if (rsnd_is_gen1(priv)) + ops = &rsnd_src_gen1_ops; + if (rsnd_is_gen2(priv)) + ops = &rsnd_src_gen2_ops; + if (!ops) { + dev_err(dev, "unknown Generation\n"); + return -EIO; + } + rsnd_of_parse_src(pdev, of_data, priv); /* @@ -655,12 +661,6 @@ int rsnd_src_probe(struct platform_device *pdev, src->info = &info->src_info[i]; src->clk = clk; - ops = &rsnd_src_non_ops; - if (rsnd_is_gen1(priv)) - ops = &rsnd_src_gen1_ops; - if (rsnd_is_gen2(priv)) - ops = &rsnd_src_gen2_ops; - rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i); dev_dbg(dev, "SRC%d probed\n", i); -- cgit v0.10.2 From 8aefda5046f417c551e3acdeb2cf37949a4b75e9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:25:43 -0700 Subject: ASoC: rsnd: module name is unified Renesas sound driver uses many modules (= SSI/SRC/DVC), and each module had own name. But, each module name can be used as several purpose, like clock name, DMA name etc... This patch uses common name for each module. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 74769b1..ed00070 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -13,6 +13,9 @@ #define RSND_DVC_NAME_SIZE 16 #define RSND_DVC_VOLUME_MAX 100 #define RSND_DVC_VOLUME_NUM 2 + +#define DVC_NAME "dvc" + struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; @@ -43,6 +46,17 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_VOL1R, vol[1]); } +static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); + + return 0; +} + static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, struct rsnd_dai *rdai) { @@ -208,7 +222,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_dvc_ops = { - .name = "dvc (gen2)", + .name = DVC_NAME, + .probe = rsnd_dvc_probe_gen2, .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, .start = rsnd_dvc_start, @@ -255,7 +270,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, priv->dvc = dvc; for_each_rsnd_dvc(dvc, priv, i) { - snprintf(name, RSND_DVC_NAME_SIZE, "dvc.%d", i); + snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", + DVC_NAME, i); clk = devm_clk_get(dev, name); if (IS_ERR(clk)) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c5ddbcc..4b5671b 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -10,6 +10,8 @@ */ #include "rsnd.h" +#define SRC_NAME "src" + struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; @@ -389,6 +391,17 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, return 0; } +static int rsnd_src_probe_gen1(struct rsnd_mod *mod, + struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod)); + + return 0; +} + static int rsnd_src_init_gen1(struct rsnd_mod *mod, struct rsnd_dai *rdai) { @@ -434,7 +447,8 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_src_gen1_ops = { - .name = "sru (gen1)", + .name = SRC_NAME, + .probe = rsnd_src_probe_gen1, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, .start = rsnd_src_start_gen1, @@ -498,6 +512,8 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, if (ret < 0) dev_err(dev, "SRC DMA failed\n"); + dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); + return ret; } @@ -558,7 +574,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_src_gen2_ops = { - .name = "src (gen2)", + .name = SRC_NAME, .probe = rsnd_src_probe_gen2, .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, @@ -652,7 +668,8 @@ int rsnd_src_probe(struct platform_device *pdev, priv->src = src; for_each_rsnd_src(src, priv, i) { - snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i); + snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", + SRC_NAME, i); clk = devm_clk_get(dev, name); if (IS_ERR(clk)) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index ea8d4e7..2d94a62 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -57,6 +57,8 @@ */ #define CONT (1 << 8) /* WS Continue Function */ +#define SSI_NAME "ssi" + struct rsnd_ssi { struct clk *clk; struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ @@ -373,6 +375,8 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, if (ret) dev_err(dev, "SSI request interrupt failed\n"); + dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod)); + return ret; } @@ -405,7 +409,7 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssi_pio_ops = { - .name = "ssi (pio)", + .name = SSI_NAME, .probe = rsnd_ssi_pio_probe, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, @@ -430,6 +434,8 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, if (ret < 0) dev_err(dev, "SSI DMA failed\n"); + dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod)); + return ret; } @@ -480,7 +486,7 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, } static struct rsnd_mod_ops rsnd_ssi_dma_ops = { - .name = "ssi (dma)", + .name = SSI_NAME, .probe = rsnd_ssi_dma_probe, .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, @@ -493,7 +499,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { * Non SSI */ static struct rsnd_mod_ops rsnd_ssi_non_ops = { - .name = "ssi (non)", + .name = SSI_NAME, }; /* @@ -620,7 +626,8 @@ int rsnd_ssi_probe(struct platform_device *pdev, for_each_rsnd_ssi(ssi, priv, i) { pinfo = &info->ssi_info[i]; - snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); + snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", + SSI_NAME, i); clk = devm_clk_get(dev, name); if (IS_ERR(clk)) -- cgit v0.10.2 From 199e7688bdf7d188d70c3432c96ec13d8a14b341 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:25:49 -0700 Subject: ASoC: rsnd: care DMA slave channel name for DT Renesas sound driver is supporting to use DMAEngine. But, DMA slave channel name "tx", "rx" is not enough in DT case. Becuase, it has many ports and path combination. This patch adds rsnd_dma_of_name() to find DMA channel name, for example memory to SSI0 is "mem_ssi0", SSI0 to memory is "ssi0_mem", SSI0 to SRC0 is "ssi0_src0", SRC0 to SSI0 is "src0_ssi0", SRC0 to DVC0 is "src0_dvc0"... Renesas sound want to use PIO transfer mode for some reasons. It will be PIO tranfer mode if device node doesn't have DMA settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index a44e917..8346cab 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -20,6 +20,7 @@ Required properties: SSI subnode properties: - interrupts : Should contain SSI interrupt for PIO transfer - shared-pin : if shared clock pin +- pio-transfer : use PIO transfer mode SRC subnode properties: no properties at this point diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 073a293..cddb76d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -256,11 +256,81 @@ int rsnd_dma_available(struct rsnd_dma *dma) return !!dma->chan; } +#define DMA_NAME_SIZE 16 +#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ +static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) +{ + if (mod) + return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + else + return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); + +} + +static void rsnd_dma_of_name(struct rsnd_dma *dma, + int is_play, char *dma_name) +{ + struct rsnd_mod *this = rsnd_dma_to_mod(dma); + struct rsnd_dai_stream *io = rsnd_mod_to_io(this); + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mod[MOD_MAX]; + struct rsnd_mod *src_mod, *dst_mod; + int i, index; + + + for (i = 0; i < MOD_MAX; i++) + mod[i] = NULL; + + /* + * in play case... + * + * src -> dst + * + * mem -> SSI + * mem -> SRC -> SSI + * mem -> SRC -> DVC -> SSI + */ + mod[0] = NULL; /* for "mem" */ + index = 1; + for (i = 1; i < MOD_MAX; i++) { + if (!src) { + mod[i] = ssi; + break; + } else if (!dvc) { + mod[i] = src; + src = NULL; + } else { + mod[i] = dvc; + dvc = NULL; + } + + if (mod[i] == this) + index = i; + } + + if (is_play) { + src_mod = mod[index - 1]; + dst_mod = mod[index]; + } else { + src_mod = mod[index]; + dst_mod = mod[index + 1]; + } + + index = 0; + index = _rsnd_dma_of_name(dma_name + index, src_mod); + *(dma_name + index++) = '_'; + index = _rsnd_dma_of_name(dma_name + index, dst_mod); +} + int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int is_play, int id) { struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg; + char dma_name[DMA_NAME_SIZE]; dma_cap_mask_t mask; int ret; @@ -272,9 +342,17 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); + if (dev->of_node) + rsnd_dma_of_name(dma, is_play, dma_name); + else + snprintf(dma_name, DMA_NAME_SIZE, + is_play ? "tx" : "rx"); + + dev_dbg(dev, "dma name : %s\n", dma_name); + dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, (void *)id, dev, - is_play ? "tx" : "rx"); + dma_name); if (!dma->chan) { dev_err(dev, "can't get dma channel\n"); return -EIO; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2d94a62..e0a4ba7 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -589,6 +589,12 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, * irq */ ssi_info->pio_irq = irq_of_parse_and_map(np, 0); + + /* + * DMA + */ + ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? + 0 : 1; } rsnd_of_parse_ssi_end: -- cgit v0.10.2 From ad32d0c7b0e993433df152ae747652647eb65a27 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 May 2014 23:25:54 -0700 Subject: ASoC: rsnd: add rsnd_gen_dma_addr() for DMAC addr The DMAC src/dst addr needs to be set from driver when DT case. (It was set from SoC/DMAEngine code when non-DT case) This patch adds rsnd_gen_dma_addr() to set DMAC src/dst addr. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cddb76d..ebb5d46 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -358,10 +358,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, return -EIO; } - cfg.slave_id = id; - cfg.dst_addr = 0; /* use default addr when playback */ - cfg.src_addr = 0; /* use default addr when capture */ - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); ret = dmaengine_slave_config(dma->chan, &cfg); if (ret < 0) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index a1583b5..1dd2b7d 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -156,6 +156,101 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, } /* + * DMA read/write register offset + * + * RSND_xxx_I_N for Audio DMAC input + * RSND_xxx_O_N for Audio DMAC output + * RSND_xxx_I_P for Audio DMAC peri peri input + * RSND_xxx_O_P for Audio DMAC peri peri output + * + * ex) R-Car H2 case + * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out + * SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000 + * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 + * CMD : 0xec500000 / 0xec008000 0xec308000 + */ +#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) +#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) + +#define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) + +#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) +#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) + +#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) +#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) + +#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) +#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) + +void rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_dma *dma, + struct dma_slave_config *cfg, + int is_play, int slave_id) +{ + struct platform_device *pdev = rsnd_priv_to_pdev(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + dma_addr_t ssi_reg = platform_get_resource(pdev, + IORESOURCE_MEM, RSND_GEN2_SSI)->start; + dma_addr_t src_reg = platform_get_resource(pdev, + IORESOURCE_MEM, RSND_GEN2_SCU)->start; + int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); + int use_src = !!rsnd_io_to_mod_src(io); + int use_dvc = !!rsnd_io_to_mod_dvc(io); + int id = rsnd_mod_id(mod); + struct dma_addr { + dma_addr_t src_addr; + dma_addr_t dst_addr; + } dma_addrs[2][2][3] = { + { /* SRC */ + /* Capture */ + {{ 0, 0 }, + { RDMA_SRC_O_N(src, id), 0 }, + { RDMA_CMD_O_N(src, id), 0 }}, + /* Playback */ + {{ 0, 0, }, + { 0, RDMA_SRC_I_N(src, id) }, + { 0, RDMA_SRC_I_N(src, id) }} + }, { /* SSI */ + /* Capture */ + {{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, + { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, + /* Playback */ + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, + { RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }} + } + }; + + cfg->slave_id = slave_id; + cfg->src_addr = 0; + cfg->dst_addr = 0; + cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + + /* + * gen1 uses default DMA addr + */ + if (rsnd_is_gen1(priv)) + return; + + /* it shouldn't happen */ + if (use_dvc & !use_src) { + dev_err(dev, "DVC is selected without SRC\n"); + return; + } + + cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; + cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; + + dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", + id, cfg->src_addr, cfg->dst_addr); +} + +/* * Gen2 */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 344f941..39d98af 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -281,6 +281,11 @@ int rsnd_gen_probe(struct platform_device *pdev, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); +void rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_dma *dma, + struct dma_slave_config *cfg, + int is_play, int slave_id); + #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) -- cgit v0.10.2 From 4c715c758c72ec5885ccfadf4e98ca76262ba619 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 May 2014 17:16:49 -0700 Subject: ASoC: pxa: pxa-ssp: Terminate of match table Failure to terminate this match table can lead to boot failures depending on where the compiler places the match table. Signed-off-by: Stephen Boyd Acked-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index a3119a0..dd35e7b 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -810,6 +810,7 @@ static const struct snd_soc_component_driver pxa_ssp_component = { #ifdef CONFIG_OF static const struct of_device_id pxa_ssp_of_ids[] = { { .compatible = "mrvl,pxa-ssp-dai" }, + {} }; #endif -- cgit v0.10.2 From 50dfb69d1bb0062e2811547525c73e9a45a423e9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 14:34:36 +0300 Subject: ASoC: jack: Basic GPIO descriptor conversion This patch does basic GPIO descriptor conversion to soc-jack. Even the GPIOs are still passed and requested using legacy GPIO numbers the driver internals are converted to use GPIO descriptor API. Motivation for this is to prepare soc-jack so that it will allow registering jack GPIO pins using both GPIO descriptors and legacy GPIO numbers. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 0b83168..c6bd40f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -606,6 +606,7 @@ struct snd_soc_jack_gpio { struct snd_soc_jack *jack; struct delayed_work work; + struct gpio_desc *desc; void *data; int (*jack_status_check)(void *data); diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index b903f82..7203842 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -240,7 +241,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) int enable; int report; - enable = gpio_get_value_cansleep(gpio->gpio); + enable = gpiod_get_value_cansleep(gpio->desc); if (gpio->invert) enable = !enable; @@ -314,14 +315,16 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (ret) goto undo; - ret = gpio_direction_input(gpios[i].gpio); + gpios[i].desc = gpio_to_desc(gpios[i].gpio); + + ret = gpiod_direction_input(gpios[i].desc); if (ret) goto err; INIT_DELAYED_WORK(&gpios[i].work, gpio_work); gpios[i].jack = jack; - ret = request_any_context_irq(gpio_to_irq(gpios[i].gpio), + ret = request_any_context_irq(gpiod_to_irq(gpios[i].desc), gpio_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -331,7 +334,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, goto err; if (gpios[i].wake) { - ret = irq_set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); + ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1); if (ret != 0) dev_err(jack->codec->dev, "ASoC: " "Failed to mark GPIO %d as wake source: %d\n", @@ -339,7 +342,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, } /* Expose GPIO value over sysfs for diagnostic purposes */ - gpio_export(gpios[i].gpio, false); + gpiod_export(gpios[i].desc, false); /* Update initial jack status */ schedule_delayed_work(&gpios[i].work, @@ -372,10 +375,10 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, int i; for (i = 0; i < count; i++) { - gpio_unexport(gpios[i].gpio); - free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]); + gpiod_unexport(gpios[i].desc); + free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]); cancel_delayed_work_sync(&gpios[i].work); - gpio_free(gpios[i].gpio); + gpiod_put(gpios[i].desc); gpios[i].jack = NULL; } } -- cgit v0.10.2 From f025d3b9c64e1f7feb75a559d4a12f5f8c6a4a25 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 14:34:37 +0300 Subject: ASoC: jack: Add support for GPIO descriptor defined jack pins Allow jack GPIO pins be defined also using GPIO descriptor-based interface in addition to legacy GPIO numbers. This is done by adding two new fields to struct snd_soc_jack_gpio: idx and gpiod_dev. Legacy GPIO numbers are used only when GPIO consumer device gpiod_dev is NULL and otherwise idx is the descriptor index within the GPIO consumer device. New function snd_soc_jack_add_gpiods() is added for typical cases where all GPIO descriptor jack pins belong to same GPIO consumer device. For other cases the caller must set the gpiod_dev in struct snd_soc_jack_gpio before calling snd_soc_jack_add_gpios(). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index c6bd40f..61bea88 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -453,6 +453,9 @@ int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage); #ifdef CONFIG_GPIOLIB int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios); +int snd_soc_jack_add_gpiods(struct device *gpiod_dev, + struct snd_soc_jack *jack, + int count, struct snd_soc_jack_gpio *gpios); void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios); #else @@ -462,6 +465,13 @@ static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, return 0; } +int snd_soc_jack_add_gpiods(struct device *gpiod_dev, + struct snd_soc_jack *jack, + int count, struct snd_soc_jack_gpio *gpios) +{ + return 0; +} + static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios) { @@ -586,7 +596,9 @@ struct snd_soc_jack_zone { /** * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection * - * @gpio: gpio number + * @gpio: legacy gpio number + * @idx: gpio descriptor index within the GPIO consumer device + * @gpiod_dev GPIO consumer device * @name: gpio name * @report: value to report when jack detected * @invert: report presence in low state @@ -598,6 +610,8 @@ struct snd_soc_jack_zone { */ struct snd_soc_jack_gpio { unsigned int gpio; + unsigned int idx; + struct device *gpiod_dev; const char *name; int report; int invert; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 7203842..d0d9881 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -298,24 +298,41 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, int i, ret; for (i = 0; i < count; i++) { - if (!gpio_is_valid(gpios[i].gpio)) { - dev_err(jack->codec->dev, "ASoC: Invalid gpio %d\n", - gpios[i].gpio); - ret = -EINVAL; - goto undo; - } if (!gpios[i].name) { - dev_err(jack->codec->dev, "ASoC: No name for gpio %d\n", - gpios[i].gpio); + dev_err(jack->codec->dev, + "ASoC: No name for gpio at index %d\n", i); ret = -EINVAL; goto undo; } - ret = gpio_request(gpios[i].gpio, gpios[i].name); - if (ret) - goto undo; - - gpios[i].desc = gpio_to_desc(gpios[i].gpio); + if (gpios[i].gpiod_dev) { + /* GPIO descriptor */ + gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, + gpios[i].name, + gpios[i].idx); + if (IS_ERR(gpios[i].desc)) { + ret = PTR_ERR(gpios[i].desc); + dev_err(gpios[i].gpiod_dev, + "ASoC: Cannot get gpio at index %d: %d", + i, ret); + goto undo; + } + } else { + /* legacy GPIO number */ + if (!gpio_is_valid(gpios[i].gpio)) { + dev_err(jack->codec->dev, + "ASoC: Invalid gpio %d\n", + gpios[i].gpio); + ret = -EINVAL; + goto undo; + } + + ret = gpio_request(gpios[i].gpio, gpios[i].name); + if (ret) + goto undo; + + gpios[i].desc = gpio_to_desc(gpios[i].gpio); + } ret = gpiod_direction_input(gpios[i].desc); if (ret) @@ -336,9 +353,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (gpios[i].wake) { ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1); if (ret != 0) - dev_err(jack->codec->dev, "ASoC: " - "Failed to mark GPIO %d as wake source: %d\n", - gpios[i].gpio, ret); + dev_err(jack->codec->dev, + "ASoC: Failed to mark GPIO at index %d as wake source: %d\n", + i, ret); } /* Expose GPIO value over sysfs for diagnostic purposes */ @@ -361,6 +378,30 @@ undo: EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios); /** + * snd_soc_jack_add_gpiods - Associate GPIO descriptor pins with an ASoC jack + * + * @gpiod_dev: GPIO consumer device + * @jack: ASoC jack + * @count: number of pins + * @gpios: array of gpio pins + * + * This function will request gpio, set data direction and request irq + * for each gpio in the array. + */ +int snd_soc_jack_add_gpiods(struct device *gpiod_dev, + struct snd_soc_jack *jack, + int count, struct snd_soc_jack_gpio *gpios) +{ + int i; + + for (i = 0; i < count; i++) + gpios[i].gpiod_dev = gpiod_dev; + + return snd_soc_jack_add_gpios(jack, count, gpios); +} +EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods); + +/** * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack * * @jack: ASoC jack -- cgit v0.10.2 From 87c1936426d13d4f0dba29430c792e6d3562f2be Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 26 May 2014 11:51:14 +0300 Subject: ASoC: omap-pcm: Move omap-pcm under include/sound Make including the omap-pcm.h outside sound/soc/omap more convenient. Signed-off-by: Jyri Sarha Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/include/sound/omap-pcm.h b/include/sound/omap-pcm.h new file mode 100644 index 0000000..c1d2f31 --- /dev/null +++ b/include/sound/omap-pcm.h @@ -0,0 +1,30 @@ +/* + * omap-pcm.h - OMAP PCM driver + * + * Copyright (C) 2014 Texas Instruments, Inc. + * + * Author: Peter Ujfalusi + * + * 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. + */ + +#ifndef __OMAP_PCM_H__ +#define __OMAP_PCM_H__ + +#if IS_ENABLED(CONFIG_SND_OMAP_SOC) +int omap_pcm_platform_register(struct device *dev); +#else +static inline int omap_pcm_platform_register(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_SND_OMAP_SOC */ + +#endif /* __OMAP_PCM_H__ */ diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 14058dc..9afb146 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -33,10 +33,10 @@ #include #include #include +#include #include "davinci-pcm.h" #include "davinci-mcasp.h" -#include "../omap/omap-pcm.h" #define MCASP_MAX_AFIFO_DEPTH 64 diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 53da041..6925d71 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -40,9 +40,9 @@ #include #include #include +#include #include "omap-dmic.h" -#include "omap-pcm.h" struct omap_dmic { struct device *dev; diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index 537a1ec..eb9c392 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -34,9 +34,9 @@ #include #include #include