mirror of https://gitee.com/openkylin/linux.git
ASoC: arizona-jack: convert into a helper library for codec drivers
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(). Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Acked-by: Charles Keepax <ckeepax@opensource.cirrus.com> Tested-by: Charles Keepax <ckeepax@opensource.cirrus.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20210307151807.35201-10-hdegoede@redhat.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
688c8461a4
commit
ffcc84b9e8
|
@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o
|
||||||
snd-soc-ak4671-objs := ak4671.o
|
snd-soc-ak4671-objs := ak4671.o
|
||||||
snd-soc-ak5386-objs := ak5386.o
|
snd-soc-ak5386-objs := ak5386.o
|
||||||
snd-soc-ak5558-objs := ak5558.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-bd28623-objs := bd28623.o
|
||||||
snd-soc-bt-sco-objs := bt-sco.o
|
snd-soc-bt-sco-objs := bt-sco.o
|
||||||
snd-soc-cpcap-objs := cpcap.o
|
snd-soc-cpcap-objs := cpcap.o
|
||||||
|
|
|
@ -7,14 +7,12 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
@ -1337,27 +1335,16 @@ static int arizona_extcon_device_get_pdata(struct device *dev,
|
||||||
return 0;
|
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_pdata *pdata = &arizona->pdata;
|
||||||
struct arizona_priv *info;
|
int ret, mode;
|
||||||
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;
|
|
||||||
|
|
||||||
if (!dev_get_platdata(arizona->dev))
|
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)) {
|
if (IS_ERR(info->micvdd)) {
|
||||||
ret = PTR_ERR(info->micvdd);
|
ret = PTR_ERR(info->micvdd);
|
||||||
dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
|
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);
|
mutex_init(&info->lock);
|
||||||
info->arizona = arizona;
|
|
||||||
info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
|
info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
|
||||||
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
|
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
|
||||||
INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
|
INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
|
||||||
INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
|
INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
|
||||||
platform_set_drvdata(pdev, info);
|
|
||||||
|
|
||||||
switch (arizona->type) {
|
switch (arizona->type) {
|
||||||
case WM5102:
|
case WM5102:
|
||||||
|
@ -1404,20 +1389,20 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
break;
|
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)) {
|
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;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
ret = devm_extcon_dev_register(dev, info->edev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
|
dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
|
||||||
ret);
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->input = devm_input_allocate_device(&pdev->dev);
|
info->input = devm_input_allocate_device(dev);
|
||||||
if (!info->input) {
|
if (!info->input) {
|
||||||
dev_err(arizona->dev, "Can't allocate input dev\n");
|
dev_err(arizona->dev, "Can't allocate input dev\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1448,7 +1433,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
else
|
else
|
||||||
mode = GPIOF_OUT_INIT_LOW;
|
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");
|
mode, "MICD polarity");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
|
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) {
|
if (arizona->pdata.hpdet_id_gpio > 0) {
|
||||||
ret = devm_gpio_request_one(&pdev->dev,
|
ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
|
||||||
arizona->pdata.hpdet_id_gpio,
|
|
||||||
GPIOF_OUT_INIT_LOW,
|
GPIOF_OUT_INIT_LOW,
|
||||||
"HPDET");
|
"HPDET");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
|
dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
|
||||||
arizona->pdata.hpdet_id_gpio, ret);
|
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)
|
if (arizona->pdata.micd_bias_start_time)
|
||||||
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||||
ARIZONA_MICD_BIAS_STARTTIME_MASK,
|
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) {
|
if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
|
||||||
dev_err(arizona->dev, "Too many MICD ranges: %d\n",
|
dev_err(arizona->dev, "Too many MICD ranges: %d\n",
|
||||||
arizona->pdata.num_micd_ranges);
|
arizona->pdata.num_micd_ranges);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->num_micd_ranges > 1) {
|
if (info->num_micd_ranges > 1) {
|
||||||
for (i = 1; i < info->num_micd_ranges; i++) {
|
for (i = 1; i < info->num_micd_ranges; i++) {
|
||||||
if (info->micd_ranges[i - 1].max >
|
if (info->micd_ranges[i - 1].max >
|
||||||
info->micd_ranges[i].max) {
|
info->micd_ranges[i].max) {
|
||||||
dev_err(arizona->dev,
|
dev_err(arizona->dev, "MICD ranges must be sorted\n");
|
||||||
"MICD ranges must be sorted\n");
|
return -EINVAL;
|
||||||
ret = -EINVAL;
|
|
||||||
goto err_gpio;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1559,8 +1564,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
|
if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
|
||||||
dev_err(arizona->dev, "Unsupported MICD level %d\n",
|
dev_err(arizona->dev, "Unsupported MICD level %d\n",
|
||||||
info->micd_ranges[i].max);
|
info->micd_ranges[i].max);
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
goto err_gpio;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
|
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,
|
ret = arizona_request_irq(arizona, jack_irq_rise,
|
||||||
"JACKDET rise", arizona_jackdet, info);
|
"JACKDET rise", arizona_jackdet, info);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
|
dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret);
|
||||||
ret);
|
|
||||||
goto err_pm;
|
goto err_pm;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
|
ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
|
dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret);
|
||||||
ret);
|
|
||||||
goto err_rise;
|
goto err_rise;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arizona_request_irq(arizona, jack_irq_fall,
|
ret = arizona_request_irq(arizona, jack_irq_fall,
|
||||||
"JACKDET fall", arizona_jackdet, info);
|
"JACKDET fall", arizona_jackdet, info);
|
||||||
if (ret != 0) {
|
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;
|
goto err_rise_wake;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
|
ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
|
dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret);
|
||||||
ret);
|
|
||||||
goto err_fall;
|
goto err_fall;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
|
ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
|
||||||
"MICDET", arizona_micdet, info);
|
"MICDET", arizona_micdet, info);
|
||||||
if (ret != 0) {
|
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;
|
goto err_fall_wake;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
|
ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
|
||||||
"HPDET", arizona_hpdet_irq, info);
|
"HPDET", arizona_hpdet_irq, info);
|
||||||
if (ret != 0) {
|
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;
|
goto err_micdet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1677,12 +1678,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = regulator_allow_bypass(info->micvdd, true);
|
ret = regulator_allow_bypass(info->micvdd, true);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
|
dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret);
|
||||||
ret);
|
|
||||||
|
|
||||||
ret = input_register_device(info->input);
|
ret = input_register_device(info->input);
|
||||||
if (ret) {
|
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;
|
goto err_hpdet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1704,14 +1704,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
arizona_free_irq(arizona, jack_irq_rise, info);
|
arizona_free_irq(arizona, jack_irq_rise, info);
|
||||||
err_pm:
|
err_pm:
|
||||||
pm_runtime_put(arizona->dev);
|
pm_runtime_put(arizona->dev);
|
||||||
err_gpio:
|
|
||||||
gpiod_put(info->micd_pol_gpio);
|
|
||||||
return ret;
|
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;
|
struct arizona *arizona = info->arizona;
|
||||||
int jack_irq_rise, jack_irq_fall;
|
int jack_irq_rise, jack_irq_fall;
|
||||||
bool change;
|
bool change;
|
||||||
|
@ -1739,8 +1736,7 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
||||||
ARIZONA_MICD_ENA, 0,
|
ARIZONA_MICD_ENA, 0,
|
||||||
&change);
|
&change);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
|
dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret);
|
||||||
ret);
|
|
||||||
} else if (change) {
|
} else if (change) {
|
||||||
regulator_disable(info->micvdd);
|
regulator_disable(info->micvdd);
|
||||||
pm_runtime_put(arizona->dev);
|
pm_runtime_put(arizona->dev);
|
||||||
|
@ -1753,22 +1749,17 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
||||||
ARIZONA_JD1_ENA, 0);
|
ARIZONA_JD1_ENA, 0);
|
||||||
arizona_clk32k_disable(arizona);
|
arizona_clk32k_disable(arizona);
|
||||||
|
|
||||||
gpiod_put(info->micd_pol_gpio);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver arizona_extcon_driver = {
|
int arizona_jack_set_jack(struct snd_soc_component *component,
|
||||||
.driver = {
|
struct snd_soc_jack *jack, void *data)
|
||||||
.name = "arizona-extcon",
|
{
|
||||||
},
|
struct arizona_priv *info = snd_soc_component_get_drvdata(component);
|
||||||
.probe = arizona_extcon_probe,
|
|
||||||
.remove = arizona_extcon_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_platform_driver(arizona_extcon_driver);
|
if (jack)
|
||||||
|
return arizona_jack_enable_jack_detect(info, jack);
|
||||||
MODULE_DESCRIPTION("Arizona Extcon driver");
|
else
|
||||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
return arizona_jack_disable_jack_detect(info);
|
||||||
MODULE_LICENSE("GPL");
|
}
|
||||||
MODULE_ALIAS("platform:extcon-arizona");
|
EXPORT_SYMBOL_GPL(arizona_jack_set_jack);
|
||||||
|
|
|
@ -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_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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue