brintos

brintos / linux-shallow public Read only

0
0
Text · 27.6 KiB · d9ab003 Raw
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