Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add support for jack detection to codec present in

Merge series from Ondřej Jirman <megi@xff.cz>:

This series adds support for jack detection to this codec. I used
and tested this on Pinephone. It works quite nicely. I tested it
against Android headset mic button resistor specification.

The patches are a rewritten and debugged version of the original
ones from Arnaud Ferraris and Samuel Holland, improved to better
handle headset button presses and with more robust plug-in/out
event debouncing, and to use set_jack API instead of sniffing
the sound card widget names, to detect the type of jack connector.

+399 -20
+61 -12
sound/soc/sunxi/sun50i-codec-analog.c
··· 115 115 #define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e 116 116 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7 117 117 118 + #define SUN50I_ADDA_MDET_CTRL 0x1c 119 + #define SUN50I_ADDA_MDET_CTRL_SELDETADC_FS 4 120 + #define SUN50I_ADDA_MDET_CTRL_SELDETADC_DB 2 121 + #define SUN50I_ADDA_MDET_CTRL_SELDETADC_BF 0 122 + 118 123 #define SUN50I_ADDA_JACK_MIC_CTRL 0x1d 124 + #define SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN 7 119 125 #define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN 6 120 126 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5 127 + #define SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN 4 121 128 122 129 /* mixer controls */ 123 130 static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { ··· 303 296 SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0), 304 297 }; 305 298 299 + static int sun50i_codec_hbias_event(struct snd_soc_dapm_widget *w, 300 + struct snd_kcontrol *kcontrol, int event) 301 + { 302 + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 303 + u32 value = !!SND_SOC_DAPM_EVENT_ON(event); 304 + 305 + regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, 306 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN), 307 + value << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN); 308 + 309 + return 0; 310 + } 311 + 306 312 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { 307 313 /* DAC */ 308 314 SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, ··· 387 367 /* Microphone Bias */ 388 368 SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL, 389 369 SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN, 390 - 0, NULL, 0), 370 + 0, sun50i_codec_hbias_event, 371 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 391 372 392 373 /* Mic input path */ 393 374 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL, ··· 492 471 { "EARPIECE", NULL, "Earpiece Amp" }, 493 472 }; 494 473 495 - static int sun50i_a64_codec_suspend(struct snd_soc_component *component) 474 + static int sun50i_a64_codec_set_bias_level(struct snd_soc_component *component, 475 + enum snd_soc_bias_level level) 496 476 { 497 - return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, 498 - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 499 - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); 500 - } 477 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 478 + int hbias; 501 479 502 - static int sun50i_a64_codec_resume(struct snd_soc_component *component) 503 - { 504 - return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, 505 - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0); 480 + switch (level) { 481 + case SND_SOC_BIAS_OFF: 482 + regmap_clear_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, 483 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | 484 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN)); 485 + 486 + regmap_set_bits(component->regmap, SUN50I_ADDA_HP_CTRL, 487 + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); 488 + break; 489 + case SND_SOC_BIAS_STANDBY: 490 + regmap_clear_bits(component->regmap, SUN50I_ADDA_HP_CTRL, 491 + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); 492 + 493 + hbias = snd_soc_dapm_get_pin_status(dapm, "HBIAS"); 494 + regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, 495 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | 496 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN), 497 + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | 498 + hbias << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN); 499 + break; 500 + default: 501 + break; 502 + } 503 + 504 + return 0; 506 505 } 507 506 508 507 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { ··· 532 491 .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), 533 492 .dapm_routes = sun50i_a64_codec_routes, 534 493 .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), 535 - .suspend = sun50i_a64_codec_suspend, 536 - .resume = sun50i_a64_codec_resume, 494 + .set_bias_level = sun50i_a64_codec_set_bias_level, 495 + .idle_bias_on = true, 496 + .suspend_bias_off = true, 537 497 }; 538 498 539 499 static const struct of_device_id sun50i_codec_analog_of_match[] = { ··· 568 526 regmap_update_bits(regmap, SUN50I_ADDA_JACK_MIC_CTRL, 569 527 BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN), 570 528 enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN); 529 + 530 + /* Select sample interval of the ADC sample to 16ms */ 531 + regmap_update_bits(regmap, SUN50I_ADDA_MDET_CTRL, 532 + 0x7 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS | 533 + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF, 534 + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS | 535 + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF); 571 536 572 537 return devm_snd_soc_register_component(&pdev->dev, 573 538 &sun50i_codec_analog_cmpnt_drv,
+338 -8
sound/soc/sunxi/sun8i-codec.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/delay.h> 14 14 #include <linux/clk.h> 15 + #include <linux/input.h> 15 16 #include <linux/io.h> 17 + #include <linux/irq.h> 18 + #include <linux/mutex.h> 16 19 #include <linux/of.h> 17 20 #include <linux/pm_runtime.h> 18 21 #include <linux/regmap.h> 19 22 #include <linux/log2.h> 20 23 24 + #include <sound/jack.h> 21 25 #include <sound/pcm_params.h> 22 26 #include <sound/soc.h> 23 27 #include <sound/soc-dapm.h> ··· 122 118 #define SUN8I_ADC_VOL_CTRL 0x104 123 119 #define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8 124 120 #define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0 121 + #define SUN8I_HMIC_CTRL1 0x110 122 + #define SUN8I_HMIC_CTRL1_HMIC_M 12 123 + #define SUN8I_HMIC_CTRL1_HMIC_N 8 124 + #define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB 5 125 + #define SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN 4 126 + #define SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN 3 127 + #define SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN 0 128 + #define SUN8I_HMIC_CTRL2 0x114 129 + #define SUN8I_HMIC_CTRL2_HMIC_SAMPLE 14 130 + #define SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD 8 131 + #define SUN8I_HMIC_CTRL2_HMIC_SF 6 132 + #define SUN8I_HMIC_STS 0x118 133 + #define SUN8I_HMIC_STS_MDATA_DISCARD 13 134 + #define SUN8I_HMIC_STS_HMIC_DATA 8 135 + #define SUN8I_HMIC_STS_JACK_OUT_IRQ_ST 4 136 + #define SUN8I_HMIC_STS_JACK_IN_IRQ_ST 3 137 + #define SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST 0 125 138 #define SUN8I_DAC_DIG_CTRL 0x120 126 139 #define SUN8I_DAC_DIG_CTRL_ENDA 15 127 140 #define SUN8I_DAC_VOL_CTRL 0x124 ··· 164 143 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4) 165 144 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2) 166 145 #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK GENMASK(1, 0) 146 + #define SUN8I_HMIC_CTRL1_HMIC_M_MASK GENMASK(15, 12) 147 + #define SUN8I_HMIC_CTRL1_HMIC_N_MASK GENMASK(11, 8) 148 + #define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB_MASK GENMASK(6, 5) 149 + #define SUN8I_HMIC_CTRL2_HMIC_SAMPLE_MASK GENMASK(15, 14) 150 + #define SUN8I_HMIC_CTRL2_HMIC_SF_MASK GENMASK(7, 6) 151 + #define SUN8I_HMIC_STS_HMIC_DATA_MASK GENMASK(12, 8) 152 + 153 + #define SUN8I_CODEC_BUTTONS (SND_JACK_BTN_0|\ 154 + SND_JACK_BTN_1|\ 155 + SND_JACK_BTN_2|\ 156 + SND_JACK_BTN_3) 167 157 168 158 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 169 159 ··· 209 177 }; 210 178 211 179 struct sun8i_codec_quirks { 212 - bool legacy_widgets : 1; 213 - bool lrck_inversion : 1; 180 + bool bus_clock : 1; 181 + bool jack_detection : 1; 182 + bool legacy_widgets : 1; 183 + bool lrck_inversion : 1; 184 + }; 185 + 186 + enum { 187 + SUN8I_JACK_STATUS_DISCONNECTED, 188 + SUN8I_JACK_STATUS_WAITING_HBIAS, 189 + SUN8I_JACK_STATUS_CONNECTED, 214 190 }; 215 191 216 192 struct sun8i_codec { 193 + struct snd_soc_component *component; 217 194 struct regmap *regmap; 195 + struct clk *clk_bus; 218 196 struct clk *clk_module; 219 197 const struct sun8i_codec_quirks *quirks; 220 198 struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS]; 199 + struct snd_soc_jack *jack; 200 + struct delayed_work jack_work; 201 + int jack_irq; 202 + int jack_status; 203 + int jack_last_sample; 204 + ktime_t jack_hbias_ready; 205 + struct mutex jack_mutex; 206 + int last_hmic_irq; 221 207 unsigned int sysclk_rate; 222 208 int sysclk_refcnt; 223 209 }; ··· 246 196 { 247 197 struct sun8i_codec *scodec = dev_get_drvdata(dev); 248 198 int ret; 199 + 200 + if (scodec->clk_bus) { 201 + ret = clk_prepare_enable(scodec->clk_bus); 202 + if (ret) { 203 + dev_err(dev, "Failed to enable the bus clock\n"); 204 + return ret; 205 + } 206 + } 249 207 250 208 regcache_cache_only(scodec->regmap, false); 251 209 ··· 272 214 273 215 regcache_cache_only(scodec->regmap, true); 274 216 regcache_mark_dirty(scodec->regmap); 217 + 218 + if (scodec->clk_bus) 219 + clk_disable_unprepare(scodec->clk_bus); 275 220 276 221 return 0; 277 222 } ··· 1293 1232 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); 1294 1233 int ret; 1295 1234 1235 + scodec->component = component; 1236 + 1296 1237 /* Add widgets for backward compatibility with old device trees. */ 1297 1238 if (scodec->quirks->legacy_widgets) { 1298 1239 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, ··· 1331 1268 return 0; 1332 1269 } 1333 1270 1271 + static void sun8i_codec_set_hmic_bias(struct sun8i_codec *scodec, bool enable) 1272 + { 1273 + struct snd_soc_dapm_context *dapm = &scodec->component->card->dapm; 1274 + int irq_mask = BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN); 1275 + 1276 + if (enable) 1277 + snd_soc_dapm_force_enable_pin(dapm, "HBIAS"); 1278 + else 1279 + snd_soc_dapm_disable_pin(dapm, "HBIAS"); 1280 + 1281 + snd_soc_dapm_sync(dapm); 1282 + 1283 + regmap_update_bits(scodec->regmap, SUN8I_HMIC_CTRL1, 1284 + irq_mask, enable ? irq_mask : 0); 1285 + } 1286 + 1287 + static void sun8i_codec_jack_work(struct work_struct *work) 1288 + { 1289 + struct sun8i_codec *scodec = container_of(work, struct sun8i_codec, 1290 + jack_work.work); 1291 + unsigned int mdata; 1292 + int type_mask = scodec->jack->jack->type; 1293 + int type; 1294 + 1295 + guard(mutex)(&scodec->jack_mutex); 1296 + 1297 + if (scodec->jack_status == SUN8I_JACK_STATUS_DISCONNECTED) { 1298 + if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_IN_IRQ_ST) 1299 + return; 1300 + 1301 + scodec->jack_last_sample = -1; 1302 + 1303 + if (type_mask & SND_JACK_MICROPHONE) { 1304 + /* 1305 + * If we were in disconnected state, we enable HBIAS and 1306 + * wait 600ms before reading initial HDATA value. 1307 + */ 1308 + scodec->jack_hbias_ready = ktime_add_ms(ktime_get(), 600); 1309 + sun8i_codec_set_hmic_bias(scodec, true); 1310 + queue_delayed_work(system_power_efficient_wq, 1311 + &scodec->jack_work, 1312 + msecs_to_jiffies(610)); 1313 + scodec->jack_status = SUN8I_JACK_STATUS_WAITING_HBIAS; 1314 + } else { 1315 + snd_soc_jack_report(scodec->jack, SND_JACK_HEADPHONE, 1316 + type_mask); 1317 + scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED; 1318 + } 1319 + } else if (scodec->jack_status == SUN8I_JACK_STATUS_WAITING_HBIAS) { 1320 + /* 1321 + * If we're waiting for HBIAS to stabilize, and we get plug-out 1322 + * interrupt and nothing more for > 100ms, just cancel the 1323 + * initialization. 1324 + */ 1325 + if (scodec->last_hmic_irq == SUN8I_HMIC_STS_JACK_OUT_IRQ_ST) { 1326 + scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED; 1327 + sun8i_codec_set_hmic_bias(scodec, false); 1328 + return; 1329 + } 1330 + 1331 + /* 1332 + * If we're not done waiting for HBIAS to stabilize, wait more. 1333 + */ 1334 + if (!ktime_after(ktime_get(), scodec->jack_hbias_ready)) { 1335 + s64 msecs = ktime_ms_delta(scodec->jack_hbias_ready, 1336 + ktime_get()); 1337 + 1338 + queue_delayed_work(system_power_efficient_wq, 1339 + &scodec->jack_work, 1340 + msecs_to_jiffies(msecs + 10)); 1341 + return; 1342 + } 1343 + 1344 + /* 1345 + * Everything is stabilized, determine jack type and report it. 1346 + */ 1347 + regmap_read(scodec->regmap, SUN8I_HMIC_STS, &mdata); 1348 + mdata &= SUN8I_HMIC_STS_HMIC_DATA_MASK; 1349 + mdata >>= SUN8I_HMIC_STS_HMIC_DATA; 1350 + 1351 + regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0); 1352 + 1353 + type = mdata < 16 ? SND_JACK_HEADPHONE : SND_JACK_HEADSET; 1354 + if (type == SND_JACK_HEADPHONE) 1355 + sun8i_codec_set_hmic_bias(scodec, false); 1356 + 1357 + snd_soc_jack_report(scodec->jack, type, type_mask); 1358 + scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED; 1359 + } else if (scodec->jack_status == SUN8I_JACK_STATUS_CONNECTED) { 1360 + if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_OUT_IRQ_ST) 1361 + return; 1362 + 1363 + scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED; 1364 + if (type_mask & SND_JACK_MICROPHONE) 1365 + sun8i_codec_set_hmic_bias(scodec, false); 1366 + 1367 + snd_soc_jack_report(scodec->jack, 0, type_mask); 1368 + } 1369 + } 1370 + 1371 + static irqreturn_t sun8i_codec_jack_irq(int irq, void *dev_id) 1372 + { 1373 + struct sun8i_codec *scodec = dev_id; 1374 + int type = SND_JACK_HEADSET; 1375 + unsigned int status, value; 1376 + 1377 + guard(mutex)(&scodec->jack_mutex); 1378 + 1379 + regmap_read(scodec->regmap, SUN8I_HMIC_STS, &status); 1380 + regmap_write(scodec->regmap, SUN8I_HMIC_STS, status); 1381 + 1382 + /* 1383 + * De-bounce in/out interrupts via a delayed work re-scheduling to 1384 + * 100ms after each interrupt.. 1385 + */ 1386 + if (status & BIT(SUN8I_HMIC_STS_JACK_OUT_IRQ_ST)) { 1387 + /* 1388 + * Out interrupt has priority over in interrupt so that if 1389 + * we get both, we assume the disconnected state, which is 1390 + * safer. 1391 + */ 1392 + scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_OUT_IRQ_ST; 1393 + mod_delayed_work(system_power_efficient_wq, &scodec->jack_work, 1394 + msecs_to_jiffies(100)); 1395 + } else if (status & BIT(SUN8I_HMIC_STS_JACK_IN_IRQ_ST)) { 1396 + scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_IN_IRQ_ST; 1397 + mod_delayed_work(system_power_efficient_wq, &scodec->jack_work, 1398 + msecs_to_jiffies(100)); 1399 + } else if (status & BIT(SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST)) { 1400 + /* 1401 + * Ignore data interrupts until jack status turns to connected 1402 + * state, which is after HMIC enable stabilization is completed. 1403 + * Until then tha data are bogus. 1404 + */ 1405 + if (scodec->jack_status != SUN8I_JACK_STATUS_CONNECTED) 1406 + return IRQ_HANDLED; 1407 + 1408 + value = (status & SUN8I_HMIC_STS_HMIC_DATA_MASK) >> 1409 + SUN8I_HMIC_STS_HMIC_DATA; 1410 + 1411 + /* 1412 + * Assumes 60 mV per ADC LSB increment, 2V bias voltage, 2.2kOhm 1413 + * bias resistor. 1414 + */ 1415 + if (value == 0) 1416 + type |= SND_JACK_BTN_0; 1417 + else if (value == 1) 1418 + type |= SND_JACK_BTN_3; 1419 + else if (value <= 3) 1420 + type |= SND_JACK_BTN_1; 1421 + else if (value <= 8) 1422 + type |= SND_JACK_BTN_2; 1423 + 1424 + /* 1425 + * De-bounce. Only report button after two consecutive A/D 1426 + * samples are identical. 1427 + */ 1428 + if (scodec->jack_last_sample >= 0 && 1429 + scodec->jack_last_sample == value) 1430 + snd_soc_jack_report(scodec->jack, type, 1431 + scodec->jack->jack->type); 1432 + 1433 + scodec->jack_last_sample = value; 1434 + } 1435 + 1436 + return IRQ_HANDLED; 1437 + } 1438 + 1439 + static int sun8i_codec_enable_jack_detect(struct snd_soc_component *component, 1440 + struct snd_soc_jack *jack, void *data) 1441 + { 1442 + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); 1443 + struct platform_device *pdev = to_platform_device(component->dev); 1444 + int ret; 1445 + 1446 + if (!scodec->quirks->jack_detection) 1447 + return 0; 1448 + 1449 + scodec->jack = jack; 1450 + 1451 + scodec->jack_irq = platform_get_irq(pdev, 0); 1452 + if (scodec->jack_irq < 0) 1453 + return scodec->jack_irq; 1454 + 1455 + /* Reserved value required for jack IRQs to trigger. */ 1456 + regmap_write(scodec->regmap, SUN8I_HMIC_CTRL1, 1457 + 0xf << SUN8I_HMIC_CTRL1_HMIC_N | 1458 + 0x0 << SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB | 1459 + 0x4 << SUN8I_HMIC_CTRL1_HMIC_M); 1460 + 1461 + /* Sample the ADC at 128 Hz; bypass smooth filter. */ 1462 + regmap_write(scodec->regmap, SUN8I_HMIC_CTRL2, 1463 + 0x0 << SUN8I_HMIC_CTRL2_HMIC_SAMPLE | 1464 + 0x17 << SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD | 1465 + 0x0 << SUN8I_HMIC_CTRL2_HMIC_SF); 1466 + 1467 + /* Do not discard any MDATA, enable user written MDATA threshold. */ 1468 + regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0); 1469 + 1470 + regmap_set_bits(scodec->regmap, SUN8I_HMIC_CTRL1, 1471 + BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) | 1472 + BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN)); 1473 + 1474 + ret = devm_request_threaded_irq(&pdev->dev, scodec->jack_irq, 1475 + NULL, sun8i_codec_jack_irq, 1476 + IRQF_ONESHOT, 1477 + dev_name(&pdev->dev), scodec); 1478 + if (ret) 1479 + return ret; 1480 + 1481 + return 0; 1482 + } 1483 + 1484 + static void sun8i_codec_disable_jack_detect(struct snd_soc_component *component) 1485 + { 1486 + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); 1487 + 1488 + if (!scodec->quirks->jack_detection) 1489 + return; 1490 + 1491 + devm_free_irq(component->dev, scodec->jack_irq, scodec); 1492 + 1493 + cancel_delayed_work_sync(&scodec->jack_work); 1494 + 1495 + regmap_clear_bits(scodec->regmap, SUN8I_HMIC_CTRL1, 1496 + BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) | 1497 + BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN) | 1498 + BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN)); 1499 + 1500 + scodec->jack = NULL; 1501 + } 1502 + 1503 + static int sun8i_codec_component_set_jack(struct snd_soc_component *component, 1504 + struct snd_soc_jack *jack, void *data) 1505 + { 1506 + int ret = 0; 1507 + 1508 + if (jack) 1509 + ret = sun8i_codec_enable_jack_detect(component, jack, data); 1510 + else 1511 + sun8i_codec_disable_jack_detect(component); 1512 + 1513 + return ret; 1514 + } 1515 + 1334 1516 static const struct snd_soc_component_driver sun8i_soc_component = { 1335 1517 .controls = sun8i_codec_controls, 1336 1518 .num_controls = ARRAY_SIZE(sun8i_codec_controls), ··· 1583 1275 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), 1584 1276 .dapm_routes = sun8i_codec_dapm_routes, 1585 1277 .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), 1278 + .set_jack = sun8i_codec_component_set_jack, 1586 1279 .probe = sun8i_codec_component_probe, 1587 1280 .idle_bias_on = 1, 1281 + .suspend_bias_off = 1, 1588 1282 .endianness = 1, 1589 1283 }; 1284 + 1285 + static bool sun8i_codec_volatile_reg(struct device *dev, unsigned int reg) 1286 + { 1287 + return reg == SUN8I_HMIC_STS; 1288 + } 1590 1289 1591 1290 static const struct regmap_config sun8i_codec_regmap_config = { 1592 1291 .reg_bits = 32, 1593 1292 .reg_stride = 4, 1594 1293 .val_bits = 32, 1294 + .volatile_reg = sun8i_codec_volatile_reg, 1595 1295 .max_register = SUN8I_DAC_MXR_SRC, 1596 1296 1597 1297 .cache_type = REGCACHE_FLAT, ··· 1615 1299 if (!scodec) 1616 1300 return -ENOMEM; 1617 1301 1302 + scodec->quirks = of_device_get_match_data(&pdev->dev); 1303 + INIT_DELAYED_WORK(&scodec->jack_work, sun8i_codec_jack_work); 1304 + mutex_init(&scodec->jack_mutex); 1305 + 1306 + platform_set_drvdata(pdev, scodec); 1307 + 1308 + if (scodec->quirks->bus_clock) { 1309 + scodec->clk_bus = devm_clk_get(&pdev->dev, "bus"); 1310 + if (IS_ERR(scodec->clk_bus)) { 1311 + dev_err(&pdev->dev, "Failed to get the bus clock\n"); 1312 + return PTR_ERR(scodec->clk_bus); 1313 + } 1314 + } 1315 + 1618 1316 scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); 1619 1317 if (IS_ERR(scodec->clk_module)) { 1620 1318 dev_err(&pdev->dev, "Failed to get the module clock\n"); ··· 1641 1311 return PTR_ERR(base); 1642 1312 } 1643 1313 1644 - scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, 1645 - &sun8i_codec_regmap_config); 1314 + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, 1315 + &sun8i_codec_regmap_config); 1646 1316 if (IS_ERR(scodec->regmap)) { 1647 1317 dev_err(&pdev->dev, "Failed to create our regmap\n"); 1648 1318 return PTR_ERR(scodec->regmap); 1649 1319 } 1650 1320 1651 - scodec->quirks = of_device_get_match_data(&pdev->dev); 1652 - 1653 - platform_set_drvdata(pdev, scodec); 1654 - 1321 + regcache_cache_only(scodec->regmap, true); 1655 1322 pm_runtime_enable(&pdev->dev); 1656 1323 if (!pm_runtime_enabled(&pdev->dev)) { 1657 1324 ret = sun8i_codec_runtime_resume(&pdev->dev); ··· 1684 1357 } 1685 1358 1686 1359 static const struct sun8i_codec_quirks sun8i_a33_quirks = { 1360 + .bus_clock = true, 1687 1361 .legacy_widgets = true, 1688 1362 .lrck_inversion = true, 1689 1363 }; 1690 1364 1691 1365 static const struct sun8i_codec_quirks sun50i_a64_quirks = { 1366 + .bus_clock = true, 1367 + .jack_detection = true, 1692 1368 }; 1693 1369 1694 1370 static const struct of_device_id sun8i_codec_of_match[] = {