From 35386320898ec01f922929877a723fe1d4ddf04b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 May 2014 11:43:55 -0700 Subject: [PATCH 01/12] 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 --- sound/soc/intel/sst-baytrail-ipc.c | 2 +- sound/soc/intel/sst-haswell-ipc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 7c1ec003d55d..18273d26718a 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 e7996b39a484..a8fd60c67341 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); From 50dfb69d1bb0062e2811547525c73e9a45a423e9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 14:34:36 +0300 Subject: [PATCH 02/12] 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 --- include/sound/soc.h | 1 + sound/soc/soc-jack.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0b83168d8ff4..c6bd40f2c40b 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 b903f822d1b2..7203842fea66 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; } } From f025d3b9c64e1f7feb75a559d4a12f5f8c6a4a25 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 14:34:37 +0300 Subject: [PATCH 03/12] 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 --- include/sound/soc.h | 16 +++++++++- sound/soc/soc-jack.c | 71 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index c6bd40f2c40b..61bea882a74b 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 7203842fea66..d0d98810af91 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; + 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; + } - gpios[i].desc = gpio_to_desc(gpios[i].gpio); + 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 */ @@ -360,6 +377,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 * From 83ad152d03b594b6a3fb9f3d313622b491cd6168 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 27 May 2014 13:54:18 +0300 Subject: [PATCH 04/12] ASoC: jack: Clarify GPIO descriptor lookup in struct snd_soc_jack_gpio doc Clarify struct snd_soc_jack_gpio documentation for the idx and name fields. Because name is passed as connection ID to gpiod_get_index() when using GPIO descriptor defined jack pins it is not only used as a label in debugfs but also as function name lookup in systems that support functions names for GPIOs. Clarify also idx since the index is within the function of the GPIO consumer device and not within the device itself only. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 61bea882a74b..a2408a5b96a7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -597,9 +597,11 @@ struct snd_soc_jack_zone { * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection * * @gpio: legacy gpio number - * @idx: gpio descriptor index within the GPIO consumer device + * @idx: gpio descriptor index within the function of the GPIO + * consumer device * @gpiod_dev GPIO consumer device - * @name: gpio name + * @name: gpio name. Also as connection ID for the GPIO consumer + * device function name lookup * @report: value to report when jack detected * @invert: report presence in low state * @debouce_time: debouce time in ms From e667487b67d96fc2471529e3a5b404f51dc52b39 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 27 May 2014 10:39:57 +0300 Subject: [PATCH 05/12] ASoC: jack: Fix multiple definition of `snd_soc_jack_add_gpiods' Commit f025d3b9c64e ("ASoC: jack: Add support for GPIO descriptor defined jack pins") caused build error when CONFIG_GPIOLIB is not set: sound/include/sound/soc.h:470: multiple definition of `snd_soc_jack_add_gpiods' sound/soc/soc-core.o:sound/include/sound/soc.h:470: first defined here make[2]: *** [sound/soc/snd-soc-core.o] Error 1 make[2]: *** Waiting for unfinished jobs.... make[1]: *** [sound/soc] Error 2 make: *** [sound] Error 2 Fix this by marking snd_soc_jack_add_gpiods() as static inline in soc.h. Reported-by: kbuild test robot Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- include/sound/soc.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index a2408a5b96a7..ac21cc22c4e9 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -465,9 +465,10 @@ 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) +static inline 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; } From 9b351d46893e827940e2e8da04f1791e8ec452ca Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 30 May 2014 15:16:43 +0300 Subject: [PATCH 06/12] ASoC: Intel: Add Baytrail byt-max98090 machine driver Add machine driver and ACPI probing for Baytrail SST with MAX98090 codec. Jack detect code from Kevin Strasser , GPIO resolving from Mika Westerberg and fixes and cleanups from Liam Girdwood . Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 9 ++ sound/soc/intel/Makefile | 2 + sound/soc/intel/byt-max98090.c | 203 +++++++++++++++++++++++++++++++++ sound/soc/intel/sst-acpi.c | 1 + 4 files changed, 215 insertions(+) create mode 100644 sound/soc/intel/byt-max98090.c diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 3c81b3891209..cd3498736e91 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -49,3 +49,12 @@ config SND_SOC_INTEL_BYT_RT5640_MACH help This adds audio driver for Intel Baytrail platform based boards with the RT5640 audio codec. + +config SND_SOC_INTEL_BYT_MAX98090_MACH + tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" + depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS + select SND_SOC_INTEL_BAYTRAIL + select SND_SOC_MAX98090 + help + This adds audio driver for Intel Baytrail platform based boards + with the MAX98090 audio codec. diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 0db4e2f336dc..4bfca79a42ba 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -23,6 +23,8 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o # Machine support snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o +snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c new file mode 100644 index 000000000000..5fc98c64a3f4 --- /dev/null +++ b/sound/soc/intel/byt-max98090.c @@ -0,0 +1,203 @@ +/* + * Intel Baytrail SST MAX98090 machine driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/max98090.h" + +struct byt_max98090_private { + struct snd_soc_jack jack; +}; + +static const struct snd_soc_dapm_widget byt_max98090_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_route byt_max98090_audio_map[] = { + {"IN34", NULL, "Headset Mic"}, + {"IN34", NULL, "MICBIAS"}, + {"MICBIAS", NULL, "Headset Mic"}, + {"DMICL", NULL, "Int Mic"}, + {"Headphone", NULL, "HPL"}, + {"Headphone", NULL, "HPR"}, + {"Ext Spk", NULL, "SPKL"}, + {"Ext Spk", NULL, "SPKR"}, +}; + +static const struct snd_kcontrol_new byt_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Ext Spk"), +}; + +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Ext Spk", + .mask = SND_JACK_LINEOUT, + }, + { + .pin = "Int Mic", + .mask = SND_JACK_LINEIN, + }, +}; + +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + { + .name = "hp-gpio", + .idx = 0, + .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, + .debounce_time = 200, + }, + { + .name = "mic-gpio", + .idx = 1, + .report = SND_JACK_MICROPHONE | SND_JACK_LINEIN, + .debounce_time = 200, + }, +}; + +static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_card *card = runtime->card; + struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card); + struct snd_soc_jack *jack = &drv->jack; + + card->dapm.idle_bias_off = true; + + ret = snd_soc_dai_set_sysclk(runtime->codec_dai, + M98090_REG_SYSTEM_CLOCK, + 25000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + /* Enable jack detection */ + ret = snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, jack); + if (ret) + return ret; + + ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (ret) + return ret; + + ret = snd_soc_jack_add_gpiods(card->dev->parent, jack, + ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + if (ret) + return ret; + + return max98090_mic_detect(codec, jack); +} + +static struct snd_soc_dai_link byt_max98090_dais[] = { + { + .name = "Baytrail Audio", + .stream_name = "Audio", + .cpu_dai_name = "baytrail-pcm-audio", + .codec_dai_name = "HiFi", + .codec_name = "i2c-193C9890:00", + .platform_name = "baytrail-pcm-audio", + .init = byt_max98090_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, +}; + +static struct snd_soc_card byt_max98090_card = { + .name = "byt-max98090", + .dai_link = byt_max98090_dais, + .num_links = ARRAY_SIZE(byt_max98090_dais), + .dapm_widgets = byt_max98090_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets), + .dapm_routes = byt_max98090_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), + .controls = byt_max98090_controls, + .num_controls = ARRAY_SIZE(byt_max98090_controls), +}; + +static int byt_max98090_probe(struct platform_device *pdev) +{ + int ret_val = 0; + struct byt_max98090_private *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); + if (!priv) { + dev_err(&pdev->dev, "allocation failed\n"); + return -ENOMEM; + } + + byt_max98090_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&byt_max98090_card, priv); + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card); + if (ret_val) { + dev_err(&pdev->dev, + "snd_soc_register_card failed %d\n", ret_val); + return ret_val; + } + + return ret_val; +} + +static int byt_max98090_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card); + + snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + + return 0; +} + +static struct platform_driver byt_max98090_driver = { + .probe = byt_max98090_probe, + .remove = byt_max98090_remove, + .driver = { + .name = "byt-max98090", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(byt_max98090_driver) + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver"); +MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:byt-max98090"); diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 18aee77f8d4a..42edc6f4fc4a 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -247,6 +247,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { static struct sst_acpi_mach baytrail_machines[] = { { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, + { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" }, {} }; From 9cf0e4520d45d5425f3a5257d346e3310e1a63b4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 30 May 2014 10:52:29 +0300 Subject: [PATCH 07/12] ASoC: Intel: byt/hsw: Add missing kthread_stop to error/cleanup path Baytrail and Haswell SST IPC don't stop the kernel thread in error and cleanup path thus leaving orphan kernel thread behind in such a case. Also while at it, fix one error path in sst-haswell-ipc.c that doesn't free hsw->msg. [Jarkko: I edited the commit log a little] Signed-off-by: Imre Deak Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/sst-baytrail-ipc.c | 5 ++++- sound/soc/intel/sst-haswell-ipc.c | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 18273d26718a..40a25fce0faa 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -907,7 +907,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); if (byt->dsp == NULL) { err = -ENODEV; - goto err_free_msg; + goto dsp_err; } /* keep the DSP in reset state for base FW loading */ @@ -940,6 +940,8 @@ boot_err: sst_fw_free(byt_sst_fw); fw_err: sst_dsp_free(byt->dsp); +dsp_err: + kthread_stop(byt->tx_thread); err_free_msg: kfree(byt->msg); @@ -954,6 +956,7 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) sst_dsp_reset(byt->dsp); sst_fw_free_all(byt->dsp); sst_dsp_free(byt->dsp); + kthread_stop(byt->tx_thread); kfree(byt->msg); } EXPORT_SYMBOL_GPL(sst_byt_dsp_free); diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index a8fd60c67341..b6c14a39b0b1 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1730,7 +1730,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) ret = msg_empty_list_init(hsw); if (ret < 0) - goto list_err; + return -ENOMEM; /* start the IPC message thread */ init_kthread_worker(&hsw->kworker); @@ -1740,7 +1740,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (IS_ERR(hsw->tx_thread)) { ret = PTR_ERR(hsw->tx_thread); dev_err(hsw->dev, "error: failed to create message TX task\n"); - goto list_err; + goto err_free_msg; } init_kthread_work(&hsw->kwork, ipc_tx_msgs); @@ -1750,7 +1750,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); if (hsw->dsp == NULL) { ret = -ENODEV; - goto list_err; + goto dsp_err; } /* keep the DSP in reset state for base FW loading */ @@ -1794,8 +1794,11 @@ boot_err: sst_fw_free(hsw_sst_fw); fw_err: sst_dsp_free(hsw->dsp); +dsp_err: + kthread_stop(hsw->tx_thread); +err_free_msg: kfree(hsw->msg); -list_err: + return ret; } EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); @@ -1808,6 +1811,7 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) sst_fw_free_all(hsw->dsp); sst_dsp_free(hsw->dsp); kfree(hsw->scratch); + kthread_stop(hsw->tx_thread); kfree(hsw->msg); } EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); From 58dcc48816ad1db8d2e33ddf659c2bda64f645c4 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 16:56:30 +0300 Subject: [PATCH 08/12] ASoC: Intel: Clear stored Baytrail DSP DMA pointer before stream start Stored DSP DMA pointer must be cleared before starting the stream since PCM pointer callback sst_byt_pcm_pointer() can be called before pointer is updated. In that case last position of previous stream was wronly returned. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/sst-baytrail-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 3af38576e91e..8eab97368ea7 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c @@ -180,6 +180,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: + pcm_data->hw_ptr = 0; sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: From a018c285501c2beb54335b1eeddfeab4cd476974 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 26 May 2014 16:56:31 +0300 Subject: [PATCH 09/12] ASoC: Intel: remove duplicate headers A few files contain duplicate headers. This patch removes the second entry of duplicate in each file under question. There is no functional changes. Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Cc: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/sst-baytrail-ipc.c | 1 - sound/soc/intel/sst-haswell-ipc.c | 1 - sound/soc/intel/sst-haswell-pcm.c | 1 - 3 files changed, 3 deletions(-) diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 40a25fce0faa..d207b22ea330 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index b6c14a39b0b1..434236343ddf 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 9d5f64a583a3..c53cd5772d58 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include From 8eb776ab17232b02d915b90f5dd14c45af86c3a0 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 28 May 2014 12:35:39 +0300 Subject: [PATCH 10/12] ASoC: Intel: Use devm_snd_soc_register_card Simplify byt-rt5640.c and haswell.c machine drivers by using devm_snd_soc_register_card(). Remove also needless dev_set_drvdata() from byt_rt5640_probe() since snd_soc_register_card() does it too. Signed-off-by: Jarkko Nikula Cc: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 14 +------------- sound/soc/intel/haswell.c | 9 +-------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index dbc63d09f424..eac6566f42e6 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -152,25 +152,13 @@ static const struct dev_pm_ops byt_rt5640_pm_ops = { static int byt_rt5640_probe(struct platform_device *pdev) { struct snd_soc_card *card = &byt_rt5640_card; - struct device *dev = &pdev->dev; card->dev = &pdev->dev; - dev_set_drvdata(dev, card); - return snd_soc_register_card(card); -} - -static int byt_rt5640_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; + return devm_snd_soc_register_card(&pdev->dev, card); } static struct platform_driver byt_rt5640_audio = { .probe = byt_rt5640_probe, - .remove = byt_rt5640_remove, .driver = { .name = "byt-rt5640", .owner = THIS_MODULE, diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 54345a2a7386..6faa8de24f24 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c @@ -208,18 +208,11 @@ static int haswell_audio_probe(struct platform_device *pdev) { haswell_rt5640.dev = &pdev->dev; - return snd_soc_register_card(&haswell_rt5640); -} - -static int haswell_audio_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&haswell_rt5640); - return 0; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } static struct platform_driver haswell_audio = { .probe = haswell_audio_probe, - .remove = haswell_audio_remove, .driver = { .name = "haswell-audio", .owner = THIS_MODULE, From 4af72f4e6911a0bfd51c5a806c3a8642a9c4665e Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 May 2014 16:56:33 +0300 Subject: [PATCH 11/12] ASoC: Intel: byt-rt5640: Use card PM ops from core Use card PM ops from ASoC core instead of defining custom PM ops here since we are calling anyway common suspend/resume callbacks. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index eac6566f42e6..ac52c77721b1 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -138,17 +138,6 @@ static struct snd_soc_card byt_rt5640_card = { .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), }; -#ifdef CONFIG_PM_SLEEP -static const struct dev_pm_ops byt_rt5640_pm_ops = { - .suspend = snd_soc_suspend, - .resume = snd_soc_resume, -}; - -#define BYT_RT5640_PM_OPS (&byt_rt5640_pm_ops) -#else -#define BYT_RT5640_PM_OPS NULL -#endif - static int byt_rt5640_probe(struct platform_device *pdev) { struct snd_soc_card *card = &byt_rt5640_card; @@ -162,7 +151,7 @@ static struct platform_driver byt_rt5640_audio = { .driver = { .name = "byt-rt5640", .owner = THIS_MODULE, - .pm = BYT_RT5640_PM_OPS, + .pm = &snd_soc_pm_ops, }, }; module_platform_driver(byt_rt5640_audio) From d8188f00e7f57412b5bb4405f636cb7c3d8f42a6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Jun 2014 20:12:05 +0100 Subject: [PATCH 12/12] ASoC: intel: The Baytrail/MAX98090 driver depends on I2C Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index cd3498736e91..c30fedb3e149 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -52,7 +52,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS + depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help