.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * wm8960.c -- WM8960 ALSA SoC Audio driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2007-11 Wolfson Microelectronics, plc |
---|
5 | 6 | * |
---|
6 | 7 | * Author: Liam Girdwood |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
611 | 608 | * - lrclk = sysclk / dac_divs |
---|
612 | 609 | * - 10 * bclk = sysclk / bclk_divs |
---|
613 | 610 | * |
---|
614 | | - * If we cannot find an exact match for (sysclk, lrclk, bclk) |
---|
615 | | - * triplet, we relax the bclk such that bclk is chosen as the |
---|
616 | | - * closest available frequency greater than expected bclk. |
---|
617 | | - * |
---|
618 | | - * @wm8960_priv: wm8960 codec private data |
---|
| 611 | + * @wm8960: codec private data |
---|
619 | 612 | * @mclk: MCLK used to derive sysclk |
---|
620 | 613 | * @sysclk_idx: sysclk_divs index for found sysclk |
---|
621 | 614 | * @dac_idx: dac_divs index for found lrclk |
---|
.. | .. |
---|
632 | 625 | { |
---|
633 | 626 | int sysclk, bclk, lrclk; |
---|
634 | 627 | int i, j, k; |
---|
635 | | - int diff, closest = mclk; |
---|
| 628 | + int diff; |
---|
636 | 629 | |
---|
637 | 630 | /* marker for no match */ |
---|
638 | 631 | *bclk_idx = -1; |
---|
.. | .. |
---|
655 | 648 | *dac_idx = j; |
---|
656 | 649 | *bclk_idx = k; |
---|
657 | 650 | break; |
---|
658 | | - } |
---|
659 | | - if (diff > 0 && closest > diff) { |
---|
660 | | - *sysclk_idx = i; |
---|
661 | | - *dac_idx = j; |
---|
662 | | - *bclk_idx = k; |
---|
663 | | - closest = diff; |
---|
664 | 651 | } |
---|
665 | 652 | } |
---|
666 | 653 | if (k != ARRAY_SIZE(bclk_divs)) |
---|
.. | .. |
---|
751 | 738 | { |
---|
752 | 739 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); |
---|
753 | 740 | int freq_out, freq_in; |
---|
754 | | - u16 iface1 = snd_soc_component_read32(component, WM8960_IFACE1); |
---|
| 741 | + u16 iface1 = snd_soc_component_read(component, WM8960_IFACE1); |
---|
755 | 742 | int i, j, k; |
---|
756 | 743 | int ret; |
---|
757 | 744 | |
---|
.. | .. |
---|
828 | 815 | { |
---|
829 | 816 | struct snd_soc_component *component = dai->component; |
---|
830 | 817 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); |
---|
831 | | - u16 iface = snd_soc_component_read32(component, WM8960_IFACE1) & 0xfff3; |
---|
| 818 | + u16 iface = snd_soc_component_read(component, WM8960_IFACE1) & 0xfff3; |
---|
832 | 819 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
---|
833 | 820 | int i; |
---|
834 | 821 | |
---|
.. | .. |
---|
852 | 839 | iface |= 0x000c; |
---|
853 | 840 | break; |
---|
854 | 841 | } |
---|
855 | | - /* fall through */ |
---|
| 842 | + fallthrough; |
---|
856 | 843 | default: |
---|
857 | 844 | dev_err(component->dev, "unsupported width %d\n", |
---|
858 | 845 | params_width(params)); |
---|
.. | .. |
---|
894 | 881 | return 0; |
---|
895 | 882 | } |
---|
896 | 883 | |
---|
897 | | -static int wm8960_mute(struct snd_soc_dai *dai, int mute) |
---|
| 884 | +static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction) |
---|
898 | 885 | { |
---|
899 | 886 | struct snd_soc_component *component = dai->component; |
---|
900 | 887 | |
---|
.. | .. |
---|
909 | 896 | enum snd_soc_bias_level level) |
---|
910 | 897 | { |
---|
911 | 898 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); |
---|
912 | | - u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2); |
---|
| 899 | + u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); |
---|
913 | 900 | int ret; |
---|
914 | 901 | |
---|
915 | 902 | switch (level) { |
---|
.. | .. |
---|
999 | 986 | enum snd_soc_bias_level level) |
---|
1000 | 987 | { |
---|
1001 | 988 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); |
---|
1002 | | - u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2); |
---|
| 989 | + u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); |
---|
1003 | 990 | int reg, ret; |
---|
1004 | 991 | |
---|
1005 | 992 | switch (level) { |
---|
.. | .. |
---|
1218 | 1205 | if (!freq_in || !freq_out) |
---|
1219 | 1206 | return 0; |
---|
1220 | 1207 | |
---|
1221 | | - reg = snd_soc_component_read32(component, WM8960_PLL1) & ~0x3f; |
---|
| 1208 | + reg = snd_soc_component_read(component, WM8960_PLL1) & ~0x3f; |
---|
1222 | 1209 | reg |= pll_div.pre_div << 4; |
---|
1223 | 1210 | reg |= pll_div.n; |
---|
1224 | 1211 | |
---|
.. | .. |
---|
1261 | 1248 | |
---|
1262 | 1249 | switch (div_id) { |
---|
1263 | 1250 | case WM8960_SYSCLKDIV: |
---|
1264 | | - reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1f9; |
---|
| 1251 | + reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1f9; |
---|
1265 | 1252 | snd_soc_component_write(component, WM8960_CLOCK1, reg | div); |
---|
1266 | 1253 | break; |
---|
1267 | 1254 | case WM8960_DACDIV: |
---|
1268 | | - reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1c7; |
---|
| 1255 | + reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1c7; |
---|
1269 | 1256 | snd_soc_component_write(component, WM8960_CLOCK1, reg | div); |
---|
1270 | 1257 | break; |
---|
1271 | 1258 | case WM8960_OPCLKDIV: |
---|
1272 | | - reg = snd_soc_component_read32(component, WM8960_PLL1) & 0x03f; |
---|
| 1259 | + reg = snd_soc_component_read(component, WM8960_PLL1) & 0x03f; |
---|
1273 | 1260 | snd_soc_component_write(component, WM8960_PLL1, reg | div); |
---|
1274 | 1261 | break; |
---|
1275 | 1262 | case WM8960_DCLKDIV: |
---|
1276 | | - reg = snd_soc_component_read32(component, WM8960_CLOCK2) & 0x03f; |
---|
| 1263 | + reg = snd_soc_component_read(component, WM8960_CLOCK2) & 0x03f; |
---|
1277 | 1264 | snd_soc_component_write(component, WM8960_CLOCK2, reg | div); |
---|
1278 | 1265 | break; |
---|
1279 | 1266 | case WM8960_TOCLKSEL: |
---|
1280 | | - reg = snd_soc_component_read32(component, WM8960_ADDCTL1) & 0x1fd; |
---|
| 1267 | + reg = snd_soc_component_read(component, WM8960_ADDCTL1) & 0x1fd; |
---|
1281 | 1268 | snd_soc_component_write(component, WM8960_ADDCTL1, reg | div); |
---|
1282 | 1269 | break; |
---|
1283 | 1270 | default: |
---|
.. | .. |
---|
1331 | 1318 | static const struct snd_soc_dai_ops wm8960_dai_ops = { |
---|
1332 | 1319 | .hw_params = wm8960_hw_params, |
---|
1333 | 1320 | .hw_free = wm8960_hw_free, |
---|
1334 | | - .digital_mute = wm8960_mute, |
---|
| 1321 | + .mute_stream = wm8960_mute, |
---|
1335 | 1322 | .set_fmt = wm8960_set_dai_fmt, |
---|
1336 | 1323 | .set_clkdiv = wm8960_set_dai_clkdiv, |
---|
1337 | 1324 | .set_pll = wm8960_set_dai_pll, |
---|
1338 | 1325 | .set_sysclk = wm8960_set_dai_sysclk, |
---|
| 1326 | + .no_capture_mute = 1, |
---|
1339 | 1327 | }; |
---|
1340 | 1328 | |
---|
1341 | 1329 | static struct snd_soc_dai_driver wm8960_dai = { |
---|
.. | .. |
---|
1405 | 1393 | |
---|
1406 | 1394 | if (of_property_read_bool(np, "wlf,shared-lrclk")) |
---|
1407 | 1395 | pdata->shared_lrclk = true; |
---|
| 1396 | + |
---|
| 1397 | + of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_cfg, |
---|
| 1398 | + ARRAY_SIZE(pdata->gpio_cfg)); |
---|
| 1399 | + |
---|
| 1400 | + of_property_read_u32_array(np, "wlf,hp-cfg", pdata->hp_cfg, |
---|
| 1401 | + ARRAY_SIZE(pdata->hp_cfg)); |
---|
1408 | 1402 | } |
---|
1409 | 1403 | |
---|
1410 | 1404 | static int wm8960_i2c_probe(struct i2c_client *i2c, |
---|
.. | .. |
---|
1462 | 1456 | regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); |
---|
1463 | 1457 | regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); |
---|
1464 | 1458 | |
---|
| 1459 | + /* ADCLRC pin configured as GPIO. */ |
---|
| 1460 | + regmap_update_bits(wm8960->regmap, WM8960_IFACE2, 1 << 6, |
---|
| 1461 | + wm8960->pdata.gpio_cfg[0] << 6); |
---|
| 1462 | + regmap_update_bits(wm8960->regmap, WM8960_ADDCTL4, 0xF << 4, |
---|
| 1463 | + wm8960->pdata.gpio_cfg[1] << 4); |
---|
| 1464 | + |
---|
| 1465 | + /* Enable headphone jack detect */ |
---|
| 1466 | + regmap_update_bits(wm8960->regmap, WM8960_ADDCTL4, 3 << 2, |
---|
| 1467 | + wm8960->pdata.hp_cfg[0] << 2); |
---|
| 1468 | + regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 3 << 5, |
---|
| 1469 | + wm8960->pdata.hp_cfg[1] << 5); |
---|
| 1470 | + regmap_update_bits(wm8960->regmap, WM8960_ADDCTL1, 3, |
---|
| 1471 | + wm8960->pdata.hp_cfg[2]); |
---|
| 1472 | + |
---|
1465 | 1473 | i2c_set_clientdata(i2c, wm8960); |
---|
1466 | 1474 | |
---|
1467 | 1475 | ret = devm_snd_soc_register_component(&i2c->dev, |
---|