1 // SPDX-License-Identifier: GPL-2.0-only OR MI 1 2 // 3 // Analog Devices' SSM3515 audio amp driver 4 // 5 // Copyright (C) The Asahi Linux Contributors 6 7 #include <linux/bits.h> 8 #include <linux/bitfield.h> 9 #include <linux/device.h> 10 #include <linux/i2c.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/regmap.h> 14 15 #include <sound/pcm.h> 16 #include <sound/pcm_params.h> 17 #include <sound/soc.h> 18 #include <sound/tlv.h> 19 20 21 #define SSM3515_PWR 0x00 22 #define SSM3515_PWR_APWDN_EN BIT(7) 23 #define SSM3515_PWR_BSNS_PWDN BIT(6) 24 #define SSM3515_PWR_S_RST BIT(1) 25 #define SSM3515_PWR_SPWDN BIT(0) 26 27 #define SSM3515_GEC 0x01 28 #define SSM3515_GEC_EDGE BIT(4) 29 #define SSM3515_GEC_EDGE_SHIFT 4 30 #define SSM3515_GEC_ANA_GAIN GENMASK(1, 0) 31 32 #define SSM3515_DAC 0x02 33 #define SSM3515_DAC_HV BIT(7) 34 #define SSM3515_DAC_MUTE BIT(6) 35 #define SSM3515_DAC_HPF BIT(5) 36 #define SSM3515_DAC_LPM BIT(4) 37 #define SSM3515_DAC_FS GENMASK(2, 0) 38 39 #define SSM3515_DAC_VOL 0x03 40 41 #define SSM3515_SAI1 0x04 42 #define SSM3515_SAI1_DAC_POL BIT(7) 43 #define SSM3515_SAI1_BCLK_POL BIT(6) 44 #define SSM3515_SAI1_TDM_BCLKS GENMASK(5, 3) 45 #define SSM3515_SAI1_FSYNC_MODE BIT(2) 46 #define SSM3515_SAI1_SDATA_FMT BIT(1) 47 #define SSM3515_SAI1_SAI_MODE BIT(0) 48 49 #define SSM3515_SAI2 0x05 50 #define SSM3515_SAI2_DATA_WIDTH BIT(7) 51 #define SSM3515_SAI2_AUTO_SLOT BIT(4) 52 #define SSM3515_SAI2_TDM_SLOT GENMASK(3, 0) 53 54 #define SSM3515_VBAT_OUT 0x06 55 56 #define SSM3515_STATUS 0x0a 57 #define SSM3515_STATUS_UVLO_REG BIT(6) 58 #define SSM3515_STATUS_LIM_EG BIT(5) 59 #define SSM3515_STATUS_CLIP BIT(4) 60 #define SSM3515_STATUS_AMP_OC BIT(3) 61 #define SSM3515_STATUS_OTF BIT(2) 62 #define SSM3515_STATUS_OTW BIT(1) 63 #define SSM3515_STATUS_BAT_WARN BIT(0) 64 65 static bool ssm3515_volatile_reg(struct device 66 { 67 switch (reg) { 68 case SSM3515_STATUS: 69 case SSM3515_VBAT_OUT: 70 return true; 71 72 default: 73 return false; 74 } 75 } 76 77 static const struct reg_default ssm3515_reg_de 78 { SSM3515_PWR, 0x81 }, 79 { SSM3515_GEC, 0x01 }, 80 { SSM3515_DAC, 0x32 }, 81 { SSM3515_DAC_VOL, 0x40 }, 82 { SSM3515_SAI1, 0x11 }, 83 { SSM3515_SAI2, 0x00 }, 84 }; 85 86 static const struct regmap_config ssm3515_i2c_ 87 .reg_bits = 8, 88 .val_bits = 8, 89 .volatile_reg = ssm3515_volatile_reg, 90 .max_register = 0xb, 91 .reg_defaults = ssm3515_reg_defaults, 92 .num_reg_defaults = ARRAY_SIZE(ssm3515 93 .cache_type = REGCACHE_FLAT, 94 }; 95 96 struct ssm3515_data { 97 struct device *dev; 98 struct regmap *regmap; 99 }; 100 101 // The specced range is -71.25...24.00 dB with 102 // and a mute item below that. This is represe 103 // with the mute item mapped onto the low end. 104 static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_ 105 106 static const char * const ssm3515_ana_gain_tex 107 "8.4 V Span", "12.6 V Span", "14 V Spa 108 }; 109 110 static SOC_ENUM_SINGLE_DECL(ssm3515_ana_gain_e 111 __bf_shf(SSM3515_G 112 ssm3515_ana_gain_t 113 114 static const struct snd_kcontrol_new ssm3515_s 115 SOC_SINGLE_TLV("DAC Playback Volume", 116 0, 255, 1, ssm3515_dac_ 117 SOC_SINGLE("Low EMI Mode Switch", SSM3 118 __bf_shf(SSM3515_GEC_EDGE), 119 SOC_SINGLE("Soft Volume Ramping Switch 120 __bf_shf(SSM3515_DAC_HV), 1 121 SOC_SINGLE("HPF Switch", SSM3515_DAC, 122 __bf_shf(SSM3515_DAC_HPF), 123 SOC_SINGLE("DAC Invert Switch", SSM351 124 __bf_shf(SSM3515_SAI1_DAC_P 125 SOC_ENUM("DAC Analog Gain Select", ssm 126 }; 127 128 static void ssm3515_read_faults(struct snd_soc 129 { 130 int ret; 131 132 ret = snd_soc_component_read(component 133 if (ret <= 0) { 134 /* 135 * If the read was erroneous, 136 * and that's all that's appro 137 */ 138 return; 139 } 140 141 dev_err(component->dev, "device report 142 FIELD_GET(SSM3515_STATUS_UVLO_ 143 FIELD_GET(SSM3515_STATUS_LIM_E 144 FIELD_GET(SSM3515_STATUS_CLIP, 145 FIELD_GET(SSM3515_STATUS_AMP_O 146 FIELD_GET(SSM3515_STATUS_OTF, 147 FIELD_GET(SSM3515_STATUS_OTW, 148 FIELD_GET(SSM3515_STATUS_BAT_W 149 } 150 151 static int ssm3515_probe(struct snd_soc_compon 152 { 153 int ret; 154 155 /* Start out muted */ 156 ret = snd_soc_component_update_bits(co 157 SSM3515_DAC_MUTE, SSM3 158 if (ret < 0) 159 return ret; 160 161 /* Disable the 'master power-down' */ 162 ret = snd_soc_component_update_bits(co 163 SSM3515_PWR_SPWDN, 0); 164 if (ret < 0) 165 return ret; 166 167 return 0; 168 } 169 170 static int ssm3515_mute(struct snd_soc_dai *da 171 { 172 int ret; 173 174 ret = snd_soc_component_update_bits(da 175 SS 176 SS 177 FI 178 if (ret < 0) 179 return ret; 180 return 0; 181 } 182 183 static int ssm3515_hw_params(struct snd_pcm_su 184 struct snd_pcm_hw 185 struct snd_soc_da 186 { 187 struct snd_soc_component *component = 188 int ret, rateval; 189 190 switch (params_format(params)) { 191 case SNDRV_PCM_FORMAT_S16: 192 case SNDRV_PCM_FORMAT_S24: 193 ret = snd_soc_component_update 194 SSM3515_SAI2, 195 FIELD_PREP(SSM 196 par 197 if (ret < 0) 198 return ret; 199 break; 200 201 default: 202 return -EINVAL; 203 } 204 205 switch (params_rate(params)) { 206 case 8000 ... 12000: 207 rateval = 0; 208 break; 209 case 16000 ... 24000: 210 rateval = 1; 211 break; 212 case 32000 ... 48000: 213 rateval = 2; 214 break; 215 case 64000 ... 96000: 216 rateval = 3; 217 break; 218 case 128000 ... 192000: 219 rateval = 4; 220 break; 221 case 48001 ... 63999: /* this is ...72 222 rateval = 5; 223 break; 224 default: 225 return -EINVAL; 226 } 227 228 ret = snd_soc_component_update_bits(co 229 SSM3515_DAC, SSM3515_D 230 FIELD_PREP(SSM3515_DAC 231 if (ret < 0) 232 return ret; 233 234 return 0; 235 } 236 237 static int ssm3515_set_fmt(struct snd_soc_dai 238 { 239 struct snd_soc_component *component = 240 bool fpol_inv = false; /* non-inverted 241 int ret; 242 u8 sai1 = 0; 243 244 switch (fmt & SND_SOC_DAIFMT_INV_MASK) 245 case SND_SOC_DAIFMT_IB_NF: 246 case SND_SOC_DAIFMT_IB_IF: 247 sai1 |= SSM3515_SAI1_BCLK_POL; 248 break; 249 } 250 251 switch (fmt & SND_SOC_DAIFMT_FORMAT_MA 252 case SND_SOC_DAIFMT_I2S: 253 fpol_inv = 1; 254 sai1 &= ~SSM3515_SAI1_SDATA_FM 255 break; 256 case SND_SOC_DAIFMT_LEFT_J: 257 fpol_inv = 0; 258 sai1 |= SSM3515_SAI1_SDATA_FMT 259 break; 260 default: 261 return -EINVAL; 262 } 263 264 switch (fmt & SND_SOC_DAIFMT_INV_MASK) 265 case SND_SOC_DAIFMT_NB_IF: 266 case SND_SOC_DAIFMT_IB_IF: 267 fpol_inv ^= 1; 268 break; 269 } 270 271 /* Set the serial input to 'TDM mode' 272 sai1 |= SSM3515_SAI1_SAI_MODE; 273 274 if (fpol_inv) { 275 /* 276 * We configure the codec in a 277 * FSYNC_MODE bit of SAI1 is s 278 * what the datasheet calls 'P 279 * FSYNC mode'. 280 * 281 * Experiments suggest that th 282 * the FSYNC polarity, so go w 283 */ 284 sai1 |= SSM3515_SAI1_FSYNC_MOD 285 } 286 287 ret = snd_soc_component_update_bits(co 288 SSM3515_SAI1_BCLK_POL 289 SSM3515_SAI1_SAI_MODE 290 291 if (ret < 0) 292 return ret; 293 return 0; 294 } 295 296 static int ssm3515_set_tdm_slot(struct snd_soc 297 unsigned int t 298 unsigned int r 299 int slots, int 300 { 301 struct snd_soc_component *component = 302 int slot, tdm_bclks_val, ret; 303 304 if (tx_mask == 0 || rx_mask != 0) 305 return -EINVAL; 306 307 slot = __ffs(tx_mask); 308 309 if (tx_mask & ~BIT(slot)) 310 return -EINVAL; 311 312 switch (slot_width) { 313 case 16: 314 tdm_bclks_val = 0; 315 break; 316 case 24: 317 tdm_bclks_val = 1; 318 break; 319 case 32: 320 tdm_bclks_val = 2; 321 break; 322 case 48: 323 tdm_bclks_val = 3; 324 break; 325 case 64: 326 tdm_bclks_val = 4; 327 break; 328 default: 329 return -EINVAL; 330 } 331 332 ret = snd_soc_component_update_bits(co 333 SSM3515_SAI1_TDM_BCLKS 334 FIELD_PREP(SSM3515_SAI 335 if (ret < 0) 336 return ret; 337 338 ret = snd_soc_component_update_bits(co 339 SSM3515_SAI2_TDM_SLOT, 340 FIELD_PREP(SSM3515_SAI 341 if (ret < 0) 342 return ret; 343 344 return 0; 345 } 346 347 static int ssm3515_hw_free(struct snd_pcm_subs 348 struct snd_soc_dai 349 { 350 /* 351 * We don't get live notification of f 352 * this time, when playback is over, c 353 * over anything and if so, log it. 354 */ 355 ssm3515_read_faults(dai->component); 356 return 0; 357 } 358 359 static const struct snd_soc_dai_ops ssm3515_da 360 .mute_stream = ssm3515_mute, 361 .hw_params = ssm3515_hw_params, 362 .set_fmt = ssm3515_set_fmt, 363 .set_tdm_slot = ssm3515_set_tdm_slot 364 .hw_free = ssm3515_hw_free, 365 }; 366 367 static struct snd_soc_dai_driver ssm3515_dai_d 368 .name = "SSM3515 SAI", 369 .id = 0, 370 .playback = { 371 .stream_name = "Playback", 372 .channels_min = 1, 373 .channels_max = 1, 374 .rates = SNDRV_PCM_RATE_CONTIN 375 .formats = SNDRV_PCM_FMTBIT_S1 376 }, 377 .ops = &ssm3515_dai_ops, 378 }; 379 380 static const struct snd_soc_dapm_widget ssm351 381 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_ 382 SND_SOC_DAPM_OUTPUT("OUT"), 383 }; 384 385 static const struct snd_soc_dapm_route ssm3515 386 {"OUT", NULL, "DAC"}, 387 {"DAC", NULL, "Playback"}, 388 }; 389 390 static const struct snd_soc_component_driver s 391 .probe = ssm3515_probe, 392 .controls = ssm3515_snd_controls, 393 .num_controls = ARRAY_SIZE(ssm3515_snd 394 .dapm_widgets = ssm3515_dapm_widgets, 395 .num_dapm_widgets = ARRAY_SIZE(ssm3515 396 .dapm_routes = ssm3515_dapm_routes, 397 .num_dapm_routes = ARRAY_SIZE(ssm3515_ 398 .endianness = 1, 399 }; 400 401 static int ssm3515_i2c_probe(struct i2c_client 402 { 403 struct ssm3515_data *data; 404 int ret; 405 406 data = devm_kzalloc(&client->dev, size 407 if (!data) 408 return -ENOMEM; 409 410 data->dev = &client->dev; 411 i2c_set_clientdata(client, data); 412 413 data->regmap = devm_regmap_init_i2c(cl 414 if (IS_ERR(data->regmap)) 415 return dev_err_probe(data->dev 416 "initiali 417 418 /* Perform a reset */ 419 ret = regmap_update_bits(data->regmap, 420 SSM3515_PWR_S_RST, SSM 421 if (ret < 0) 422 return dev_err_probe(data->dev 423 "performi 424 regmap_reinit_cache(data->regmap, &ssm 425 426 return devm_snd_soc_register_component 427 &ssm3515_asoc_componen 428 &ssm3515_dai_driver, 1 429 } 430 431 static const struct of_device_id ssm3515_of_ma 432 { .compatible = "adi,ssm3515" }, 433 {} 434 }; 435 MODULE_DEVICE_TABLE(of, ssm3515_of_match); 436 437 static struct i2c_driver ssm3515_i2c_driver = 438 .driver = { 439 .name = "ssm3515", 440 .of_match_table = ssm3515_of_m 441 }, 442 .probe = ssm3515_i2c_probe, 443 }; 444 module_i2c_driver(ssm3515_i2c_driver); 445 446 MODULE_AUTHOR("Martin PoviĊĦer <povik+lin@cute 447 MODULE_DESCRIPTION("ASoC SSM3515 audio amp dri 448 MODULE_LICENSE("Dual MIT/GPL"); 449
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.