brintos

brintos / linux-shallow public Read only

0
0
Text · 33.2 KiB · 15e5e3e Raw
1081 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver4 *5 * Copyright (c) 2015 Dialog Semiconductor Ltd.6 *7 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>8 */9 10#include <linux/module.h>11#include <linux/platform_device.h>12#include <linux/clk.h>13#include <linux/i2c.h>14#include <linux/property.h>15#include <linux/pm_wakeirq.h>16#include <linux/slab.h>17#include <linux/delay.h>18#include <linux/workqueue.h>19#include <sound/soc.h>20#include <sound/jack.h>21#include <sound/da7219.h>22 23#include "da7219.h"24#include "da7219-aad.h"25 26 27/*28 * Detection control29 */30 31void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack)32{33	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);34 35	da7219->aad->jack = jack;36	da7219->aad->jack_inserted = false;37 38	/* Send an initial empty report */39	snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);40 41	/* Enable/Disable jack detection */42	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,43			    DA7219_ACCDET_EN_MASK,44			    (jack ? DA7219_ACCDET_EN_MASK : 0));45}46 47/*48 * Button/HPTest work49 */50 51static void da7219_aad_btn_det_work(struct work_struct *work)52{53	struct da7219_aad_priv *da7219_aad =54		container_of(work, struct da7219_aad_priv, btn_det_work);55	struct snd_soc_component *component = da7219_aad->component;56	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);57	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);58	u8 statusa, micbias_ctrl;59	bool micbias_up = false;60	int retries = 0;61 62	/* Drive headphones/lineout */63	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,64			    DA7219_HP_L_AMP_OE_MASK,65			    DA7219_HP_L_AMP_OE_MASK);66	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,67			    DA7219_HP_R_AMP_OE_MASK,68			    DA7219_HP_R_AMP_OE_MASK);69 70	/* Make sure mic bias is up */71	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");72	snd_soc_dapm_sync(dapm);73 74	do {75		statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);76		if (statusa & DA7219_MICBIAS_UP_STS_MASK)77			micbias_up = true;78		else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)79			msleep(DA7219_AAD_MICBIAS_CHK_DELAY);80	} while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));81 82	if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)83		dev_warn(component->dev, "Mic bias status check timed out");84 85	da7219->micbias_on_event = true;86 87	/*88	 * Mic bias pulse required to enable mic, must be done before enabling89	 * button detection to prevent erroneous button readings.90	 */91	if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {92		/* Pulse higher level voltage */93		micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);94		snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL,95				    DA7219_MICBIAS1_LEVEL_MASK,96				    da7219_aad->micbias_pulse_lvl);97		msleep(da7219_aad->micbias_pulse_time);98		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl);99 100	}101 102	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,103			    DA7219_BUTTON_CONFIG_MASK,104			    da7219_aad->btn_cfg);105}106 107static void da7219_aad_hptest_work(struct work_struct *work)108{109	struct da7219_aad_priv *da7219_aad =110		container_of(work, struct da7219_aad_priv, hptest_work);111	struct snd_soc_component *component = da7219_aad->component;112	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);113	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);114 115	__le16 tonegen_freq_hptest;116	u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;117	int report = 0, ret;118 119	/* Lock DAPM, Kcontrols affected by this test and the PLL */120	snd_soc_dapm_mutex_lock(dapm);121	mutex_lock(&da7219->ctrl_lock);122	mutex_lock(&da7219->pll_lock);123 124	/* Ensure MCLK is available for HP test procedure */125	if (da7219->mclk) {126		ret = clk_prepare_enable(da7219->mclk);127		if (ret) {128			dev_err(component->dev, "Failed to enable mclk - %d\n", ret);129			mutex_unlock(&da7219->pll_lock);130			mutex_unlock(&da7219->ctrl_lock);131			snd_soc_dapm_mutex_unlock(dapm);132			return;133		}134	}135 136	/*137	 * If MCLK not present, then we're using the internal oscillator and138	 * require different frequency settings to achieve the same result.139	 *140	 * If MCLK is present, but PLL is not enabled then we enable it here to141	 * ensure a consistent detection procedure.142	 */143	pll_srm_sts = snd_soc_component_read(component, DA7219_PLL_SRM_STS);144	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {145		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);146 147		pll_ctrl = snd_soc_component_read(component, DA7219_PLL_CTRL);148		if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)149			da7219_set_pll(component, DA7219_SYSCLK_PLL,150				       DA7219_PLL_FREQ_OUT_98304);151	} else {152		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);153	}154 155	/* Ensure gain ramping at fastest rate */156	gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL);157	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);158 159	/* Bypass cache so it saves current settings */160	regcache_cache_bypass(da7219->regmap, true);161 162	/* Make sure Tone Generator is disabled */163	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);164 165	/* Enable HPTest block, 1KOhms check */166	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,167			    DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,168			    DA7219_HPTEST_EN_MASK |169			    DA7219_HPTEST_RES_SEL_1KOHMS);170 171	/* Set gains to 0db */172	snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);173	snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);174	snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);175	snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);176 177	/* Disable DAC filters, EQs and soft mute */178	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,179			    0);180	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,181			    0);182	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5,183			    DA7219_DAC_SOFTMUTE_EN_MASK, 0);184 185	/* Enable HP left & right paths */186	snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK,187			    DA7219_CP_EN_MASK);188	snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC,189			    DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,190			    DA7219_DAC_L_SRC_TONEGEN |191			    DA7219_DAC_R_SRC_TONEGEN);192	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL,193			    DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,194			    DA7219_DAC_L_EN_MASK);195	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL,196			    DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,197			    DA7219_DAC_R_EN_MASK);198	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT,199			    DA7219_MIXOUT_L_MIX_SELECT_MASK,200			    DA7219_MIXOUT_L_MIX_SELECT_MASK);201	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT,202			    DA7219_MIXOUT_R_MIX_SELECT_MASK,203			    DA7219_MIXOUT_R_MIX_SELECT_MASK);204	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L,205			    DA7219_OUTFILT_ST_1L_SRC_MASK,206			    DA7219_DMIX_ST_SRC_OUTFILT1L);207	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R,208			    DA7219_OUTFILT_ST_1R_SRC_MASK,209			    DA7219_DMIX_ST_SRC_OUTFILT1R);210	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL,211			    DA7219_MIXOUT_L_AMP_EN_MASK,212			    DA7219_MIXOUT_L_AMP_EN_MASK);213	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL,214			    DA7219_MIXOUT_R_AMP_EN_MASK,215			    DA7219_MIXOUT_R_AMP_EN_MASK);216	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,217			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,218			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);219	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,220			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,221			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);222	msleep(DA7219_SETTLING_DELAY);223	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,224			    DA7219_HP_L_AMP_MUTE_EN_MASK |225			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);226	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,227			    DA7219_HP_R_AMP_MUTE_EN_MASK |228			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);229 230	/*231	 * If we're running from the internal oscillator then give audio paths232	 * time to settle before running test.233	 */234	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))235		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);236 237	/* Configure & start Tone Generator */238	snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);239	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,240			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));241	snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2,242			    DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,243			    DA7219_SWG_SEL_SRAMP |244			    DA7219_TONE_GEN_GAIN_MINUS_15DB);245	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);246 247	msleep(DA7219_AAD_HPTEST_PERIOD);248 249	/* Grab comparator reading */250	accdet_cfg8 = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_8);251	if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)252		report |= SND_JACK_HEADPHONE;253	else254		report |= SND_JACK_LINEOUT;255 256	/* Stop tone generator */257	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);258 259	msleep(DA7219_AAD_HPTEST_PERIOD);260 261	/* Restore original settings from cache */262	regcache_mark_dirty(da7219->regmap);263	regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,264			     DA7219_HP_R_CTRL);265	msleep(DA7219_SETTLING_DELAY);266	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,267			     DA7219_MIXOUT_R_CTRL);268	regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,269			     DA7219_DROUTING_ST_OUTFILT_1R);270	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,271			     DA7219_MIXOUT_R_SELECT);272	regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,273			     DA7219_DAC_R_CTRL);274	regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,275			     DA7219_DIG_ROUTING_DAC);276	regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);277	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,278			     DA7219_DAC_FILTERS5);279	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,280			     DA7219_DAC_FILTERS1);281	regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,282			     DA7219_HP_R_GAIN);283	regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,284			     DA7219_DAC_R_GAIN);285	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,286			     DA7219_TONE_GEN_ON_PER);287	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,288			     DA7219_TONE_GEN_FREQ1_U);289	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,290			     DA7219_TONE_GEN_CFG2);291 292	regcache_cache_bypass(da7219->regmap, false);293 294	/* Disable HPTest block */295	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,296			    DA7219_HPTEST_EN_MASK, 0);297 298	/*299	 * If we're running from the internal oscillator then give audio paths300	 * time to settle before allowing headphones to be driven as required.301	 */302	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))303		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);304 305	/* Restore gain ramping rate */306	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);307 308	/* Drive Headphones/lineout */309	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,310			    DA7219_HP_L_AMP_OE_MASK);311	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,312			    DA7219_HP_R_AMP_OE_MASK);313 314	/* Restore PLL to previous configuration, if re-configured */315	if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&316	    ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))317		da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0);318 319	/* Remove MCLK, if previously enabled */320	if (da7219->mclk)321		clk_disable_unprepare(da7219->mclk);322 323	mutex_unlock(&da7219->pll_lock);324	mutex_unlock(&da7219->ctrl_lock);325	snd_soc_dapm_mutex_unlock(dapm);326 327	/*328	 * Only send report if jack hasn't been removed during process,329	 * otherwise it's invalid and we drop it.330	 */331	if (da7219_aad->jack_inserted)332		snd_soc_jack_report(da7219_aad->jack, report,333				    SND_JACK_HEADSET | SND_JACK_LINEOUT);334}335 336static void da7219_aad_jack_det_work(struct work_struct *work)337{338	struct da7219_aad_priv *da7219_aad =339		container_of(work, struct da7219_aad_priv, jack_det_work.work);340	struct snd_soc_component *component = da7219_aad->component;341 342	/* Enable ground switch */343	snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01);344}345 346/*347 * IRQ348 */349 350static irqreturn_t da7219_aad_irq_thread(int irq, void *data)351{352	struct da7219_aad_priv *da7219_aad = data;353	struct snd_soc_component *component = da7219_aad->component;354	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);355	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);356	u8 events[DA7219_AAD_IRQ_REG_MAX];357	u8 statusa;358	int i, ret, report = 0, mask = 0;359 360	/* Read current IRQ events */361	ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,362			       events, DA7219_AAD_IRQ_REG_MAX);363	if (ret) {364		dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret);365		return IRQ_NONE;366	}367 368	if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])369		return IRQ_NONE;370 371	/* Read status register for jack insertion & type status */372	statusa = snd_soc_component_read(component, DA7219_ACCDET_STATUS_A);373 374	if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_INSERTED_MASK) {375		u8 srm_st;376		int delay = 0;377 378		srm_st = snd_soc_component_read(component,379					DA7219_PLL_SRM_STS) & DA7219_PLL_SRM_STS_MCLK;380		delay = (da7219_aad->gnd_switch_delay * ((srm_st == 0x0) ? 2 : 1) - 2);381		queue_delayed_work(da7219_aad->aad_wq,382							&da7219_aad->jack_det_work,383							msecs_to_jiffies(delay));384	}385 386	/* Clear events */387	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,388			  events, DA7219_AAD_IRQ_REG_MAX);389 390	dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",391		events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],392		statusa);393 394	if (statusa & DA7219_JACK_INSERTION_STS_MASK) {395		/* Jack Insertion */396		if (events[DA7219_AAD_IRQ_REG_A] &397		    DA7219_E_JACK_INSERTED_MASK) {398			report |= SND_JACK_MECHANICAL;399			mask |= SND_JACK_MECHANICAL;400			da7219_aad->jack_inserted = true;401		}402 403		/* Jack type detection */404		if (events[DA7219_AAD_IRQ_REG_A] &405		    DA7219_E_JACK_DETECT_COMPLETE_MASK) {406			/*407			 * If 4-pole, then enable button detection, else perform408			 * HP impedance test to determine output type to report.409			 *410			 * We schedule work here as the tasks themselves can411			 * take time to complete, and in particular for hptest412			 * we want to be able to check if the jack was removed413			 * during the procedure as this will invalidate the414			 * result. By doing this as work, the IRQ thread can415			 * handle a removal, and we can check at the end of416			 * hptest if we have a valid result or not.417			 */418 419			cancel_delayed_work_sync(&da7219_aad->jack_det_work);420			/* Disable ground switch */421			snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);422 423			if (statusa & DA7219_JACK_TYPE_STS_MASK) {424				report |= SND_JACK_HEADSET;425				mask |=	SND_JACK_HEADSET | SND_JACK_LINEOUT;426				queue_work(da7219_aad->aad_wq, &da7219_aad->btn_det_work);427			} else {428				queue_work(da7219_aad->aad_wq, &da7219_aad->hptest_work);429			}430		}431 432		/* Button support for 4-pole jack */433		if (statusa & DA7219_JACK_TYPE_STS_MASK) {434			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {435				/* Button Press */436				if (events[DA7219_AAD_IRQ_REG_B] &437				    (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {438					report |= SND_JACK_BTN_0 >> i;439					mask |= SND_JACK_BTN_0 >> i;440				}441			}442			snd_soc_jack_report(da7219_aad->jack, report, mask);443 444			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {445				/* Button Release */446				if (events[DA7219_AAD_IRQ_REG_B] &447				    (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {448					report &= ~(SND_JACK_BTN_0 >> i);449					mask |= SND_JACK_BTN_0 >> i;450				}451			}452		}453	} else {454		/* Jack removal */455		if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {456			report = 0;457			mask |= DA7219_AAD_REPORT_ALL_MASK;458			da7219_aad->jack_inserted = false;459 460			/* Cancel any pending work */461			cancel_delayed_work_sync(&da7219_aad->jack_det_work);462			cancel_work_sync(&da7219_aad->btn_det_work);463			cancel_work_sync(&da7219_aad->hptest_work);464 465			/* Un-drive headphones/lineout */466			snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,467					    DA7219_HP_R_AMP_OE_MASK, 0);468			snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,469					    DA7219_HP_L_AMP_OE_MASK, 0);470 471			/* Ensure button detection disabled */472			snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,473					    DA7219_BUTTON_CONFIG_MASK, 0);474 475			da7219->micbias_on_event = false;476 477			/* Disable mic bias */478			snd_soc_dapm_disable_pin(dapm, "Mic Bias");479			snd_soc_dapm_sync(dapm);480 481			/* Disable ground switch */482			snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);483		}484	}485 486	snd_soc_jack_report(da7219_aad->jack, report, mask);487 488	return IRQ_HANDLED;489}490 491/*492 * DT/ACPI to pdata conversion493 */494 495static enum da7219_aad_micbias_pulse_lvl496	da7219_aad_fw_micbias_pulse_lvl(struct device *dev, u32 val)497{498	switch (val) {499	case 2800:500		return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;501	case 2900:502		return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;503	default:504		dev_warn(dev, "Invalid micbias pulse level");505		return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;506	}507}508 509static enum da7219_aad_btn_cfg510	da7219_aad_fw_btn_cfg(struct device *dev, u32 val)511{512	switch (val) {513	case 2:514		return DA7219_AAD_BTN_CFG_2MS;515	case 5:516		return DA7219_AAD_BTN_CFG_5MS;517	case 10:518		return DA7219_AAD_BTN_CFG_10MS;519	case 50:520		return DA7219_AAD_BTN_CFG_50MS;521	case 100:522		return DA7219_AAD_BTN_CFG_100MS;523	case 200:524		return DA7219_AAD_BTN_CFG_200MS;525	case 500:526		return DA7219_AAD_BTN_CFG_500MS;527	default:528		dev_warn(dev, "Invalid button config");529		return DA7219_AAD_BTN_CFG_10MS;530	}531}532 533static enum da7219_aad_mic_det_thr534	da7219_aad_fw_mic_det_thr(struct device *dev, u32 val)535{536	switch (val) {537	case 200:538		return DA7219_AAD_MIC_DET_THR_200_OHMS;539	case 500:540		return DA7219_AAD_MIC_DET_THR_500_OHMS;541	case 750:542		return DA7219_AAD_MIC_DET_THR_750_OHMS;543	case 1000:544		return DA7219_AAD_MIC_DET_THR_1000_OHMS;545	default:546		dev_warn(dev, "Invalid mic detect threshold");547		return DA7219_AAD_MIC_DET_THR_500_OHMS;548	}549}550 551static enum da7219_aad_jack_ins_deb552	da7219_aad_fw_jack_ins_deb(struct device *dev, u32 val)553{554	switch (val) {555	case 5:556		return DA7219_AAD_JACK_INS_DEB_5MS;557	case 10:558		return DA7219_AAD_JACK_INS_DEB_10MS;559	case 20:560		return DA7219_AAD_JACK_INS_DEB_20MS;561	case 50:562		return DA7219_AAD_JACK_INS_DEB_50MS;563	case 100:564		return DA7219_AAD_JACK_INS_DEB_100MS;565	case 200:566		return DA7219_AAD_JACK_INS_DEB_200MS;567	case 500:568		return DA7219_AAD_JACK_INS_DEB_500MS;569	case 1000:570		return DA7219_AAD_JACK_INS_DEB_1S;571	default:572		dev_warn(dev, "Invalid jack insert debounce");573		return DA7219_AAD_JACK_INS_DEB_20MS;574	}575}576 577static enum da7219_aad_jack_ins_det_pty578	da7219_aad_fw_jack_ins_det_pty(struct device *dev, const char *str)579{580	if (!strcmp(str, "low")) {581		return DA7219_AAD_JACK_INS_DET_PTY_LOW;582	} else if (!strcmp(str, "high")) {583		return DA7219_AAD_JACK_INS_DET_PTY_HIGH;584	} else {585		dev_warn(dev, "Invalid jack insertion detection polarity");586		return DA7219_AAD_JACK_INS_DET_PTY_LOW;587	}588}589 590static enum da7219_aad_jack_det_rate591	da7219_aad_fw_jack_det_rate(struct device *dev, const char *str)592{593	if (!strcmp(str, "32_64")) {594		return DA7219_AAD_JACK_DET_RATE_32_64MS;595	} else if (!strcmp(str, "64_128")) {596		return DA7219_AAD_JACK_DET_RATE_64_128MS;597	} else if (!strcmp(str, "128_256")) {598		return DA7219_AAD_JACK_DET_RATE_128_256MS;599	} else if (!strcmp(str, "256_512")) {600		return DA7219_AAD_JACK_DET_RATE_256_512MS;601	} else {602		dev_warn(dev, "Invalid jack detect rate");603		return DA7219_AAD_JACK_DET_RATE_256_512MS;604	}605}606 607static enum da7219_aad_jack_rem_deb608	da7219_aad_fw_jack_rem_deb(struct device *dev, u32 val)609{610	switch (val) {611	case 1:612		return DA7219_AAD_JACK_REM_DEB_1MS;613	case 5:614		return DA7219_AAD_JACK_REM_DEB_5MS;615	case 10:616		return DA7219_AAD_JACK_REM_DEB_10MS;617	case 20:618		return DA7219_AAD_JACK_REM_DEB_20MS;619	default:620		dev_warn(dev, "Invalid jack removal debounce");621		return DA7219_AAD_JACK_REM_DEB_1MS;622	}623}624 625static enum da7219_aad_btn_avg626	da7219_aad_fw_btn_avg(struct device *dev, u32 val)627{628	switch (val) {629	case 1:630		return DA7219_AAD_BTN_AVG_1;631	case 2:632		return DA7219_AAD_BTN_AVG_2;633	case 4:634		return DA7219_AAD_BTN_AVG_4;635	case 8:636		return DA7219_AAD_BTN_AVG_8;637	default:638		dev_warn(dev, "Invalid button average value");639		return DA7219_AAD_BTN_AVG_2;640	}641}642 643static enum da7219_aad_adc_1bit_rpt644	da7219_aad_fw_adc_1bit_rpt(struct device *dev, u32 val)645{646	switch (val) {647	case 1:648		return DA7219_AAD_ADC_1BIT_RPT_1;649	case 2:650		return DA7219_AAD_ADC_1BIT_RPT_2;651	case 4:652		return DA7219_AAD_ADC_1BIT_RPT_4;653	case 8:654		return DA7219_AAD_ADC_1BIT_RPT_8;655	default:656		dev_warn(dev, "Invalid ADC 1-bit repeat value");657		return DA7219_AAD_ADC_1BIT_RPT_1;658	}659}660 661static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)662{663	struct i2c_client *i2c = to_i2c_client(dev);664	struct fwnode_handle *aad_np;665	struct da7219_aad_pdata *aad_pdata;666	const char *fw_str;667	u32 fw_val32;668 669	aad_np = device_get_named_child_node(dev, "da7219_aad");670	if (!aad_np)671		return NULL;672 673	aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);674	if (!aad_pdata) {675		fwnode_handle_put(aad_np);676		return NULL;677	}678 679	aad_pdata->irq = i2c->irq;680 681	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",682				     &fw_val32) >= 0)683		aad_pdata->micbias_pulse_lvl =684			da7219_aad_fw_micbias_pulse_lvl(dev, fw_val32);685	else686		aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;687 688	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",689				     &fw_val32) >= 0)690		aad_pdata->micbias_pulse_time = fw_val32;691 692	if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)693		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(dev, fw_val32);694	else695		aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;696 697	if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)698		aad_pdata->mic_det_thr =699			da7219_aad_fw_mic_det_thr(dev, fw_val32);700	else701		aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_200_OHMS;702 703	if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)704		aad_pdata->jack_ins_deb =705			da7219_aad_fw_jack_ins_deb(dev, fw_val32);706	else707		aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;708 709	if (!fwnode_property_read_string(aad_np, "dlg,jack-ins-det-pty", &fw_str))710		aad_pdata->jack_ins_det_pty =711			da7219_aad_fw_jack_ins_det_pty(dev, fw_str);712	else713		aad_pdata->jack_ins_det_pty = DA7219_AAD_JACK_INS_DET_PTY_LOW;714 715	if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))716		aad_pdata->jack_det_rate =717			da7219_aad_fw_jack_det_rate(dev, fw_str);718	else719		aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;720 721	if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)722		aad_pdata->jack_rem_deb =723			da7219_aad_fw_jack_rem_deb(dev, fw_val32);724	else725		aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;726 727	if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)728		aad_pdata->a_d_btn_thr = (u8) fw_val32;729	else730		aad_pdata->a_d_btn_thr = 0xA;731 732	if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)733		aad_pdata->d_b_btn_thr = (u8) fw_val32;734	else735		aad_pdata->d_b_btn_thr = 0x16;736 737	if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)738		aad_pdata->b_c_btn_thr = (u8) fw_val32;739	else740		aad_pdata->b_c_btn_thr = 0x21;741 742	if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)743		aad_pdata->c_mic_btn_thr = (u8) fw_val32;744	else745		aad_pdata->c_mic_btn_thr = 0x3E;746 747	if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)748		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(dev, fw_val32);749	else750		aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;751 752	if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)753		aad_pdata->adc_1bit_rpt =754			da7219_aad_fw_adc_1bit_rpt(dev, fw_val32);755	else756		aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;757 758	fwnode_handle_put(aad_np);759 760	return aad_pdata;761}762 763static void da7219_aad_handle_pdata(struct snd_soc_component *component)764{765	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);766	struct da7219_aad_priv *da7219_aad = da7219->aad;767	struct da7219_pdata *pdata = da7219->pdata;768 769	if ((pdata) && (pdata->aad_pdata)) {770		struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;771		u8 cfg, mask;772 773		da7219_aad->irq = aad_pdata->irq;774 775		switch (aad_pdata->micbias_pulse_lvl) {776		case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:777		case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:778			da7219_aad->micbias_pulse_lvl =779				(aad_pdata->micbias_pulse_lvl <<780				 DA7219_MICBIAS1_LEVEL_SHIFT);781			break;782		default:783			break;784		}785 786		da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;787 788		switch (aad_pdata->btn_cfg) {789		case DA7219_AAD_BTN_CFG_2MS:790		case DA7219_AAD_BTN_CFG_5MS:791		case DA7219_AAD_BTN_CFG_10MS:792		case DA7219_AAD_BTN_CFG_50MS:793		case DA7219_AAD_BTN_CFG_100MS:794		case DA7219_AAD_BTN_CFG_200MS:795		case DA7219_AAD_BTN_CFG_500MS:796			da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<797						DA7219_BUTTON_CONFIG_SHIFT);798		}799 800		cfg = 0;801		mask = 0;802		switch (aad_pdata->mic_det_thr) {803		case DA7219_AAD_MIC_DET_THR_200_OHMS:804		case DA7219_AAD_MIC_DET_THR_500_OHMS:805		case DA7219_AAD_MIC_DET_THR_750_OHMS:806		case DA7219_AAD_MIC_DET_THR_1000_OHMS:807			cfg |= (aad_pdata->mic_det_thr <<808				DA7219_MIC_DET_THRESH_SHIFT);809			mask |= DA7219_MIC_DET_THRESH_MASK;810		}811		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg);812 813		cfg = 0;814		mask = 0;815		switch (aad_pdata->jack_ins_deb) {816		case DA7219_AAD_JACK_INS_DEB_5MS:817		case DA7219_AAD_JACK_INS_DEB_10MS:818		case DA7219_AAD_JACK_INS_DEB_20MS:819		case DA7219_AAD_JACK_INS_DEB_50MS:820		case DA7219_AAD_JACK_INS_DEB_100MS:821		case DA7219_AAD_JACK_INS_DEB_200MS:822		case DA7219_AAD_JACK_INS_DEB_500MS:823		case DA7219_AAD_JACK_INS_DEB_1S:824			cfg |= (aad_pdata->jack_ins_deb <<825				DA7219_JACKDET_DEBOUNCE_SHIFT);826			mask |= DA7219_JACKDET_DEBOUNCE_MASK;827		}828		switch (aad_pdata->jack_det_rate) {829		case DA7219_AAD_JACK_DET_RATE_32_64MS:830		case DA7219_AAD_JACK_DET_RATE_64_128MS:831		case DA7219_AAD_JACK_DET_RATE_128_256MS:832		case DA7219_AAD_JACK_DET_RATE_256_512MS:833			cfg |= (aad_pdata->jack_det_rate <<834				DA7219_JACK_DETECT_RATE_SHIFT);835			mask |= DA7219_JACK_DETECT_RATE_MASK;836		}837		switch (aad_pdata->jack_rem_deb) {838		case DA7219_AAD_JACK_REM_DEB_1MS:839		case DA7219_AAD_JACK_REM_DEB_5MS:840		case DA7219_AAD_JACK_REM_DEB_10MS:841		case DA7219_AAD_JACK_REM_DEB_20MS:842			cfg |= (aad_pdata->jack_rem_deb <<843				DA7219_JACKDET_REM_DEB_SHIFT);844			mask |= DA7219_JACKDET_REM_DEB_MASK;845		}846		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg);847 848		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3,849			      aad_pdata->a_d_btn_thr);850		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4,851			      aad_pdata->d_b_btn_thr);852		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5,853			      aad_pdata->b_c_btn_thr);854		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6,855			      aad_pdata->c_mic_btn_thr);856 857		cfg = 0;858		mask = 0;859		switch (aad_pdata->btn_avg) {860		case DA7219_AAD_BTN_AVG_1:861		case DA7219_AAD_BTN_AVG_2:862		case DA7219_AAD_BTN_AVG_4:863		case DA7219_AAD_BTN_AVG_8:864			cfg |= (aad_pdata->btn_avg <<865				DA7219_BUTTON_AVERAGE_SHIFT);866			mask |= DA7219_BUTTON_AVERAGE_MASK;867		}868		switch (aad_pdata->adc_1bit_rpt) {869		case DA7219_AAD_ADC_1BIT_RPT_1:870		case DA7219_AAD_ADC_1BIT_RPT_2:871		case DA7219_AAD_ADC_1BIT_RPT_4:872		case DA7219_AAD_ADC_1BIT_RPT_8:873			cfg |= (aad_pdata->adc_1bit_rpt <<874			       DA7219_ADC_1_BIT_REPEAT_SHIFT);875			mask |= DA7219_ADC_1_BIT_REPEAT_MASK;876		}877		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);878 879		switch (aad_pdata->jack_ins_det_pty) {880		case DA7219_AAD_JACK_INS_DET_PTY_LOW:881			snd_soc_component_write(component, 0xF0, 0x8B);882			snd_soc_component_write(component, 0x75, 0x80);883			snd_soc_component_write(component, 0xF0, 0x00);884			break;885		case DA7219_AAD_JACK_INS_DET_PTY_HIGH:886			snd_soc_component_write(component, 0xF0, 0x8B);887			snd_soc_component_write(component, 0x75, 0x00);888			snd_soc_component_write(component, 0xF0, 0x00);889			break;890		default:891			break;892		}893	}894}895 896static void da7219_aad_handle_gnd_switch_time(struct snd_soc_component *component)897{898	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);899	struct da7219_aad_priv *da7219_aad = da7219->aad;900	u8 jack_det;901 902	jack_det = snd_soc_component_read(component, DA7219_ACCDET_CONFIG_2)903		& DA7219_JACK_DETECT_RATE_MASK;904	switch (jack_det) {905	case 0x00:906		da7219_aad->gnd_switch_delay = 32;907		break;908	case 0x10:909		da7219_aad->gnd_switch_delay = 64;910		break;911	case 0x20:912		da7219_aad->gnd_switch_delay = 128;913		break;914	case 0x30:915		da7219_aad->gnd_switch_delay = 256;916		break;917	default:918		da7219_aad->gnd_switch_delay = 32;919		break;920	}921}922 923/*924 * Suspend/Resume925 */926 927void da7219_aad_suspend(struct snd_soc_component *component)928{929	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);930	struct da7219_aad_priv *da7219_aad = da7219->aad;931	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);932	u8 micbias_ctrl;933 934	disable_irq(da7219_aad->irq);935 936	if (da7219_aad->jack) {937		/* Disable jack detection during suspend */938		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,939				    DA7219_ACCDET_EN_MASK, 0);940		cancel_delayed_work_sync(&da7219_aad->jack_det_work);941		/* Disable ground switch */942		snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);943 944		/*945		 * If we have a 4-pole jack inserted, then micbias will be946		 * enabled. We can disable micbias here, and keep a note to947		 * re-enable it on resume. If jack removal occurred during948		 * suspend then this will be dealt with through the IRQ handler.949		 */950		if (da7219_aad->jack_inserted) {951			micbias_ctrl = snd_soc_component_read(component, DA7219_MICBIAS_CTRL);952			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {953				snd_soc_dapm_disable_pin(dapm, "Mic Bias");954				snd_soc_dapm_sync(dapm);955				da7219_aad->micbias_resume_enable = true;956			}957		}958	}959}960 961void da7219_aad_resume(struct snd_soc_component *component)962{963	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);964	struct da7219_aad_priv *da7219_aad = da7219->aad;965	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);966 967	if (da7219_aad->jack) {968		/* Re-enable micbias if previously enabled for 4-pole jack */969		if (da7219_aad->jack_inserted &&970		    da7219_aad->micbias_resume_enable) {971			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");972			snd_soc_dapm_sync(dapm);973			da7219_aad->micbias_resume_enable = false;974		}975 976		/* Re-enable jack detection */977		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,978				    DA7219_ACCDET_EN_MASK,979				    DA7219_ACCDET_EN_MASK);980	}981 982	enable_irq(da7219_aad->irq);983}984 985 986/*987 * Init/Exit988 */989 990int da7219_aad_init(struct snd_soc_component *component)991{992	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);993	struct da7219_aad_priv *da7219_aad = da7219->aad;994	u8 mask[DA7219_AAD_IRQ_REG_MAX];995	int ret;996 997	da7219_aad->component = component;998 999	/* Handle any DT/ACPI/platform data */1000	da7219_aad_handle_pdata(component);1001 1002	/* Disable button detection */1003	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,1004			    DA7219_BUTTON_CONFIG_MASK, 0);1005 1006	da7219_aad_handle_gnd_switch_time(component);1007 1008	da7219_aad->aad_wq = create_singlethread_workqueue("da7219-aad");1009	if (!da7219_aad->aad_wq) {1010		dev_err(component->dev, "Failed to create aad workqueue\n");1011		return -ENOMEM;1012	}1013 1014	INIT_DELAYED_WORK(&da7219_aad->jack_det_work, da7219_aad_jack_det_work);1015	INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);1016	INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);1017 1018	ret = request_threaded_irq(da7219_aad->irq, NULL,1019				   da7219_aad_irq_thread,1020				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,1021				   "da7219-aad", da7219_aad);1022	if (ret) {1023		dev_err(component->dev, "Failed to request IRQ: %d\n", ret);1024		return ret;1025	}1026 1027	/* Unmask AAD IRQs */1028	memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);1029	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,1030			  &mask, DA7219_AAD_IRQ_REG_MAX);1031 1032	return 0;1033}1034 1035void da7219_aad_exit(struct snd_soc_component *component)1036{1037	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);1038	struct da7219_aad_priv *da7219_aad = da7219->aad;1039	u8 mask[DA7219_AAD_IRQ_REG_MAX];1040 1041	/* Mask off AAD IRQs */1042	memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);1043	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,1044			  mask, DA7219_AAD_IRQ_REG_MAX);1045 1046	free_irq(da7219_aad->irq, da7219_aad);1047 1048	cancel_delayed_work_sync(&da7219_aad->jack_det_work);1049	cancel_work_sync(&da7219_aad->btn_det_work);1050	cancel_work_sync(&da7219_aad->hptest_work);1051	destroy_workqueue(da7219_aad->aad_wq);1052}1053 1054/*1055 * AAD related I2C probe handling1056 */1057 1058int da7219_aad_probe(struct i2c_client *i2c)1059{1060	struct da7219_priv *da7219 = i2c_get_clientdata(i2c);1061	struct device *dev = &i2c->dev;1062	struct da7219_aad_priv *da7219_aad;1063 1064	da7219_aad = devm_kzalloc(dev, sizeof(*da7219_aad), GFP_KERNEL);1065	if (!da7219_aad)1066		return -ENOMEM;1067 1068	da7219->aad = da7219_aad;1069 1070	/* Retrieve any DT/ACPI/platform data */1071	if (da7219->pdata && !da7219->pdata->aad_pdata)1072		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(dev);1073 1074	return 0;1075}1076 1077MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");1078MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");1079MODULE_AUTHOR("David Rau <David.Rau.opensource@dm.renesas.com>");1080MODULE_LICENSE("GPL");1081