535 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// rk3328 ALSA SoC Audio driver4//5// Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.6 7#include <linux/clk.h>8#include <linux/delay.h>9#include <linux/device.h>10#include <linux/gpio/consumer.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/regmap.h>15#include <linux/mfd/syscon.h>16#include <sound/dmaengine_pcm.h>17#include <sound/pcm_params.h>18#include "rk3328_codec.h"19 20/*21 * volume setting22 * 0: -39dB23 * 26: 0dB24 * 31: 6dB25 * Step: 1.5dB26 */27#define OUT_VOLUME (0x18)28#define RK3328_GRF_SOC_CON2 (0x0408)29#define RK3328_GRF_SOC_CON10 (0x0428)30#define INITIAL_FREQ (11289600)31 32struct rk3328_codec_priv {33 struct regmap *regmap;34 struct gpio_desc *mute;35 struct clk *mclk;36 struct clk *pclk;37 unsigned int sclk;38 int spk_depop_time; /* msec */39};40 41static const struct reg_default rk3328_codec_reg_defaults[] = {42 { CODEC_RESET, 0x03 },43 { DAC_INIT_CTRL1, 0x00 },44 { DAC_INIT_CTRL2, 0x50 },45 { DAC_INIT_CTRL3, 0x0e },46 { DAC_PRECHARGE_CTRL, 0x01 },47 { DAC_PWR_CTRL, 0x00 },48 { DAC_CLK_CTRL, 0x00 },49 { HPMIX_CTRL, 0x00 },50 { HPOUT_CTRL, 0x00 },51 { HPOUTL_GAIN_CTRL, 0x00 },52 { HPOUTR_GAIN_CTRL, 0x00 },53 { HPOUT_POP_CTRL, 0x11 },54};55 56static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328)57{58 regmap_write(rk3328->regmap, CODEC_RESET, 0x00);59 mdelay(10);60 regmap_write(rk3328->regmap, CODEC_RESET, 0x03);61 62 return 0;63}64 65static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)66{67 struct rk3328_codec_priv *rk3328 =68 snd_soc_component_get_drvdata(dai->component);69 unsigned int val;70 71 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {72 case SND_SOC_DAIFMT_CBC_CFC:73 val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;74 break;75 case SND_SOC_DAIFMT_CBP_CFP:76 val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;77 break;78 default:79 return -EINVAL;80 }81 82 regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1,83 PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);84 85 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {86 case SND_SOC_DAIFMT_DSP_A:87 case SND_SOC_DAIFMT_DSP_B:88 val = DAC_MODE_PCM;89 break;90 case SND_SOC_DAIFMT_I2S:91 val = DAC_MODE_I2S;92 break;93 case SND_SOC_DAIFMT_RIGHT_J:94 val = DAC_MODE_RJM;95 break;96 case SND_SOC_DAIFMT_LEFT_J:97 val = DAC_MODE_LJM;98 break;99 default:100 return -EINVAL;101 }102 103 regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2,104 DAC_MODE_MASK, val);105 106 return 0;107}108 109static int rk3328_mute_stream(struct snd_soc_dai *dai, int mute, int direction)110{111 struct rk3328_codec_priv *rk3328 =112 snd_soc_component_get_drvdata(dai->component);113 unsigned int val;114 115 if (mute)116 val = HPOUTL_MUTE | HPOUTR_MUTE;117 else118 val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;119 120 regmap_update_bits(rk3328->regmap, HPOUT_CTRL,121 HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);122 123 return 0;124}125 126static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms)127{128 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,129 DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);130 mdelay(10);131 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,132 DAC_CHARGE_CURRENT_ALL_MASK,133 DAC_CHARGE_CURRENT_ALL_ON);134 mdelay(wait_ms);135 136 return 0;137}138 139static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms)140{141 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,142 DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);143 mdelay(10);144 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,145 DAC_CHARGE_CURRENT_ALL_MASK,146 DAC_CHARGE_CURRENT_ALL_ON);147 mdelay(wait_ms);148 149 return 0;150}151 152static const struct rk3328_reg_msk_val playback_open_list[] = {153 { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },154 { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,155 DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },156 { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK,157 HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },158 { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,159 HPOUTR_POP_WORK | HPOUTL_POP_WORK },160 { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },161 { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,162 HPMIXL_INIT_EN | HPMIXR_INIT_EN },163 { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },164 { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,165 HPOUTL_INIT_EN | HPOUTR_INIT_EN },166 { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,167 DACL_REFV_ON | DACR_REFV_ON },168 { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,169 DACL_CLK_ON | DACR_CLK_ON },170 { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },171 { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,172 DACL_INIT_ON | DACR_INIT_ON },173 { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,174 DACL_SELECT | DACR_SELECT },175 { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,176 HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },177 { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,178 HPOUTL_UNMUTE | HPOUTR_UNMUTE },179};180 181static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328)182{183 int i;184 185 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,186 DAC_CHARGE_CURRENT_ALL_MASK,187 DAC_CHARGE_CURRENT_I);188 189 for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) {190 regmap_update_bits(rk3328->regmap,191 playback_open_list[i].reg,192 playback_open_list[i].msk,193 playback_open_list[i].val);194 mdelay(1);195 }196 197 msleep(rk3328->spk_depop_time);198 gpiod_set_value(rk3328->mute, 0);199 200 regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,201 HPOUTL_GAIN_MASK, OUT_VOLUME);202 regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,203 HPOUTR_GAIN_MASK, OUT_VOLUME);204 205 return 0;206}207 208static const struct rk3328_reg_msk_val playback_close_list[] = {209 { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,210 HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },211 { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,212 DACL_UNSELECT | DACR_UNSELECT },213 { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,214 HPOUTL_MUTE | HPOUTR_MUTE },215 { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,216 HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },217 { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },218 { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },219 { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },220 { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,221 DACL_CLK_OFF | DACR_CLK_OFF },222 { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,223 DACL_REFV_OFF | DACR_REFV_OFF },224 { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,225 HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },226 { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,227 DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },228 { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },229 { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,230 HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },231 { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,232 DACL_INIT_OFF | DACR_INIT_OFF },233};234 235static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328)236{237 size_t i;238 239 gpiod_set_value(rk3328->mute, 1);240 241 regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,242 HPOUTL_GAIN_MASK, 0);243 regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,244 HPOUTR_GAIN_MASK, 0);245 246 for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) {247 regmap_update_bits(rk3328->regmap,248 playback_close_list[i].reg,249 playback_close_list[i].msk,250 playback_close_list[i].val);251 mdelay(1);252 }253 254 /* Workaround for silence when changed Fs 48 -> 44.1kHz */255 rk3328_codec_reset(rk3328);256 257 regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,258 DAC_CHARGE_CURRENT_ALL_MASK,259 DAC_CHARGE_CURRENT_ALL_ON);260 261 return 0;262}263 264static int rk3328_hw_params(struct snd_pcm_substream *substream,265 struct snd_pcm_hw_params *params,266 struct snd_soc_dai *dai)267{268 struct rk3328_codec_priv *rk3328 =269 snd_soc_component_get_drvdata(dai->component);270 unsigned int val = 0;271 272 switch (params_format(params)) {273 case SNDRV_PCM_FORMAT_S16_LE:274 val = DAC_VDL_16BITS;275 break;276 case SNDRV_PCM_FORMAT_S20_3LE:277 val = DAC_VDL_20BITS;278 break;279 case SNDRV_PCM_FORMAT_S24_LE:280 val = DAC_VDL_24BITS;281 break;282 case SNDRV_PCM_FORMAT_S32_LE:283 val = DAC_VDL_32BITS;284 break;285 default:286 return -EINVAL;287 }288 regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);289 290 val = DAC_WL_32BITS | DAC_RST_DIS;291 regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3,292 DAC_WL_MASK | DAC_RST_MASK, val);293 294 return 0;295}296 297static int rk3328_pcm_startup(struct snd_pcm_substream *substream,298 struct snd_soc_dai *dai)299{300 struct rk3328_codec_priv *rk3328 =301 snd_soc_component_get_drvdata(dai->component);302 303 return rk3328_codec_open_playback(rk3328);304}305 306static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream,307 struct snd_soc_dai *dai)308{309 struct rk3328_codec_priv *rk3328 =310 snd_soc_component_get_drvdata(dai->component);311 312 rk3328_codec_close_playback(rk3328);313}314 315static const struct snd_soc_dai_ops rk3328_dai_ops = {316 .hw_params = rk3328_hw_params,317 .set_fmt = rk3328_set_dai_fmt,318 .mute_stream = rk3328_mute_stream,319 .startup = rk3328_pcm_startup,320 .shutdown = rk3328_pcm_shutdown,321 .no_capture_mute = 1,322};323 324static struct snd_soc_dai_driver rk3328_dai[] = {325 {326 .name = "rk3328-hifi",327 .id = RK3328_HIFI,328 .playback = {329 .stream_name = "HIFI Playback",330 .channels_min = 1,331 .channels_max = 2,332 .rates = SNDRV_PCM_RATE_8000_96000,333 .formats = (SNDRV_PCM_FMTBIT_S16_LE |334 SNDRV_PCM_FMTBIT_S20_3LE |335 SNDRV_PCM_FMTBIT_S24_LE |336 SNDRV_PCM_FMTBIT_S32_LE),337 },338 .capture = {339 .stream_name = "HIFI Capture",340 .channels_min = 2,341 .channels_max = 8,342 .rates = SNDRV_PCM_RATE_8000_96000,343 .formats = (SNDRV_PCM_FMTBIT_S16_LE |344 SNDRV_PCM_FMTBIT_S20_3LE |345 SNDRV_PCM_FMTBIT_S24_LE |346 SNDRV_PCM_FMTBIT_S32_LE),347 },348 .ops = &rk3328_dai_ops,349 },350};351 352static int rk3328_codec_probe(struct snd_soc_component *component)353{354 struct rk3328_codec_priv *rk3328 =355 snd_soc_component_get_drvdata(component);356 357 rk3328_codec_reset(rk3328);358 rk3328_codec_power_on(rk3328, 0);359 360 return 0;361}362 363static void rk3328_codec_remove(struct snd_soc_component *component)364{365 struct rk3328_codec_priv *rk3328 =366 snd_soc_component_get_drvdata(component);367 368 rk3328_codec_close_playback(rk3328);369 rk3328_codec_power_off(rk3328, 0);370}371 372static const struct snd_soc_component_driver soc_codec_rk3328 = {373 .probe = rk3328_codec_probe,374 .remove = rk3328_codec_remove,375};376 377static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg)378{379 switch (reg) {380 case CODEC_RESET:381 case DAC_INIT_CTRL1:382 case DAC_INIT_CTRL2:383 case DAC_INIT_CTRL3:384 case DAC_PRECHARGE_CTRL:385 case DAC_PWR_CTRL:386 case DAC_CLK_CTRL:387 case HPMIX_CTRL:388 case DAC_SELECT:389 case HPOUT_CTRL:390 case HPOUTL_GAIN_CTRL:391 case HPOUTR_GAIN_CTRL:392 case HPOUT_POP_CTRL:393 return true;394 default:395 return false;396 }397}398 399static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg)400{401 switch (reg) {402 case CODEC_RESET:403 return true;404 default:405 return false;406 }407}408 409static const struct regmap_config rk3328_codec_regmap_config = {410 .reg_bits = 32,411 .reg_stride = 4,412 .val_bits = 32,413 .max_register = HPOUT_POP_CTRL,414 .writeable_reg = rk3328_codec_write_read_reg,415 .readable_reg = rk3328_codec_write_read_reg,416 .volatile_reg = rk3328_codec_volatile_reg,417 .reg_defaults = rk3328_codec_reg_defaults,418 .num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults),419 .cache_type = REGCACHE_FLAT,420};421 422static int rk3328_platform_probe(struct platform_device *pdev)423{424 struct device_node *rk3328_np = pdev->dev.of_node;425 struct rk3328_codec_priv *rk3328;426 struct regmap *grf;427 void __iomem *base;428 int ret = 0;429 430 rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL);431 if (!rk3328)432 return -ENOMEM;433 434 grf = syscon_regmap_lookup_by_phandle(rk3328_np,435 "rockchip,grf");436 if (IS_ERR(grf)) {437 dev_err(&pdev->dev, "missing 'rockchip,grf'\n");438 return PTR_ERR(grf);439 }440 /* enable i2s_acodec_en */441 regmap_write(grf, RK3328_GRF_SOC_CON2,442 (BIT(14) << 16 | BIT(14)));443 444 ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms",445 &rk3328->spk_depop_time);446 if (ret < 0) {447 dev_info(&pdev->dev, "spk_depop_time use default value.\n");448 rk3328->spk_depop_time = 200;449 }450 451 rk3328->mute = gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_HIGH);452 if (IS_ERR(rk3328->mute))453 return PTR_ERR(rk3328->mute);454 /*455 * Rock64 is the only supported platform to have widely relied on456 * this; if we do happen to come across an old DTB, just leave the457 * external mute forced off.458 */459 if (!rk3328->mute && of_machine_is_compatible("pine64,rock64")) {460 dev_warn(&pdev->dev, "assuming implicit control of GPIO_MUTE; update devicetree if possible\n");461 regmap_write(grf, RK3328_GRF_SOC_CON10, BIT(17) | BIT(1));462 }463 464 rk3328->mclk = devm_clk_get(&pdev->dev, "mclk");465 if (IS_ERR(rk3328->mclk))466 return PTR_ERR(rk3328->mclk);467 468 ret = clk_prepare_enable(rk3328->mclk);469 if (ret)470 return ret;471 clk_set_rate(rk3328->mclk, INITIAL_FREQ);472 473 rk3328->pclk = devm_clk_get(&pdev->dev, "pclk");474 if (IS_ERR(rk3328->pclk)) {475 dev_err(&pdev->dev, "can't get acodec pclk\n");476 ret = PTR_ERR(rk3328->pclk);477 goto err_unprepare_mclk;478 }479 480 ret = clk_prepare_enable(rk3328->pclk);481 if (ret < 0) {482 dev_err(&pdev->dev, "failed to enable acodec pclk\n");483 goto err_unprepare_mclk;484 }485 486 base = devm_platform_ioremap_resource(pdev, 0);487 if (IS_ERR(base)) {488 ret = PTR_ERR(base);489 goto err_unprepare_pclk;490 }491 492 rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base,493 &rk3328_codec_regmap_config);494 if (IS_ERR(rk3328->regmap)) {495 ret = PTR_ERR(rk3328->regmap);496 goto err_unprepare_pclk;497 }498 499 platform_set_drvdata(pdev, rk3328);500 501 ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328,502 rk3328_dai,503 ARRAY_SIZE(rk3328_dai));504 if (ret)505 goto err_unprepare_pclk;506 507 return 0;508 509err_unprepare_pclk:510 clk_disable_unprepare(rk3328->pclk);511 512err_unprepare_mclk:513 clk_disable_unprepare(rk3328->mclk);514 return ret;515}516 517static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {518 { .compatible = "rockchip,rk3328-codec", },519 {},520};521MODULE_DEVICE_TABLE(of, rk3328_codec_of_match);522 523static struct platform_driver rk3328_codec_driver = {524 .driver = {525 .name = "rk3328-codec",526 .of_match_table = of_match_ptr(rk3328_codec_of_match),527 },528 .probe = rk3328_platform_probe,529};530module_platform_driver(rk3328_codec_driver);531 532MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");533MODULE_DESCRIPTION("ASoC rk3328 codec driver");534MODULE_LICENSE("GPL v2");535