diff options
author | Mark Brown <broonie@kernel.org> | 2021-03-25 00:29:33 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2021-03-25 00:29:33 +0100 |
commit | 3f994c25868729fb63a4eef42a7040e563eff365 (patch) | |
tree | 1106ef299ade5e437bec1b76ea07450f0e7dee74 /sound/soc | |
parent | ASoC: fsl_micfil: Don't use devm_regmap_init_mmio_clk (diff) | |
parent | ASoC: Intel: bytcr_wm5102: Add jack detect support (diff) | |
download | linux-3f994c25868729fb63a4eef42a7040e563eff365.tar.xz linux-3f994c25868729fb63a4eef42a7040e563eff365.zip |
Merge series "MFD/extcon/ASoC: Rework arizona codec jack-detect support" from Hans de Goede <hdegoede@redhat.com>:
Hi All,
Here is v4 of my series to rework the arizona codec jack-detect support
to use the snd_soc_jack helpers instead of direct extcon reporting.
As discussed before here is a resend rebased on 5.12-rc2, making sure that
all patches this depends on are in place.
Lee, can you pick-up patches 1-6 through the MFD tree and then send a
pull-req to Mark so that Mark can merge the Asoc parts throught the ASoC
tree ?
Patches 2-6 touch drivers/extcon, these all have an Ack from Chanwoo Choi
for merging these through the MFD tree.
Here is some more generic info on this series from the previous
cover-letter:
This is done by reworking the extcon driver into an arizona-jackdet
library and then modifying the codec drivers to use that directly,
replacing the old separate extcon child-devices and extcon-driver.
This brings the arizona-codec jack-detect handling inline with how
all other ASoC codec driver do this. This was developed and tested on
a Lenovo Yoga Tablet 1051L with a WM5102 codec.
This was also tested by Charles Keepax, one of the Cirrus Codec folks.
Regards,
Hans
Hans de Goede (13):
mfd: arizona: Drop arizona-extcon cells
extcon: arizona: Fix some issues when HPDET IRQ fires after the jack
has been unplugged
extcon: arizona: Fix various races on driver unbind
extcon: arizona: Fix flags parameter to the gpiod_get("wlf,micd-pol")
call
extcon: arizona: Always use pm_runtime_get_sync() when we need the
device to be awake
ASoC/extcon: arizona: Move arizona jack code to
sound/soc/codecs/arizona-jack.c
ASoC: arizona-jack: Move jack-detect variables to struct arizona_priv
ASoC: arizona-jack: Use arizona->dev for runtime-pm
ASoC: arizona-jack: convert into a helper library for codec drivers
ASoC: arizona-jack: Use snd_soc_jack to report jack events
ASoC: arizona-jack: Cleanup logging
ASoC: arizona: Make the wm5102, wm5110, wm8997 and wm8998 drivers use
the new jack library
ASoC: Intel: bytcr_wm5102: Add jack detect support
MAINTAINERS | 3 +-
drivers/extcon/Kconfig | 8 -
drivers/extcon/Makefile | 1 -
drivers/mfd/arizona-core.c | 20 -
sound/soc/codecs/Makefile | 2 +-
.../soc/codecs/arizona-jack.c | 577 +++++++-----------
sound/soc/codecs/arizona.h | 44 ++
sound/soc/codecs/wm5102.c | 12 +-
sound/soc/codecs/wm5110.c | 12 +-
sound/soc/codecs/wm8997.c | 14 +-
sound/soc/codecs/wm8998.c | 9 +
sound/soc/intel/boards/bytcr_wm5102.c | 28 +-
12 files changed, 325 insertions(+), 405 deletions(-)
rename drivers/extcon/extcon-arizona.c => sound/soc/codecs/arizona-jack.c (76%)
--
2.30.1
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/arizona-jack.c | 544 | ||||
-rw-r--r-- | sound/soc/codecs/arizona.h | 44 | ||||
-rw-r--r-- | sound/soc/codecs/wm5102.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/wm5110.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/wm8997.c | 14 | ||||
-rw-r--r-- | sound/soc/codecs/wm8998.c | 9 | ||||
-rw-r--r-- | sound/soc/intel/boards/bytcr_wm5102.c | 28 |
8 files changed, 306 insertions, 359 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index edff5c5b92d3..a710dfea7876 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 56d2ce05de50..9c15ddba6008 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -7,19 +7,17 @@ #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> -#include <linux/extcon-provider.h> +#include <sound/jack.h> #include <sound/soc.h> #include <linux/mfd/arizona/core.h> @@ -27,8 +25,16 @@ #include <linux/mfd/arizona/registers.h> #include <dt-bindings/mfd/arizona.h> +#include "arizona.h" + #define ARIZONA_MAX_MICD_RANGE 8 +/* + * The hardware supports 8 ranges / buttons, but the snd-jack interface + * only supports 6 buttons (button 0-5). + */ +#define ARIZONA_MAX_MICD_BUTTONS 6 + #define ARIZONA_MICD_CLAMP_MODE_JDL 0x4 #define ARIZONA_MICD_CLAMP_MODE_JDH 0x5 #define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9 @@ -61,47 +67,6 @@ #define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8) -struct arizona_extcon_info { - struct device *dev; - struct arizona *arizona; - struct mutex lock; - struct regulator *micvdd; - struct input_dev *input; - - u16 last_jackdet; - - int micd_mode; - const struct arizona_micd_config *micd_modes; - int micd_num_modes; - - const struct arizona_micd_range *micd_ranges; - int num_micd_ranges; - - bool micd_reva; - bool micd_clamp; - - struct delayed_work hpdet_work; - struct delayed_work micd_detect_work; - struct delayed_work micd_timeout_work; - - bool hpdet_active; - bool hpdet_done; - bool hpdet_retried; - - int num_hpdet_res; - unsigned int hpdet_res[3]; - - bool mic; - bool detecting; - int jack_flips; - - int hpdet_ip_version; - - struct extcon_dev *edev; - - struct gpio_desc *micd_pol_gpio; -}; - static const struct arizona_micd_config micd_default_modes[] = { { ARIZONA_ACCDET_SRC, 1, 0 }, { 0, 2, 1 }, @@ -127,17 +92,9 @@ static const int arizona_micd_levels[] = { 1257, 30000, }; -static const unsigned int arizona_cable[] = { - EXTCON_MECHANICAL, - EXTCON_JACK_MICROPHONE, - EXTCON_JACK_HEADPHONE, - EXTCON_JACK_LINE_OUT, - EXTCON_NONE, -}; - -static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); +static void arizona_start_hpdet_acc_id(struct arizona_priv *info); -static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, +static void arizona_extcon_hp_clamp(struct arizona_priv *info, bool clamp) { struct arizona *arizona = info->arizona; @@ -166,9 +123,8 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, ARIZONA_HP_TEST_CTRL_1, ARIZONA_HP1_TST_CAP_SEL_MASK, cap_sel); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to set TST_CAP_SEL: %d\n", ret); + if (ret) + dev_warn(arizona->dev, "Failed to set TST_CAP_SEL: %d\n", ret); break; default: mask = ARIZONA_RMV_SHRT_HP1L; @@ -187,24 +143,20 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA, 0); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to disable headphone outputs: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable headphone outputs: %d\n", ret); } if (mask) { ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L, mask, val); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do clamp: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R, mask, val); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do clamp: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); } /* Restore the desired state while not doing the clamp */ @@ -213,16 +165,14 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA, arizona->hp_ena); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to restore headphone outputs: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to restore headphone outputs: %d\n", ret); } snd_soc_dapm_mutex_unlock(arizona->dapm); } -static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) +static void arizona_extcon_set_mode(struct arizona_priv *info, int mode) { struct arizona *arizona = info->arizona; @@ -243,7 +193,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); } -static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) +static const char *arizona_extcon_get_micbias(struct arizona_priv *info) { switch (info->micd_modes[0].bias) { case 1: @@ -257,7 +207,7 @@ static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) } } -static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) +static void arizona_extcon_pulse_micbias(struct arizona_priv *info) { struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); @@ -266,23 +216,21 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) int ret; ret = snd_soc_component_force_enable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, "Failed to enable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); if (!arizona->pdata.micd_force_micbias) { ret = snd_soc_component_disable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, "Failed to disable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); } } -static void arizona_start_mic(struct arizona_extcon_info *info) +static void arizona_start_mic(struct arizona_priv *info) { struct arizona *arizona = info->arizona; bool change; @@ -290,22 +238,17 @@ static void arizona_start_mic(struct arizona_extcon_info *info) unsigned int mode; /* Microphone detection can't use idle mode */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); if (info->detecting) { ret = regulator_allow_bypass(info->micvdd, false); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to regulate MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to regulate MICVDD: %d\n", ret); } ret = regulator_enable(info->micvdd); - if (ret != 0) { - dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", ret); if (info->micd_reva) { const struct reg_sequence reva[] = { @@ -335,11 +278,11 @@ static void arizona_start_mic(struct arizona_extcon_info *info) dev_err(arizona->dev, "Failed to enable micd: %d\n", ret); } else if (!change) { regulator_disable(info->micvdd); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); } } -static void arizona_stop_mic(struct arizona_extcon_info *info) +static void arizona_stop_mic(struct arizona_priv *info) { struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); @@ -355,10 +298,8 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) dev_err(arizona->dev, "Failed to disable micd: %d\n", ret); ret = snd_soc_component_disable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to disable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); @@ -373,15 +314,13 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) } ret = regulator_allow_bypass(info->micvdd, true); - if (ret != 0) { - dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); if (change) { regulator_disable(info->micvdd); - pm_runtime_mark_last_busy(info->dev); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_mark_last_busy(arizona->dev); + pm_runtime_put_autosuspend(arizona->dev); } } @@ -407,24 +346,22 @@ static struct { { 1000, 10000 }, }; -static int arizona_hpdet_read(struct arizona_extcon_info *info) +static int arizona_hpdet_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val, range; int ret; ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read HPDET status: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read HPDET status: %d\n", ret); return ret; } switch (info->hpdet_ip_version) { case 0: if (!(val & ARIZONA_HP_DONE)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } @@ -433,15 +370,13 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) case 1: if (!(val & ARIZONA_HP_DONE_B)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read HP value: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read HP value: %d\n", ret); return -EAGAIN; } @@ -454,8 +389,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) (val < arizona_hpdet_b_ranges[range].threshold || val >= ARIZONA_HPDET_B_RANGE_MAX)) { range++; - dev_dbg(arizona->dev, "Moving to HPDET range %d\n", - range); + dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range); regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_IMPEDANCE_RANGE_MASK, @@ -471,8 +405,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) return ARIZONA_HPDET_MAX; } - dev_dbg(arizona->dev, "HPDET read %d in range %d\n", - val, range); + dev_dbg(arizona->dev, "HPDET read %d in range %d\n", val, range); val = arizona_hpdet_b_ranges[range].factor_b / ((val * 100) - @@ -481,8 +414,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) case 2: if (!(val & ARIZONA_HP_DONE_B)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } @@ -518,8 +450,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) break; default: - dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", - info->hpdet_ip_version); + dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", info->hpdet_ip_version); return -EINVAL; } @@ -527,7 +458,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) return val; } -static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, +static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading, bool *mic) { struct arizona *arizona = info->arizona; @@ -573,7 +504,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, info->num_hpdet_res = 0; info->hpdet_retried = true; arizona_start_hpdet_acc_id(info); - pm_runtime_put(info->dev); + pm_runtime_put(arizona->dev); return -EAGAIN; } @@ -597,11 +528,10 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, static irqreturn_t arizona_hpdet_irq(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; - unsigned int report = EXTCON_JACK_HEADPHONE; - int ret, reading, state; + int ret, reading, state, report; bool mic = false; mutex_lock(&info->lock); @@ -614,11 +544,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) } /* If the cable was removed while measuring ignore the result */ - state = extcon_get_state(info->edev, EXTCON_MECHANICAL); - if (state < 0) { - dev_err(arizona->dev, "Failed to check cable state: %d\n", state); - goto out; - } else if (!state) { + state = info->jack->status & SND_JACK_MECHANICAL; + if (!state) { dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n"); goto done; } @@ -644,14 +571,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) /* Report high impedence cables as line outputs */ if (reading >= 5000) - report = EXTCON_JACK_LINE_OUT; + report = SND_JACK_LINEOUT; else - report = EXTCON_JACK_HEADPHONE; + report = SND_JACK_HEADPHONE; - ret = extcon_set_state_sync(info->edev, report, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report HP/line: %d\n", - ret); + snd_soc_jack_report(info->jack, report, SND_JACK_LINEOUT | SND_JACK_HEADPHONE); done: /* Reset back to starting range */ @@ -670,7 +594,7 @@ done: arizona_start_mic(info); if (info->hpdet_active) { - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); info->hpdet_active = false; } @@ -684,7 +608,7 @@ out: return IRQ_HANDLED; } -static void arizona_identify_headphone(struct arizona_extcon_info *info) +static void arizona_identify_headphone(struct arizona_priv *info) { struct arizona *arizona = info->arizona; int ret; @@ -695,7 +619,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) dev_dbg(arizona->dev, "Starting HPDET\n"); /* Make sure we keep the device enabled during the measurement */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); info->hpdet_active = true; @@ -714,9 +638,8 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_POLL, ARIZONA_HP_POLL); - if (ret != 0) { - dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); goto err; } @@ -724,12 +647,11 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) err: arizona_extcon_hp_clamp(info, false); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); /* Just report headphone */ - ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); + snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, + SND_JACK_LINEOUT | SND_JACK_HEADPHONE); if (info->mic) arizona_start_mic(info); @@ -737,7 +659,7 @@ err: info->hpdet_active = false; } -static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) +static void arizona_start_hpdet_acc_id(struct arizona_priv *info) { struct arizona *arizona = info->arizona; int hp_reading = 32; @@ -747,7 +669,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) dev_dbg(arizona->dev, "Starting identification via HPDET\n"); /* Make sure we keep the device enabled during the measurement */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); info->hpdet_active = true; @@ -767,10 +689,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_POLL, ARIZONA_HP_POLL); - if (ret != 0) { - dev_err(arizona->dev, - "Can't start HPDETL measurement: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); goto err; } } else { @@ -781,17 +701,16 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) err: /* Just report headphone */ - ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); + snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, + SND_JACK_LINEOUT | SND_JACK_HEADPHONE); info->hpdet_active = false; } static void arizona_micd_timeout_work(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, micd_timeout_work.work); mutex_lock(&info->lock); @@ -805,7 +724,7 @@ static void arizona_micd_timeout_work(struct work_struct *work) mutex_unlock(&info->lock); } -static int arizona_micd_adc_read(struct arizona_extcon_info *info) +static int arizona_micd_adc_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val; @@ -816,9 +735,8 @@ static int arizona_micd_adc_read(struct arizona_extcon_info *info) ARIZONA_MICD_ENA, 0); ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to read MICDET_ADCVAL: %d\n", ret); + if (ret) { + dev_err(arizona->dev, "Failed to read MICDET_ADCVAL: %d\n", ret); return ret; } @@ -842,7 +760,7 @@ static int arizona_micd_adc_read(struct arizona_extcon_info *info) return val; } -static int arizona_micd_read(struct arizona_extcon_info *info) +static int arizona_micd_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val = 0; @@ -850,17 +768,15 @@ static int arizona_micd_read(struct arizona_extcon_info *info) for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) { ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to read MICDET: %d\n", ret); + if (ret) { + dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); return ret; } dev_dbg(arizona->dev, "MICDET: %x\n", val); if (!(val & ARIZONA_MICD_VALID)) { - dev_warn(arizona->dev, - "Microphone detection state invalid\n"); + dev_warn(arizona->dev, "Microphone detection state invalid\n"); return -EINVAL; } } @@ -875,7 +791,7 @@ static int arizona_micd_read(struct arizona_extcon_info *info) static int arizona_micdet_reading(void *priv) { - struct arizona_extcon_info *info = priv; + struct arizona_priv *info = priv; struct arizona *arizona = info->arizona; int ret, val; @@ -904,18 +820,12 @@ static int arizona_micdet_reading(void *priv) arizona_identify_headphone(info); - ret = extcon_set_state_sync(info->edev, - EXTCON_JACK_MICROPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Headset report failed: %d\n", - ret); + snd_soc_jack_report(info->jack, SND_JACK_MICROPHONE, SND_JACK_MICROPHONE); /* Don't need to regulate for button detection */ ret = regulator_allow_bypass(info->micvdd, true); - if (ret != 0) { - dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); return 0; } @@ -969,9 +879,9 @@ static int arizona_micdet_reading(void *priv) static int arizona_button_reading(void *priv) { - struct arizona_extcon_info *info = priv; + struct arizona_priv *info = priv; struct arizona *arizona = info->arizona; - int val, key, lvl, i; + int val, key, lvl; val = arizona_micd_read(info); if (val < 0) @@ -988,27 +898,20 @@ static int arizona_button_reading(void *priv) lvl = val & ARIZONA_MICD_LVL_MASK; lvl >>= ARIZONA_MICD_LVL_SHIFT; - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { - key = info->micd_ranges[ffs(lvl) - 1].key; - input_report_key(info->input, key, 1); - input_sync(info->input); + key = ffs(lvl) - 1; + snd_soc_jack_report(info->jack, + SND_JACK_BTN_0 >> key, + info->micd_button_mask); } else { dev_err(arizona->dev, "Button out of range\n"); } } else { - dev_warn(arizona->dev, "Button with no mic: %x\n", - val); + dev_warn(arizona->dev, "Button with no mic: %x\n", val); } } else { dev_dbg(arizona->dev, "Mic button released\n"); - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - input_sync(info->input); + snd_soc_jack_report(info->jack, 0, info->micd_button_mask); arizona_extcon_pulse_micbias(info); } @@ -1017,24 +920,17 @@ static int arizona_button_reading(void *priv) static void arizona_micd_detect(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, micd_detect_work.work); struct arizona *arizona = info->arizona; - int ret; cancel_delayed_work_sync(&info->micd_timeout_work); mutex_lock(&info->lock); /* If the cable was removed while measuring ignore the result */ - ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); - if (ret < 0) { - dev_err(arizona->dev, "Failed to check cable state: %d\n", - ret); - mutex_unlock(&info->lock); - return; - } else if (!ret) { + if (!(info->jack->status & SND_JACK_MECHANICAL)) { dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); mutex_unlock(&info->lock); return; @@ -1045,13 +941,13 @@ static void arizona_micd_detect(struct work_struct *work) else arizona_button_reading(info); - pm_runtime_mark_last_busy(info->dev); + pm_runtime_mark_last_busy(arizona->dev); mutex_unlock(&info->lock); } static irqreturn_t arizona_micdet(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; int debounce = arizona->pdata.micd_detect_debounce; @@ -1075,8 +971,8 @@ static irqreturn_t arizona_micdet(int irq, void *data) static void arizona_hpdet_work(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, hpdet_work.work); mutex_lock(&info->lock); @@ -1084,7 +980,7 @@ static void arizona_hpdet_work(struct work_struct *work) mutex_unlock(&info->lock); } -static int arizona_hpdet_wait(struct arizona_extcon_info *info) +static int arizona_hpdet_wait(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val; @@ -1094,8 +990,7 @@ static int arizona_hpdet_wait(struct arizona_extcon_info *info) ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); if (ret) { - dev_err(arizona->dev, - "Failed to read HPDET state: %d\n", ret); + dev_err(arizona->dev, "Failed to read HPDET state: %d\n", ret); return ret; } @@ -1120,7 +1015,7 @@ static int arizona_hpdet_wait(struct arizona_extcon_info *info) static irqreturn_t arizona_jackdet(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; unsigned int val, present, mask; bool cancelled_hp, cancelled_mic; @@ -1129,7 +1024,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); mutex_lock(&info->lock); @@ -1145,11 +1040,10 @@ static irqreturn_t arizona_jackdet(int irq, void *data) } ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read jackdet status: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); mutex_unlock(&info->lock); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); return IRQ_NONE; } @@ -1175,12 +1069,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) if (info->last_jackdet == present) { dev_dbg(arizona->dev, "Detected jack\n"); - ret = extcon_set_state_sync(info->edev, - EXTCON_MECHANICAL, true); - - if (ret != 0) - dev_err(arizona->dev, "Mechanical report failed: %d\n", - ret); + snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); info->detecting = true; info->mic = false; @@ -1211,18 +1100,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) info->hpdet_done = false; info->hpdet_retried = false; - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - input_sync(info->input); - - for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { - ret = extcon_set_state_sync(info->edev, - arizona_cable[i], false); - if (ret != 0) - dev_err(arizona->dev, - "Removal report failed: %d\n", ret); - } + snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); /* * If the jack was removed during a headphone detection we @@ -1249,8 +1127,8 @@ out: mutex_unlock(&info->lock); - pm_runtime_mark_last_busy(info->dev); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_mark_last_busy(arizona->dev); + pm_runtime_put_autosuspend(arizona->dev); return IRQ_HANDLED; } @@ -1333,8 +1211,7 @@ static int arizona_extcon_device_get_pdata(struct device *dev, pdata->hpdet_channel = val; break; default: - dev_err(arizona->dev, - "Wrong wlf,hpdet-channel DT value %d\n", val); + dev_err(arizona->dev, "Wrong wlf,hpdet-channel DT value %d\n", val); pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL; } @@ -1376,41 +1253,24 @@ 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_extcon_info *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"); - if (IS_ERR(info->micvdd)) { - ret = PTR_ERR(info->micvdd); - dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret); - return ret; - } + info->micvdd = devm_regulator_get(dev, "MICVDD"); + if (IS_ERR(info->micvdd)) + return dev_err_probe(arizona->dev, PTR_ERR(info->micvdd), "getting MICVDD\n"); mutex_init(&info->lock); - info->arizona = arizona; - info->dev = &pdev->dev; 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: @@ -1444,29 +1304,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) break; } - info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable); - if (IS_ERR(info->edev)) { - dev_err(&pdev->dev, "failed to allocate extcon device\n"); - return -ENOMEM; - } - - ret = devm_extcon_dev_register(&pdev->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); - if (!info->input) { - dev_err(arizona->dev, "Can't allocate input dev\n"); - ret = -ENOMEM; - return ret; - } - - info->input->name = "Headset"; - info->input->phys = "arizona/extcon"; - if (!pdata->micd_timeout) pdata->micd_timeout = DEFAULT_MICD_TIMEOUT; @@ -1488,7 +1325,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", @@ -1513,25 +1350,44 @@ static int arizona_extcon_probe(struct platform_device *pdev) mode); if (IS_ERR(info->micd_pol_gpio)) { ret = PTR_ERR(info->micd_pol_gpio); - dev_err(arizona->dev, - "Failed to get microphone polarity GPIO: %d\n", - ret); + dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n"); return ret; } } 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, @@ -1569,19 +1425,18 @@ static int arizona_extcon_probe(struct platform_device *pdev) info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges); } - 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); + if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_BUTTONS) { + dev_err(arizona->dev, "Too many MICD ranges: %d > %d\n", + arizona->pdata.num_micd_ranges, ARIZONA_MAX_MICD_BUTTONS); + 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; } } } @@ -1599,16 +1454,18 @@ 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", arizona_micd_levels[j], i); arizona_micd_set_level(arizona, i, j); - input_set_capability(info->input, EV_KEY, - info->micd_ranges[i].key); + + /* SND_JACK_BTN_# masks start with the most significant bit */ + info->micd_button_mask |= SND_JACK_BTN_0 >> i; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0 >> i, + info->micd_ranges[i].key); /* Enable reporting of that range */ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, @@ -1656,9 +1513,9 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona_extcon_set_mode(info, 0); - pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); + info->jack = jack; + + pm_runtime_get_sync(arizona->dev); if (info->micd_clamp) { jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; @@ -1671,43 +1528,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; } @@ -1719,21 +1573,12 @@ 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); - goto err_hpdet; - } - - pm_runtime_put(&pdev->dev); + pm_runtime_put(arizona->dev); return 0; -err_hpdet: - arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); err_micdet: arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); err_fall_wake: @@ -1745,21 +1590,21 @@ err_rise_wake: err_rise: arizona_free_irq(arizona, jack_irq_rise, info); err_pm: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); -err_gpio: - gpiod_put(info->micd_pol_gpio); + pm_runtime_put(arizona->dev); + info->jack = NULL; return ret; } -static int arizona_extcon_remove(struct platform_device *pdev) +static int arizona_jack_disable_jack_detect(struct arizona_priv *info) { - struct arizona_extcon_info *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; int jack_irq_rise, jack_irq_fall; bool change; int ret; + if (!info->jack) + return 0; + if (info->micd_clamp) { jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; @@ -1782,11 +1627,10 @@ 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(info->dev); + pm_runtime_put(arizona->dev); } regmap_update_bits(arizona->regmap, @@ -1795,25 +1639,19 @@ static int arizona_extcon_remove(struct platform_device *pdev) regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, ARIZONA_JD1_ENA, 0); arizona_clk32k_disable(arizona); - - gpiod_put(info->micd_pol_gpio); - - pm_runtime_disable(&pdev->dev); + info->jack = NULL; 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 b3abbe80f11d..ecd8890eefc1 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -91,6 +91,41 @@ struct arizona_priv { unsigned int dvfs_reqs; struct mutex dvfs_lock; bool dvfs_cached; + + /* Variables used by arizona-jack.c code */ + struct mutex lock; + struct delayed_work hpdet_work; + struct delayed_work micd_detect_work; + struct delayed_work micd_timeout_work; + struct snd_soc_jack *jack; + struct regulator *micvdd; + struct gpio_desc *micd_pol_gpio; + + u16 last_jackdet; + + int micd_mode; + const struct arizona_micd_config *micd_modes; + int micd_num_modes; + + int micd_button_mask; + const struct arizona_micd_range *micd_ranges; + int num_micd_ranges; + + bool micd_reva; + bool micd_clamp; + + bool hpdet_active; + bool hpdet_done; + bool hpdet_retried; + + bool mic; + bool detecting; + + int num_hpdet_res; + unsigned int hpdet_res[3]; + + int jack_flips; + int hpdet_ip_version; }; struct arizona_voice_trigger_info { @@ -222,6 +257,9 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_RATE_ENUM_SIZE 4 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14 +/* SND_JACK_* mask for supported cable/switch types */ +#define ARIZONA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_MECHANICAL) + extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; @@ -351,4 +389,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 diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index fe33f2d88f55..34b665895bdf 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2004,6 +2004,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { .remove = wm5102_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm5102_set_fll, + .set_jack = arizona_jack_set_jack, .name = DRV_NAME, .compress_ops = &wm5102_compress_ops, .controls = wm5102_snd_controls, @@ -2057,6 +2058,11 @@ static int wm5102_probe(struct platform_device *pdev) if (ret != 0) return ret; + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm5102->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) wm5102->fll[i].vco_mult = 1; @@ -2089,7 +2095,7 @@ static int wm5102_probe(struct platform_device *pdev) wm5102); if (ret != 0) { dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; + goto err_jack_codec_dev; } ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); @@ -2123,6 +2129,8 @@ err_spk_irqs: err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm5102->core); return ret; } @@ -2141,6 +2149,8 @@ static int wm5102_remove(struct platform_device *pdev) arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + arizona_jack_codec_dev_remove(&wm5102->core); + return 0; } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 52c0a575cc4f..76efca0fe515 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2370,6 +2370,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { .remove = wm5110_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm5110_set_fll, + .set_jack = arizona_jack_set_jack, .name = DRV_NAME, .compress_ops = &wm5110_compress_ops, .controls = wm5110_snd_controls, @@ -2424,6 +2425,11 @@ static int wm5110_probe(struct platform_device *pdev) return ret; } + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm5110->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) wm5110->fll[i].vco_mult = 3; @@ -2456,7 +2462,7 @@ static int wm5110_probe(struct platform_device *pdev) wm5110); if (ret != 0) { dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; + goto err_jack_codec_dev; } ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); @@ -2490,6 +2496,8 @@ err_spk_irqs: err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm5110->core); return ret; } @@ -2510,6 +2518,8 @@ static int wm5110_remove(struct platform_device *pdev) arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + arizona_jack_codec_dev_remove(&wm5110->core); + return 0; } diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 99c3ebae6ba6..38ef631d1a1f 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1096,6 +1096,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = { .remove = wm8997_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm8997_set_fll, + .set_jack = arizona_jack_set_jack, .controls = wm8997_snd_controls, .num_controls = ARRAY_SIZE(wm8997_snd_controls), .dapm_widgets = wm8997_dapm_widgets, @@ -1132,6 +1133,11 @@ static int wm8997_probe(struct platform_device *pdev) arizona_init_dvfs(&wm8997->core); + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm8997->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) wm8997->fll[i].vco_mult = 1; @@ -1163,10 +1169,10 @@ static int wm8997_probe(struct platform_device *pdev) ret = arizona_init_vol_limit(arizona); if (ret < 0) - return ret; + goto err_jack_codec_dev; ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_jack_codec_dev; ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8997, @@ -1181,6 +1187,8 @@ static int wm8997_probe(struct platform_device *pdev) err_spk_irqs: arizona_free_spk_irqs(arizona); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm8997->core); return ret; } @@ -1194,6 +1202,8 @@ static int wm8997_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_jack_codec_dev_remove(&wm8997->core); + return 0; } diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index b6f717aa5478..00b59fc9b1fe 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1316,6 +1316,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = { .remove = wm8998_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm8998_set_fll, + .set_jack = arizona_jack_set_jack, .controls = wm8998_snd_controls, .num_controls = ARRAY_SIZE(wm8998_snd_controls), .dapm_widgets = wm8998_dapm_widgets, @@ -1350,6 +1351,11 @@ static int wm8998_probe(struct platform_device *pdev) wm8998->core.arizona = arizona; wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */ + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm8998->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++) wm8998->fll[i].vco_mult = 1; @@ -1392,6 +1398,7 @@ err_spk_irqs: arizona_free_spk_irqs(arizona); err_pm_disable: pm_runtime_disable(&pdev->dev); + arizona_jack_codec_dev_remove(&wm8998->core); return ret; } @@ -1405,6 +1412,8 @@ static int wm8998_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_jack_codec_dev_remove(&wm8998->core); + return 0; } diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index fd584e380340..8d8ab9be256f 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -31,6 +32,7 @@ #define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */ struct byt_wm5102_private { + struct snd_soc_jack jack; struct clk *mclk; struct gpio_desc *spkvdd_en_gpio; }; @@ -177,11 +179,23 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), }; +static struct snd_soc_jack_pin byt_wm5102_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); - int ret; + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + int ret, jack_type; card->dapm.idle_bias_off = true; @@ -210,6 +224,18 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) return ret; } + jack_type = ARIZONA_JACK_MASK | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3; + ret = snd_soc_card_jack_new(card, "Headset", jack_type, + &priv->jack, byt_wm5102_pins, + ARRAY_SIZE(byt_wm5102_pins)); + if (ret) { + dev_err(card->dev, "Error creating jack: %d\n", ret); + return ret; + } + + snd_soc_component_set_jack(component, &priv->jack, NULL); + return 0; } |