~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/cs42l43-jack.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // CS42L43 CODEC driver jack handling
  4 //
  5 // Copyright (C) 2022-2023 Cirrus Logic, Inc. and
  6 //                         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 
 32 static const unsigned int cs42l43_accdet_us[] = {
 33         20, 100, 1000, 10000, 50000, 75000, 100000, 200000,
 34 };
 35 
 36 static const unsigned int cs42l43_accdet_db_ms[] = {
 37         0, 125, 250, 500, 750, 1000, 1250, 1500,
 38 };
 39 
 40 static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 };
 41 
 42 static const unsigned int cs42l43_accdet_bias_sense[] = {
 43         14, 24, 43, 52, 61, 71, 90, 99, 0,
 44 };
 45 
 46 static 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 
 70 int 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         else
167                 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 
231 done:
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 
242 error:
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 
251 static 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 
280 static 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 
300 irqreturn_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 0x3
311 #define CS42L43_JACK_ABSENT 0x0
312 
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 
322 static 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 
334 static 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 
351 static 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 512
366 #define CS42L43_BUTTON_ROUT 2210
367 
368 void 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         else
408                 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 
423 error:
424         mutex_unlock(&priv->jack_lock);
425 
426         pm_runtime_mark_last_busy(priv->dev);
427         pm_runtime_put_autosuspend(priv->dev);
428 }
429 
430 irqreturn_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 reading
435         queue_delayed_work(system_wq, &priv->button_press_work,
436                            msecs_to_jiffies(20));
437 
438         return IRQ_HANDLED;
439 }
440 
441 void 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 
469 irqreturn_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 
478 void 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 
511 static 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 
557 static 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 
605 static 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 impedance
638         case 0x1: // high impedance
639                 return CS42L43_JACK_HEADPHONE;
640         case 0x2: // lineout
641         case 0x3: // Open circuit
642                 return CS42L43_JACK_LINEOUT;
643         default:
644                 return -EINVAL;
645         }
646 }
647 
648 static 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: // CTIA
681         case 0x1: // OMTP
682                 return cs42l43_run_load_detect(priv, true);
683         case 0x2: // 3-pole
684                 return cs42l43_run_load_detect(priv, false);
685         case 0x3: // Open-circuit
686                 return CS42L43_JACK_EXTENSION;
687         default:
688                 return -EINVAL;
689         }
690 }
691 
692 static 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 
712 void 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 
764 error:
765         mutex_unlock(&priv->jack_lock);
766 
767         pm_runtime_mark_last_busy(priv->dev);
768         pm_runtime_put_autosuspend(priv->dev);
769 }
770 
771 irqreturn_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 
786 enum 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 
804 static 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 
855 static const char * const cs42l43_jack_text[] = {
856         "None", "CTIA", "OMTP", "Headphone", "Line-Out",
857         "Line-In", "Microphone", "Optical",
858 };
859 
860 static_assert(ARRAY_SIZE(cs42l43_jack_override_modes) ==
861               ARRAY_SIZE(cs42l43_jack_text) - 1);
862 
863 SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text);
864 
865 int 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 
877 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php