Merge remote-tracking branches 'asoc/topic/gpio' and 'asoc/topic/intel' into asoc-next

This commit is contained in:
Mark Brown 2014-06-03 10:39:50 +01:00
commit 9713d5d0c4
12 changed files with 319 additions and 67 deletions

View File

@ -452,6 +452,9 @@ int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage);
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios); 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, void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios); struct snd_soc_jack_gpio *gpios);
#else #else
@ -461,6 +464,14 @@ static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
return 0; return 0;
} }
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;
}
static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios) struct snd_soc_jack_gpio *gpios)
{ {
@ -587,8 +598,12 @@ struct snd_soc_jack_zone {
/** /**
* struct snd_soc_jack_gpio - Describes a gpio pin for jack detection * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
* *
* @gpio: gpio number * @gpio: legacy gpio number
* @name: gpio name * @idx: gpio descriptor index within the function of the GPIO
* consumer device
* @gpiod_dev GPIO consumer device
* @name: gpio name. Also as connection ID for the GPIO consumer
* device function name lookup
* @report: value to report when jack detected * @report: value to report when jack detected
* @invert: report presence in low state * @invert: report presence in low state
* @debouce_time: debouce time in ms * @debouce_time: debouce time in ms
@ -599,6 +614,8 @@ struct snd_soc_jack_zone {
*/ */
struct snd_soc_jack_gpio { struct snd_soc_jack_gpio {
unsigned int gpio; unsigned int gpio;
unsigned int idx;
struct device *gpiod_dev;
const char *name; const char *name;
int report; int report;
int invert; int invert;
@ -607,6 +624,7 @@ struct snd_soc_jack_gpio {
struct snd_soc_jack *jack; struct snd_soc_jack *jack;
struct delayed_work work; struct delayed_work work;
struct gpio_desc *desc;
void *data; void *data;
int (*jack_status_check)(void *data); int (*jack_status_check)(void *data);

View File

@ -49,3 +49,12 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
help help
This adds audio driver for Intel Baytrail platform based boards This adds audio driver for Intel Baytrail platform based boards
with the RT5640 audio codec. 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 && I2C
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.

View File

@ -23,6 +23,8 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
# Machine support # Machine support
snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-haswell-objs := haswell.o
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.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_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_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o

View File

@ -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 <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#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");

View File

@ -132,43 +132,20 @@ static struct snd_soc_card byt_rt5640_card = {
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), .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) static int byt_rt5640_probe(struct platform_device *pdev)
{ {
struct snd_soc_card *card = &byt_rt5640_card; struct snd_soc_card *card = &byt_rt5640_card;
struct device *dev = &pdev->dev;
card->dev = &pdev->dev; card->dev = &pdev->dev;
dev_set_drvdata(dev, card); return devm_snd_soc_register_card(&pdev->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;
} }
static struct platform_driver byt_rt5640_audio = { static struct platform_driver byt_rt5640_audio = {
.probe = byt_rt5640_probe, .probe = byt_rt5640_probe,
.remove = byt_rt5640_remove,
.driver = { .driver = {
.name = "byt-rt5640", .name = "byt-rt5640",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = BYT_RT5640_PM_OPS, .pm = &snd_soc_pm_ops,
}, },
}; };
module_platform_driver(byt_rt5640_audio) module_platform_driver(byt_rt5640_audio)

View File

@ -202,18 +202,11 @@ static int haswell_audio_probe(struct platform_device *pdev)
{ {
haswell_rt5640.dev = &pdev->dev; haswell_rt5640.dev = &pdev->dev;
return snd_soc_register_card(&haswell_rt5640); return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
}
static int haswell_audio_remove(struct platform_device *pdev)
{
snd_soc_unregister_card(&haswell_rt5640);
return 0;
} }
static struct platform_driver haswell_audio = { static struct platform_driver haswell_audio = {
.probe = haswell_audio_probe, .probe = haswell_audio_probe,
.remove = haswell_audio_remove,
.driver = { .driver = {
.name = "haswell-audio", .name = "haswell-audio",
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -247,6 +247,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
static struct sst_acpi_mach baytrail_machines[] = { static struct sst_acpi_mach baytrail_machines[] = {
{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
{ "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" },
{} {}
}; };

View File

@ -22,7 +22,6 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/list.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/firmware.h> #include <linux/firmware.h>
@ -892,7 +891,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
/* start the IPC message thread */ /* start the IPC message thread */
init_kthread_worker(&byt->kworker); init_kthread_worker(&byt->kworker);
byt->tx_thread = kthread_run(kthread_worker_fn, byt->tx_thread = kthread_run(kthread_worker_fn,
&byt->kworker, &byt->kworker, "%s",
dev_name(byt->dev)); dev_name(byt->dev));
if (IS_ERR(byt->tx_thread)) { if (IS_ERR(byt->tx_thread)) {
err = PTR_ERR(byt->tx_thread); err = PTR_ERR(byt->tx_thread);
@ -907,7 +906,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
if (byt->dsp == NULL) { if (byt->dsp == NULL) {
err = -ENODEV; err = -ENODEV;
goto err_free_msg; goto dsp_err;
} }
/* keep the DSP in reset state for base FW loading */ /* keep the DSP in reset state for base FW loading */
@ -940,6 +939,8 @@ boot_err:
sst_fw_free(byt_sst_fw); sst_fw_free(byt_sst_fw);
fw_err: fw_err:
sst_dsp_free(byt->dsp); sst_dsp_free(byt->dsp);
dsp_err:
kthread_stop(byt->tx_thread);
err_free_msg: err_free_msg:
kfree(byt->msg); kfree(byt->msg);
@ -954,6 +955,7 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
sst_dsp_reset(byt->dsp); sst_dsp_reset(byt->dsp);
sst_fw_free_all(byt->dsp); sst_fw_free_all(byt->dsp);
sst_dsp_free(byt->dsp); sst_dsp_free(byt->dsp);
kthread_stop(byt->tx_thread);
kfree(byt->msg); kfree(byt->msg);
} }
EXPORT_SYMBOL_GPL(sst_byt_dsp_free); EXPORT_SYMBOL_GPL(sst_byt_dsp_free);

View File

@ -180,6 +180,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
pcm_data->hw_ptr = 0;
sst_byt_stream_start(byt, pcm_data->stream, 0); sst_byt_stream_start(byt, pcm_data->stream, 0);
break; break;
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:

View File

@ -25,7 +25,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/list.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/firmware.h> #include <linux/firmware.h>
@ -1730,17 +1729,17 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
ret = msg_empty_list_init(hsw); ret = msg_empty_list_init(hsw);
if (ret < 0) if (ret < 0)
goto list_err; return -ENOMEM;
/* start the IPC message thread */ /* start the IPC message thread */
init_kthread_worker(&hsw->kworker); init_kthread_worker(&hsw->kworker);
hsw->tx_thread = kthread_run(kthread_worker_fn, hsw->tx_thread = kthread_run(kthread_worker_fn,
&hsw->kworker, &hsw->kworker, "%s",
dev_name(hsw->dev)); dev_name(hsw->dev));
if (IS_ERR(hsw->tx_thread)) { if (IS_ERR(hsw->tx_thread)) {
ret = PTR_ERR(hsw->tx_thread); ret = PTR_ERR(hsw->tx_thread);
dev_err(hsw->dev, "error: failed to create message TX task\n"); 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); init_kthread_work(&hsw->kwork, ipc_tx_msgs);
@ -1750,7 +1749,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
if (hsw->dsp == NULL) { if (hsw->dsp == NULL) {
ret = -ENODEV; ret = -ENODEV;
goto list_err; goto dsp_err;
} }
/* keep the DSP in reset state for base FW loading */ /* keep the DSP in reset state for base FW loading */
@ -1794,8 +1793,11 @@ boot_err:
sst_fw_free(hsw_sst_fw); sst_fw_free(hsw_sst_fw);
fw_err: fw_err:
sst_dsp_free(hsw->dsp); sst_dsp_free(hsw->dsp);
dsp_err:
kthread_stop(hsw->tx_thread);
err_free_msg:
kfree(hsw->msg); kfree(hsw->msg);
list_err:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
@ -1808,6 +1810,7 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
sst_fw_free_all(hsw->dsp); sst_fw_free_all(hsw->dsp);
sst_dsp_free(hsw->dsp); sst_dsp_free(hsw->dsp);
kfree(hsw->scratch); kfree(hsw->scratch);
kthread_stop(hsw->tx_thread);
kfree(hsw->msg); kfree(hsw->msg);
} }
EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);

View File

@ -17,7 +17,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>

View File

@ -14,6 +14,7 @@
#include <sound/jack.h> #include <sound/jack.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -240,7 +241,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
int enable; int enable;
int report; int report;
enable = gpio_get_value_cansleep(gpio->gpio); enable = gpiod_get_value_cansleep(gpio->desc);
if (gpio->invert) if (gpio->invert)
enable = !enable; enable = !enable;
@ -297,31 +298,50 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
int i, ret; int i, ret;
for (i = 0; i < count; i++) { 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) { if (!gpios[i].name) {
dev_err(jack->codec->dev, "ASoC: No name for gpio %d\n", dev_err(jack->codec->dev,
gpios[i].gpio); "ASoC: No name for gpio at index %d\n", i);
ret = -EINVAL; ret = -EINVAL;
goto undo; goto undo;
} }
ret = gpio_request(gpios[i].gpio, gpios[i].name); if (gpios[i].gpiod_dev) {
if (ret) /* GPIO descriptor */
goto undo; 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_direction_input(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) if (ret)
goto err; goto err;
INIT_DELAYED_WORK(&gpios[i].work, gpio_work); INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack; 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, gpio_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
@ -331,15 +351,15 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
goto err; goto err;
if (gpios[i].wake) { 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) if (ret != 0)
dev_err(jack->codec->dev, "ASoC: " dev_err(jack->codec->dev,
"Failed to mark GPIO %d as wake source: %d\n", "ASoC: Failed to mark GPIO at index %d as wake source: %d\n",
gpios[i].gpio, ret); i, ret);
} }
/* Expose GPIO value over sysfs for diagnostic purposes */ /* Expose GPIO value over sysfs for diagnostic purposes */
gpio_export(gpios[i].gpio, false); gpiod_export(gpios[i].desc, false);
/* Update initial jack status */ /* Update initial jack status */
schedule_delayed_work(&gpios[i].work, schedule_delayed_work(&gpios[i].work,
@ -357,6 +377,30 @@ undo:
} }
EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios); 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 * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
* *
@ -372,10 +416,10 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
int i; int i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
gpio_unexport(gpios[i].gpio); gpiod_unexport(gpios[i].desc);
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]); free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
cancel_delayed_work_sync(&gpios[i].work); cancel_delayed_work_sync(&gpios[i].work);
gpio_free(gpios[i].gpio); gpiod_put(gpios[i].desc);
gpios[i].jack = NULL; gpios[i].jack = NULL;
} }
} }