Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | // |
| 3 | // rt715-sdca.c -- rt715 ALSA SoC audio driver |
| 4 | // |
| 5 | // Copyright(c) 2020 Realtek Semiconductor Corp. |
| 6 | // |
| 7 | // |
| 8 | // |
| 9 | |
| 10 | #include <linux/module.h> |
| 11 | #include <linux/moduleparam.h> |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/init.h> |
| 14 | #include <linux/pm_runtime.h> |
| 15 | #include <linux/pm.h> |
| 16 | #include <linux/soundwire/sdw.h> |
| 17 | #include <linux/regmap.h> |
| 18 | #include <linux/slab.h> |
| 19 | #include <linux/platform_device.h> |
| 20 | #include <sound/core.h> |
| 21 | #include <sound/pcm.h> |
| 22 | #include <sound/pcm_params.h> |
| 23 | #include <sound/soc.h> |
| 24 | #include <sound/soc-dapm.h> |
| 25 | #include <sound/initval.h> |
| 26 | #include <sound/tlv.h> |
| 27 | #include <linux/soundwire/sdw_registers.h> |
| 28 | |
| 29 | #include "rt715-sdca.h" |
| 30 | |
| 31 | static int rt715_sdca_index_write(struct rt715_sdca_priv *rt715, |
| 32 | unsigned int nid, unsigned int reg, unsigned int value) |
| 33 | { |
| 34 | struct regmap *regmap = rt715->mbq_regmap; |
| 35 | unsigned int addr; |
| 36 | int ret; |
| 37 | |
| 38 | addr = (nid << 20) | reg; |
| 39 | |
| 40 | ret = regmap_write(regmap, addr, value); |
| 41 | if (ret < 0) |
| 42 | dev_err(&rt715->slave->dev, |
| 43 | "Failed to set private value: %08x <= %04x %d\n", ret, addr, |
| 44 | value); |
| 45 | |
| 46 | return ret; |
| 47 | } |
| 48 | |
| 49 | static int rt715_sdca_index_read(struct rt715_sdca_priv *rt715, |
| 50 | unsigned int nid, unsigned int reg, unsigned int *value) |
| 51 | { |
| 52 | struct regmap *regmap = rt715->mbq_regmap; |
| 53 | unsigned int addr; |
| 54 | int ret; |
| 55 | |
| 56 | addr = (nid << 20) | reg; |
| 57 | |
| 58 | ret = regmap_read(regmap, addr, value); |
| 59 | if (ret < 0) |
| 60 | dev_err(&rt715->slave->dev, |
| 61 | "Failed to get private value: %06x => %04x ret=%d\n", |
| 62 | addr, *value, ret); |
| 63 | |
| 64 | return ret; |
| 65 | } |
| 66 | |
| 67 | static int rt715_sdca_index_update_bits(struct rt715_sdca_priv *rt715, |
| 68 | unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) |
| 69 | { |
| 70 | unsigned int tmp; |
| 71 | int ret; |
| 72 | |
| 73 | ret = rt715_sdca_index_read(rt715, nid, reg, &tmp); |
| 74 | if (ret < 0) |
| 75 | return ret; |
| 76 | |
| 77 | set_mask_bits(&tmp, mask, val); |
| 78 | |
| 79 | return rt715_sdca_index_write(rt715, nid, reg, tmp); |
| 80 | } |
| 81 | |
| 82 | static inline unsigned int rt715_sdca_vol_gain(unsigned int u_ctrl_val, |
| 83 | unsigned int vol_max, unsigned int vol_gain_sft) |
| 84 | { |
| 85 | unsigned int val; |
| 86 | |
| 87 | if (u_ctrl_val > vol_max) |
| 88 | u_ctrl_val = vol_max; |
| 89 | val = u_ctrl_val; |
| 90 | u_ctrl_val = |
| 91 | ((abs(u_ctrl_val - vol_gain_sft) * RT715_SDCA_DB_STEP) << 8) / 1000; |
| 92 | if (val <= vol_gain_sft) { |
| 93 | u_ctrl_val = ~u_ctrl_val; |
| 94 | u_ctrl_val += 1; |
| 95 | } |
| 96 | u_ctrl_val &= 0xffff; |
| 97 | |
| 98 | return u_ctrl_val; |
| 99 | } |
| 100 | |
| 101 | static inline unsigned int rt715_sdca_boost_gain(unsigned int u_ctrl_val, |
| 102 | unsigned int b_max, unsigned int b_gain_sft) |
| 103 | { |
| 104 | if (u_ctrl_val > b_max) |
| 105 | u_ctrl_val = b_max; |
| 106 | |
| 107 | return (u_ctrl_val * 10) << b_gain_sft; |
| 108 | } |
| 109 | |
| 110 | static inline unsigned int rt715_sdca_get_gain(unsigned int reg_val, |
| 111 | unsigned int gain_sft) |
| 112 | { |
| 113 | unsigned int neg_flag = 0; |
| 114 | |
| 115 | if (reg_val & BIT(15)) { |
| 116 | reg_val = ~(reg_val - 1) & 0xffff; |
| 117 | neg_flag = 1; |
| 118 | } |
| 119 | reg_val *= 1000; |
| 120 | reg_val >>= 8; |
| 121 | if (neg_flag) |
| 122 | reg_val = gain_sft - reg_val / RT715_SDCA_DB_STEP; |
| 123 | else |
| 124 | reg_val = gain_sft + reg_val / RT715_SDCA_DB_STEP; |
| 125 | |
| 126 | return reg_val; |
| 127 | } |
| 128 | |
| 129 | /* SDCA Volume/Boost control */ |
| 130 | static int rt715_sdca_set_amp_gain_put(struct snd_kcontrol *kcontrol, |
| 131 | struct snd_ctl_elem_value *ucontrol) |
| 132 | { |
| 133 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 134 | struct soc_mixer_control *mc = |
| 135 | (struct soc_mixer_control *)kcontrol->private_value; |
| 136 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 137 | unsigned int gain_val, i, k_changed = 0; |
| 138 | int ret; |
| 139 | |
| 140 | for (i = 0; i < 2; i++) { |
| 141 | if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_orig[i]) { |
| 142 | k_changed = 1; |
| 143 | break; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | for (i = 0; i < 2; i++) { |
| 148 | rt715->kctl_2ch_orig[i] = ucontrol->value.integer.value[i]; |
| 149 | gain_val = |
| 150 | rt715_sdca_vol_gain(ucontrol->value.integer.value[i], mc->max, |
| 151 | mc->shift); |
| 152 | ret = regmap_write(rt715->mbq_regmap, mc->reg + i, gain_val); |
| 153 | if (ret != 0) { |
| 154 | dev_err(component->dev, "Failed to write 0x%x=0x%x\n", |
| 155 | mc->reg + i, gain_val); |
| 156 | return ret; |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | return k_changed; |
| 161 | } |
| 162 | |
| 163 | static int rt715_sdca_set_amp_gain_4ch_put(struct snd_kcontrol *kcontrol, |
| 164 | struct snd_ctl_elem_value *ucontrol) |
| 165 | { |
| 166 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 167 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 168 | struct rt715_sdca_kcontrol_private *p = |
| 169 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 170 | unsigned int reg_base = p->reg_base, k_changed = 0; |
| 171 | const unsigned int gain_sft = 0x2f; |
| 172 | unsigned int gain_val, i; |
| 173 | int ret; |
| 174 | |
| 175 | for (i = 0; i < 4; i++) { |
| 176 | if (ucontrol->value.integer.value[i] != rt715->kctl_4ch_orig[i]) { |
| 177 | k_changed = 1; |
| 178 | break; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | for (i = 0; i < 4; i++) { |
| 183 | rt715->kctl_4ch_orig[i] = ucontrol->value.integer.value[i]; |
| 184 | gain_val = |
| 185 | rt715_sdca_vol_gain(ucontrol->value.integer.value[i], p->max, |
| 186 | gain_sft); |
| 187 | ret = regmap_write(rt715->mbq_regmap, reg_base + i, |
| 188 | gain_val); |
| 189 | if (ret != 0) { |
| 190 | dev_err(component->dev, "Failed to write 0x%x=0x%x\n", |
| 191 | reg_base + i, gain_val); |
| 192 | return ret; |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | return k_changed; |
| 197 | } |
| 198 | |
| 199 | static int rt715_sdca_set_amp_gain_8ch_put(struct snd_kcontrol *kcontrol, |
| 200 | struct snd_ctl_elem_value *ucontrol) |
| 201 | { |
| 202 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 203 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 204 | struct rt715_sdca_kcontrol_private *p = |
| 205 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 206 | unsigned int reg_base = p->reg_base, i, k_changed = 0; |
| 207 | const unsigned int gain_sft = 8; |
| 208 | unsigned int gain_val, reg; |
| 209 | int ret; |
| 210 | |
| 211 | for (i = 0; i < 8; i++) { |
| 212 | if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_orig[i]) { |
| 213 | k_changed = 1; |
| 214 | break; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | for (i = 0; i < 8; i++) { |
| 219 | rt715->kctl_8ch_orig[i] = ucontrol->value.integer.value[i]; |
| 220 | gain_val = |
| 221 | rt715_sdca_boost_gain(ucontrol->value.integer.value[i], p->max, |
| 222 | gain_sft); |
| 223 | reg = i < 7 ? reg_base + i : (reg_base - 1) | BIT(15); |
| 224 | ret = regmap_write(rt715->mbq_regmap, reg, gain_val); |
| 225 | if (ret != 0) { |
| 226 | dev_err(component->dev, "Failed to write 0x%x=0x%x\n", |
| 227 | reg, gain_val); |
| 228 | return ret; |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | return k_changed; |
| 233 | } |
| 234 | |
| 235 | static int rt715_sdca_set_amp_gain_get(struct snd_kcontrol *kcontrol, |
| 236 | struct snd_ctl_elem_value *ucontrol) |
| 237 | { |
| 238 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 239 | struct soc_mixer_control *mc = |
| 240 | (struct soc_mixer_control *)kcontrol->private_value; |
| 241 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 242 | unsigned int val, i; |
| 243 | int ret; |
| 244 | |
| 245 | for (i = 0; i < 2; i++) { |
| 246 | ret = regmap_read(rt715->mbq_regmap, mc->reg + i, &val); |
| 247 | if (ret < 0) { |
| 248 | dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", |
| 249 | mc->reg + i, ret); |
| 250 | return ret; |
| 251 | } |
| 252 | ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, mc->shift); |
| 253 | } |
| 254 | |
| 255 | return 0; |
| 256 | } |
| 257 | |
| 258 | static int rt715_sdca_set_amp_gain_4ch_get(struct snd_kcontrol *kcontrol, |
| 259 | struct snd_ctl_elem_value *ucontrol) |
| 260 | { |
| 261 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 262 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 263 | struct rt715_sdca_kcontrol_private *p = |
| 264 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 265 | unsigned int reg_base = p->reg_base, i; |
| 266 | const unsigned int gain_sft = 0x2f; |
| 267 | unsigned int val; |
| 268 | int ret; |
| 269 | |
| 270 | for (i = 0; i < 4; i++) { |
| 271 | ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val); |
| 272 | if (ret < 0) { |
| 273 | dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", |
| 274 | reg_base + i, ret); |
| 275 | return ret; |
| 276 | } |
| 277 | ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, gain_sft); |
| 278 | } |
| 279 | |
| 280 | return 0; |
| 281 | } |
| 282 | |
| 283 | static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol, |
| 284 | struct snd_ctl_elem_value *ucontrol) |
| 285 | { |
| 286 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 287 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 288 | struct rt715_sdca_kcontrol_private *p = |
| 289 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 290 | unsigned int reg_base = p->reg_base; |
| 291 | const unsigned int gain_sft = 8; |
| 292 | unsigned int val_l, val_r; |
| 293 | unsigned int i, reg; |
| 294 | int ret; |
| 295 | |
| 296 | for (i = 0; i < 8; i += 2) { |
| 297 | ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val_l); |
| 298 | if (ret < 0) { |
| 299 | dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", |
| 300 | reg_base + i, ret); |
| 301 | return ret; |
| 302 | } |
| 303 | ucontrol->value.integer.value[i] = (val_l >> gain_sft) / 10; |
| 304 | |
| 305 | reg = (i == 6) ? (reg_base - 1) | BIT(15) : reg_base + 1 + i; |
| 306 | ret = regmap_read(rt715->mbq_regmap, reg, &val_r); |
| 307 | if (ret < 0) { |
| 308 | dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", |
| 309 | reg, ret); |
| 310 | return ret; |
| 311 | } |
| 312 | ucontrol->value.integer.value[i + 1] = (val_r >> gain_sft) / 10; |
| 313 | } |
| 314 | |
| 315 | return 0; |
| 316 | } |
| 317 | |
| 318 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0); |
| 319 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); |
| 320 | |
| 321 | static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol, |
| 322 | struct snd_ctl_elem_value *ucontrol) |
| 323 | { |
| 324 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 325 | struct rt715_sdca_kcontrol_private *p = |
| 326 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 327 | unsigned int reg_base = p->reg_base; |
| 328 | unsigned int invert = p->invert, i; |
| 329 | int val; |
| 330 | |
| 331 | for (i = 0; i < p->count; i += 2) { |
| 332 | val = snd_soc_component_read(component, reg_base + i); |
| 333 | if (val < 0) |
| 334 | return -EINVAL; |
| 335 | ucontrol->value.integer.value[i] = invert ? p->max - val : val; |
| 336 | |
| 337 | val = snd_soc_component_read(component, reg_base + 1 + i); |
| 338 | if (val < 0) |
| 339 | return -EINVAL; |
| 340 | ucontrol->value.integer.value[i + 1] = |
| 341 | invert ? p->max - val : val; |
| 342 | } |
| 343 | |
| 344 | return 0; |
| 345 | } |
| 346 | |
| 347 | static int rt715_sdca_put_volsw(struct snd_kcontrol *kcontrol, |
| 348 | struct snd_ctl_elem_value *ucontrol) |
| 349 | { |
| 350 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
| 351 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 352 | struct rt715_sdca_kcontrol_private *p = |
| 353 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 354 | unsigned int val[4] = {0}, val_mask, i, k_changed = 0; |
| 355 | unsigned int reg = p->reg_base; |
| 356 | unsigned int shift = p->shift; |
| 357 | unsigned int max = p->max; |
| 358 | unsigned int mask = (1 << fls(max)) - 1; |
| 359 | unsigned int invert = p->invert; |
| 360 | int err; |
| 361 | |
| 362 | for (i = 0; i < 4; i++) { |
| 363 | if (ucontrol->value.integer.value[i] != rt715->kctl_switch_orig[i]) { |
| 364 | k_changed = 1; |
| 365 | break; |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | for (i = 0; i < 2; i++) { |
| 370 | rt715->kctl_switch_orig[i * 2] = ucontrol->value.integer.value[i * 2]; |
| 371 | val[i * 2] = ucontrol->value.integer.value[i * 2] & mask; |
| 372 | if (invert) |
| 373 | val[i * 2] = max - val[i * 2]; |
| 374 | val_mask = mask << shift; |
| 375 | val[i * 2] <<= shift; |
| 376 | |
| 377 | rt715->kctl_switch_orig[i * 2 + 1] = |
| 378 | ucontrol->value.integer.value[i * 2 + 1]; |
| 379 | val[i * 2 + 1] = |
| 380 | ucontrol->value.integer.value[i * 2 + 1] & mask; |
| 381 | if (invert) |
| 382 | val[i * 2 + 1] = max - val[i * 2 + 1]; |
| 383 | |
| 384 | val[i * 2 + 1] <<= shift; |
| 385 | |
| 386 | err = snd_soc_component_update_bits(component, reg + i * 2, val_mask, |
| 387 | val[i * 2]); |
| 388 | if (err < 0) |
| 389 | return err; |
| 390 | |
| 391 | err = snd_soc_component_update_bits(component, reg + 1 + i * 2, |
| 392 | val_mask, val[i * 2 + 1]); |
| 393 | if (err < 0) |
| 394 | return err; |
| 395 | } |
| 396 | |
| 397 | return k_changed; |
| 398 | } |
| 399 | |
| 400 | static int rt715_sdca_fu_info(struct snd_kcontrol *kcontrol, |
| 401 | struct snd_ctl_elem_info *uinfo) |
| 402 | { |
| 403 | struct rt715_sdca_kcontrol_private *p = |
| 404 | (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; |
| 405 | |
| 406 | if (p->max == 1) |
| 407 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
| 408 | else |
| 409 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 410 | uinfo->count = p->count; |
| 411 | uinfo->value.integer.min = 0; |
| 412 | uinfo->value.integer.max = p->max; |
| 413 | return 0; |
| 414 | } |
| 415 | |
| 416 | #define RT715_SDCA_PR_VALUE(xreg_base, xcount, xmax, xshift, xinvert) \ |
| 417 | ((unsigned long)&(struct rt715_sdca_kcontrol_private) \ |
| 418 | {.reg_base = xreg_base, .count = xcount, .max = xmax, \ |
| 419 | .shift = xshift, .invert = xinvert}) |
| 420 | |
| 421 | #define RT715_SDCA_FU_CTRL(xname, reg_base, xshift, xmax, xinvert, xcount) \ |
| 422 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 423 | .info = rt715_sdca_fu_info, \ |
| 424 | .get = rt715_sdca_get_volsw, \ |
| 425 | .put = rt715_sdca_put_volsw, \ |
| 426 | .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, \ |
| 427 | xshift, xinvert)} |
| 428 | |
| 429 | #define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
| 430 | xhandler_get, xhandler_put) \ |
| 431 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 432 | .info = snd_soc_info_volsw, \ |
| 433 | .get = xhandler_get, .put = xhandler_put, \ |
| 434 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ |
| 435 | xmax, xinvert) } |
| 436 | |
| 437 | #define RT715_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ |
| 438 | xhandler_put, tlv_array, xcount, xmax) \ |
| 439 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 440 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
| 441 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
| 442 | .tlv.p = (tlv_array), \ |
| 443 | .info = rt715_sdca_fu_info, \ |
| 444 | .get = xhandler_get, .put = xhandler_put, \ |
| 445 | .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) } |
| 446 | |
| 447 | #define RT715_SDCA_BOOST_EXT_TLV(xname, reg_base, xhandler_get,\ |
| 448 | xhandler_put, tlv_array, xcount, xmax) \ |
| 449 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 450 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
| 451 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
| 452 | .tlv.p = (tlv_array), \ |
| 453 | .info = rt715_sdca_fu_info, \ |
| 454 | .get = xhandler_get, .put = xhandler_put, \ |
| 455 | .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) } |
| 456 | |
| 457 | static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = { |
| 458 | /* Capture switch */ |
| 459 | SOC_DOUBLE_R("FU0A Capture Switch", |
| 460 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, |
| 461 | RT715_SDCA_FU_MUTE_CTRL, CH_01), |
| 462 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, |
| 463 | RT715_SDCA_FU_MUTE_CTRL, CH_02), |
| 464 | 0, 1, 1), |
| 465 | RT715_SDCA_FU_CTRL("FU02 Capture Switch", |
| 466 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, |
| 467 | RT715_SDCA_FU_MUTE_CTRL, CH_01), |
| 468 | 0, 1, 1, 4), |
| 469 | RT715_SDCA_FU_CTRL("FU06 Capture Switch", |
| 470 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, |
| 471 | RT715_SDCA_FU_MUTE_CTRL, CH_01), |
| 472 | 0, 1, 1, 4), |
| 473 | /* Volume Control */ |
| 474 | SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume", |
| 475 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, |
| 476 | RT715_SDCA_FU_VOL_CTRL, CH_01), |
| 477 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, |
| 478 | RT715_SDCA_FU_VOL_CTRL, CH_02), |
| 479 | 0x2f, 0x7f, 0, |
| 480 | rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put, |
| 481 | in_vol_tlv), |
| 482 | RT715_SDCA_EXT_TLV("FU02 Capture Volume", |
| 483 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, |
| 484 | RT715_SDCA_FU_VOL_CTRL, CH_01), |
| 485 | rt715_sdca_set_amp_gain_4ch_get, |
| 486 | rt715_sdca_set_amp_gain_4ch_put, |
| 487 | in_vol_tlv, 4, 0x7f), |
| 488 | RT715_SDCA_EXT_TLV("FU06 Capture Volume", |
| 489 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, |
| 490 | RT715_SDCA_FU_VOL_CTRL, CH_01), |
| 491 | rt715_sdca_set_amp_gain_4ch_get, |
| 492 | rt715_sdca_set_amp_gain_4ch_put, |
| 493 | in_vol_tlv, 4, 0x7f), |
| 494 | /* MIC Boost Control */ |
| 495 | RT715_SDCA_BOOST_EXT_TLV("FU0E Boost", |
| 496 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, |
| 497 | RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), |
| 498 | rt715_sdca_set_amp_gain_8ch_get, |
| 499 | rt715_sdca_set_amp_gain_8ch_put, |
| 500 | mic_vol_tlv, 8, 3), |
| 501 | RT715_SDCA_BOOST_EXT_TLV("FU0C Boost", |
| 502 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, |
| 503 | RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), |
| 504 | rt715_sdca_set_amp_gain_8ch_get, |
| 505 | rt715_sdca_set_amp_gain_8ch_put, |
| 506 | mic_vol_tlv, 8, 3), |
| 507 | }; |
| 508 | |
| 509 | static int rt715_sdca_mux_get(struct snd_kcontrol *kcontrol, |
| 510 | struct snd_ctl_elem_value *ucontrol) |
| 511 | { |
| 512 | struct snd_soc_component *component = |
| 513 | snd_soc_dapm_kcontrol_component(kcontrol); |
| 514 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 515 | unsigned int val, mask_sft; |
| 516 | |
| 517 | if (strstr(ucontrol->id.name, "ADC 22 Mux")) |
| 518 | mask_sft = 12; |
| 519 | else if (strstr(ucontrol->id.name, "ADC 23 Mux")) |
| 520 | mask_sft = 8; |
| 521 | else if (strstr(ucontrol->id.name, "ADC 24 Mux")) |
| 522 | mask_sft = 4; |
| 523 | else if (strstr(ucontrol->id.name, "ADC 25 Mux")) |
| 524 | mask_sft = 0; |
| 525 | else |
| 526 | return -EINVAL; |
| 527 | |
| 528 | rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL, |
| 529 | RT715_HDA_LEGACY_MUX_CTL1, &val); |
| 530 | val = (val >> mask_sft) & 0xf; |
| 531 | |
| 532 | /* |
| 533 | * The first two indices of ADC Mux 24/25 are routed to the same |
| 534 | * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2. |
| 535 | * To have a unique set of inputs, we skip the index1 of the muxes. |
| 536 | */ |
| 537 | if ((strstr(ucontrol->id.name, "ADC 24 Mux") || |
| 538 | strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0) |
| 539 | val -= 1; |
| 540 | ucontrol->value.enumerated.item[0] = val; |
| 541 | |
| 542 | return 0; |
| 543 | } |
| 544 | |
| 545 | static int rt715_sdca_mux_put(struct snd_kcontrol *kcontrol, |
| 546 | struct snd_ctl_elem_value *ucontrol) |
| 547 | { |
| 548 | struct snd_soc_component *component = |
| 549 | snd_soc_dapm_kcontrol_component(kcontrol); |
| 550 | struct snd_soc_dapm_context *dapm = |
| 551 | snd_soc_dapm_kcontrol_dapm(kcontrol); |
| 552 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 553 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 554 | unsigned int *item = ucontrol->value.enumerated.item; |
| 555 | unsigned int val, val2 = 0, change, mask_sft; |
| 556 | |
| 557 | if (item[0] >= e->items) |
| 558 | return -EINVAL; |
| 559 | |
| 560 | if (strstr(ucontrol->id.name, "ADC 22 Mux")) |
| 561 | mask_sft = 12; |
| 562 | else if (strstr(ucontrol->id.name, "ADC 23 Mux")) |
| 563 | mask_sft = 8; |
| 564 | else if (strstr(ucontrol->id.name, "ADC 24 Mux")) |
| 565 | mask_sft = 4; |
| 566 | else if (strstr(ucontrol->id.name, "ADC 25 Mux")) |
| 567 | mask_sft = 0; |
| 568 | else |
| 569 | return -EINVAL; |
| 570 | |
| 571 | /* Verb ID = 0x701h, nid = e->reg */ |
| 572 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
| 573 | |
| 574 | rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL, |
| 575 | RT715_HDA_LEGACY_MUX_CTL1, &val2); |
| 576 | val2 = (val2 >> mask_sft) & 0xf; |
| 577 | |
| 578 | change = val != val2; |
| 579 | |
| 580 | if (change) |
| 581 | rt715_sdca_index_update_bits(rt715, RT715_VENDOR_HDA_CTL, |
| 582 | RT715_HDA_LEGACY_MUX_CTL1, 0xf << mask_sft, val << mask_sft); |
| 583 | |
| 584 | snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); |
| 585 | |
| 586 | return change; |
| 587 | } |
| 588 | |
| 589 | static const char * const adc_22_23_mux_text[] = { |
| 590 | "MIC1", |
| 591 | "MIC2", |
| 592 | "LINE1", |
| 593 | "LINE2", |
| 594 | "DMIC1", |
| 595 | "DMIC2", |
| 596 | "DMIC3", |
| 597 | "DMIC4", |
| 598 | }; |
| 599 | |
| 600 | /* |
| 601 | * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and |
| 602 | * 1 will be connected to the same dmic source, therefore we skip index 1 to |
| 603 | * avoid misunderstanding on usage of dapm routing. |
| 604 | */ |
| 605 | static int rt715_adc_24_25_values[] = { |
| 606 | 0, |
| 607 | 2, |
| 608 | 3, |
| 609 | 4, |
| 610 | 5, |
| 611 | }; |
| 612 | |
| 613 | static const char * const adc_24_mux_text[] = { |
| 614 | "MIC2", |
| 615 | "DMIC1", |
| 616 | "DMIC2", |
| 617 | "DMIC3", |
| 618 | "DMIC4", |
| 619 | }; |
| 620 | |
| 621 | static const char * const adc_25_mux_text[] = { |
| 622 | "MIC1", |
| 623 | "DMIC1", |
| 624 | "DMIC2", |
| 625 | "DMIC3", |
| 626 | "DMIC4", |
| 627 | }; |
| 628 | |
| 629 | static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0, |
| 630 | adc_22_23_mux_text); |
| 631 | |
| 632 | static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0, |
| 633 | adc_22_23_mux_text); |
| 634 | |
| 635 | static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum, |
| 636 | SND_SOC_NOPM, 0, 0xf, |
| 637 | adc_24_mux_text, rt715_adc_24_25_values); |
| 638 | static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum, |
| 639 | SND_SOC_NOPM, 0, 0xf, |
| 640 | adc_25_mux_text, rt715_adc_24_25_values); |
| 641 | |
| 642 | static const struct snd_kcontrol_new rt715_adc22_mux = |
| 643 | SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum, |
| 644 | rt715_sdca_mux_get, rt715_sdca_mux_put); |
| 645 | |
| 646 | static const struct snd_kcontrol_new rt715_adc23_mux = |
| 647 | SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum, |
| 648 | rt715_sdca_mux_get, rt715_sdca_mux_put); |
| 649 | |
| 650 | static const struct snd_kcontrol_new rt715_adc24_mux = |
| 651 | SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum, |
| 652 | rt715_sdca_mux_get, rt715_sdca_mux_put); |
| 653 | |
| 654 | static const struct snd_kcontrol_new rt715_adc25_mux = |
| 655 | SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum, |
| 656 | rt715_sdca_mux_get, rt715_sdca_mux_put); |
| 657 | |
| 658 | static int rt715_sdca_pde23_24_event(struct snd_soc_dapm_widget *w, |
| 659 | struct snd_kcontrol *kcontrol, int event) |
| 660 | { |
| 661 | struct snd_soc_component *component = |
| 662 | snd_soc_dapm_to_component(w->dapm); |
| 663 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 664 | |
| 665 | switch (event) { |
| 666 | case SND_SOC_DAPM_POST_PMU: |
| 667 | regmap_write(rt715->regmap, |
| 668 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, |
| 669 | RT715_SDCA_REQ_POW_CTRL, |
| 670 | CH_00), 0x00); |
| 671 | break; |
| 672 | case SND_SOC_DAPM_PRE_PMD: |
| 673 | regmap_write(rt715->regmap, |
| 674 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, |
| 675 | RT715_SDCA_REQ_POW_CTRL, |
| 676 | CH_00), 0x03); |
| 677 | break; |
| 678 | } |
| 679 | return 0; |
| 680 | } |
| 681 | |
| 682 | static const struct snd_soc_dapm_widget rt715_sdca_dapm_widgets[] = { |
| 683 | SND_SOC_DAPM_INPUT("DMIC1"), |
| 684 | SND_SOC_DAPM_INPUT("DMIC2"), |
| 685 | SND_SOC_DAPM_INPUT("DMIC3"), |
| 686 | SND_SOC_DAPM_INPUT("DMIC4"), |
| 687 | SND_SOC_DAPM_INPUT("MIC1"), |
| 688 | SND_SOC_DAPM_INPUT("MIC2"), |
| 689 | SND_SOC_DAPM_INPUT("LINE1"), |
| 690 | SND_SOC_DAPM_INPUT("LINE2"), |
| 691 | |
| 692 | SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0, |
| 693 | rt715_sdca_pde23_24_event, |
| 694 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
| 695 | |
| 696 | SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0), |
| 697 | SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0), |
| 698 | SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0), |
| 699 | SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0), |
| 700 | SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, |
| 701 | &rt715_adc22_mux), |
| 702 | SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, |
| 703 | &rt715_adc23_mux), |
| 704 | SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0, |
| 705 | &rt715_adc24_mux), |
| 706 | SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0, |
| 707 | &rt715_adc25_mux), |
| 708 | SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), |
| 709 | SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0), |
| 710 | }; |
| 711 | |
| 712 | static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { |
| 713 | {"DP6TX", NULL, "ADC 09"}, |
| 714 | {"DP6TX", NULL, "ADC 08"}, |
| 715 | {"DP4TX", NULL, "ADC 07"}, |
| 716 | {"DP4TX", NULL, "ADC 27"}, |
| 717 | {"DP4TX", NULL, "ADC 09"}, |
| 718 | {"DP4TX", NULL, "ADC 08"}, |
| 719 | |
| 720 | {"LINE1", NULL, "PDE23_24"}, |
| 721 | {"LINE2", NULL, "PDE23_24"}, |
| 722 | {"MIC1", NULL, "PDE23_24"}, |
| 723 | {"MIC2", NULL, "PDE23_24"}, |
| 724 | {"DMIC1", NULL, "PDE23_24"}, |
| 725 | {"DMIC2", NULL, "PDE23_24"}, |
| 726 | {"DMIC3", NULL, "PDE23_24"}, |
| 727 | {"DMIC4", NULL, "PDE23_24"}, |
| 728 | |
| 729 | {"ADC 09", NULL, "ADC 22 Mux"}, |
| 730 | {"ADC 08", NULL, "ADC 23 Mux"}, |
| 731 | {"ADC 07", NULL, "ADC 24 Mux"}, |
| 732 | {"ADC 27", NULL, "ADC 25 Mux"}, |
| 733 | {"ADC 22 Mux", "MIC1", "MIC1"}, |
| 734 | {"ADC 22 Mux", "MIC2", "MIC2"}, |
| 735 | {"ADC 22 Mux", "LINE1", "LINE1"}, |
| 736 | {"ADC 22 Mux", "LINE2", "LINE2"}, |
| 737 | {"ADC 22 Mux", "DMIC1", "DMIC1"}, |
| 738 | {"ADC 22 Mux", "DMIC2", "DMIC2"}, |
| 739 | {"ADC 22 Mux", "DMIC3", "DMIC3"}, |
| 740 | {"ADC 22 Mux", "DMIC4", "DMIC4"}, |
| 741 | {"ADC 23 Mux", "MIC1", "MIC1"}, |
| 742 | {"ADC 23 Mux", "MIC2", "MIC2"}, |
| 743 | {"ADC 23 Mux", "LINE1", "LINE1"}, |
| 744 | {"ADC 23 Mux", "LINE2", "LINE2"}, |
| 745 | {"ADC 23 Mux", "DMIC1", "DMIC1"}, |
| 746 | {"ADC 23 Mux", "DMIC2", "DMIC2"}, |
| 747 | {"ADC 23 Mux", "DMIC3", "DMIC3"}, |
| 748 | {"ADC 23 Mux", "DMIC4", "DMIC4"}, |
| 749 | {"ADC 24 Mux", "MIC2", "MIC2"}, |
| 750 | {"ADC 24 Mux", "DMIC1", "DMIC1"}, |
| 751 | {"ADC 24 Mux", "DMIC2", "DMIC2"}, |
| 752 | {"ADC 24 Mux", "DMIC3", "DMIC3"}, |
| 753 | {"ADC 24 Mux", "DMIC4", "DMIC4"}, |
| 754 | {"ADC 25 Mux", "MIC1", "MIC1"}, |
| 755 | {"ADC 25 Mux", "DMIC1", "DMIC1"}, |
| 756 | {"ADC 25 Mux", "DMIC2", "DMIC2"}, |
| 757 | {"ADC 25 Mux", "DMIC3", "DMIC3"}, |
| 758 | {"ADC 25 Mux", "DMIC4", "DMIC4"}, |
| 759 | }; |
| 760 | |
| 761 | static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { |
| 762 | .controls = rt715_sdca_snd_controls, |
| 763 | .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls), |
| 764 | .dapm_widgets = rt715_sdca_dapm_widgets, |
| 765 | .num_dapm_widgets = ARRAY_SIZE(rt715_sdca_dapm_widgets), |
| 766 | .dapm_routes = rt715_sdca_audio_map, |
| 767 | .num_dapm_routes = ARRAY_SIZE(rt715_sdca_audio_map), |
| 768 | }; |
| 769 | |
| 770 | static int rt715_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, |
| 771 | int direction) |
| 772 | { |
| 773 | struct rt715_sdw_stream_data *stream; |
| 774 | |
| 775 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
| 776 | if (!stream) |
| 777 | return -ENOMEM; |
| 778 | |
| 779 | stream->sdw_stream = sdw_stream; |
| 780 | |
| 781 | /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ |
| 782 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) |
| 783 | dai->playback_dma_data = stream; |
| 784 | else |
| 785 | dai->capture_dma_data = stream; |
| 786 | |
| 787 | return 0; |
| 788 | } |
| 789 | |
| 790 | static void rt715_sdca_shutdown(struct snd_pcm_substream *substream, |
| 791 | struct snd_soc_dai *dai) |
| 792 | |
| 793 | { |
| 794 | struct rt715_sdw_stream_data *stream; |
| 795 | |
| 796 | stream = snd_soc_dai_get_dma_data(dai, substream); |
| 797 | if (!stream) |
| 798 | return; |
| 799 | |
| 800 | snd_soc_dai_set_dma_data(dai, substream, NULL); |
| 801 | kfree(stream); |
| 802 | } |
| 803 | |
| 804 | static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream, |
| 805 | struct snd_pcm_hw_params *params, |
| 806 | struct snd_soc_dai *dai) |
| 807 | { |
| 808 | struct snd_soc_component *component = dai->component; |
| 809 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 810 | struct sdw_stream_config stream_config; |
| 811 | struct sdw_port_config port_config; |
| 812 | enum sdw_data_direction direction; |
| 813 | struct rt715_sdw_stream_data *stream; |
| 814 | int retval, port, num_channels; |
| 815 | unsigned int val; |
| 816 | |
| 817 | stream = snd_soc_dai_get_dma_data(dai, substream); |
| 818 | |
| 819 | if (!stream) |
| 820 | return -EINVAL; |
| 821 | |
| 822 | if (!rt715->slave) |
| 823 | return -EINVAL; |
| 824 | |
| 825 | switch (dai->id) { |
| 826 | case RT715_AIF1: |
| 827 | direction = SDW_DATA_DIR_TX; |
| 828 | port = 6; |
| 829 | rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, |
| 830 | 0xa500); |
| 831 | break; |
| 832 | case RT715_AIF2: |
| 833 | direction = SDW_DATA_DIR_TX; |
| 834 | port = 4; |
| 835 | rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, |
| 836 | 0xaf00); |
| 837 | break; |
| 838 | default: |
| 839 | dev_err(component->dev, "Invalid DAI id %d\n", dai->id); |
| 840 | return -EINVAL; |
| 841 | } |
| 842 | |
| 843 | stream_config.frame_rate = params_rate(params); |
| 844 | stream_config.ch_count = params_channels(params); |
| 845 | stream_config.bps = snd_pcm_format_width(params_format(params)); |
| 846 | stream_config.direction = direction; |
| 847 | |
| 848 | num_channels = params_channels(params); |
| 849 | port_config.ch_mask = GENMASK(num_channels - 1, 0); |
| 850 | port_config.num = port; |
| 851 | |
| 852 | retval = sdw_stream_add_slave(rt715->slave, &stream_config, |
| 853 | &port_config, 1, stream->sdw_stream); |
| 854 | if (retval) { |
| 855 | dev_err(component->dev, "Unable to configure port, retval:%d\n", |
| 856 | retval); |
| 857 | return retval; |
| 858 | } |
| 859 | |
| 860 | switch (params_rate(params)) { |
| 861 | case 8000: |
| 862 | val = 0x1; |
| 863 | break; |
| 864 | case 11025: |
| 865 | val = 0x2; |
| 866 | break; |
| 867 | case 12000: |
| 868 | val = 0x3; |
| 869 | break; |
| 870 | case 16000: |
| 871 | val = 0x4; |
| 872 | break; |
| 873 | case 22050: |
| 874 | val = 0x5; |
| 875 | break; |
| 876 | case 24000: |
| 877 | val = 0x6; |
| 878 | break; |
| 879 | case 32000: |
| 880 | val = 0x7; |
| 881 | break; |
| 882 | case 44100: |
| 883 | val = 0x8; |
| 884 | break; |
| 885 | case 48000: |
| 886 | val = 0x9; |
| 887 | break; |
| 888 | case 88200: |
| 889 | val = 0xa; |
| 890 | break; |
| 891 | case 96000: |
| 892 | val = 0xb; |
| 893 | break; |
| 894 | case 176400: |
| 895 | val = 0xc; |
| 896 | break; |
| 897 | case 192000: |
| 898 | val = 0xd; |
| 899 | break; |
| 900 | case 384000: |
| 901 | val = 0xe; |
| 902 | break; |
| 903 | case 768000: |
| 904 | val = 0xf; |
| 905 | break; |
| 906 | default: |
| 907 | dev_err(component->dev, "Unsupported sample rate %d\n", |
| 908 | params_rate(params)); |
| 909 | return -EINVAL; |
| 910 | } |
| 911 | |
| 912 | regmap_write(rt715->regmap, |
| 913 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN, |
| 914 | RT715_SDCA_FREQ_IND_CTRL, CH_00), val); |
| 915 | |
| 916 | return 0; |
| 917 | } |
| 918 | |
| 919 | static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream, |
| 920 | struct snd_soc_dai *dai) |
| 921 | { |
| 922 | struct snd_soc_component *component = dai->component; |
| 923 | struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); |
| 924 | struct rt715_sdw_stream_data *stream = |
| 925 | snd_soc_dai_get_dma_data(dai, substream); |
| 926 | |
| 927 | if (!rt715->slave) |
| 928 | return -EINVAL; |
| 929 | |
| 930 | sdw_stream_remove_slave(rt715->slave, stream->sdw_stream); |
| 931 | return 0; |
| 932 | } |
| 933 | |
| 934 | #define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
| 935 | #define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
| 936 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) |
| 937 | |
Ye Bin | 1f34084 | 2021-04-08 14:26:54 +0800 | [diff] [blame] | 938 | static const struct snd_soc_dai_ops rt715_sdca_ops = { |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 939 | .hw_params = rt715_sdca_pcm_hw_params, |
| 940 | .hw_free = rt715_sdca_pcm_hw_free, |
Pierre-Louis Bossart | e844456 | 2021-12-24 10:10:31 +0800 | [diff] [blame] | 941 | .set_stream = rt715_sdca_set_sdw_stream, |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 942 | .shutdown = rt715_sdca_shutdown, |
| 943 | }; |
| 944 | |
| 945 | static struct snd_soc_dai_driver rt715_sdca_dai[] = { |
| 946 | { |
| 947 | .name = "rt715-aif1", |
| 948 | .id = RT715_AIF1, |
| 949 | .capture = { |
| 950 | .stream_name = "DP6 Capture", |
| 951 | .channels_min = 1, |
| 952 | .channels_max = 2, |
| 953 | .rates = RT715_STEREO_RATES, |
| 954 | .formats = RT715_FORMATS, |
| 955 | }, |
| 956 | .ops = &rt715_sdca_ops, |
| 957 | }, |
| 958 | { |
| 959 | .name = "rt715-aif2", |
| 960 | .id = RT715_AIF2, |
| 961 | .capture = { |
| 962 | .stream_name = "DP4 Capture", |
| 963 | .channels_min = 1, |
| 964 | .channels_max = 2, |
| 965 | .rates = RT715_STEREO_RATES, |
| 966 | .formats = RT715_FORMATS, |
| 967 | }, |
| 968 | .ops = &rt715_sdca_ops, |
| 969 | }, |
| 970 | }; |
| 971 | |
| 972 | /* Bus clock frequency */ |
| 973 | #define RT715_CLK_FREQ_9600000HZ 9600000 |
| 974 | #define RT715_CLK_FREQ_12000000HZ 12000000 |
| 975 | #define RT715_CLK_FREQ_6000000HZ 6000000 |
| 976 | #define RT715_CLK_FREQ_4800000HZ 4800000 |
| 977 | #define RT715_CLK_FREQ_2400000HZ 2400000 |
| 978 | #define RT715_CLK_FREQ_12288000HZ 12288000 |
| 979 | |
| 980 | int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, |
| 981 | struct regmap *regmap, struct sdw_slave *slave) |
| 982 | { |
| 983 | struct rt715_sdca_priv *rt715; |
| 984 | int ret; |
| 985 | |
| 986 | rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL); |
| 987 | if (!rt715) |
| 988 | return -ENOMEM; |
| 989 | |
| 990 | dev_set_drvdata(dev, rt715); |
| 991 | rt715->slave = slave; |
| 992 | rt715->regmap = regmap; |
| 993 | rt715->mbq_regmap = mbq_regmap; |
| 994 | rt715->hw_sdw_ver = slave->id.sdw_version; |
| 995 | /* |
| 996 | * Mark hw_init to false |
| 997 | * HW init will be performed when device reports present |
| 998 | */ |
| 999 | rt715->hw_init = false; |
Pierre-Louis Bossart | d34d089 | 2021-06-07 17:22:33 -0500 | [diff] [blame] | 1000 | rt715->first_hw_init = false; |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 1001 | |
| 1002 | ret = devm_snd_soc_register_component(dev, |
| 1003 | &soc_codec_dev_rt715_sdca, |
| 1004 | rt715_sdca_dai, |
| 1005 | ARRAY_SIZE(rt715_sdca_dai)); |
| 1006 | |
| 1007 | return ret; |
| 1008 | } |
| 1009 | |
| 1010 | int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) |
| 1011 | { |
| 1012 | struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); |
| 1013 | unsigned int hw_ver; |
| 1014 | |
| 1015 | if (rt715->hw_init) |
| 1016 | return 0; |
| 1017 | |
| 1018 | /* |
| 1019 | * PM runtime is only enabled when a Slave reports as Attached |
| 1020 | */ |
Pierre-Louis Bossart | d34d089 | 2021-06-07 17:22:33 -0500 | [diff] [blame] | 1021 | if (!rt715->first_hw_init) { |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 1022 | /* set autosuspend parameters */ |
| 1023 | pm_runtime_set_autosuspend_delay(&slave->dev, 3000); |
| 1024 | pm_runtime_use_autosuspend(&slave->dev); |
| 1025 | |
| 1026 | /* update count of parent 'active' children */ |
| 1027 | pm_runtime_set_active(&slave->dev); |
| 1028 | |
| 1029 | /* make sure the device does not suspend immediately */ |
| 1030 | pm_runtime_mark_last_busy(&slave->dev); |
| 1031 | |
| 1032 | pm_runtime_enable(&slave->dev); |
| 1033 | |
Pierre-Louis Bossart | d34d089 | 2021-06-07 17:22:33 -0500 | [diff] [blame] | 1034 | rt715->first_hw_init = true; |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 1035 | } |
| 1036 | |
| 1037 | pm_runtime_get_noresume(&slave->dev); |
| 1038 | |
| 1039 | rt715_sdca_index_read(rt715, RT715_VENDOR_REG, |
| 1040 | RT715_PRODUCT_NUM, &hw_ver); |
| 1041 | hw_ver = hw_ver & 0x000f; |
| 1042 | |
| 1043 | /* set clock selector = external */ |
| 1044 | regmap_write(rt715->regmap, |
| 1045 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, |
| 1046 | RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1); |
| 1047 | /* set GPIO_4/5/6 to be 3rd/4th DMIC usage */ |
| 1048 | if (hw_ver == 0x0) |
| 1049 | rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, |
| 1050 | RT715_AD_FUNC_EN, 0x54, 0x54); |
| 1051 | else if (hw_ver == 0x1) { |
| 1052 | rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, |
| 1053 | RT715_AD_FUNC_EN, 0x55, 0x55); |
| 1054 | rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, |
| 1055 | RT715_REV_1, 0x40, 0x40); |
| 1056 | } |
Jack Yu | e343d34a | 2021-06-07 17:22:35 -0500 | [diff] [blame] | 1057 | /* DFLL Calibration trigger */ |
| 1058 | rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, |
| 1059 | RT715_DFLL_VAD, 0x1, 0x1); |
Jack Yu | 20d1705 | 2021-03-02 18:30:42 +0800 | [diff] [blame] | 1060 | /* trigger mode = VAD enable */ |
| 1061 | regmap_write(rt715->regmap, |
| 1062 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, |
| 1063 | RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2); |
| 1064 | /* SMPU-1 interrupt enable mask */ |
| 1065 | regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1); |
| 1066 | |
| 1067 | /* Mark Slave initialization complete */ |
| 1068 | rt715->hw_init = true; |
| 1069 | |
| 1070 | pm_runtime_mark_last_busy(&slave->dev); |
| 1071 | pm_runtime_put_autosuspend(&slave->dev); |
| 1072 | |
| 1073 | return 0; |
| 1074 | } |
| 1075 | |
| 1076 | MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA"); |
| 1077 | MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); |
| 1078 | MODULE_LICENSE("GPL v2"); |