[v3,09/13] ASoC: arizona-jack: convert into a helper library for codec drivers
diff mbox series

Message ID 20210122164107.361939-10-hdegoede@redhat.com
State New, archived
Headers show
Series
  • MFD/extcon/ASoC: Rework arizona codec jack-detect support
Related show

Commit Message

Hans de Goede Jan. 22, 2021, 4:41 p.m. UTC
Convert the arizona extcon driver into a helper library for direct use
from the arizona codec-drivers, rather then being bound to a separate
MFD cell.

Note the probe (and remove) sequence is split into 2 parts:

1. The arizona_jack_codec_dev_probe() function inits a bunch of
jack-detect specific variables in struct arizona_priv and tries to get
a number of resources where getting them may fail with -EPROBE_DEFER.

2. Then once the machine driver has create a snd_sock_jack through
snd_soc_card_jack_new() it calls snd_soc_component_set_jack() on
the codec component, which will call the new arizona_jack_set_jack(),
which sets up jack-detection and requests the IRQs.

This split is necessary, because the IRQ handlers need access to the
arizona->dapm pointer and the snd_sock_jack which are not available
when the codec-driver's probe function runs.

Note this requires that machine-drivers for codecs which are converted
to use the new helper functions from arizona-jack.c are modified to
create a snd_soc_jack through snd_soc_card_jack_new() and register
this jack with the codec through snd_soc_component_set_jack().

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v3:
- Pass dev (the codec-device) to devm_regulator_get instead of
  passing arizona->dev. This is necessary so that the regulator gets
  properly released when the coded driver unbinds.
---
 sound/soc/codecs/Makefile       |   2 +-
 sound/soc/codecs/arizona-jack.c | 125 +++++++++++++++-----------------
 sound/soc/codecs/arizona.h      |   6 ++
 3 files changed, 65 insertions(+), 68 deletions(-)

Comments

Andy Shevchenko Jan. 22, 2021, 8:47 p.m. UTC | #1
On Fri, Jan 22, 2021 at 6:41 PM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Convert the arizona extcon driver into a helper library for direct use
> from the arizona codec-drivers, rather then being bound to a separate
> MFD cell.
>
> Note the probe (and remove) sequence is split into 2 parts:
>
> 1. The arizona_jack_codec_dev_probe() function inits a bunch of
> jack-detect specific variables in struct arizona_priv and tries to get
> a number of resources where getting them may fail with -EPROBE_DEFER.
>
> 2. Then once the machine driver has create a snd_sock_jack through
> snd_soc_card_jack_new() it calls snd_soc_component_set_jack() on
> the codec component, which will call the new arizona_jack_set_jack(),
> which sets up jack-detection and requests the IRQs.
>
> This split is necessary, because the IRQ handlers need access to the
> arizona->dapm pointer and the snd_sock_jack which are not available
> when the codec-driver's probe function runs.
>
> Note this requires that machine-drivers for codecs which are converted
> to use the new helper functions from arizona-jack.c are modified to
> create a snd_soc_jack through snd_soc_card_jack_new() and register
> this jack with the codec through snd_soc_component_set_jack().

Okay, it seems that messages are on behalf of the parent while managed
resources are being attached to the actual device.
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>


> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v3:
> - Pass dev (the codec-device) to devm_regulator_get instead of
>   passing arizona->dev. This is necessary so that the regulator gets
>   properly released when the coded driver unbinds.
> ---
>  sound/soc/codecs/Makefile       |   2 +-
>  sound/soc/codecs/arizona-jack.c | 125 +++++++++++++++-----------------
>  sound/soc/codecs/arizona.h      |   6 ++
>  3 files changed, 65 insertions(+), 68 deletions(-)
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index d277f0366e09..2e976cfaa862 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o
>  snd-soc-ak4671-objs := ak4671.o
>  snd-soc-ak5386-objs := ak5386.o
>  snd-soc-ak5558-objs := ak5558.o
> -snd-soc-arizona-objs := arizona.o
> +snd-soc-arizona-objs := arizona.o arizona-jack.o
>  snd-soc-bd28623-objs := bd28623.o
>  snd-soc-bt-sco-objs := bt-sco.o
>  snd-soc-cpcap-objs := cpcap.o
> diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
> index a6e8071f84ab..e121490eb379 100644
> --- a/sound/soc/codecs/arizona-jack.c
> +++ b/sound/soc/codecs/arizona-jack.c
> @@ -7,14 +7,12 @@
>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> -#include <linux/i2c.h>
>  #include <linux/slab.h>
>  #include <linux/interrupt.h>
>  #include <linux/err.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/gpio.h>
>  #include <linux/input.h>
> -#include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/property.h>
>  #include <linux/regulator/consumer.h>
> @@ -1337,27 +1335,16 @@ static int arizona_extcon_device_get_pdata(struct device *dev,
>         return 0;
>  }
>
> -static int arizona_extcon_probe(struct platform_device *pdev)
> +int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
>  {
> -       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
> +       struct arizona *arizona = info->arizona;
>         struct arizona_pdata *pdata = &arizona->pdata;
> -       struct arizona_priv *info;
> -       unsigned int val;
> -       unsigned int clamp_mode;
> -       int jack_irq_fall, jack_irq_rise;
> -       int ret, mode, i, j;
> -
> -       if (!arizona->dapm || !arizona->dapm->card)
> -               return -EPROBE_DEFER;
> -
> -       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> -       if (!info)
> -               return -ENOMEM;
> +       int ret, mode;
>
>         if (!dev_get_platdata(arizona->dev))
> -               arizona_extcon_device_get_pdata(&pdev->dev, arizona);
> +               arizona_extcon_device_get_pdata(dev, arizona);
>
> -       info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
> +       info->micvdd = devm_regulator_get(dev, "MICVDD");
>         if (IS_ERR(info->micvdd)) {
>                 ret = PTR_ERR(info->micvdd);
>                 dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
> @@ -1365,12 +1352,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>         }
>
>         mutex_init(&info->lock);
> -       info->arizona = arizona;
>         info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
>         INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
>         INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
>         INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
> -       platform_set_drvdata(pdev, info);
>
>         switch (arizona->type) {
>         case WM5102:
> @@ -1404,20 +1389,20 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>                 break;
>         }
>
> -       info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
> +       info->edev = devm_extcon_dev_allocate(dev, arizona_cable);
>         if (IS_ERR(info->edev)) {
> -               dev_err(&pdev->dev, "failed to allocate extcon device\n");
> +               dev_err(arizona->dev, "failed to allocate extcon device\n");
>                 return -ENOMEM;
>         }
>
> -       ret = devm_extcon_dev_register(&pdev->dev, info->edev);
> +       ret = devm_extcon_dev_register(dev, info->edev);
>         if (ret < 0) {
>                 dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
>                         ret);
>                 return ret;
>         }
>
> -       info->input = devm_input_allocate_device(&pdev->dev);
> +       info->input = devm_input_allocate_device(dev);
>         if (!info->input) {
>                 dev_err(arizona->dev, "Can't allocate input dev\n");
>                 ret = -ENOMEM;
> @@ -1448,7 +1433,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>                 else
>                         mode = GPIOF_OUT_INIT_LOW;
>
> -               ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
> +               ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio,
>                                             mode, "MICD polarity");
>                 if (ret != 0) {
>                         dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
> @@ -1481,17 +1466,38 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>         }
>
>         if (arizona->pdata.hpdet_id_gpio > 0) {
> -               ret = devm_gpio_request_one(&pdev->dev,
> -                                           arizona->pdata.hpdet_id_gpio,
> +               ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
>                                             GPIOF_OUT_INIT_LOW,
>                                             "HPDET");
>                 if (ret != 0) {
>                         dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
>                                 arizona->pdata.hpdet_id_gpio, ret);
> -                       goto err_gpio;
> +                       gpiod_put(info->micd_pol_gpio);
> +                       return ret;
>                 }
>         }
>
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe);
> +
> +int arizona_jack_codec_dev_remove(struct arizona_priv *info)
> +{
> +       gpiod_put(info->micd_pol_gpio);
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove);
> +
> +static int arizona_jack_enable_jack_detect(struct arizona_priv *info,
> +                                          struct snd_soc_jack *jack)
> +{
> +       struct arizona *arizona = info->arizona;
> +       struct arizona_pdata *pdata = &arizona->pdata;
> +       unsigned int val;
> +       unsigned int clamp_mode;
> +       int jack_irq_fall, jack_irq_rise;
> +       int ret, i, j;
> +
>         if (arizona->pdata.micd_bias_start_time)
>                 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
>                                    ARIZONA_MICD_BIAS_STARTTIME_MASK,
> @@ -1532,16 +1538,15 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>         if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
>                 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
>                         arizona->pdata.num_micd_ranges);
> +               return -EINVAL;
>         }
>
>         if (info->num_micd_ranges > 1) {
>                 for (i = 1; i < info->num_micd_ranges; i++) {
>                         if (info->micd_ranges[i - 1].max >
>                             info->micd_ranges[i].max) {
> -                               dev_err(arizona->dev,
> -                                       "MICD ranges must be sorted\n");
> -                               ret = -EINVAL;
> -                               goto err_gpio;
> +                               dev_err(arizona->dev, "MICD ranges must be sorted\n");
> +                               return -EINVAL;
>                         }
>                 }
>         }
> @@ -1559,8 +1564,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>                 if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
>                         dev_err(arizona->dev, "Unsupported MICD level %d\n",
>                                 info->micd_ranges[i].max);
> -                       ret = -EINVAL;
> -                       goto err_gpio;
> +                       return -EINVAL;
>                 }
>
>                 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
> @@ -1629,43 +1633,40 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>         ret = arizona_request_irq(arizona, jack_irq_rise,
>                                   "JACKDET rise", arizona_jackdet, info);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
> -                       ret);
> +               dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret);
>                 goto err_pm;
>         }
>
>         ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
> -                       ret);
> +               dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret);
>                 goto err_rise;
>         }
>
>         ret = arizona_request_irq(arizona, jack_irq_fall,
>                                   "JACKDET fall", arizona_jackdet, info);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
> +               dev_err(arizona->dev, "Failed to get JD fall IRQ: %d\n", ret);
>                 goto err_rise_wake;
>         }
>
>         ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
> -                       ret);
> +               dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret);
>                 goto err_fall;
>         }
>
>         ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
>                                   "MICDET", arizona_micdet, info);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
> +               dev_err(arizona->dev, "Failed to get MICDET IRQ: %d\n", ret);
>                 goto err_fall_wake;
>         }
>
>         ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
>                                   "HPDET", arizona_hpdet_irq, info);
>         if (ret != 0) {
> -               dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
> +               dev_err(arizona->dev, "Failed to get HPDET IRQ: %d\n", ret);
>                 goto err_micdet;
>         }
>
> @@ -1677,12 +1678,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>
>         ret = regulator_allow_bypass(info->micvdd, true);
>         if (ret != 0)
> -               dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
> -                        ret);
> +               dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret);
>
>         ret = input_register_device(info->input);
>         if (ret) {
> -               dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
> +               dev_err(arizona->dev, "Can't register input device: %d\n", ret);
>                 goto err_hpdet;
>         }
>
> @@ -1704,14 +1704,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
>         arizona_free_irq(arizona, jack_irq_rise, info);
>  err_pm:
>         pm_runtime_put(arizona->dev);
> -err_gpio:
> -       gpiod_put(info->micd_pol_gpio);
>         return ret;
>  }
>
> -static int arizona_extcon_remove(struct platform_device *pdev)
> +static int arizona_jack_disable_jack_detect(struct arizona_priv *info)
>  {
> -       struct arizona_priv *info = platform_get_drvdata(pdev);
>         struct arizona *arizona = info->arizona;
>         int jack_irq_rise, jack_irq_fall;
>         bool change;
> @@ -1739,8 +1736,7 @@ static int arizona_extcon_remove(struct platform_device *pdev)
>                                        ARIZONA_MICD_ENA, 0,
>                                        &change);
>         if (ret < 0) {
> -               dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
> -                       ret);
> +               dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret);
>         } else if (change) {
>                 regulator_disable(info->micvdd);
>                 pm_runtime_put(arizona->dev);
> @@ -1753,22 +1749,17 @@ static int arizona_extcon_remove(struct platform_device *pdev)
>                            ARIZONA_JD1_ENA, 0);
>         arizona_clk32k_disable(arizona);
>
> -       gpiod_put(info->micd_pol_gpio);
> -
>         return 0;
>  }
>
> -static struct platform_driver arizona_extcon_driver = {
> -       .driver         = {
> -               .name   = "arizona-extcon",
> -       },
> -       .probe          = arizona_extcon_probe,
> -       .remove         = arizona_extcon_remove,
> -};
> -
> -module_platform_driver(arizona_extcon_driver);
> +int arizona_jack_set_jack(struct snd_soc_component *component,
> +                         struct snd_soc_jack *jack, void *data)
> +{
> +       struct arizona_priv *info = snd_soc_component_get_drvdata(component);
>
> -MODULE_DESCRIPTION("Arizona Extcon driver");
> -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
> -MODULE_LICENSE("GPL");
> -MODULE_ALIAS("platform:extcon-arizona");
> +       if (jack)
> +               return arizona_jack_enable_jack_detect(info, jack);
> +       else
> +               return arizona_jack_disable_jack_detect(info);
> +}
> +EXPORT_SYMBOL_GPL(arizona_jack_set_jack);
> diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
> index 7132dbc3c840..fc515845a3e6 100644
> --- a/sound/soc/codecs/arizona.h
> +++ b/sound/soc/codecs/arizona.h
> @@ -386,4 +386,10 @@ static inline int arizona_unregister_notifier(struct snd_soc_component *componen
>
>  int arizona_of_get_audio_pdata(struct arizona *arizona);
>
> +int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev);
> +int arizona_jack_codec_dev_remove(struct arizona_priv *info);
> +
> +int arizona_jack_set_jack(struct snd_soc_component *component,
> +                         struct snd_soc_jack *jack, void *data);
> +
>  #endif
> --
> 2.28.0
>

