.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Driver for the PCM512x CODECs |
---|
3 | 4 | * |
---|
4 | 5 | * Author: Mark Brown <broonie@kernel.org> |
---|
5 | 6 | * Copyright 2014 Linaro Ltd |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * version 2 as published by the Free Software Foundation. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, but |
---|
12 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | | - * General Public License for more details. |
---|
15 | 7 | */ |
---|
16 | 8 | |
---|
17 | 9 | |
---|
.. | .. |
---|
53 | 45 | unsigned long overclock_pll; |
---|
54 | 46 | unsigned long overclock_dac; |
---|
55 | 47 | unsigned long overclock_dsp; |
---|
| 48 | + int mute; |
---|
| 49 | + struct mutex mutex; |
---|
| 50 | + unsigned int bclk_ratio; |
---|
56 | 51 | }; |
---|
57 | 52 | |
---|
58 | 53 | /* |
---|
.. | .. |
---|
384 | 379 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, |
---|
385 | 380 | pcm512x_ramp_step_text); |
---|
386 | 381 | |
---|
| 382 | +static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) |
---|
| 383 | +{ |
---|
| 384 | + return regmap_update_bits( |
---|
| 385 | + pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, |
---|
| 386 | + (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) |
---|
| 387 | + | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); |
---|
| 388 | +} |
---|
| 389 | + |
---|
| 390 | +static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, |
---|
| 391 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 392 | +{ |
---|
| 393 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 394 | + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); |
---|
| 395 | + |
---|
| 396 | + mutex_lock(&pcm512x->mutex); |
---|
| 397 | + ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); |
---|
| 398 | + ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); |
---|
| 399 | + mutex_unlock(&pcm512x->mutex); |
---|
| 400 | + |
---|
| 401 | + return 0; |
---|
| 402 | +} |
---|
| 403 | + |
---|
| 404 | +static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, |
---|
| 405 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 406 | +{ |
---|
| 407 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 408 | + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); |
---|
| 409 | + int ret, changed = 0; |
---|
| 410 | + |
---|
| 411 | + mutex_lock(&pcm512x->mutex); |
---|
| 412 | + |
---|
| 413 | + if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { |
---|
| 414 | + pcm512x->mute ^= 0x4; |
---|
| 415 | + changed = 1; |
---|
| 416 | + } |
---|
| 417 | + if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { |
---|
| 418 | + pcm512x->mute ^= 0x2; |
---|
| 419 | + changed = 1; |
---|
| 420 | + } |
---|
| 421 | + |
---|
| 422 | + if (changed) { |
---|
| 423 | + ret = pcm512x_update_mute(pcm512x); |
---|
| 424 | + if (ret != 0) { |
---|
| 425 | + dev_err(component->dev, |
---|
| 426 | + "Failed to update digital mute: %d\n", ret); |
---|
| 427 | + mutex_unlock(&pcm512x->mutex); |
---|
| 428 | + return ret; |
---|
| 429 | + } |
---|
| 430 | + } |
---|
| 431 | + |
---|
| 432 | + mutex_unlock(&pcm512x->mutex); |
---|
| 433 | + |
---|
| 434 | + return changed; |
---|
| 435 | +} |
---|
| 436 | + |
---|
387 | 437 | static const struct snd_kcontrol_new pcm512x_controls[] = { |
---|
388 | 438 | SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, |
---|
389 | 439 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), |
---|
.. | .. |
---|
391 | 441 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), |
---|
392 | 442 | SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, |
---|
393 | 443 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), |
---|
394 | | -SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, |
---|
395 | | - PCM512x_RQMR_SHIFT, 1, 1), |
---|
| 444 | +{ |
---|
| 445 | + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
---|
| 446 | + .name = "Digital Playback Switch", |
---|
| 447 | + .index = 0, |
---|
| 448 | + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
---|
| 449 | + .info = snd_ctl_boolean_stereo_info, |
---|
| 450 | + .get = pcm512x_digital_playback_switch_get, |
---|
| 451 | + .put = pcm512x_digital_playback_switch_put |
---|
| 452 | +}, |
---|
396 | 453 | |
---|
397 | 454 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), |
---|
398 | 455 | SOC_ENUM("DSP Program", pcm512x_dsp_program), |
---|
.. | .. |
---|
851 | 908 | int fssp; |
---|
852 | 909 | int gpio; |
---|
853 | 910 | |
---|
854 | | - lrclk_div = snd_soc_params_to_frame_size(params); |
---|
855 | | - if (lrclk_div == 0) { |
---|
856 | | - dev_err(dev, "No LRCLK?\n"); |
---|
857 | | - return -EINVAL; |
---|
| 911 | + if (pcm512x->bclk_ratio > 0) { |
---|
| 912 | + lrclk_div = pcm512x->bclk_ratio; |
---|
| 913 | + } else { |
---|
| 914 | + lrclk_div = snd_soc_params_to_frame_size(params); |
---|
| 915 | + |
---|
| 916 | + if (lrclk_div == 0) { |
---|
| 917 | + dev_err(dev, "No LRCLK?\n"); |
---|
| 918 | + return -EINVAL; |
---|
| 919 | + } |
---|
858 | 920 | } |
---|
859 | 921 | |
---|
860 | 922 | if (!pcm512x->pll_out) { |
---|
861 | 923 | sck_rate = clk_get_rate(pcm512x->sclk); |
---|
862 | | - bclk_div = params->rate_den * 64 / lrclk_div; |
---|
863 | | - bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); |
---|
| 924 | + bclk_rate = params_rate(params) * lrclk_div; |
---|
| 925 | + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); |
---|
864 | 926 | |
---|
865 | 927 | mck_rate = sck_rate; |
---|
866 | 928 | } else { |
---|
.. | .. |
---|
1319 | 1381 | return 0; |
---|
1320 | 1382 | } |
---|
1321 | 1383 | |
---|
| 1384 | +static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) |
---|
| 1385 | +{ |
---|
| 1386 | + struct snd_soc_component *component = dai->component; |
---|
| 1387 | + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); |
---|
| 1388 | + |
---|
| 1389 | + if (ratio > 256) |
---|
| 1390 | + return -EINVAL; |
---|
| 1391 | + |
---|
| 1392 | + pcm512x->bclk_ratio = ratio; |
---|
| 1393 | + |
---|
| 1394 | + return 0; |
---|
| 1395 | +} |
---|
| 1396 | + |
---|
| 1397 | +static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) |
---|
| 1398 | +{ |
---|
| 1399 | + struct snd_soc_component *component = dai->component; |
---|
| 1400 | + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); |
---|
| 1401 | + int ret; |
---|
| 1402 | + unsigned int mute_det; |
---|
| 1403 | + |
---|
| 1404 | + mutex_lock(&pcm512x->mutex); |
---|
| 1405 | + |
---|
| 1406 | + if (mute) { |
---|
| 1407 | + pcm512x->mute |= 0x1; |
---|
| 1408 | + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, |
---|
| 1409 | + PCM512x_RQML | PCM512x_RQMR, |
---|
| 1410 | + PCM512x_RQML | PCM512x_RQMR); |
---|
| 1411 | + if (ret != 0) { |
---|
| 1412 | + dev_err(component->dev, |
---|
| 1413 | + "Failed to set digital mute: %d\n", ret); |
---|
| 1414 | + goto unlock; |
---|
| 1415 | + } |
---|
| 1416 | + |
---|
| 1417 | + regmap_read_poll_timeout(pcm512x->regmap, |
---|
| 1418 | + PCM512x_ANALOG_MUTE_DET, |
---|
| 1419 | + mute_det, (mute_det & 0x3) == 0, |
---|
| 1420 | + 200, 10000); |
---|
| 1421 | + } else { |
---|
| 1422 | + pcm512x->mute &= ~0x1; |
---|
| 1423 | + ret = pcm512x_update_mute(pcm512x); |
---|
| 1424 | + if (ret != 0) { |
---|
| 1425 | + dev_err(component->dev, |
---|
| 1426 | + "Failed to update digital mute: %d\n", ret); |
---|
| 1427 | + goto unlock; |
---|
| 1428 | + } |
---|
| 1429 | + |
---|
| 1430 | + regmap_read_poll_timeout(pcm512x->regmap, |
---|
| 1431 | + PCM512x_ANALOG_MUTE_DET, |
---|
| 1432 | + mute_det, |
---|
| 1433 | + (mute_det & 0x3) |
---|
| 1434 | + == ((~pcm512x->mute >> 1) & 0x3), |
---|
| 1435 | + 200, 10000); |
---|
| 1436 | + } |
---|
| 1437 | + |
---|
| 1438 | +unlock: |
---|
| 1439 | + mutex_unlock(&pcm512x->mutex); |
---|
| 1440 | + |
---|
| 1441 | + return ret; |
---|
| 1442 | +} |
---|
| 1443 | + |
---|
1322 | 1444 | static const struct snd_soc_dai_ops pcm512x_dai_ops = { |
---|
1323 | 1445 | .startup = pcm512x_dai_startup, |
---|
1324 | 1446 | .hw_params = pcm512x_hw_params, |
---|
1325 | 1447 | .set_fmt = pcm512x_set_fmt, |
---|
| 1448 | + .mute_stream = pcm512x_mute, |
---|
| 1449 | + .set_bclk_ratio = pcm512x_set_bclk_ratio, |
---|
| 1450 | + .no_capture_mute = 1, |
---|
1326 | 1451 | }; |
---|
1327 | 1452 | |
---|
1328 | 1453 | static struct snd_soc_dai_driver pcm512x_dai = { |
---|
.. | .. |
---|
1388 | 1513 | if (!pcm512x) |
---|
1389 | 1514 | return -ENOMEM; |
---|
1390 | 1515 | |
---|
| 1516 | + mutex_init(&pcm512x->mutex); |
---|
| 1517 | + |
---|
1391 | 1518 | dev_set_drvdata(dev, pcm512x); |
---|
1392 | 1519 | pcm512x->regmap = regmap; |
---|
1393 | 1520 | |
---|
.. | .. |
---|
1406 | 1533 | pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; |
---|
1407 | 1534 | |
---|
1408 | 1535 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { |
---|
1409 | | - ret = regulator_register_notifier(pcm512x->supplies[i].consumer, |
---|
1410 | | - &pcm512x->supply_nb[i]); |
---|
| 1536 | + ret = devm_regulator_register_notifier( |
---|
| 1537 | + pcm512x->supplies[i].consumer, |
---|
| 1538 | + &pcm512x->supply_nb[i]); |
---|
1411 | 1539 | if (ret != 0) { |
---|
1412 | 1540 | dev_err(dev, |
---|
1413 | 1541 | "Failed to register regulator notifier: %d\n", |
---|