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