Patch
diff mbox series

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d277f0366e09..2e976cfaa862 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -43,7 +43,7 @@  snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-ak5558-objs := ak5558.o
-snd-soc-arizona-objs := arizona.o
+snd-soc-arizona-objs := arizona.o arizona-jack.o
 snd-soc-bd28623-objs := bd28623.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-cpcap-objs := cpcap.o
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
index a6e8071f84ab..e121490eb379 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -7,14 +7,12 @@ 
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio.h>
 #include <linux/input.h>
-#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
@@ -1337,27 +1335,16 @@  static int arizona_extcon_device_get_pdata(struct device *dev,
 	return 0;
 }
 
-static int arizona_extcon_probe(struct platform_device *pdev)
+int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
 {
-	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct arizona *arizona = info->arizona;
 	struct arizona_pdata *pdata = &arizona->pdata;
-	struct arizona_priv *info;
-	unsigned int val;
-	unsigned int clamp_mode;
-	int jack_irq_fall, jack_irq_rise;
-	int ret, mode, i, j;
-
-	if (!arizona->dapm || !arizona->dapm->card)
-		return -EPROBE_DEFER;
-
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
+	int ret, mode;
 
 	if (!dev_get_platdata(arizona->dev))
-		arizona_extcon_device_get_pdata(&pdev->dev, arizona);
+		arizona_extcon_device_get_pdata(dev, arizona);
 
-	info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
+	info->micvdd = devm_regulator_get(dev, "MICVDD");
 	if (IS_ERR(info->micvdd)) {
 		ret = PTR_ERR(info->micvdd);
 		dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
@@ -1365,12 +1352,10 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 	}
 
 	mutex_init(&info->lock);
-	info->arizona = arizona;
 	info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
 	INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
 	INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
 	INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
-	platform_set_drvdata(pdev, info);
 
 	switch (arizona->type) {
 	case WM5102:
@@ -1404,20 +1389,20 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 		break;
 	}
 
-	info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
+	info->edev = devm_extcon_dev_allocate(dev, arizona_cable);
 	if (IS_ERR(info->edev)) {
-		dev_err(&pdev->dev, "failed to allocate extcon device\n");
+		dev_err(arizona->dev, "failed to allocate extcon device\n");
 		return -ENOMEM;
 	}
 
-	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
+	ret = devm_extcon_dev_register(dev, info->edev);
 	if (ret < 0) {
 		dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
 			ret);
 		return ret;
 	}
 
