|
@@ -14,6 +14,10 @@
|
|
#include <sound/jack.h>
|
|
#include <sound/jack.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-dapm.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
|
|
* 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;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
|
|
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 */
|