2 * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
4 * Copyright (c) 2015 Dialog Semiconductor Ltd.
6 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/clk.h>
17 #include <linux/i2c.h>
18 #include <linux/property.h>
19 #include <linux/pm_wakeirq.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/workqueue.h>
23 #include <sound/soc.h>
24 #include <sound/jack.h>
25 #include <sound/da7219.h>
28 #include "da7219-aad.h"
35 void da7219_aad_jack_det(struct snd_soc_codec
*codec
, struct snd_soc_jack
*jack
)
37 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
39 da7219
->aad
->jack
= jack
;
40 da7219
->aad
->jack_inserted
= false;
42 /* Send an initial empty report */
43 snd_soc_jack_report(jack
, 0, DA7219_AAD_REPORT_ALL_MASK
);
45 /* Enable/Disable jack detection */
46 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_1
,
47 DA7219_ACCDET_EN_MASK
,
48 (jack
? DA7219_ACCDET_EN_MASK
: 0));
50 EXPORT_SYMBOL_GPL(da7219_aad_jack_det
);
56 static void da7219_aad_btn_det_work(struct work_struct
*work
)
58 struct da7219_aad_priv
*da7219_aad
=
59 container_of(work
, struct da7219_aad_priv
, btn_det_work
);
60 struct snd_soc_codec
*codec
= da7219_aad
->codec
;
61 struct snd_soc_dapm_context
*dapm
= snd_soc_codec_get_dapm(codec
);
62 u8 statusa
, micbias_ctrl
;
63 bool micbias_up
= false;
66 /* Drive headphones/lineout */
67 snd_soc_update_bits(codec
, DA7219_HP_L_CTRL
,
68 DA7219_HP_L_AMP_OE_MASK
,
69 DA7219_HP_L_AMP_OE_MASK
);
70 snd_soc_update_bits(codec
, DA7219_HP_R_CTRL
,
71 DA7219_HP_R_AMP_OE_MASK
,
72 DA7219_HP_R_AMP_OE_MASK
);
74 /* Make sure mic bias is up */
75 snd_soc_dapm_force_enable_pin(dapm
, "Mic Bias");
76 snd_soc_dapm_sync(dapm
);
79 statusa
= snd_soc_read(codec
, DA7219_ACCDET_STATUS_A
);
80 if (statusa
& DA7219_MICBIAS_UP_STS_MASK
)
82 else if (retries
++ < DA7219_AAD_MICBIAS_CHK_RETRIES
)
83 msleep(DA7219_AAD_MICBIAS_CHK_DELAY
);
84 } while ((!micbias_up
) && (retries
< DA7219_AAD_MICBIAS_CHK_RETRIES
));
86 if (retries
>= DA7219_AAD_MICBIAS_CHK_RETRIES
)
87 dev_warn(codec
->dev
, "Mic bias status check timed out");
90 * Mic bias pulse required to enable mic, must be done before enabling
91 * button detection to prevent erroneous button readings.
93 if (da7219_aad
->micbias_pulse_lvl
&& da7219_aad
->micbias_pulse_time
) {
94 /* Pulse higher level voltage */
95 micbias_ctrl
= snd_soc_read(codec
, DA7219_MICBIAS_CTRL
);
96 snd_soc_update_bits(codec
, DA7219_MICBIAS_CTRL
,
97 DA7219_MICBIAS1_LEVEL_MASK
,
98 da7219_aad
->micbias_pulse_lvl
);
99 msleep(da7219_aad
->micbias_pulse_time
);
100 snd_soc_write(codec
, DA7219_MICBIAS_CTRL
, micbias_ctrl
);
104 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_1
,
105 DA7219_BUTTON_CONFIG_MASK
,
106 da7219_aad
->btn_cfg
);
109 static void da7219_aad_hptest_work(struct work_struct
*work
)
111 struct da7219_aad_priv
*da7219_aad
=
112 container_of(work
, struct da7219_aad_priv
, hptest_work
);
113 struct snd_soc_codec
*codec
= da7219_aad
->codec
;
114 struct snd_soc_dapm_context
*dapm
= snd_soc_codec_get_dapm(codec
);
115 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
117 u16 tonegen_freq_hptest
;
119 int report
= 0, ret
= 0;
121 /* Lock DAPM and any Kcontrols that are affected by this test */
122 snd_soc_dapm_mutex_lock(dapm
);
123 mutex_lock(&da7219
->lock
);
125 /* Ensure MCLK is available for HP test procedure */
127 ret
= clk_prepare_enable(da7219
->mclk
);
129 dev_err(codec
->dev
, "Failed to enable mclk - %d\n", ret
);
130 mutex_unlock(&da7219
->lock
);
131 snd_soc_dapm_mutex_unlock(dapm
);
136 /* Bypass cache so it saves current settings */
137 regcache_cache_bypass(da7219
->regmap
, true);
139 /* Make sure Tone Generator is disabled */
140 snd_soc_write(codec
, DA7219_TONE_GEN_CFG1
, 0);
142 /* Enable HPTest block, 1KOhms check */
143 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_8
,
144 DA7219_HPTEST_EN_MASK
| DA7219_HPTEST_RES_SEL_MASK
,
145 DA7219_HPTEST_EN_MASK
|
146 DA7219_HPTEST_RES_SEL_1KOHMS
);
148 /* Set gains to 0db */
149 snd_soc_write(codec
, DA7219_DAC_L_GAIN
, DA7219_DAC_DIGITAL_GAIN_0DB
);
150 snd_soc_write(codec
, DA7219_DAC_R_GAIN
, DA7219_DAC_DIGITAL_GAIN_0DB
);
151 snd_soc_write(codec
, DA7219_HP_L_GAIN
, DA7219_HP_AMP_GAIN_0DB
);
152 snd_soc_write(codec
, DA7219_HP_R_GAIN
, DA7219_HP_AMP_GAIN_0DB
);
154 /* Disable DAC filters, EQs and soft mute */
155 snd_soc_update_bits(codec
, DA7219_DAC_FILTERS1
, DA7219_HPF_MODE_MASK
,
157 snd_soc_update_bits(codec
, DA7219_DAC_FILTERS4
, DA7219_DAC_EQ_EN_MASK
,
159 snd_soc_update_bits(codec
, DA7219_DAC_FILTERS5
,
160 DA7219_DAC_SOFTMUTE_EN_MASK
, 0);
162 /* Enable HP left & right paths */
163 snd_soc_update_bits(codec
, DA7219_CP_CTRL
, DA7219_CP_EN_MASK
,
165 snd_soc_update_bits(codec
, DA7219_DIG_ROUTING_DAC
,
166 DA7219_DAC_L_SRC_MASK
| DA7219_DAC_R_SRC_MASK
,
167 DA7219_DAC_L_SRC_TONEGEN
|
168 DA7219_DAC_R_SRC_TONEGEN
);
169 snd_soc_update_bits(codec
, DA7219_DAC_L_CTRL
,
170 DA7219_DAC_L_EN_MASK
| DA7219_DAC_L_MUTE_EN_MASK
,
171 DA7219_DAC_L_EN_MASK
);
172 snd_soc_update_bits(codec
, DA7219_DAC_R_CTRL
,
173 DA7219_DAC_R_EN_MASK
| DA7219_DAC_R_MUTE_EN_MASK
,
174 DA7219_DAC_R_EN_MASK
);
175 snd_soc_update_bits(codec
, DA7219_MIXOUT_L_SELECT
,
176 DA7219_MIXOUT_L_MIX_SELECT_MASK
,
177 DA7219_MIXOUT_L_MIX_SELECT_MASK
);
178 snd_soc_update_bits(codec
, DA7219_MIXOUT_R_SELECT
,
179 DA7219_MIXOUT_R_MIX_SELECT_MASK
,
180 DA7219_MIXOUT_R_MIX_SELECT_MASK
);
181 snd_soc_update_bits(codec
, DA7219_DROUTING_ST_OUTFILT_1L
,
182 DA7219_OUTFILT_ST_1L_SRC_MASK
,
183 DA7219_DMIX_ST_SRC_OUTFILT1L
);
184 snd_soc_update_bits(codec
, DA7219_DROUTING_ST_OUTFILT_1R
,
185 DA7219_OUTFILT_ST_1R_SRC_MASK
,
186 DA7219_DMIX_ST_SRC_OUTFILT1R
);
187 snd_soc_update_bits(codec
, DA7219_MIXOUT_L_CTRL
,
188 DA7219_MIXOUT_L_AMP_EN_MASK
,
189 DA7219_MIXOUT_L_AMP_EN_MASK
);
190 snd_soc_update_bits(codec
, DA7219_MIXOUT_R_CTRL
,
191 DA7219_MIXOUT_R_AMP_EN_MASK
,
192 DA7219_MIXOUT_R_AMP_EN_MASK
);
193 snd_soc_write(codec
, DA7219_HP_L_CTRL
,
194 DA7219_HP_L_AMP_OE_MASK
| DA7219_HP_L_AMP_EN_MASK
);
195 snd_soc_write(codec
, DA7219_HP_R_CTRL
,
196 DA7219_HP_R_AMP_OE_MASK
| DA7219_HP_R_AMP_EN_MASK
);
198 /* Configure & start Tone Generator */
199 snd_soc_write(codec
, DA7219_TONE_GEN_ON_PER
, DA7219_BEEP_ON_PER_MASK
);
200 tonegen_freq_hptest
= cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ
);
201 regmap_raw_write(da7219
->regmap
, DA7219_TONE_GEN_FREQ1_L
,
202 &tonegen_freq_hptest
, sizeof(tonegen_freq_hptest
));
203 snd_soc_update_bits(codec
, DA7219_TONE_GEN_CFG2
,
204 DA7219_SWG_SEL_MASK
| DA7219_TONE_GEN_GAIN_MASK
,
205 DA7219_SWG_SEL_SRAMP
|
206 DA7219_TONE_GEN_GAIN_MINUS_15DB
);
207 snd_soc_write(codec
, DA7219_TONE_GEN_CFG1
, DA7219_START_STOPN_MASK
);
209 msleep(DA7219_AAD_HPTEST_PERIOD
);
211 /* Grab comparator reading */
212 accdet_cfg8
= snd_soc_read(codec
, DA7219_ACCDET_CONFIG_8
);
213 if (accdet_cfg8
& DA7219_HPTEST_COMP_MASK
)
214 report
|= SND_JACK_HEADPHONE
;
216 report
|= SND_JACK_LINEOUT
;
218 /* Stop tone generator */
219 snd_soc_write(codec
, DA7219_TONE_GEN_CFG1
, 0);
221 msleep(DA7219_AAD_HPTEST_PERIOD
);
223 /* Restore original settings from cache */
224 regcache_mark_dirty(da7219
->regmap
);
225 regcache_sync_region(da7219
->regmap
, DA7219_HP_L_CTRL
,
227 regcache_sync_region(da7219
->regmap
, DA7219_MIXOUT_L_CTRL
,
228 DA7219_MIXOUT_R_CTRL
);
229 regcache_sync_region(da7219
->regmap
, DA7219_DROUTING_ST_OUTFILT_1L
,
230 DA7219_DROUTING_ST_OUTFILT_1R
);
231 regcache_sync_region(da7219
->regmap
, DA7219_MIXOUT_L_SELECT
,
232 DA7219_MIXOUT_R_SELECT
);
233 regcache_sync_region(da7219
->regmap
, DA7219_DAC_L_CTRL
,
235 regcache_sync_region(da7219
->regmap
, DA7219_DIG_ROUTING_DAC
,
236 DA7219_DIG_ROUTING_DAC
);
237 regcache_sync_region(da7219
->regmap
, DA7219_CP_CTRL
, DA7219_CP_CTRL
);
238 regcache_sync_region(da7219
->regmap
, DA7219_DAC_FILTERS5
,
239 DA7219_DAC_FILTERS5
);
240 regcache_sync_region(da7219
->regmap
, DA7219_DAC_FILTERS4
,
241 DA7219_DAC_FILTERS1
);
242 regcache_sync_region(da7219
->regmap
, DA7219_HP_L_GAIN
,
244 regcache_sync_region(da7219
->regmap
, DA7219_DAC_L_GAIN
,
246 regcache_sync_region(da7219
->regmap
, DA7219_TONE_GEN_ON_PER
,
247 DA7219_TONE_GEN_ON_PER
);
248 regcache_sync_region(da7219
->regmap
, DA7219_TONE_GEN_FREQ1_L
,
249 DA7219_TONE_GEN_FREQ1_U
);
250 regcache_sync_region(da7219
->regmap
, DA7219_TONE_GEN_CFG1
,
251 DA7219_TONE_GEN_CFG2
);
253 regcache_cache_bypass(da7219
->regmap
, false);
255 /* Disable HPTest block */
256 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_8
,
257 DA7219_HPTEST_EN_MASK
, 0);
259 /* Drive Headphones/lineout */
260 snd_soc_update_bits(codec
, DA7219_HP_L_CTRL
, DA7219_HP_L_AMP_OE_MASK
,
261 DA7219_HP_L_AMP_OE_MASK
);
262 snd_soc_update_bits(codec
, DA7219_HP_R_CTRL
, DA7219_HP_R_AMP_OE_MASK
,
263 DA7219_HP_R_AMP_OE_MASK
);
265 /* Remove MCLK, if previously enabled */
267 clk_disable_unprepare(da7219
->mclk
);
269 mutex_unlock(&da7219
->lock
);
270 snd_soc_dapm_mutex_unlock(dapm
);
273 * Only send report if jack hasn't been removed during process,
274 * otherwise it's invalid and we drop it.
276 if (da7219_aad
->jack_inserted
)
277 snd_soc_jack_report(da7219_aad
->jack
, report
,
278 SND_JACK_HEADSET
| SND_JACK_LINEOUT
);
286 static irqreturn_t
da7219_aad_irq_thread(int irq
, void *data
)
288 struct da7219_aad_priv
*da7219_aad
= data
;
289 struct snd_soc_codec
*codec
= da7219_aad
->codec
;
290 struct snd_soc_dapm_context
*dapm
= snd_soc_codec_get_dapm(codec
);
291 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
292 u8 events
[DA7219_AAD_IRQ_REG_MAX
];
294 int i
, report
= 0, mask
= 0;
296 /* Read current IRQ events */
297 regmap_bulk_read(da7219
->regmap
, DA7219_ACCDET_IRQ_EVENT_A
,
298 events
, DA7219_AAD_IRQ_REG_MAX
);
300 if (!events
[DA7219_AAD_IRQ_REG_A
] && !events
[DA7219_AAD_IRQ_REG_B
])
303 /* Read status register for jack insertion & type status */
304 statusa
= snd_soc_read(codec
, DA7219_ACCDET_STATUS_A
);
307 regmap_bulk_write(da7219
->regmap
, DA7219_ACCDET_IRQ_EVENT_A
,
308 events
, DA7219_AAD_IRQ_REG_MAX
);
310 dev_dbg(codec
->dev
, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
311 events
[DA7219_AAD_IRQ_REG_A
], events
[DA7219_AAD_IRQ_REG_B
],
314 if (statusa
& DA7219_JACK_INSERTION_STS_MASK
) {
316 if (events
[DA7219_AAD_IRQ_REG_A
] &
317 DA7219_E_JACK_INSERTED_MASK
) {
318 report
|= SND_JACK_MECHANICAL
;
319 mask
|= SND_JACK_MECHANICAL
;
320 da7219_aad
->jack_inserted
= true;
323 /* Jack type detection */
324 if (events
[DA7219_AAD_IRQ_REG_A
] &
325 DA7219_E_JACK_DETECT_COMPLETE_MASK
) {
327 * If 4-pole, then enable button detection, else perform
328 * HP impedance test to determine output type to report.
330 * We schedule work here as the tasks themselves can
331 * take time to complete, and in particular for hptest
332 * we want to be able to check if the jack was removed
333 * during the procedure as this will invalidate the
334 * result. By doing this as work, the IRQ thread can
335 * handle a removal, and we can check at the end of
336 * hptest if we have a valid result or not.
338 if (statusa
& DA7219_JACK_TYPE_STS_MASK
) {
339 report
|= SND_JACK_HEADSET
;
340 mask
|= SND_JACK_HEADSET
| SND_JACK_LINEOUT
;
341 schedule_work(&da7219_aad
->btn_det_work
);
343 schedule_work(&da7219_aad
->hptest_work
);
347 /* Button support for 4-pole jack */
348 if (statusa
& DA7219_JACK_TYPE_STS_MASK
) {
349 for (i
= 0; i
< DA7219_AAD_MAX_BUTTONS
; ++i
) {
351 if (events
[DA7219_AAD_IRQ_REG_B
] &
352 (DA7219_E_BUTTON_A_PRESSED_MASK
<< i
)) {
353 report
|= SND_JACK_BTN_0
>> i
;
354 mask
|= SND_JACK_BTN_0
>> i
;
357 snd_soc_jack_report(da7219_aad
->jack
, report
, mask
);
359 for (i
= 0; i
< DA7219_AAD_MAX_BUTTONS
; ++i
) {
361 if (events
[DA7219_AAD_IRQ_REG_B
] &
362 (DA7219_E_BUTTON_A_RELEASED_MASK
>> i
)) {
363 report
&= ~(SND_JACK_BTN_0
>> i
);
364 mask
|= SND_JACK_BTN_0
>> i
;
370 if (events
[DA7219_AAD_IRQ_REG_A
] & DA7219_E_JACK_REMOVED_MASK
) {
372 mask
|= DA7219_AAD_REPORT_ALL_MASK
;
373 da7219_aad
->jack_inserted
= false;
375 /* Un-drive headphones/lineout */
376 snd_soc_update_bits(codec
, DA7219_HP_R_CTRL
,
377 DA7219_HP_R_AMP_OE_MASK
, 0);
378 snd_soc_update_bits(codec
, DA7219_HP_L_CTRL
,
379 DA7219_HP_L_AMP_OE_MASK
, 0);
381 /* Ensure button detection disabled */
382 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_1
,
383 DA7219_BUTTON_CONFIG_MASK
, 0);
385 /* Disable mic bias */
386 snd_soc_dapm_disable_pin(dapm
, "Mic Bias");
387 snd_soc_dapm_sync(dapm
);
389 /* Cancel any pending work */
390 cancel_work_sync(&da7219_aad
->btn_det_work
);
391 cancel_work_sync(&da7219_aad
->hptest_work
);
395 snd_soc_jack_report(da7219_aad
->jack
, report
, mask
);
401 * DT/ACPI to pdata conversion
404 static enum da7219_aad_micbias_pulse_lvl
405 da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_codec
*codec
, u32 val
)
409 return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V
;
411 return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V
;
413 dev_warn(codec
->dev
, "Invalid micbias pulse level");
414 return DA7219_AAD_MICBIAS_PULSE_LVL_OFF
;
418 static enum da7219_aad_btn_cfg
419 da7219_aad_fw_btn_cfg(struct snd_soc_codec
*codec
, u32 val
)
423 return DA7219_AAD_BTN_CFG_2MS
;
425 return DA7219_AAD_BTN_CFG_5MS
;
427 return DA7219_AAD_BTN_CFG_10MS
;
429 return DA7219_AAD_BTN_CFG_50MS
;
431 return DA7219_AAD_BTN_CFG_100MS
;
433 return DA7219_AAD_BTN_CFG_200MS
;
435 return DA7219_AAD_BTN_CFG_500MS
;
437 dev_warn(codec
->dev
, "Invalid button config");
438 return DA7219_AAD_BTN_CFG_10MS
;
442 static enum da7219_aad_mic_det_thr
443 da7219_aad_fw_mic_det_thr(struct snd_soc_codec
*codec
, u32 val
)
447 return DA7219_AAD_MIC_DET_THR_200_OHMS
;
449 return DA7219_AAD_MIC_DET_THR_500_OHMS
;
451 return DA7219_AAD_MIC_DET_THR_750_OHMS
;
453 return DA7219_AAD_MIC_DET_THR_1000_OHMS
;
455 dev_warn(codec
->dev
, "Invalid mic detect threshold");
456 return DA7219_AAD_MIC_DET_THR_500_OHMS
;
460 static enum da7219_aad_jack_ins_deb
461 da7219_aad_fw_jack_ins_deb(struct snd_soc_codec
*codec
, u32 val
)
465 return DA7219_AAD_JACK_INS_DEB_5MS
;
467 return DA7219_AAD_JACK_INS_DEB_10MS
;
469 return DA7219_AAD_JACK_INS_DEB_20MS
;
471 return DA7219_AAD_JACK_INS_DEB_50MS
;
473 return DA7219_AAD_JACK_INS_DEB_100MS
;
475 return DA7219_AAD_JACK_INS_DEB_200MS
;
477 return DA7219_AAD_JACK_INS_DEB_500MS
;
479 return DA7219_AAD_JACK_INS_DEB_1S
;
481 dev_warn(codec
->dev
, "Invalid jack insert debounce");
482 return DA7219_AAD_JACK_INS_DEB_20MS
;
486 static enum da7219_aad_jack_det_rate
487 da7219_aad_fw_jack_det_rate(struct snd_soc_codec
*codec
, const char *str
)
489 if (!strcmp(str
, "32ms_64ms")) {
490 return DA7219_AAD_JACK_DET_RATE_32_64MS
;
491 } else if (!strcmp(str
, "64ms_128ms")) {
492 return DA7219_AAD_JACK_DET_RATE_64_128MS
;
493 } else if (!strcmp(str
, "128ms_256ms")) {
494 return DA7219_AAD_JACK_DET_RATE_128_256MS
;
495 } else if (!strcmp(str
, "256ms_512ms")) {
496 return DA7219_AAD_JACK_DET_RATE_256_512MS
;
498 dev_warn(codec
->dev
, "Invalid jack detect rate");
499 return DA7219_AAD_JACK_DET_RATE_256_512MS
;
503 static enum da7219_aad_jack_rem_deb
504 da7219_aad_fw_jack_rem_deb(struct snd_soc_codec
*codec
, u32 val
)
508 return DA7219_AAD_JACK_REM_DEB_1MS
;
510 return DA7219_AAD_JACK_REM_DEB_5MS
;
512 return DA7219_AAD_JACK_REM_DEB_10MS
;
514 return DA7219_AAD_JACK_REM_DEB_20MS
;
516 dev_warn(codec
->dev
, "Invalid jack removal debounce");
517 return DA7219_AAD_JACK_REM_DEB_1MS
;
521 static enum da7219_aad_btn_avg
522 da7219_aad_fw_btn_avg(struct snd_soc_codec
*codec
, u32 val
)
526 return DA7219_AAD_BTN_AVG_1
;
528 return DA7219_AAD_BTN_AVG_2
;
530 return DA7219_AAD_BTN_AVG_4
;
532 return DA7219_AAD_BTN_AVG_8
;
534 dev_warn(codec
->dev
, "Invalid button average value");
535 return DA7219_AAD_BTN_AVG_2
;
539 static enum da7219_aad_adc_1bit_rpt
540 da7219_aad_fw_adc_1bit_rpt(struct snd_soc_codec
*codec
, u32 val
)
544 return DA7219_AAD_ADC_1BIT_RPT_1
;
546 return DA7219_AAD_ADC_1BIT_RPT_2
;
548 return DA7219_AAD_ADC_1BIT_RPT_4
;
550 return DA7219_AAD_ADC_1BIT_RPT_8
;
552 dev_warn(codec
->dev
, "Invalid ADC 1-bit repeat value");
553 return DA7219_AAD_ADC_1BIT_RPT_1
;
557 static struct da7219_aad_pdata
*da7219_aad_fw_to_pdata(struct snd_soc_codec
*codec
)
559 struct device
*dev
= codec
->dev
;
560 struct i2c_client
*i2c
= to_i2c_client(dev
);
561 struct fwnode_handle
*aad_np
;
562 struct da7219_aad_pdata
*aad_pdata
;
566 aad_np
= device_get_named_child_node(dev
, "da7219_aad");
570 aad_pdata
= devm_kzalloc(codec
->dev
, sizeof(*aad_pdata
), GFP_KERNEL
);
574 aad_pdata
->irq
= i2c
->irq
;
576 if (fwnode_property_read_u32(aad_np
, "dlg,micbias-pulse-lvl",
578 aad_pdata
->micbias_pulse_lvl
=
579 da7219_aad_fw_micbias_pulse_lvl(codec
, fw_val32
);
581 aad_pdata
->micbias_pulse_lvl
= DA7219_AAD_MICBIAS_PULSE_LVL_OFF
;
583 if (fwnode_property_read_u32(aad_np
, "dlg,micbias-pulse-time",
585 aad_pdata
->micbias_pulse_time
= fw_val32
;
587 if (fwnode_property_read_u32(aad_np
, "dlg,btn-cfg", &fw_val32
) >= 0)
588 aad_pdata
->btn_cfg
= da7219_aad_fw_btn_cfg(codec
, fw_val32
);
590 aad_pdata
->btn_cfg
= DA7219_AAD_BTN_CFG_10MS
;
592 if (fwnode_property_read_u32(aad_np
, "dlg,mic-det-thr", &fw_val32
) >= 0)
593 aad_pdata
->mic_det_thr
=
594 da7219_aad_fw_mic_det_thr(codec
, fw_val32
);
596 aad_pdata
->mic_det_thr
= DA7219_AAD_MIC_DET_THR_500_OHMS
;
598 if (fwnode_property_read_u32(aad_np
, "dlg,jack-ins-deb", &fw_val32
) >= 0)
599 aad_pdata
->jack_ins_deb
=
600 da7219_aad_fw_jack_ins_deb(codec
, fw_val32
);
602 aad_pdata
->jack_ins_deb
= DA7219_AAD_JACK_INS_DEB_20MS
;
604 if (!fwnode_property_read_string(aad_np
, "dlg,jack-det-rate", &fw_str
))
605 aad_pdata
->jack_det_rate
=
606 da7219_aad_fw_jack_det_rate(codec
, fw_str
);
608 aad_pdata
->jack_det_rate
= DA7219_AAD_JACK_DET_RATE_256_512MS
;
610 if (fwnode_property_read_u32(aad_np
, "dlg,jack-rem-deb", &fw_val32
) >= 0)
611 aad_pdata
->jack_rem_deb
=
612 da7219_aad_fw_jack_rem_deb(codec
, fw_val32
);
614 aad_pdata
->jack_rem_deb
= DA7219_AAD_JACK_REM_DEB_1MS
;
616 if (fwnode_property_read_u32(aad_np
, "dlg,a-d-btn-thr", &fw_val32
) >= 0)
617 aad_pdata
->a_d_btn_thr
= (u8
) fw_val32
;
619 aad_pdata
->a_d_btn_thr
= 0xA;
621 if (fwnode_property_read_u32(aad_np
, "dlg,d-b-btn-thr", &fw_val32
) >= 0)
622 aad_pdata
->d_b_btn_thr
= (u8
) fw_val32
;
624 aad_pdata
->d_b_btn_thr
= 0x16;
626 if (fwnode_property_read_u32(aad_np
, "dlg,b-c-btn-thr", &fw_val32
) >= 0)
627 aad_pdata
->b_c_btn_thr
= (u8
) fw_val32
;
629 aad_pdata
->b_c_btn_thr
= 0x21;
631 if (fwnode_property_read_u32(aad_np
, "dlg,c-mic-btn-thr", &fw_val32
) >= 0)
632 aad_pdata
->c_mic_btn_thr
= (u8
) fw_val32
;
634 aad_pdata
->c_mic_btn_thr
= 0x3E;
636 if (fwnode_property_read_u32(aad_np
, "dlg,btn-avg", &fw_val32
) >= 0)
637 aad_pdata
->btn_avg
= da7219_aad_fw_btn_avg(codec
, fw_val32
);
639 aad_pdata
->btn_avg
= DA7219_AAD_BTN_AVG_2
;
641 if (fwnode_property_read_u32(aad_np
, "dlg,adc-1bit-rpt", &fw_val32
) >= 0)
642 aad_pdata
->adc_1bit_rpt
=
643 da7219_aad_fw_adc_1bit_rpt(codec
, fw_val32
);
645 aad_pdata
->adc_1bit_rpt
= DA7219_AAD_ADC_1BIT_RPT_1
;
650 static void da7219_aad_handle_pdata(struct snd_soc_codec
*codec
)
652 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
653 struct da7219_aad_priv
*da7219_aad
= da7219
->aad
;
654 struct da7219_pdata
*pdata
= da7219
->pdata
;
656 if ((pdata
) && (pdata
->aad_pdata
)) {
657 struct da7219_aad_pdata
*aad_pdata
= pdata
->aad_pdata
;
660 da7219_aad
->irq
= aad_pdata
->irq
;
662 switch (aad_pdata
->micbias_pulse_lvl
) {
663 case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V
:
664 case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V
:
665 da7219_aad
->micbias_pulse_lvl
=
666 (aad_pdata
->micbias_pulse_lvl
<<
667 DA7219_MICBIAS1_LEVEL_SHIFT
);
673 da7219_aad
->micbias_pulse_time
= aad_pdata
->micbias_pulse_time
;
675 switch (aad_pdata
->btn_cfg
) {
676 case DA7219_AAD_BTN_CFG_2MS
:
677 case DA7219_AAD_BTN_CFG_5MS
:
678 case DA7219_AAD_BTN_CFG_10MS
:
679 case DA7219_AAD_BTN_CFG_50MS
:
680 case DA7219_AAD_BTN_CFG_100MS
:
681 case DA7219_AAD_BTN_CFG_200MS
:
682 case DA7219_AAD_BTN_CFG_500MS
:
683 da7219_aad
->btn_cfg
= (aad_pdata
->btn_cfg
<<
684 DA7219_BUTTON_CONFIG_SHIFT
);
689 switch (aad_pdata
->mic_det_thr
) {
690 case DA7219_AAD_MIC_DET_THR_200_OHMS
:
691 case DA7219_AAD_MIC_DET_THR_500_OHMS
:
692 case DA7219_AAD_MIC_DET_THR_750_OHMS
:
693 case DA7219_AAD_MIC_DET_THR_1000_OHMS
:
694 cfg
|= (aad_pdata
->mic_det_thr
<<
695 DA7219_MIC_DET_THRESH_SHIFT
);
696 mask
|= DA7219_MIC_DET_THRESH_MASK
;
698 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_1
, mask
, cfg
);
702 switch (aad_pdata
->jack_ins_deb
) {
703 case DA7219_AAD_JACK_INS_DEB_5MS
:
704 case DA7219_AAD_JACK_INS_DEB_10MS
:
705 case DA7219_AAD_JACK_INS_DEB_20MS
:
706 case DA7219_AAD_JACK_INS_DEB_50MS
:
707 case DA7219_AAD_JACK_INS_DEB_100MS
:
708 case DA7219_AAD_JACK_INS_DEB_200MS
:
709 case DA7219_AAD_JACK_INS_DEB_500MS
:
710 case DA7219_AAD_JACK_INS_DEB_1S
:
711 cfg
|= (aad_pdata
->jack_ins_deb
<<
712 DA7219_JACKDET_DEBOUNCE_SHIFT
);
713 mask
|= DA7219_JACKDET_DEBOUNCE_MASK
;
715 switch (aad_pdata
->jack_det_rate
) {
716 case DA7219_AAD_JACK_DET_RATE_32_64MS
:
717 case DA7219_AAD_JACK_DET_RATE_64_128MS
:
718 case DA7219_AAD_JACK_DET_RATE_128_256MS
:
719 case DA7219_AAD_JACK_DET_RATE_256_512MS
:
720 cfg
|= (aad_pdata
->jack_det_rate
<<
721 DA7219_JACK_DETECT_RATE_SHIFT
);
722 mask
|= DA7219_JACK_DETECT_RATE_MASK
;
724 switch (aad_pdata
->jack_rem_deb
) {
725 case DA7219_AAD_JACK_REM_DEB_1MS
:
726 case DA7219_AAD_JACK_REM_DEB_5MS
:
727 case DA7219_AAD_JACK_REM_DEB_10MS
:
728 case DA7219_AAD_JACK_REM_DEB_20MS
:
729 cfg
|= (aad_pdata
->jack_rem_deb
<<
730 DA7219_JACKDET_REM_DEB_SHIFT
);
731 mask
|= DA7219_JACKDET_REM_DEB_MASK
;
733 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_2
, mask
, cfg
);
735 snd_soc_write(codec
, DA7219_ACCDET_CONFIG_3
,
736 aad_pdata
->a_d_btn_thr
);
737 snd_soc_write(codec
, DA7219_ACCDET_CONFIG_4
,
738 aad_pdata
->d_b_btn_thr
);
739 snd_soc_write(codec
, DA7219_ACCDET_CONFIG_5
,
740 aad_pdata
->b_c_btn_thr
);
741 snd_soc_write(codec
, DA7219_ACCDET_CONFIG_6
,
742 aad_pdata
->c_mic_btn_thr
);
746 switch (aad_pdata
->btn_avg
) {
747 case DA7219_AAD_BTN_AVG_1
:
748 case DA7219_AAD_BTN_AVG_2
:
749 case DA7219_AAD_BTN_AVG_4
:
750 case DA7219_AAD_BTN_AVG_8
:
751 cfg
|= (aad_pdata
->btn_avg
<<
752 DA7219_BUTTON_AVERAGE_SHIFT
);
753 mask
|= DA7219_BUTTON_AVERAGE_MASK
;
755 switch (aad_pdata
->adc_1bit_rpt
) {
756 case DA7219_AAD_ADC_1BIT_RPT_1
:
757 case DA7219_AAD_ADC_1BIT_RPT_2
:
758 case DA7219_AAD_ADC_1BIT_RPT_4
:
759 case DA7219_AAD_ADC_1BIT_RPT_8
:
760 cfg
|= (aad_pdata
->adc_1bit_rpt
<<
761 DA7219_ADC_1_BIT_REPEAT_SHIFT
);
762 mask
|= DA7219_ADC_1_BIT_REPEAT_MASK
;
764 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_7
, mask
, cfg
);
773 int da7219_aad_init(struct snd_soc_codec
*codec
)
775 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
776 struct da7219_aad_priv
*da7219_aad
;
777 u8 mask
[DA7219_AAD_IRQ_REG_MAX
];
780 da7219_aad
= devm_kzalloc(codec
->dev
, sizeof(*da7219_aad
), GFP_KERNEL
);
784 da7219
->aad
= da7219_aad
;
785 da7219_aad
->codec
= codec
;
787 /* Handle any DT/ACPI/platform data */
788 if (da7219
->pdata
&& !da7219
->pdata
->aad_pdata
)
789 da7219
->pdata
->aad_pdata
= da7219_aad_fw_to_pdata(codec
);
791 da7219_aad_handle_pdata(codec
);
793 /* Disable button detection */
794 snd_soc_update_bits(codec
, DA7219_ACCDET_CONFIG_1
,
795 DA7219_BUTTON_CONFIG_MASK
, 0);
797 INIT_WORK(&da7219_aad
->btn_det_work
, da7219_aad_btn_det_work
);
798 INIT_WORK(&da7219_aad
->hptest_work
, da7219_aad_hptest_work
);
800 ret
= request_threaded_irq(da7219_aad
->irq
, NULL
,
801 da7219_aad_irq_thread
,
802 IRQF_TRIGGER_LOW
| IRQF_ONESHOT
,
803 "da7219-aad", da7219_aad
);
805 dev_err(codec
->dev
, "Failed to request IRQ: %d\n", ret
);
809 /* Unmask AAD IRQs */
810 memset(mask
, 0, DA7219_AAD_IRQ_REG_MAX
);
811 regmap_bulk_write(da7219
->regmap
, DA7219_ACCDET_IRQ_MASK_A
,
812 &mask
, DA7219_AAD_IRQ_REG_MAX
);
816 EXPORT_SYMBOL_GPL(da7219_aad_init
);
818 void da7219_aad_exit(struct snd_soc_codec
*codec
)
820 struct da7219_priv
*da7219
= snd_soc_codec_get_drvdata(codec
);
821 struct da7219_aad_priv
*da7219_aad
= da7219
->aad
;
822 u8 mask
[DA7219_AAD_IRQ_REG_MAX
];
824 /* Mask off AAD IRQs */
825 memset(mask
, DA7219_BYTE_MASK
, DA7219_AAD_IRQ_REG_MAX
);
826 regmap_bulk_write(da7219
->regmap
, DA7219_ACCDET_IRQ_MASK_A
,
827 mask
, DA7219_AAD_IRQ_REG_MAX
);
829 free_irq(da7219_aad
->irq
, da7219_aad
);
831 cancel_work_sync(&da7219_aad
->btn_det_work
);
832 cancel_work_sync(&da7219_aad
->hptest_work
);
834 EXPORT_SYMBOL_GPL(da7219_aad_exit
);
836 MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
837 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
838 MODULE_LICENSE("GPL");