-	info->input = devm_input_allocate_device(&pdev->dev);
+	info->input = devm_input_allocate_device(dev);
 	if (!info->input) {
 		dev_err(arizona->dev, "Can't allocate input dev\n");
 		ret = -ENOMEM;
@@ -1448,7 +1433,7 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 		else
 			mode = GPIOF_OUT_INIT_LOW;
 
-		ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
+		ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio,
 					    mode, "MICD polarity");
 		if (ret != 0) {
 			dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
@@ -1481,17 +1466,38 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 	}
 
 	if (arizona->pdata.hpdet_id_gpio > 0) {
-		ret = devm_gpio_request_one(&pdev->dev,
-					    arizona->pdata.hpdet_id_gpio,
+		ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
 					    GPIOF_OUT_INIT_LOW,
 					    "HPDET");
 		if (ret != 0) {
 			dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
 				arizona->pdata.hpdet_id_gpio, ret);
-			goto err_gpio;
+			gpiod_put(info->micd_pol_gpio);
+			return ret;
 		}
 	}
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe);
+
+int arizona_jack_codec_dev_remove(struct arizona_priv *info)
+{
+	gpiod_put(info->micd_pol_gpio);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove);
+
+static int arizona_jack_enable_jack_detect(struct arizona_priv *info,
+					   struct snd_soc_jack *jack)
+{
+	struct arizona *arizona = info->arizona;
+	struct arizona_pdata *pdata = &arizona->pdata;
+	unsigned int val;
+	unsigned int clamp_mode;
+	int jack_irq_fall, jack_irq_rise;
+	int ret, i, j;
+
 	if (arizona->pdata.micd_bias_start_time)
 		regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
 				   ARIZONA_MICD_BIAS_STARTTIME_MASK,
@@ -1532,16 +1538,15 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 	if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
 		dev_err(arizona->dev, "Too many MICD ranges: %d\n",
 			arizona->pdata.num_micd_ranges);
+		return -EINVAL;
 	}
 
 	if (info->num_micd_ranges > 1) {
 		for (i = 1; i < info->num_micd_ranges; i++) {
 			if (info->micd_ranges[i - 1].max >
 			    info->micd_ranges[i].max) {
-				dev_err(arizona->dev,
-					"MICD ranges must be sorted\n");
-				ret = -EINVAL;
-				goto err_gpio;
+				dev_err(arizona->dev, "MICD ranges must be sorted\n");
+				return -EINVAL;
 			}
 		}
 	}
