summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarkko Nikula <jarkko.nikula@linux.intel.com>2014-05-26 15:34:37 +0400
committerMark Brown <broonie@linaro.org>2014-05-26 18:26:00 +0400
commitf025d3b9c64e1f7feb75a559d4a12f5f8c6a4a25 (patch)
tree819909f51afd408c50379e69c55d29337365d02c
parent50dfb69d1bb0062e2811547525c73e9a45a423e9 (diff)
downloadlinux-f025d3b9c64e1f7feb75a559d4a12f5f8c6a4a25.tar.xz
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 <jarkko.nikula@linux.intel.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--include/sound/soc.h16
-rw-r--r--sound/soc/soc-jack.c73
2 files changed, 72 insertions, 17 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;
-
- 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