aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorLopez Cruz, Misael2009-03-03 15:25:04 -0600
committerMark Brown2009-03-04 14:47:38 +0000
commitec67624d33d5639bcc6ee6918cb1fc0bd1bac3a8 (patch)
tree301f1d4ae2f47cca1c7412ce49e7574de8b0dfd2 /sound
parent5f2a9384a9291d898b4bf85c4fbf497eef582977 (diff)
ASoC: Add GPIO support for jack reporting interface
Add GPIO support to jack reporting framework in ASoC using gpiolib calls. The gpio support exports two new functions: snd_soc_jack_add_gpios and snd_soc_jack_free_gpios. Client drivers using gpio feature must pass an array of jack_gpio pins belonging to a specific jack to the snd_soc_jack_add_gpios function. The framework will request the gpios, set the data direction and request irq. The framework will update power status of related jack_pins when an event on the gpio pins comes according to the reporting bits defined for each gpio. All gpio resources allocated when adding jack_gpio pins can be released using snd_soc_jack_free_gpios function. Signed-off-by: Misael Lopez Cruz <x0052729@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/soc-jack.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ab64a30bedde..bdf2484c2220 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -14,6 +14,10 @@
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
/**
* snd_soc_jack_new - Create a new jack
@@ -136,3 +140,128 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
+
+#ifdef CONFIG_GPIOLIB
+/* gpio detect */
+void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
+{
+ struct snd_soc_jack *jack = gpio->jack;
+ int enable;
+ int report;
+
+ if (gpio->debounce_time > 0)
+ mdelay(gpio->debounce_time);
+
+ enable = gpio_get_value(gpio->gpio);
+ if (gpio->invert)
+ enable = !enable;
+
+ if (enable)
+ report = gpio->report;
+ else
+ report = 0;
+
+ snd_soc_jack_report(jack, report, gpio->report);
+}
+
+/* irq handler for gpio pin */
+static irqreturn_t gpio_handler(int irq, void *data)
+{
+ struct snd_soc_jack_gpio *gpio = data;
+
+ schedule_work(&gpio->work);
+
+ return IRQ_HANDLED;
+}
+
+/* gpio work */
+static void gpio_work(struct work_struct *work)
+{
+ struct snd_soc_jack_gpio *gpio;
+
+ gpio = container_of(work, struct snd_soc_jack_gpio, work);
+ snd_soc_jack_gpio_detect(gpio);
+}
+
+/**
+ * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
+ *
+ * @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_gpios(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_gpio *gpios)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ if (!gpio_is_valid(gpios[i].gpio)) {
+ printk(KERN_ERR "Invalid gpio %d\n",
+ gpios[i].gpio);
+ ret = -EINVAL;
+ goto undo;
+ }
+ if (!gpios[i].name) {
+ printk(KERN_ERR "No name for gpio %d\n",
+ gpios[i].gpio);
+ ret = -EINVAL;
+ goto undo;
+ }
+
+ ret = gpio_request(gpios[i].gpio, gpios[i].name);
+ if (ret)
+ goto undo;
+
+ ret = gpio_direction_input(gpios[i].gpio);
+ if (ret)
+ goto err;
+
+ ret = request_irq(gpio_to_irq(gpios[i].gpio),
+ gpio_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ jack->card->dev->driver->name,
+ &gpios[i]);
+ if (ret)
+ goto err;
+
+ INIT_WORK(&gpios[i].work, gpio_work);
+ gpios[i].jack = jack;
+ }
+
+ return 0;
+
+err:
+ gpio_free(gpios[i].gpio);
+undo:
+ snd_soc_jack_free_gpios(jack, i, gpios);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios);
+
+/**
+ * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
+ *
+ * @jack: ASoC jack
+ * @count: number of pins
+ * @gpios: array of gpio pins
+ *
+ * Release gpio and irq resources for gpio pins associated with an ASoC jack.
+ */
+void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_gpio *gpios)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+ gpio_free(gpios[i].gpio);
+ gpios[i].jack = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
+#endif /* CONFIG_GPIOLIB */