| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 | 
|  | 2 | // | 
|  | 3 | // rk3328 ALSA SoC Audio driver | 
|  | 4 | // | 
|  | 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/module.h> | 
|  | 11 | #include <linux/of.h> | 
|  | 12 | #include <linux/platform_device.h> | 
|  | 13 | #include <linux/pm_runtime.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 setting | 
|  | 22 | * 0: -39dB | 
|  | 23 | * 26: 0dB | 
|  | 24 | * 31: 6dB | 
|  | 25 | * Step: 1.5dB | 
|  | 26 | */ | 
|  | 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 |  | 
|  | 32 | struct rk3328_codec_priv { | 
|  | 33 | struct regmap *regmap; | 
|  | 34 | struct regmap *grf; | 
|  | 35 | struct clk *mclk; | 
|  | 36 | struct clk *pclk; | 
|  | 37 | unsigned int sclk; | 
|  | 38 | int spk_depop_time; /* msec */ | 
|  | 39 | }; | 
|  | 40 |  | 
|  | 41 | static 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 |  | 
|  | 56 | static 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 |  | 
|  | 65 | static 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_MASTER_MASK) { | 
|  | 72 | case SND_SOC_DAIFMT_CBS_CFS: | 
|  | 73 | val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; | 
|  | 74 | break; | 
|  | 75 | case SND_SOC_DAIFMT_CBM_CFM: | 
|  | 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 |  | 
|  | 109 | static void rk3328_analog_output(struct rk3328_codec_priv *rk3328, int mute) | 
|  | 110 | { | 
|  | 111 | unsigned int val = BIT(17); | 
|  | 112 |  | 
|  | 113 | if (mute) | 
|  | 114 | val |= BIT(1); | 
|  | 115 |  | 
|  | 116 | regmap_write(rk3328->grf, RK3328_GRF_SOC_CON10, val); | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | static int rk3328_digital_mute(struct snd_soc_dai *dai, int mute) | 
|  | 120 | { | 
|  | 121 | struct rk3328_codec_priv *rk3328 = | 
|  | 122 | snd_soc_component_get_drvdata(dai->component); | 
|  | 123 | unsigned int val; | 
|  | 124 |  | 
|  | 125 | if (mute) | 
|  | 126 | val = HPOUTL_MUTE | HPOUTR_MUTE; | 
|  | 127 | else | 
|  | 128 | val = HPOUTL_UNMUTE | HPOUTR_UNMUTE; | 
|  | 129 |  | 
|  | 130 | regmap_update_bits(rk3328->regmap, HPOUT_CTRL, | 
|  | 131 | HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val); | 
|  | 132 |  | 
|  | 133 | return 0; | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms) | 
|  | 137 | { | 
|  | 138 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 139 | DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE); | 
|  | 140 | mdelay(10); | 
|  | 141 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 142 | DAC_CHARGE_CURRENT_ALL_MASK, | 
|  | 143 | DAC_CHARGE_CURRENT_ALL_ON); | 
|  | 144 | mdelay(wait_ms); | 
|  | 145 |  | 
|  | 146 | return 0; | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms) | 
|  | 150 | { | 
|  | 151 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 152 | DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE); | 
|  | 153 | mdelay(10); | 
|  | 154 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 155 | DAC_CHARGE_CURRENT_ALL_MASK, | 
|  | 156 | DAC_CHARGE_CURRENT_ALL_ON); | 
|  | 157 | mdelay(wait_ms); | 
|  | 158 |  | 
|  | 159 | return 0; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | static const struct rk3328_reg_msk_val playback_open_list[] = { | 
|  | 163 | { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON }, | 
|  | 164 | { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, | 
|  | 165 | DACL_PATH_REFV_ON | DACR_PATH_REFV_ON }, | 
|  | 166 | { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK, | 
|  | 167 | HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON }, | 
|  | 168 | { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, | 
|  | 169 | HPOUTR_POP_WORK | HPOUTL_POP_WORK }, | 
|  | 170 | { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN }, | 
|  | 171 | { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, | 
|  | 172 | HPMIXL_INIT_EN | HPMIXR_INIT_EN }, | 
|  | 173 | { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN }, | 
|  | 174 | { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, | 
|  | 175 | HPOUTL_INIT_EN | HPOUTR_INIT_EN }, | 
|  | 176 | { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, | 
|  | 177 | DACL_REFV_ON | DACR_REFV_ON }, | 
|  | 178 | { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, | 
|  | 179 | DACL_CLK_ON | DACR_CLK_ON }, | 
|  | 180 | { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON }, | 
|  | 181 | { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, | 
|  | 182 | DACL_INIT_ON | DACR_INIT_ON }, | 
|  | 183 | { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, | 
|  | 184 | DACL_SELECT | DACR_SELECT }, | 
|  | 185 | { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, | 
|  | 186 | HPMIXL_INIT2_EN | HPMIXR_INIT2_EN }, | 
|  | 187 | { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, | 
|  | 188 | HPOUTL_UNMUTE | HPOUTR_UNMUTE }, | 
|  | 189 | }; | 
|  | 190 |  | 
|  | 191 | static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328) | 
|  | 192 | { | 
|  | 193 | int i; | 
|  | 194 |  | 
|  | 195 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 196 | DAC_CHARGE_CURRENT_ALL_MASK, | 
|  | 197 | DAC_CHARGE_CURRENT_I); | 
|  | 198 |  | 
|  | 199 | for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) { | 
|  | 200 | regmap_update_bits(rk3328->regmap, | 
|  | 201 | playback_open_list[i].reg, | 
|  | 202 | playback_open_list[i].msk, | 
|  | 203 | playback_open_list[i].val); | 
|  | 204 | mdelay(1); | 
|  | 205 | } | 
|  | 206 |  | 
|  | 207 | msleep(rk3328->spk_depop_time); | 
|  | 208 | rk3328_analog_output(rk3328, 1); | 
|  | 209 |  | 
|  | 210 | regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, | 
|  | 211 | HPOUTL_GAIN_MASK, OUT_VOLUME); | 
|  | 212 | regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, | 
|  | 213 | HPOUTR_GAIN_MASK, OUT_VOLUME); | 
|  | 214 |  | 
|  | 215 | return 0; | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | static const struct rk3328_reg_msk_val playback_close_list[] = { | 
|  | 219 | { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, | 
|  | 220 | HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS }, | 
|  | 221 | { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, | 
|  | 222 | DACL_UNSELECT | DACR_UNSELECT }, | 
|  | 223 | { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, | 
|  | 224 | HPOUTL_MUTE | HPOUTR_MUTE }, | 
|  | 225 | { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, | 
|  | 226 | HPOUTL_INIT_DIS | HPOUTR_INIT_DIS }, | 
|  | 227 | { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS }, | 
|  | 228 | { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS }, | 
|  | 229 | { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF }, | 
|  | 230 | { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, | 
|  | 231 | DACL_CLK_OFF | DACR_CLK_OFF }, | 
|  | 232 | { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, | 
|  | 233 | DACL_REFV_OFF | DACR_REFV_OFF }, | 
|  | 234 | { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, | 
|  | 235 | HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE }, | 
|  | 236 | { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, | 
|  | 237 | DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF }, | 
|  | 238 | { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF }, | 
|  | 239 | { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, | 
|  | 240 | HPMIXL_INIT_DIS | HPMIXR_INIT_DIS }, | 
|  | 241 | { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, | 
|  | 242 | DACL_INIT_OFF | DACR_INIT_OFF }, | 
|  | 243 | }; | 
|  | 244 |  | 
|  | 245 | static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328) | 
|  | 246 | { | 
|  | 247 | size_t i; | 
|  | 248 |  | 
|  | 249 | rk3328_analog_output(rk3328, 0); | 
|  | 250 |  | 
|  | 251 | regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, | 
|  | 252 | HPOUTL_GAIN_MASK, 0); | 
|  | 253 | regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, | 
|  | 254 | HPOUTR_GAIN_MASK, 0); | 
|  | 255 |  | 
|  | 256 | for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) { | 
|  | 257 | regmap_update_bits(rk3328->regmap, | 
|  | 258 | playback_close_list[i].reg, | 
|  | 259 | playback_close_list[i].msk, | 
|  | 260 | playback_close_list[i].val); | 
|  | 261 | mdelay(1); | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | /* Workaround for silence when changed Fs 48 -> 44.1kHz */ | 
|  | 265 | rk3328_codec_reset(rk3328); | 
|  | 266 |  | 
|  | 267 | regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, | 
|  | 268 | DAC_CHARGE_CURRENT_ALL_MASK, | 
|  | 269 | DAC_CHARGE_CURRENT_ALL_ON); | 
|  | 270 |  | 
|  | 271 | return 0; | 
|  | 272 | } | 
|  | 273 |  | 
|  | 274 | static int rk3328_hw_params(struct snd_pcm_substream *substream, | 
|  | 275 | struct snd_pcm_hw_params *params, | 
|  | 276 | struct snd_soc_dai *dai) | 
|  | 277 | { | 
|  | 278 | struct rk3328_codec_priv *rk3328 = | 
|  | 279 | snd_soc_component_get_drvdata(dai->component); | 
|  | 280 | unsigned int val = 0; | 
|  | 281 |  | 
|  | 282 | switch (params_format(params)) { | 
|  | 283 | case SNDRV_PCM_FORMAT_S16_LE: | 
|  | 284 | val = DAC_VDL_16BITS; | 
|  | 285 | break; | 
|  | 286 | case SNDRV_PCM_FORMAT_S20_3LE: | 
|  | 287 | val = DAC_VDL_20BITS; | 
|  | 288 | break; | 
|  | 289 | case SNDRV_PCM_FORMAT_S24_LE: | 
|  | 290 | val = DAC_VDL_24BITS; | 
|  | 291 | break; | 
|  | 292 | case SNDRV_PCM_FORMAT_S32_LE: | 
|  | 293 | val = DAC_VDL_32BITS; | 
|  | 294 | break; | 
|  | 295 | default: | 
|  | 296 | return -EINVAL; | 
|  | 297 | } | 
|  | 298 | regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val); | 
|  | 299 |  | 
|  | 300 | val = DAC_WL_32BITS | DAC_RST_DIS; | 
|  | 301 | regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3, | 
|  | 302 | DAC_WL_MASK | DAC_RST_MASK, val); | 
|  | 303 |  | 
|  | 304 | return 0; | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | static int rk3328_pcm_startup(struct snd_pcm_substream *substream, | 
|  | 308 | struct snd_soc_dai *dai) | 
|  | 309 | { | 
|  | 310 | struct rk3328_codec_priv *rk3328 = | 
|  | 311 | snd_soc_component_get_drvdata(dai->component); | 
|  | 312 |  | 
|  | 313 | return rk3328_codec_open_playback(rk3328); | 
|  | 314 | } | 
|  | 315 |  | 
|  | 316 | static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream, | 
|  | 317 | struct snd_soc_dai *dai) | 
|  | 318 | { | 
|  | 319 | struct rk3328_codec_priv *rk3328 = | 
|  | 320 | snd_soc_component_get_drvdata(dai->component); | 
|  | 321 |  | 
|  | 322 | rk3328_codec_close_playback(rk3328); | 
|  | 323 | } | 
|  | 324 |  | 
|  | 325 | static const struct snd_soc_dai_ops rk3328_dai_ops = { | 
|  | 326 | .hw_params = rk3328_hw_params, | 
|  | 327 | .set_fmt = rk3328_set_dai_fmt, | 
|  | 328 | .digital_mute = rk3328_digital_mute, | 
|  | 329 | .startup = rk3328_pcm_startup, | 
|  | 330 | .shutdown = rk3328_pcm_shutdown, | 
|  | 331 | }; | 
|  | 332 |  | 
|  | 333 | static struct snd_soc_dai_driver rk3328_dai[] = { | 
|  | 334 | { | 
|  | 335 | .name = "rk3328-hifi", | 
|  | 336 | .id = RK3328_HIFI, | 
|  | 337 | .playback = { | 
|  | 338 | .stream_name = "HIFI Playback", | 
|  | 339 | .channels_min = 1, | 
|  | 340 | .channels_max = 2, | 
|  | 341 | .rates = SNDRV_PCM_RATE_8000_96000, | 
|  | 342 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 
|  | 343 | SNDRV_PCM_FMTBIT_S20_3LE | | 
|  | 344 | SNDRV_PCM_FMTBIT_S24_LE | | 
|  | 345 | SNDRV_PCM_FMTBIT_S32_LE), | 
|  | 346 | }, | 
|  | 347 | .capture = { | 
|  | 348 | .stream_name = "HIFI Capture", | 
|  | 349 | .channels_min = 2, | 
|  | 350 | .channels_max = 8, | 
|  | 351 | .rates = SNDRV_PCM_RATE_8000_96000, | 
|  | 352 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 
|  | 353 | SNDRV_PCM_FMTBIT_S20_3LE | | 
|  | 354 | SNDRV_PCM_FMTBIT_S24_LE | | 
|  | 355 | SNDRV_PCM_FMTBIT_S32_LE), | 
|  | 356 | }, | 
|  | 357 | .ops = &rk3328_dai_ops, | 
|  | 358 | }, | 
|  | 359 | }; | 
|  | 360 |  | 
|  | 361 | static int rk3328_codec_probe(struct snd_soc_component *component) | 
|  | 362 | { | 
|  | 363 | struct rk3328_codec_priv *rk3328 = | 
|  | 364 | snd_soc_component_get_drvdata(component); | 
|  | 365 |  | 
|  | 366 | rk3328_codec_reset(rk3328); | 
|  | 367 | rk3328_codec_power_on(rk3328, 0); | 
|  | 368 |  | 
|  | 369 | return 0; | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | static void rk3328_codec_remove(struct snd_soc_component *component) | 
|  | 373 | { | 
|  | 374 | struct rk3328_codec_priv *rk3328 = | 
|  | 375 | snd_soc_component_get_drvdata(component); | 
|  | 376 |  | 
|  | 377 | rk3328_codec_close_playback(rk3328); | 
|  | 378 | rk3328_codec_power_off(rk3328, 0); | 
|  | 379 | } | 
|  | 380 |  | 
|  | 381 | static const struct snd_soc_component_driver soc_codec_rk3328 = { | 
|  | 382 | .probe = rk3328_codec_probe, | 
|  | 383 | .remove = rk3328_codec_remove, | 
|  | 384 | }; | 
|  | 385 |  | 
|  | 386 | static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg) | 
|  | 387 | { | 
|  | 388 | switch (reg) { | 
|  | 389 | case CODEC_RESET: | 
|  | 390 | case DAC_INIT_CTRL1: | 
|  | 391 | case DAC_INIT_CTRL2: | 
|  | 392 | case DAC_INIT_CTRL3: | 
|  | 393 | case DAC_PRECHARGE_CTRL: | 
|  | 394 | case DAC_PWR_CTRL: | 
|  | 395 | case DAC_CLK_CTRL: | 
|  | 396 | case HPMIX_CTRL: | 
|  | 397 | case DAC_SELECT: | 
|  | 398 | case HPOUT_CTRL: | 
|  | 399 | case HPOUTL_GAIN_CTRL: | 
|  | 400 | case HPOUTR_GAIN_CTRL: | 
|  | 401 | case HPOUT_POP_CTRL: | 
|  | 402 | return true; | 
|  | 403 | default: | 
|  | 404 | return false; | 
|  | 405 | } | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg) | 
|  | 409 | { | 
|  | 410 | switch (reg) { | 
|  | 411 | case CODEC_RESET: | 
|  | 412 | return true; | 
|  | 413 | default: | 
|  | 414 | return false; | 
|  | 415 | } | 
|  | 416 | } | 
|  | 417 |  | 
|  | 418 | static const struct regmap_config rk3328_codec_regmap_config = { | 
|  | 419 | .reg_bits = 32, | 
|  | 420 | .reg_stride = 4, | 
|  | 421 | .val_bits = 32, | 
|  | 422 | .max_register = HPOUT_POP_CTRL, | 
|  | 423 | .writeable_reg = rk3328_codec_write_read_reg, | 
|  | 424 | .readable_reg = rk3328_codec_write_read_reg, | 
|  | 425 | .volatile_reg = rk3328_codec_volatile_reg, | 
|  | 426 | .reg_defaults = rk3328_codec_reg_defaults, | 
|  | 427 | .num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults), | 
|  | 428 | .cache_type = REGCACHE_FLAT, | 
|  | 429 | }; | 
|  | 430 |  | 
|  | 431 | static int rk3328_platform_probe(struct platform_device *pdev) | 
|  | 432 | { | 
|  | 433 | struct device_node *rk3328_np = pdev->dev.of_node; | 
|  | 434 | struct rk3328_codec_priv *rk3328; | 
|  | 435 | struct regmap *grf; | 
|  | 436 | void __iomem *base; | 
|  | 437 | int ret = 0; | 
|  | 438 |  | 
|  | 439 | rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL); | 
|  | 440 | if (!rk3328) | 
|  | 441 | return -ENOMEM; | 
|  | 442 |  | 
|  | 443 | grf = syscon_regmap_lookup_by_phandle(rk3328_np, | 
|  | 444 | "rockchip,grf"); | 
|  | 445 | if (IS_ERR(grf)) { | 
|  | 446 | dev_err(&pdev->dev, "missing 'rockchip,grf'\n"); | 
|  | 447 | return PTR_ERR(grf); | 
|  | 448 | } | 
|  | 449 | rk3328->grf = grf; | 
|  | 450 | /* enable i2s_acodec_en */ | 
|  | 451 | regmap_write(grf, RK3328_GRF_SOC_CON2, | 
|  | 452 | (BIT(14) << 16 | BIT(14))); | 
|  | 453 |  | 
|  | 454 | ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms", | 
|  | 455 | &rk3328->spk_depop_time); | 
|  | 456 | if (ret < 0) { | 
|  | 457 | dev_info(&pdev->dev, "spk_depop_time use default value.\n"); | 
|  | 458 | rk3328->spk_depop_time = 200; | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | rk3328_analog_output(rk3328, 0); | 
|  | 462 |  | 
|  | 463 | rk3328->mclk = devm_clk_get(&pdev->dev, "mclk"); | 
|  | 464 | if (IS_ERR(rk3328->mclk)) | 
|  | 465 | return PTR_ERR(rk3328->mclk); | 
|  | 466 |  | 
|  | 467 | ret = clk_prepare_enable(rk3328->mclk); | 
|  | 468 | if (ret) | 
|  | 469 | return ret; | 
|  | 470 | clk_set_rate(rk3328->mclk, INITIAL_FREQ); | 
|  | 471 |  | 
|  | 472 | rk3328->pclk = devm_clk_get(&pdev->dev, "pclk"); | 
|  | 473 | if (IS_ERR(rk3328->pclk)) { | 
|  | 474 | dev_err(&pdev->dev, "can't get acodec pclk\n"); | 
|  | 475 | ret = PTR_ERR(rk3328->pclk); | 
|  | 476 | goto err_unprepare_mclk; | 
|  | 477 | } | 
|  | 478 |  | 
|  | 479 | ret = clk_prepare_enable(rk3328->pclk); | 
|  | 480 | if (ret < 0) { | 
|  | 481 | dev_err(&pdev->dev, "failed to enable acodec pclk\n"); | 
|  | 482 | goto err_unprepare_mclk; | 
|  | 483 | } | 
|  | 484 |  | 
|  | 485 | base = devm_platform_ioremap_resource(pdev, 0); | 
|  | 486 | if (IS_ERR(base)) { | 
|  | 487 | ret = PTR_ERR(base); | 
|  | 488 | goto err_unprepare_pclk; | 
|  | 489 | } | 
|  | 490 |  | 
|  | 491 | rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base, | 
|  | 492 | &rk3328_codec_regmap_config); | 
|  | 493 | if (IS_ERR(rk3328->regmap)) { | 
|  | 494 | ret = PTR_ERR(rk3328->regmap); | 
|  | 495 | goto err_unprepare_pclk; | 
|  | 496 | } | 
|  | 497 |  | 
|  | 498 | platform_set_drvdata(pdev, rk3328); | 
|  | 499 |  | 
|  | 500 | ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328, | 
|  | 501 | rk3328_dai, | 
|  | 502 | ARRAY_SIZE(rk3328_dai)); | 
|  | 503 | if (ret) | 
|  | 504 | goto err_unprepare_pclk; | 
|  | 505 |  | 
|  | 506 | return 0; | 
|  | 507 |  | 
|  | 508 | err_unprepare_pclk: | 
|  | 509 | clk_disable_unprepare(rk3328->pclk); | 
|  | 510 |  | 
|  | 511 | err_unprepare_mclk: | 
|  | 512 | clk_disable_unprepare(rk3328->mclk); | 
|  | 513 | return ret; | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | static const struct of_device_id rk3328_codec_of_match[] = { | 
|  | 517 | { .compatible = "rockchip,rk3328-codec", }, | 
|  | 518 | {}, | 
|  | 519 | }; | 
|  | 520 | MODULE_DEVICE_TABLE(of, rk3328_codec_of_match); | 
|  | 521 |  | 
|  | 522 | static struct platform_driver rk3328_codec_driver = { | 
|  | 523 | .driver = { | 
|  | 524 | .name = "rk3328-codec", | 
|  | 525 | .of_match_table = of_match_ptr(rk3328_codec_of_match), | 
|  | 526 | }, | 
|  | 527 | .probe = rk3328_platform_probe, | 
|  | 528 | }; | 
|  | 529 | module_platform_driver(rk3328_codec_driver); | 
|  | 530 |  | 
|  | 531 | MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>"); | 
|  | 532 | MODULE_DESCRIPTION("ASoC rk3328 codec driver"); | 
|  | 533 | MODULE_LICENSE("GPL v2"); |