959 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// CS42L43 CODEC driver jack handling4//5// Copyright (C) 2022-2023 Cirrus Logic, Inc. and6// Cirrus Logic International Semiconductor Ltd.7 8#include <linux/build_bug.h>9#include <linux/completion.h>10#include <linux/delay.h>11#include <linux/errno.h>12#include <linux/irq.h>13#include <linux/jiffies.h>14#include <linux/mfd/cs42l43.h>15#include <linux/mfd/cs42l43-regs.h>16#include <linux/mutex.h>17#include <linux/pm_runtime.h>18#include <linux/property.h>19#include <linux/regmap.h>20#include <linux/time.h>21#include <linux/workqueue.h>22#include <sound/control.h>23#include <sound/jack.h>24#include <sound/pcm.h>25#include <sound/pcm_params.h>26#include <sound/soc-component.h>27#include <sound/soc-jack.h>28#include <sound/soc.h>29 30#include "cs42l43.h"31 32static const unsigned int cs42l43_accdet_us[] = {33 20, 100, 1000, 10000, 50000, 75000, 100000, 200000,34};35 36static const unsigned int cs42l43_accdet_db_ms[] = {37 0, 125, 250, 500, 750, 1000, 1250, 1500,38};39 40static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 };41 42static const unsigned int cs42l43_accdet_bias_sense[] = {43 14, 24, 43, 52, 61, 71, 90, 99, 0,44};45 46static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop,47 unsigned int defval, unsigned int *val,48 const unsigned int *values, const int nvalues)49{50 struct cs42l43 *cs42l43 = priv->core;51 int i, ret;52 53 ret = device_property_read_u32(cs42l43->dev, prop, &defval);54 if (ret != -EINVAL && ret < 0) {55 dev_err(priv->dev, "Property %s malformed: %d\n", prop, ret);56 return ret;57 }58 59 if (val)60 *val = defval;61 62 for (i = 0; i < nvalues; i++)63 if (defval == values[i])64 return i;65 66 dev_err(priv->dev, "Invalid value for property %s: %d\n", prop, defval);67 return -EINVAL;68}69 70int cs42l43_set_jack(struct snd_soc_component *component,71 struct snd_soc_jack *jack, void *d)72{73 struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);74 struct cs42l43 *cs42l43 = priv->core;75 /* This tip sense invert is always set, HW wants an inverted signal */76 unsigned int tip_deb = CS42L43_TIPSENSE_INV_MASK;77 unsigned int hs2 = 0x2 << CS42L43_HSDET_MODE_SHIFT;78 unsigned int autocontrol = 0, pdncntl = 0;79 int ret;80 81 dev_dbg(priv->dev, "Configure accessory detect\n");82 83 ret = pm_runtime_resume_and_get(priv->dev);84 if (ret) {85 dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret);86 return ret;87 }88 89 mutex_lock(&priv->jack_lock);90 91 priv->jack_hp = jack;92 93 if (!jack)94 goto done;95 96 ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms");97 if (ret != -EINVAL) {98 if (ret < 0) {99 dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n",100 ret);101 goto error;102 }103 104 if (ret > CS42L43_N_BUTTONS) {105 ret = -EINVAL;106 dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n");107 goto error;108 }109 110 ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms",111 priv->buttons, ret);112 if (ret < 0) {113 dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n",114 ret);115 goto error;116 }117 } else {118 priv->buttons[0] = 70;119 priv->buttons[1] = 185;120 priv->buttons[2] = 355;121 priv->buttons[3] = 735;122 }123 124 ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us,125 cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us));126 if (ret < 0)127 goto error;128 129 hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT;130 131 priv->bias_low = device_property_read_bool(cs42l43->dev, "cirrus,bias-low");132 133 ret = cs42l43_find_index(priv, "cirrus,bias-ramp-ms", 170,134 &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms,135 ARRAY_SIZE(cs42l43_accdet_ramp_ms));136 if (ret < 0)137 goto error;138 139 hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT;140 141 ret = cs42l43_find_index(priv, "cirrus,bias-sense-microamp", 14,142 &priv->bias_sense_ua, cs42l43_accdet_bias_sense,143 ARRAY_SIZE(cs42l43_accdet_bias_sense));144 if (ret < 0)145 goto error;146 147 if (priv->bias_sense_ua)148 autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT;149 150 if (!device_property_read_bool(cs42l43->dev, "cirrus,button-automute"))151 autocontrol |= CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK;152 153 ret = device_property_read_u32(cs42l43->dev, "cirrus,tip-debounce-ms",154 &priv->tip_debounce_ms);155 if (ret < 0 && ret != -EINVAL) {156 dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret);157 goto error;158 }159 160 /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */161 if (device_property_read_bool(cs42l43->dev, "cirrus,tip-invert"))162 autocontrol |= 0x1 << CS42L43_JACKDET_INV_SHIFT;163 164 if (device_property_read_bool(cs42l43->dev, "cirrus,tip-disable-pullup"))165 autocontrol |= 0x1 << CS42L43_JACKDET_MODE_SHIFT;166 else167 autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT;168 169 ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500,170 NULL, cs42l43_accdet_db_ms,171 ARRAY_SIZE(cs42l43_accdet_db_ms));172 if (ret < 0)173 goto error;174 175 tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;176 177 ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500,178 NULL, cs42l43_accdet_db_ms,179 ARRAY_SIZE(cs42l43_accdet_db_ms));180 if (ret < 0)181 goto error;182 183 tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT;184 185 if (device_property_read_bool(cs42l43->dev, "cirrus,use-ring-sense")) {186 unsigned int ring_deb = 0;187 188 priv->use_ring_sense = true;189 190 /* HW wants an inverted signal, so invert the invert */191 if (!device_property_read_bool(cs42l43->dev, "cirrus,ring-invert"))192 ring_deb |= CS42L43_RINGSENSE_INV_MASK;193 194 if (!device_property_read_bool(cs42l43->dev,195 "cirrus,ring-disable-pullup"))196 ring_deb |= CS42L43_RINGSENSE_PULLUP_PDNB_MASK;197 198 ret = cs42l43_find_index(priv, "cirrus,ring-fall-db-ms", 500,199 NULL, cs42l43_accdet_db_ms,200 ARRAY_SIZE(cs42l43_accdet_db_ms));201 if (ret < 0)202 goto error;203 204 ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT;205 206 ret = cs42l43_find_index(priv, "cirrus,ring-rise-db-ms", 500,207 NULL, cs42l43_accdet_db_ms,208 ARRAY_SIZE(cs42l43_accdet_db_ms));209 if (ret < 0)210 goto error;211 212 ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT;213 pdncntl |= CS42L43_RING_SENSE_EN_MASK;214 215 regmap_update_bits(cs42l43->regmap, CS42L43_RINGSENSE_DEB_CTRL,216 CS42L43_RINGSENSE_INV_MASK |217 CS42L43_RINGSENSE_PULLUP_PDNB_MASK |218 CS42L43_RINGSENSE_FALLING_DB_TIME_MASK |219 CS42L43_RINGSENSE_RISING_DB_TIME_MASK,220 ring_deb);221 }222 223 regmap_update_bits(cs42l43->regmap, CS42L43_TIPSENSE_DEB_CTRL,224 CS42L43_TIPSENSE_INV_MASK |225 CS42L43_TIPSENSE_FALLING_DB_TIME_MASK |226 CS42L43_TIPSENSE_RISING_DB_TIME_MASK, tip_deb);227 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,228 CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK |229 CS42L43_AUTO_HSDET_TIME_MASK, hs2);230 231done:232 ret = 0;233 234 regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,235 CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |236 CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);237 regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,238 CS42L43_RING_SENSE_EN_MASK, pdncntl);239 240 dev_dbg(priv->dev, "Successfully configured accessory detect\n");241 242error:243 mutex_unlock(&priv->jack_lock);244 245 pm_runtime_mark_last_busy(priv->dev);246 pm_runtime_put_autosuspend(priv->dev);247 248 return ret;249}250 251static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect)252{253 struct cs42l43 *cs42l43 = priv->core;254 unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT;255 256 dev_dbg(priv->dev, "Start headset bias\n");257 258 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,259 CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);260 261 if (!type_detect) {262 if (priv->bias_low)263 val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT;264 265 if (priv->bias_sense_ua)266 regmap_update_bits(cs42l43->regmap,267 CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,268 CS42L43_HSBIAS_SENSE_EN_MASK |269 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,270 CS42L43_HSBIAS_SENSE_EN_MASK |271 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);272 }273 274 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,275 CS42L43_HSBIAS_MODE_MASK, val);276 277 msleep(priv->bias_ramp_ms);278}279 280static void cs42l43_stop_hs_bias(struct cs42l43_codec *priv)281{282 struct cs42l43 *cs42l43 = priv->core;283 284 dev_dbg(priv->dev, "Stop headset bias\n");285 286 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,287 CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);288 289 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,290 CS42L43_HS_CLAMP_DISABLE_MASK, 0);291 292 if (priv->bias_sense_ua) {293 regmap_update_bits(cs42l43->regmap,294 CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,295 CS42L43_HSBIAS_SENSE_EN_MASK |296 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);297 }298}299 300irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data)301{302 struct cs42l43_codec *priv = data;303 304 queue_delayed_work(system_wq, &priv->bias_sense_timeout,305 msecs_to_jiffies(1000));306 307 return IRQ_HANDLED;308}309 310#define CS42L43_JACK_PRESENT 0x3311#define CS42L43_JACK_ABSENT 0x0312 313#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT)314#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE)315#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET)316#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)317#define CS42L43_JACK_LINEIN (SND_JACK_MECHANICAL | SND_JACK_LINEIN)318#define CS42L43_JACK_EXTENSION (SND_JACK_MECHANICAL)319#define CS42L43_JACK_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | \320 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5)321 322static inline bool cs42l43_jack_present(struct cs42l43_codec *priv)323{324 struct cs42l43 *cs42l43 = priv->core;325 unsigned int sts = 0;326 327 regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);328 329 sts = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;330 331 return sts == CS42L43_JACK_PRESENT;332}333 334static void cs42l43_start_button_detect(struct cs42l43_codec *priv)335{336 struct cs42l43 *cs42l43 = priv->core;337 unsigned int val = 0x3 << CS42L43_BUTTON_DETECT_MODE_SHIFT;338 339 dev_dbg(priv->dev, "Start button detect\n");340 341 priv->button_detect_running = true;342 343 if (priv->bias_low)344 val = 0x1 << CS42L43_BUTTON_DETECT_MODE_SHIFT;345 346 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,347 CS42L43_BUTTON_DETECT_MODE_MASK |348 CS42L43_MIC_LVL_DET_DISABLE_MASK, val);349}350 351static void cs42l43_stop_button_detect(struct cs42l43_codec *priv)352{353 struct cs42l43 *cs42l43 = priv->core;354 355 dev_dbg(priv->dev, "Stop button detect\n");356 357 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,358 CS42L43_BUTTON_DETECT_MODE_MASK |359 CS42L43_MIC_LVL_DET_DISABLE_MASK,360 CS42L43_MIC_LVL_DET_DISABLE_MASK);361 362 priv->button_detect_running = false;363}364 365#define CS42L43_BUTTON_COMB_MAX 512366#define CS42L43_BUTTON_ROUT 2210367 368void cs42l43_button_press_work(struct work_struct *work)369{370 struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,371 button_press_work.work);372 struct cs42l43 *cs42l43 = priv->core;373 unsigned int buttons = 0;374 unsigned int val = 0;375 int i, ret;376 377 ret = pm_runtime_resume_and_get(priv->dev);378 if (ret) {379 dev_err(priv->dev, "Failed to resume for button press: %d\n", ret);380 return;381 }382 383 mutex_lock(&priv->jack_lock);384 385 if (!priv->button_detect_running) {386 dev_dbg(priv->dev, "Spurious button press IRQ\n");387 goto error;388 }389 390 regmap_read(cs42l43->regmap, CS42L43_DETECT_STATUS_1, &val);391 392 /* Bail if jack removed, the button is irrelevant and likely invalid */393 if (!cs42l43_jack_present(priv)) {394 dev_dbg(priv->dev, "Button ignored due to removal\n");395 goto error;396 }397 398 if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) {399 dev_dbg(priv->dev, "Button ignored due to bias sense\n");400 goto error;401 }402 403 val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT;404 val = ((CS42L43_BUTTON_COMB_MAX << 20) / (val + 1)) - (1 << 20);405 if (val)406 val = (CS42L43_BUTTON_ROUT << 20) / val;407 else408 val = UINT_MAX;409 410 for (i = 0; i < CS42L43_N_BUTTONS; i++) {411 if (val < priv->buttons[i]) {412 buttons = SND_JACK_BTN_0 >> i;413 dev_dbg(priv->dev, "Detected button %d at %d Ohms\n", i, val);414 break;415 }416 }417 418 if (!buttons)419 dev_dbg(priv->dev, "Unrecognised button: %d Ohms\n", val);420 421 snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS);422 423error:424 mutex_unlock(&priv->jack_lock);425 426 pm_runtime_mark_last_busy(priv->dev);427 pm_runtime_put_autosuspend(priv->dev);428}429 430irqreturn_t cs42l43_button_press(int irq, void *data)431{432 struct cs42l43_codec *priv = data;433 434 // Wait for 2 full cycles of comb filter to ensure good reading435 queue_delayed_work(system_wq, &priv->button_press_work,436 msecs_to_jiffies(20));437 438 return IRQ_HANDLED;439}440 441void cs42l43_button_release_work(struct work_struct *work)442{443 struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,444 button_release_work);445 int ret;446 447 ret = pm_runtime_resume_and_get(priv->dev);448 if (ret) {449 dev_err(priv->dev, "Failed to resume for button release: %d\n", ret);450 return;451 }452 453 mutex_lock(&priv->jack_lock);454 455 if (priv->button_detect_running) {456 dev_dbg(priv->dev, "Button release IRQ\n");457 458 snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);459 } else {460 dev_dbg(priv->dev, "Spurious button release IRQ\n");461 }462 463 mutex_unlock(&priv->jack_lock);464 465 pm_runtime_mark_last_busy(priv->dev);466 pm_runtime_put_autosuspend(priv->dev);467}468 469irqreturn_t cs42l43_button_release(int irq, void *data)470{471 struct cs42l43_codec *priv = data;472 473 queue_work(system_wq, &priv->button_release_work);474 475 return IRQ_HANDLED;476}477 478void cs42l43_bias_sense_timeout(struct work_struct *work)479{480 struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,481 bias_sense_timeout.work);482 struct cs42l43 *cs42l43 = priv->core;483 int ret;484 485 ret = pm_runtime_resume_and_get(priv->dev);486 if (ret) {487 dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret);488 return;489 }490 491 mutex_lock(&priv->jack_lock);492 493 if (cs42l43_jack_present(priv) && priv->button_detect_running) {494 dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n");495 496 regmap_update_bits(cs42l43->regmap,497 CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,498 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);499 regmap_update_bits(cs42l43->regmap,500 CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,501 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,502 CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);503 }504 505 mutex_unlock(&priv->jack_lock);506 507 pm_runtime_mark_last_busy(priv->dev);508 pm_runtime_put_autosuspend(priv->dev);509}510 511static void cs42l43_start_load_detect(struct cs42l43_codec *priv)512{513 struct cs42l43 *cs42l43 = priv->core;514 515 dev_dbg(priv->dev, "Start load detect\n");516 517 snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component));518 519 priv->load_detect_running = true;520 521 if (priv->hp_ena && !priv->hp_ilimited) {522 unsigned long time_left;523 524 reinit_completion(&priv->hp_shutdown);525 526 regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,527 CS42L43_HP_EN_MASK, 0);528 529 time_left = wait_for_completion_timeout(&priv->hp_shutdown,530 msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));531 if (!time_left)532 dev_err(priv->dev, "Load detect HP power down timed out\n");533 }534 535 regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,536 CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0);537 regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0);538 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,539 CS42L43_HSBIAS_MODE_MASK, 0);540 regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,541 CS42L43_ADPTPWR_MODE_MASK, 0x4 << CS42L43_ADPTPWR_MODE_SHIFT);542 regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,543 CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, 0x6);544 regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,545 CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, 0);546 547 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,548 CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);549 550 regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,551 CS42L43_HPLOAD_DET_EN_MASK,552 CS42L43_HPLOAD_DET_EN_MASK);553 554 snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component));555}556 557static void cs42l43_stop_load_detect(struct cs42l43_codec *priv)558{559 struct cs42l43 *cs42l43 = priv->core;560 561 dev_dbg(priv->dev, "Stop load detect\n");562 563 snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component));564 565 regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,566 CS42L43_HPLOAD_DET_EN_MASK, 0);567 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,568 CS42L43_HS_CLAMP_DISABLE_MASK, 0);569 regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,570 CS42L43_HP_MSTR_VOL_CTRL_EN_MASK,571 CS42L43_HP_MSTR_VOL_CTRL_EN_MASK);572 regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,573 CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK,574 0x4 << CS42L43_HP_DIG_VOL_RAMP_SHIFT);575 regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,576 CS42L43_ADPTPWR_MODE_MASK, 0x7 << CS42L43_ADPTPWR_MODE_SHIFT);577 regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,578 CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);579 regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2,580 CS42L43_HP_HPF_EN_MASK, CS42L43_HP_HPF_EN_MASK);581 582 regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,583 CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK,584 priv->adc_ena);585 586 if (priv->hp_ena && !priv->hp_ilimited) {587 unsigned long time_left;588 589 reinit_completion(&priv->hp_startup);590 591 regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,592 CS42L43_HP_EN_MASK, priv->hp_ena);593 594 time_left = wait_for_completion_timeout(&priv->hp_startup,595 msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));596 if (!time_left)597 dev_err(priv->dev, "Load detect HP restore timed out\n");598 }599 600 priv->load_detect_running = false;601 602 snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component));603}604 605static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic)606{607 struct cs42l43 *cs42l43 = priv->core;608 unsigned int val = 0;609 unsigned long time_left;610 611 reinit_completion(&priv->load_detect);612 613 cs42l43_start_load_detect(priv);614 time_left = wait_for_completion_timeout(&priv->load_detect,615 msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS));616 cs42l43_stop_load_detect(priv);617 618 if (!time_left)619 return -ETIMEDOUT;620 621 regmap_read(cs42l43->regmap, CS42L43_LOADDETRESULTS, &val);622 623 dev_dbg(priv->dev, "Headphone load detect: 0x%x\n", val);624 625 /* Bail if jack removed, the load is irrelevant and likely invalid */626 if (!cs42l43_jack_present(priv))627 return -ENODEV;628 629 if (mic) {630 cs42l43_start_hs_bias(priv, false);631 cs42l43_start_button_detect(priv);632 633 return CS42L43_JACK_HEADSET;634 }635 636 switch (val & CS42L43_AMP3_RES_DET_MASK) {637 case 0x0: // low impedance638 case 0x1: // high impedance639 return CS42L43_JACK_HEADPHONE;640 case 0x2: // lineout641 case 0x3: // Open circuit642 return CS42L43_JACK_LINEOUT;643 default:644 return -EINVAL;645 }646}647 648static int cs42l43_run_type_detect(struct cs42l43_codec *priv)649{650 struct cs42l43 *cs42l43 = priv->core;651 int timeout_ms = ((2 * priv->detect_us) / USEC_PER_MSEC) + 200;652 unsigned int type = 0xff;653 unsigned long time_left;654 655 reinit_completion(&priv->type_detect);656 657 cs42l43_start_hs_bias(priv, true);658 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,659 CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT);660 661 time_left = wait_for_completion_timeout(&priv->type_detect,662 msecs_to_jiffies(timeout_ms));663 664 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,665 CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT);666 cs42l43_stop_hs_bias(priv);667 668 if (!time_left)669 return -ETIMEDOUT;670 671 regmap_read(cs42l43->regmap, CS42L43_HS_STAT, &type);672 673 dev_dbg(priv->dev, "Type detect: 0x%x\n", type);674 675 /* Bail if jack removed, the type is irrelevant and likely invalid */676 if (!cs42l43_jack_present(priv))677 return -ENODEV;678 679 switch (type & CS42L43_HSDET_TYPE_STS_MASK) {680 case 0x0: // CTIA681 case 0x1: // OMTP682 return cs42l43_run_load_detect(priv, true);683 case 0x2: // 3-pole684 return cs42l43_run_load_detect(priv, false);685 case 0x3: // Open-circuit686 return CS42L43_JACK_EXTENSION;687 default:688 return -EINVAL;689 }690}691 692static void cs42l43_clear_jack(struct cs42l43_codec *priv)693{694 struct cs42l43 *cs42l43 = priv->core;695 696 cs42l43_stop_button_detect(priv);697 cs42l43_stop_hs_bias(priv);698 699 regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,700 CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);701 regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,702 CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);703 regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,704 CS42L43_JACK_STEREO_CONFIG_MASK, 0);705 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,706 CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK,707 0x2 << CS42L43_HSDET_MODE_SHIFT);708 709 snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF);710}711 712void cs42l43_tip_sense_work(struct work_struct *work)713{714 struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,715 tip_sense_work.work);716 struct cs42l43 *cs42l43 = priv->core;717 unsigned int sts = 0;718 unsigned int tip, ring;719 int ret, report;720 721 ret = pm_runtime_resume_and_get(priv->dev);722 if (ret) {723 dev_err(priv->dev, "Failed to resume for tip work: %d\n", ret);724 return;725 }726 727 mutex_lock(&priv->jack_lock);728 729 regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);730 731 dev_dbg(priv->dev, "Tip sense: 0x%x\n", sts);732 733 tip = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;734 ring = (sts >> CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;735 736 if (tip == CS42L43_JACK_PRESENT) {737 if (cs42l43->sdw && !priv->jack_present) {738 priv->jack_present = true;739 pm_runtime_get(priv->dev);740 }741 742 if (priv->use_ring_sense && ring == CS42L43_JACK_ABSENT) {743 report = CS42L43_JACK_OPTICAL;744 } else {745 report = cs42l43_run_type_detect(priv);746 if (report < 0) {747 dev_err(priv->dev, "Jack detect failed: %d\n", report);748 goto error;749 }750 }751 752 snd_soc_jack_report(priv->jack_hp, report, report);753 } else {754 priv->jack_override = 0;755 756 cs42l43_clear_jack(priv);757 758 if (cs42l43->sdw && priv->jack_present) {759 pm_runtime_put(priv->dev);760 priv->jack_present = false;761 }762 }763 764error:765 mutex_unlock(&priv->jack_lock);766 767 pm_runtime_mark_last_busy(priv->dev);768 pm_runtime_put_autosuspend(priv->dev);769}770 771irqreturn_t cs42l43_tip_sense(int irq, void *data)772{773 struct cs42l43_codec *priv = data;774 775 cancel_delayed_work(&priv->bias_sense_timeout);776 cancel_delayed_work(&priv->tip_sense_work);777 cancel_delayed_work(&priv->button_press_work);778 cancel_work(&priv->button_release_work);779 780 queue_delayed_work(system_long_wq, &priv->tip_sense_work,781 msecs_to_jiffies(priv->tip_debounce_ms));782 783 return IRQ_HANDLED;784}785 786enum cs42l43_raw_jack {787 CS42L43_JACK_RAW_CTIA = 0,788 CS42L43_JACK_RAW_OMTP,789 CS42L43_JACK_RAW_HEADPHONE,790 CS42L43_JACK_RAW_LINE_OUT,791 CS42L43_JACK_RAW_LINE_IN,792 CS42L43_JACK_RAW_MICROPHONE,793 CS42L43_JACK_RAW_OPTICAL,794};795 796#define CS42L43_JACK_3_POLE_SWITCHES ((0x2 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | \797 CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | \798 CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | \799 CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | \800 CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | \801 CS42L43_HSGND_HS3_SEL_MASK | \802 CS42L43_HSGND_HS4_SEL_MASK)803 804static const struct cs42l43_jack_override_mode {805 unsigned int hsdet_mode;806 unsigned int mic_ctrl;807 unsigned int clamp_ctrl;808 int report;809} cs42l43_jack_override_modes[] = {810 [CS42L43_JACK_RAW_CTIA] = {811 .hsdet_mode = CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |812 CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |813 CS42L43_HSBIAS_OUT_HS4_SEL_MASK |814 CS42L43_HSGND_HS3_SEL_MASK,815 .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,816 .report = CS42L43_JACK_HEADSET,817 },818 [CS42L43_JACK_RAW_OMTP] = {819 .hsdet_mode = (0x1 << CS42L43_HSDET_MANUAL_MODE_SHIFT) |820 CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |821 CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |822 CS42L43_HSBIAS_OUT_HS3_SEL_MASK |823 CS42L43_HSGND_HS4_SEL_MASK,824 .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,825 .report = CS42L43_JACK_HEADSET,826 },827 [CS42L43_JACK_RAW_HEADPHONE] = {828 .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,829 .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,830 .report = CS42L43_JACK_HEADPHONE,831 },832 [CS42L43_JACK_RAW_LINE_OUT] = {833 .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,834 .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,835 .report = CS42L43_JACK_LINEOUT,836 },837 [CS42L43_JACK_RAW_LINE_IN] = {838 .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,839 .mic_ctrl = 0x2 << CS42L43_JACK_STEREO_CONFIG_SHIFT,840 .report = CS42L43_JACK_LINEIN,841 },842 [CS42L43_JACK_RAW_MICROPHONE] = {843 .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,844 .mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) |845 CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK,846 .report = CS42L43_JACK_LINEIN,847 },848 [CS42L43_JACK_RAW_OPTICAL] = {849 .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,850 .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,851 .report = CS42L43_JACK_OPTICAL,852 },853};854 855static const char * const cs42l43_jack_text[] = {856 "None", "CTIA", "OMTP", "Headphone", "Line-Out",857 "Line-In", "Microphone", "Optical",858};859 860static_assert(ARRAY_SIZE(cs42l43_jack_override_modes) ==861 ARRAY_SIZE(cs42l43_jack_text) - 1);862 863SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text);864 865int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)866{867 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);868 struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);869 870 mutex_lock(&priv->jack_lock);871 ucontrol->value.integer.value[0] = priv->jack_override;872 mutex_unlock(&priv->jack_lock);873 874 return 0;875}876 877int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)878{879 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);880 struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);881 struct cs42l43 *cs42l43 = priv->core;882 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;883 unsigned int override = ucontrol->value.integer.value[0];884 885 if (override >= e->items)886 return -EINVAL;887 888 mutex_lock(&priv->jack_lock);889 890 if (!cs42l43_jack_present(priv)) {891 mutex_unlock(&priv->jack_lock);892 return -EBUSY;893 }894 895 if (override == priv->jack_override) {896 mutex_unlock(&priv->jack_lock);897 return 0;898 }899 900 priv->jack_override = override;901 902 cs42l43_clear_jack(priv);903 904 if (!override) {905 queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0);906 } else {907 override--;908 909 regmap_update_bits(cs42l43->regmap, CS42L43_HS2,910 CS42L43_HSDET_MODE_MASK |911 CS42L43_HSDET_MANUAL_MODE_MASK |912 CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |913 CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |914 CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |915 CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |916 CS42L43_HSBIAS_OUT_HS3_SEL_MASK |917 CS42L43_HSBIAS_OUT_HS4_SEL_MASK |918 CS42L43_HSGND_HS3_SEL_MASK |919 CS42L43_HSGND_HS4_SEL_MASK,920 cs42l43_jack_override_modes[override].hsdet_mode);921 regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,922 CS42L43_HS2_BIAS_EN_MASK | CS42L43_HS1_BIAS_EN_MASK |923 CS42L43_JACK_STEREO_CONFIG_MASK,924 cs42l43_jack_override_modes[override].mic_ctrl);925 regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,926 CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,927 cs42l43_jack_override_modes[override].clamp_ctrl);928 929 switch (override) {930 case CS42L43_JACK_RAW_CTIA:931 case CS42L43_JACK_RAW_OMTP:932 cs42l43_start_hs_bias(priv, false);933 cs42l43_start_button_detect(priv);934 break;935 case CS42L43_JACK_RAW_LINE_IN:936 regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,937 CS42L43_PGA_WIDESWING_MODE_EN_MASK,938 CS42L43_PGA_WIDESWING_MODE_EN_MASK);939 regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,940 CS42L43_PGA_WIDESWING_MODE_EN_MASK,941 CS42L43_PGA_WIDESWING_MODE_EN_MASK);942 break;943 case CS42L43_JACK_RAW_MICROPHONE:944 cs42l43_start_hs_bias(priv, false);945 break;946 default:947 break;948 }949 950 snd_soc_jack_report(priv->jack_hp,951 cs42l43_jack_override_modes[override].report,952 cs42l43_jack_override_modes[override].report);953 }954 955 mutex_unlock(&priv->jack_lock);956 957 return 1;958}959