Merge remote-tracking branches 'asoc/topic/hisi', 'asoc/topic/img', 'asoc/topic/jack...
[muen/linux.git] / sound / soc / soc-jack.c
index 7daf21fee355b22c0a522d51c3de723fd6b7a1fd..99902ae1a2d95d9c6e295be964929a7b68c7acca 100644 (file)
 #include <linux/suspend.h>
 #include <trace/events/asoc.h>
 
+struct jack_gpio_tbl {
+       int count;
+       struct snd_soc_jack *jack;
+       struct snd_soc_jack_gpio *gpios;
+};
+
 /**
  * snd_soc_codec_set_jack - configure codec jack.
  * @codec: CODEC
@@ -36,10 +42,32 @@ int snd_soc_codec_set_jack(struct snd_soc_codec *codec,
        if (codec->driver->set_jack)
                return codec->driver->set_jack(codec, jack, data);
        else
-               return -EINVAL;
+               return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_jack);
 
+/**
+ * snd_soc_component_set_jack - configure component jack.
+ * @component: COMPONENTs
+ * @jack: structure to use for the jack
+ * @data: can be used if codec driver need extra data for configuring jack
+ *
+ * Configures and enables jack detection function.
+ */
+int snd_soc_component_set_jack(struct snd_soc_component *component,
+                              struct snd_soc_jack *jack, void *data)
+{
+       /* will be removed */
+       if (component->set_jack)
+               return component->set_jack(component, jack, data);
+
+       if (component->driver->set_jack)
+               return component->driver->set_jack(component, jack, data);
+
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_jack);
+
 /**
  * snd_soc_card_jack_new - Create a new jack
  * @card:  ASoC card
@@ -333,6 +361,28 @@ static int snd_soc_jack_pm_notifier(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
+static void jack_free_gpios(struct snd_soc_jack *jack, int count,
+                           struct snd_soc_jack_gpio *gpios)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               gpiod_unexport(gpios[i].desc);
+               unregister_pm_notifier(&gpios[i].pm_notifier);
+               free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
+               cancel_delayed_work_sync(&gpios[i].work);
+               gpiod_put(gpios[i].desc);
+               gpios[i].jack = NULL;
+       }
+}
+
+static void jack_devres_free_gpios(struct device *dev, void *res)
+{
+       struct jack_gpio_tbl *tbl = res;
+
+       jack_free_gpios(tbl->jack, tbl->count, tbl->gpios);
+}
+
 /**
  * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
  *
@@ -347,6 +397,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                        struct snd_soc_jack_gpio *gpios)
 {
        int i, ret;
+       struct jack_gpio_tbl *tbl;
+
+       tbl = devres_alloc(jack_devres_free_gpios, sizeof(*tbl), GFP_KERNEL);
+       if (!tbl)
+               return -ENOMEM;
+       tbl->jack = jack;
+       tbl->count = count;
+       tbl->gpios = gpios;
 
        for (i = 0; i < count; i++) {
                if (!gpios[i].name) {
@@ -424,12 +482,14 @@ got_gpio:
                                      msecs_to_jiffies(gpios[i].debounce_time));
        }
 
+       devres_add(jack->card->dev, tbl);
        return 0;
 
 err:
        gpio_free(gpios[i].gpio);
 undo:
-       snd_soc_jack_free_gpios(jack, i, gpios);
+       jack_free_gpios(jack, i, gpios);
+       devres_free(tbl);
 
        return ret;
 }
@@ -471,16 +531,8 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods);
 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++) {
-               gpiod_unexport(gpios[i].desc);
-               unregister_pm_notifier(&gpios[i].pm_notifier);
-               free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
-               cancel_delayed_work_sync(&gpios[i].work);
-               gpiod_put(gpios[i].desc);
-               gpios[i].jack = NULL;
-       }
+       jack_free_gpios(jack, count, gpios);
+       devres_destroy(jack->card->dev, jack_devres_free_gpios, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
 #endif /* CONFIG_GPIOLIB */