@@ -1559,8 +1564,7 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 		if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
 			dev_err(arizona->dev, "Unsupported MICD level %d\n",
 				info->micd_ranges[i].max);
-			ret = -EINVAL;
-			goto err_gpio;
+			return -EINVAL;
 		}
 
 		dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
@@ -1629,43 +1633,40 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 	ret = arizona_request_irq(arizona, jack_irq_rise,
 				  "JACKDET rise", arizona_jackdet, info);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
-			ret);
+		dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret);
 		goto err_pm;
 	}
 
 	ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
-			ret);
+		dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret);
 		goto err_rise;
 	}
 
 	ret = arizona_request_irq(arizona, jack_irq_fall,
 				  "JACKDET fall", arizona_jackdet, info);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
+		dev_err(arizona->dev, "Failed to get JD fall IRQ: %d\n", ret);
 		goto err_rise_wake;
 	}
 
 	ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
-			ret);
+		dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret);
 		goto err_fall;
 	}
 
 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
 				  "MICDET", arizona_micdet, info);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
+		dev_err(arizona->dev, "Failed to get MICDET IRQ: %d\n", ret);
 		goto err_fall_wake;
 	}
 
 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
 				  "HPDET", arizona_hpdet_irq, info);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
+		dev_err(arizona->dev, "Failed to get HPDET IRQ: %d\n", ret);
 		goto err_micdet;
 	}
 
