449 lines · c
1// SPDX-License-Identifier: GPL-2.0-only OR MIT2//3// Analog Devices' SSM3515 audio amp driver4//5// Copyright (C) The Asahi Linux Contributors6 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 0x0022#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 0x0128#define SSM3515_GEC_EDGE BIT(4)29#define SSM3515_GEC_EDGE_SHIFT 430#define SSM3515_GEC_ANA_GAIN GENMASK(1, 0)31 32#define SSM3515_DAC 0x0233#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 0x0340 41#define SSM3515_SAI1 0x0442#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 0x0550#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 0x0655 56#define SSM3515_STATUS 0x0a57#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 65static bool ssm3515_volatile_reg(struct device *dev, unsigned int reg)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 77static const struct reg_default ssm3515_reg_defaults[] = {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 86static const struct regmap_config ssm3515_i2c_regmap = {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_reg_defaults),93 .cache_type = REGCACHE_FLAT,94};95 96struct ssm3515_data {97 struct device *dev;98 struct regmap *regmap;99};100 101// The specced range is -71.25...24.00 dB with step size of 0.375 dB,102// and a mute item below that. This is represented by -71.62...24.00 dB103// with the mute item mapped onto the low end.104static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_volume, -7162, 2400);105 106static const char * const ssm3515_ana_gain_text[] = {107 "8.4 V Span", "12.6 V Span", "14 V Span", "15 V Span",108};109 110static SOC_ENUM_SINGLE_DECL(ssm3515_ana_gain_enum, SSM3515_GEC,111 __bf_shf(SSM3515_GEC_ANA_GAIN),112 ssm3515_ana_gain_text);113 114static const struct snd_kcontrol_new ssm3515_snd_controls[] = {115 SOC_SINGLE_TLV("DAC Playback Volume", SSM3515_DAC_VOL,116 0, 255, 1, ssm3515_dac_volume),117 SOC_SINGLE("Low EMI Mode Switch", SSM3515_GEC,118 __bf_shf(SSM3515_GEC_EDGE), 1, 0),119 SOC_SINGLE("Soft Volume Ramping Switch", SSM3515_DAC,120 __bf_shf(SSM3515_DAC_HV), 1, 1),121 SOC_SINGLE("HPF Switch", SSM3515_DAC,122 __bf_shf(SSM3515_DAC_HPF), 1, 0),123 SOC_SINGLE("DAC Invert Switch", SSM3515_SAI1,124 __bf_shf(SSM3515_SAI1_DAC_POL), 1, 0),125 SOC_ENUM("DAC Analog Gain Select", ssm3515_ana_gain_enum),126};127 128static void ssm3515_read_faults(struct snd_soc_component *component)129{130 int ret;131 132 ret = snd_soc_component_read(component, SSM3515_STATUS);133 if (ret <= 0) {134 /*135 * If the read was erroneous, ASoC core has printed a message,136 * and that's all that's appropriate in handling the error here.137 */138 return;139 }140 141 dev_err(component->dev, "device reports:%s%s%s%s%s%s%s\n",142 FIELD_GET(SSM3515_STATUS_UVLO_REG, ret) ? " voltage regulator fault" : "",143 FIELD_GET(SSM3515_STATUS_LIM_EG, ret) ? " limiter engaged" : "",144 FIELD_GET(SSM3515_STATUS_CLIP, ret) ? " clipping detected" : "",145 FIELD_GET(SSM3515_STATUS_AMP_OC, ret) ? " amp over-current fault" : "",146 FIELD_GET(SSM3515_STATUS_OTF, ret) ? " overtemperature fault" : "",147 FIELD_GET(SSM3515_STATUS_OTW, ret) ? " overtemperature warning" : "",148 FIELD_GET(SSM3515_STATUS_BAT_WARN, ret) ? " bat voltage low warning" : "");149}150 151static int ssm3515_probe(struct snd_soc_component *component)152{153 int ret;154 155 /* Start out muted */156 ret = snd_soc_component_update_bits(component, SSM3515_DAC,157 SSM3515_DAC_MUTE, SSM3515_DAC_MUTE);158 if (ret < 0)159 return ret;160 161 /* Disable the 'master power-down' */162 ret = snd_soc_component_update_bits(component, SSM3515_PWR,163 SSM3515_PWR_SPWDN, 0);164 if (ret < 0)165 return ret;166 167 return 0;168}169 170static int ssm3515_mute(struct snd_soc_dai *dai, int mute, int direction)171{172 int ret;173 174 ret = snd_soc_component_update_bits(dai->component,175 SSM3515_DAC,176 SSM3515_DAC_MUTE,177 FIELD_PREP(SSM3515_DAC_MUTE, mute));178 if (ret < 0)179 return ret;180 return 0;181}182 183static int ssm3515_hw_params(struct snd_pcm_substream *substream,184 struct snd_pcm_hw_params *params,185 struct snd_soc_dai *dai)186{187 struct snd_soc_component *component = dai->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_bits(component,194 SSM3515_SAI2, SSM3515_SAI2_DATA_WIDTH,195 FIELD_PREP(SSM3515_SAI2_DATA_WIDTH,196 params_width(params) == 16));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 ...72000 but overlaps */222 rateval = 5;223 break;224 default:225 return -EINVAL;226 }227 228 ret = snd_soc_component_update_bits(component,229 SSM3515_DAC, SSM3515_DAC_FS,230 FIELD_PREP(SSM3515_DAC_FS, rateval));231 if (ret < 0)232 return ret;233 234 return 0;235}236 237static int ssm3515_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)238{239 struct snd_soc_component *component = dai->component;240 bool fpol_inv = false; /* non-inverted: frame starts with low-to-high FSYNC */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_MASK) {252 case SND_SOC_DAIFMT_I2S:253 fpol_inv = 1;254 sai1 &= ~SSM3515_SAI1_SDATA_FMT; /* 1 bit start delay */255 break;256 case SND_SOC_DAIFMT_LEFT_J:257 fpol_inv = 0;258 sai1 |= SSM3515_SAI1_SDATA_FMT; /* no start delay */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 'TDM mode', in which the277 * FSYNC_MODE bit of SAI1 is supposed to select between278 * what the datasheet calls 'Pulsed FSYNC mode' and '50%279 * FSYNC mode'.280 *281 * Experiments suggest that this bit in fact simply selects282 * the FSYNC polarity, so go with that.283 */284 sai1 |= SSM3515_SAI1_FSYNC_MODE;285 }286 287 ret = snd_soc_component_update_bits(component, SSM3515_SAI1,288 SSM3515_SAI1_BCLK_POL | SSM3515_SAI1_SDATA_FMT |289 SSM3515_SAI1_SAI_MODE | SSM3515_SAI1_FSYNC_MODE, sai1);290 291 if (ret < 0)292 return ret;293 return 0;294}295 296static int ssm3515_set_tdm_slot(struct snd_soc_dai *dai,297 unsigned int tx_mask,298 unsigned int rx_mask,299 int slots, int slot_width)300{301 struct snd_soc_component *component = dai->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(component, SSM3515_SAI1,333 SSM3515_SAI1_TDM_BCLKS,334 FIELD_PREP(SSM3515_SAI1_TDM_BCLKS, tdm_bclks_val));335 if (ret < 0)336 return ret;337 338 ret = snd_soc_component_update_bits(component, SSM3515_SAI2,339 SSM3515_SAI2_TDM_SLOT,340 FIELD_PREP(SSM3515_SAI2_TDM_SLOT, slot));341 if (ret < 0)342 return ret;343 344 return 0;345}346 347static int ssm3515_hw_free(struct snd_pcm_substream *substream,348 struct snd_soc_dai *dai)349{350 /*351 * We don't get live notification of faults, so at least at352 * this time, when playback is over, check if we have tripped353 * over anything and if so, log it.354 */355 ssm3515_read_faults(dai->component);356 return 0;357}358 359static const struct snd_soc_dai_ops ssm3515_dai_ops = {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 367static struct snd_soc_dai_driver ssm3515_dai_driver = {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_CONTINUOUS,375 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,376 },377 .ops = &ssm3515_dai_ops,378};379 380static const struct snd_soc_dapm_widget ssm3515_dapm_widgets[] = {381 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),382 SND_SOC_DAPM_OUTPUT("OUT"),383};384 385static const struct snd_soc_dapm_route ssm3515_dapm_routes[] = {386 {"OUT", NULL, "DAC"},387 {"DAC", NULL, "Playback"},388};389 390static const struct snd_soc_component_driver ssm3515_asoc_component = {391 .probe = ssm3515_probe,392 .controls = ssm3515_snd_controls,393 .num_controls = ARRAY_SIZE(ssm3515_snd_controls),394 .dapm_widgets = ssm3515_dapm_widgets,395 .num_dapm_widgets = ARRAY_SIZE(ssm3515_dapm_widgets),396 .dapm_routes = ssm3515_dapm_routes,397 .num_dapm_routes = ARRAY_SIZE(ssm3515_dapm_routes),398 .endianness = 1,399};400 401static int ssm3515_i2c_probe(struct i2c_client *client)402{403 struct ssm3515_data *data;404 int ret;405 406 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);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(client, &ssm3515_i2c_regmap);414 if (IS_ERR(data->regmap))415 return dev_err_probe(data->dev, PTR_ERR(data->regmap),416 "initializing register map\n");417 418 /* Perform a reset */419 ret = regmap_update_bits(data->regmap, SSM3515_PWR,420 SSM3515_PWR_S_RST, SSM3515_PWR_S_RST);421 if (ret < 0)422 return dev_err_probe(data->dev, ret,423 "performing software reset\n");424 regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap);425 426 return devm_snd_soc_register_component(data->dev,427 &ssm3515_asoc_component,428 &ssm3515_dai_driver, 1);429}430 431static const struct of_device_id ssm3515_of_match[] = {432 { .compatible = "adi,ssm3515" },433 {}434};435MODULE_DEVICE_TABLE(of, ssm3515_of_match);436 437static struct i2c_driver ssm3515_i2c_driver = {438 .driver = {439 .name = "ssm3515",440 .of_match_table = ssm3515_of_match,441 },442 .probe = ssm3515_i2c_probe,443};444module_i2c_driver(ssm3515_i2c_driver);445 446MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");447MODULE_DESCRIPTION("ASoC SSM3515 audio amp driver");448MODULE_LICENSE("Dual MIT/GPL");449