@@ -1677,12 +1678,11 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 
 	ret = regulator_allow_bypass(info->micvdd, true);
 	if (ret != 0)
-		dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
-			 ret);
+		dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret);
 
 	ret = input_register_device(info->input);
 	if (ret) {
-		dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
+		dev_err(arizona->dev, "Can't register input device: %d\n", ret);
 		goto err_hpdet;
 	}
 
@@ -1704,14 +1704,11 @@  static int arizona_extcon_probe(struct platform_device *pdev)
 	arizona_free_irq(arizona, jack_irq_rise, info);
 err_pm:
 	pm_runtime_put(arizona->dev);
-err_gpio:
-	gpiod_put(info->micd_pol_gpio);
 	return ret;
 }
 
-static int arizona_extcon_remove(struct platform_device *pdev)
+static int arizona_jack_disable_jack_detect(struct arizona_priv *info)
 {
-	struct arizona_priv *info = platform_get_drvdata(pdev);
 	struct arizona *arizona = info->arizona;
 	int jack_irq_rise, jack_irq_fall;
 	bool change;
@@ -1739,8 +1736,7 @@  static int arizona_extcon_remove(struct platform_device *pdev)
 				       ARIZONA_MICD_ENA, 0,
 				       &change);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
-			ret);
+		dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret);
 	} else if (change) {
 		regulator_disable(info->micvdd);
 		pm_runtime_put(arizona->dev);
@@ -1753,22 +1749,17 @@  static int arizona_extcon_remove(struct platform_device *pdev)
 			   ARIZONA_JD1_ENA, 0);
 	arizona_clk32k_disable(arizona);
 
-	gpiod_put(info->micd_pol_gpio);
-
 	return 0;
 }
 
-static struct platform_driver arizona_extcon_driver = {
-	.driver		= {
-		.name	= "arizona-extcon",
-	},
-	.probe		= arizona_extcon_probe,
-	.remove		= arizona_extcon_remove,
-};
-
-module_platform_driver(arizona_extcon_driver);
+int arizona_jack_set_jack(struct snd_soc_component *component,
+			  struct snd_soc_jack *jack, void *data)
+{
+	struct arizona_priv *info = snd_soc_component_get_drvdata(component);
 
-MODULE_DESCRIPTION("Arizona Extcon driver");
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:extcon-arizona");
+	if (jack)
+		return arizona_jack_enable_jack_detect(info, jack);
+	else
+		return arizona_jack_disable_jack_detect(info);
+}
+EXPORT_SYMBOL_GPL(arizona_jack_set_jack);
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 7132dbc3c840..fc515845a3e6 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -386,4 +386,10 @@  static inline int arizona_unregister_notifier(struct snd_soc_component *componen
 
 int arizona_of_get_audio_pdata(struct arizona *arizona);
 
+int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev);
+int arizona_jack_codec_dev_remove(struct arizona_priv *info);
+
+int arizona_jack_set_jack(struct snd_soc_component *component,
+			  struct snd_soc_jack *jack, void *data);
+
 #endif