571 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver4//5// Copyright 2019 Analog Devices Inc.6 7#include <linux/bitfield.h>8#include <linux/module.h>9#include <linux/regmap.h>10#include <linux/regulator/consumer.h>11#include <sound/pcm_params.h>12#include <sound/soc.h>13 14#include "adau7118.h"15 16#define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0)17#define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)18#define ADAU7118_CLK_MAP_MASK GENMASK(7, 4)19#define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4)20#define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)21#define ADAU7118_TRISTATE_MASK BIT(6)22#define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x)23#define ADAU7118_DATA_FMT_MASK GENMASK(3, 1)24#define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)25#define ADAU7118_SAI_MODE_MASK BIT(0)26#define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)27#define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0)28#define ADAU7118_LRCLK_BCLK_POL(x) \29 FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)30#define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4)31#define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)32#define ADAU7118_FULL_SOFT_R_MASK BIT(1)33#define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)34 35struct adau7118_data {36 struct regmap *map;37 struct device *dev;38 struct regulator *iovdd;39 struct regulator *dvdd;40 u32 slot_width;41 u32 slots;42 bool hw_mode;43 bool right_j;44};45 46/* Input Enable */47static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {48 SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),49 SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),50 SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),51 SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),52};53 54static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {55 /* Input Enable Switches */56 SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,57 &adau7118_dapm_pdm_control[0]),58 SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,59 &adau7118_dapm_pdm_control[1]),60 SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,61 &adau7118_dapm_pdm_control[2]),62 SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,63 &adau7118_dapm_pdm_control[3]),64 65 /* PDM Clocks */66 SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),67 SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),68 69 /* Output channels */70 SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),71 0, 0),72 SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),73 0, 0),74 SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),75 0, 0),76 SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),77 0, 0),78 SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),79 0, 0),80 SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),81 0, 0),82 SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),83 0, 0),84 SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),85 0, 0),86};87 88static const struct snd_soc_dapm_route adau7118_routes_sw[] = {89 { "PDM0", "Capture Switch", "PDM_DAT0" },90 { "PDM1", "Capture Switch", "PDM_DAT1" },91 { "PDM2", "Capture Switch", "PDM_DAT2" },92 { "PDM3", "Capture Switch", "PDM_DAT3" },93 { "AIF1TX1", NULL, "PDM0" },94 { "AIF1TX2", NULL, "PDM0" },95 { "AIF1TX3", NULL, "PDM1" },96 { "AIF1TX4", NULL, "PDM1" },97 { "AIF1TX5", NULL, "PDM2" },98 { "AIF1TX6", NULL, "PDM2" },99 { "AIF1TX7", NULL, "PDM3" },100 { "AIF1TX8", NULL, "PDM3" },101 { "Capture", NULL, "PDM_CLK0" },102 { "Capture", NULL, "PDM_CLK1" },103};104 105static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {106 SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),107};108 109static const struct snd_soc_dapm_route adau7118_routes_hw[] = {110 { "AIF1TX", NULL, "PDM_DAT0" },111 { "AIF1TX", NULL, "PDM_DAT1" },112 { "AIF1TX", NULL, "PDM_DAT2" },113 { "AIF1TX", NULL, "PDM_DAT3" },114};115 116static const struct snd_soc_dapm_widget adau7118_widgets[] = {117 SND_SOC_DAPM_INPUT("PDM_DAT0"),118 SND_SOC_DAPM_INPUT("PDM_DAT1"),119 SND_SOC_DAPM_INPUT("PDM_DAT2"),120 SND_SOC_DAPM_INPUT("PDM_DAT3"),121};122 123static int adau7118_set_channel_map(struct snd_soc_dai *dai,124 unsigned int tx_num,125 const unsigned int *tx_slot,126 unsigned int rx_num,127 const unsigned int *rx_slot)128{129 struct adau7118_data *st =130 snd_soc_component_get_drvdata(dai->component);131 int chan, ret;132 133 dev_dbg(st->dev, "Set channel map, %d", tx_num);134 135 for (chan = 0; chan < tx_num; chan++) {136 ret = snd_soc_component_update_bits(dai->component,137 ADAU7118_REG_SPT_CX(chan),138 ADAU7118_SPT_SLOT_MASK,139 ADAU7118_SPT_SLOT(tx_slot[chan]));140 if (ret < 0)141 return ret;142 }143 144 return 0;145}146 147static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)148{149 struct adau7118_data *st =150 snd_soc_component_get_drvdata(dai->component);151 int ret = 0;152 u32 regval;153 154 dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);155 156 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {157 case SND_SOC_DAIFMT_I2S:158 ret = snd_soc_component_update_bits(dai->component,159 ADAU7118_REG_SPT_CTRL1,160 ADAU7118_DATA_FMT_MASK,161 ADAU7118_DATA_FMT(0));162 break;163 case SND_SOC_DAIFMT_LEFT_J:164 ret = snd_soc_component_update_bits(dai->component,165 ADAU7118_REG_SPT_CTRL1,166 ADAU7118_DATA_FMT_MASK,167 ADAU7118_DATA_FMT(1));168 break;169 case SND_SOC_DAIFMT_RIGHT_J:170 st->right_j = true;171 break;172 default:173 dev_err(st->dev, "Invalid format %d",174 fmt & SND_SOC_DAIFMT_FORMAT_MASK);175 return -EINVAL;176 }177 178 if (ret < 0)179 return ret;180 181 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {182 case SND_SOC_DAIFMT_NB_NF:183 regval = ADAU7118_LRCLK_BCLK_POL(0);184 break;185 case SND_SOC_DAIFMT_NB_IF:186 regval = ADAU7118_LRCLK_BCLK_POL(2);187 break;188 case SND_SOC_DAIFMT_IB_NF:189 regval = ADAU7118_LRCLK_BCLK_POL(1);190 break;191 case SND_SOC_DAIFMT_IB_IF:192 regval = ADAU7118_LRCLK_BCLK_POL(3);193 break;194 default:195 dev_err(st->dev, "Invalid Inv mask %d",196 fmt & SND_SOC_DAIFMT_INV_MASK);197 return -EINVAL;198 }199 200 ret = snd_soc_component_update_bits(dai->component,201 ADAU7118_REG_SPT_CTRL2,202 ADAU7118_LRCLK_BCLK_POL_MASK,203 regval);204 if (ret < 0)205 return ret;206 207 return 0;208}209 210static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)211{212 struct adau7118_data *st =213 snd_soc_component_get_drvdata(dai->component);214 int ret;215 216 dev_dbg(st->dev, "Set tristate, %d\n", tristate);217 218 ret = snd_soc_component_update_bits(dai->component,219 ADAU7118_REG_SPT_CTRL1,220 ADAU7118_TRISTATE_MASK,221 ADAU7118_TRISTATE(tristate));222 if (ret < 0)223 return ret;224 225 return 0;226}227 228static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,229 unsigned int rx_mask, int slots,230 int slot_width)231{232 struct adau7118_data *st =233 snd_soc_component_get_drvdata(dai->component);234 int ret = 0;235 u32 regval;236 237 dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);238 239 switch (slot_width) {240 case 32:241 regval = ADAU7118_SLOT_WIDTH(0);242 break;243 case 24:244 regval = ADAU7118_SLOT_WIDTH(2);245 break;246 case 16:247 regval = ADAU7118_SLOT_WIDTH(1);248 break;249 default:250 dev_err(st->dev, "Invalid slot width:%d\n", slot_width);251 return -EINVAL;252 }253 254 ret = snd_soc_component_update_bits(dai->component,255 ADAU7118_REG_SPT_CTRL1,256 ADAU7118_SLOT_WIDTH_MASK, regval);257 if (ret < 0)258 return ret;259 260 st->slot_width = slot_width;261 st->slots = slots;262 263 return 0;264}265 266static int adau7118_hw_params(struct snd_pcm_substream *substream,267 struct snd_pcm_hw_params *params,268 struct snd_soc_dai *dai)269{270 struct adau7118_data *st =271 snd_soc_component_get_drvdata(dai->component);272 u32 data_width = params_width(params), slots_width;273 int ret;274 u32 regval;275 276 if (!st->slots) {277 /* set stereo mode */278 ret = snd_soc_component_update_bits(dai->component,279 ADAU7118_REG_SPT_CTRL1,280 ADAU7118_SAI_MODE_MASK,281 ADAU7118_SAI_MODE(0));282 if (ret < 0)283 return ret;284 285 slots_width = 32;286 } else {287 slots_width = st->slot_width;288 }289 290 if (data_width > slots_width) {291 dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",292 data_width, slots_width);293 return -EINVAL;294 }295 296 if (st->right_j) {297 switch (slots_width - data_width) {298 case 8:299 /* delay bclck by 8 */300 regval = ADAU7118_DATA_FMT(2);301 break;302 case 12:303 /* delay bclck by 12 */304 regval = ADAU7118_DATA_FMT(3);305 break;306 case 16:307 /* delay bclck by 16 */308 regval = ADAU7118_DATA_FMT(4);309 break;310 default:311 dev_err(st->dev,312 "Cannot set right_j setting, slot_w:%d, data_w:%d\n",313 slots_width, data_width);314 return -EINVAL;315 }316 317 ret = snd_soc_component_update_bits(dai->component,318 ADAU7118_REG_SPT_CTRL1,319 ADAU7118_DATA_FMT_MASK,320 regval);321 if (ret < 0)322 return ret;323 }324 325 return 0;326}327 328static int adau7118_set_bias_level(struct snd_soc_component *component,329 enum snd_soc_bias_level level)330{331 struct adau7118_data *st = snd_soc_component_get_drvdata(component);332 int ret = 0;333 334 dev_dbg(st->dev, "Set bias level %d\n", level);335 336 switch (level) {337 case SND_SOC_BIAS_ON:338 case SND_SOC_BIAS_PREPARE:339 break;340 341 case SND_SOC_BIAS_STANDBY:342 if (snd_soc_component_get_bias_level(component) ==343 SND_SOC_BIAS_OFF) {344 /* power on */345 ret = regulator_enable(st->iovdd);346 if (ret)347 return ret;348 349 /* there's no timing constraints before enabling dvdd */350 ret = regulator_enable(st->dvdd);351 if (ret) {352 regulator_disable(st->iovdd);353 return ret;354 }355 356 if (st->hw_mode)357 return 0;358 359 regcache_cache_only(st->map, false);360 /* sync cache */361 ret = snd_soc_component_cache_sync(component);362 }363 break;364 case SND_SOC_BIAS_OFF:365 /* power off */366 ret = regulator_disable(st->dvdd);367 if (ret)368 return ret;369 370 ret = regulator_disable(st->iovdd);371 if (ret)372 return ret;373 374 if (st->hw_mode)375 return 0;376 377 /* cache only */378 regcache_mark_dirty(st->map);379 regcache_cache_only(st->map, true);380 381 break;382 }383 384 return ret;385}386 387static int adau7118_component_probe(struct snd_soc_component *component)388{389 struct adau7118_data *st = snd_soc_component_get_drvdata(component);390 struct snd_soc_dapm_context *dapm =391 snd_soc_component_get_dapm(component);392 int ret = 0;393 394 if (st->hw_mode) {395 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,396 ARRAY_SIZE(adau7118_widgets_hw));397 if (ret)398 return ret;399 400 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,401 ARRAY_SIZE(adau7118_routes_hw));402 } else {403 snd_soc_component_init_regmap(component, st->map);404 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,405 ARRAY_SIZE(adau7118_widgets_sw));406 if (ret)407 return ret;408 409 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,410 ARRAY_SIZE(adau7118_routes_sw));411 }412 413 return ret;414}415 416static const struct snd_soc_dai_ops adau7118_ops = {417 .hw_params = adau7118_hw_params,418 .set_channel_map = adau7118_set_channel_map,419 .set_fmt = adau7118_set_fmt,420 .set_tdm_slot = adau7118_set_tdm_slot,421 .set_tristate = adau7118_set_tristate,422};423 424static struct snd_soc_dai_driver adau7118_dai = {425 .name = "adau7118-hifi-capture",426 .capture = {427 .stream_name = "Capture",428 .channels_min = 1,429 .channels_max = 8,430 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |431 SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |432 SNDRV_PCM_FMTBIT_S24_3LE,433 .rates = SNDRV_PCM_RATE_CONTINUOUS,434 .rate_min = 4000,435 .rate_max = 192000,436 .sig_bits = 24,437 },438};439 440static const struct snd_soc_component_driver adau7118_component_driver = {441 .probe = adau7118_component_probe,442 .set_bias_level = adau7118_set_bias_level,443 .dapm_widgets = adau7118_widgets,444 .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),445 .use_pmdown_time = 1,446 .endianness = 1,447};448 449static int adau7118_regulator_setup(struct adau7118_data *st)450{451 st->iovdd = devm_regulator_get(st->dev, "iovdd");452 if (IS_ERR(st->iovdd)) {453 dev_err(st->dev, "Could not get iovdd: %ld\n",454 PTR_ERR(st->iovdd));455 return PTR_ERR(st->iovdd);456 }457 458 st->dvdd = devm_regulator_get(st->dev, "dvdd");459 if (IS_ERR(st->dvdd)) {460 dev_err(st->dev, "Could not get dvdd: %ld\n",461 PTR_ERR(st->dvdd));462 return PTR_ERR(st->dvdd);463 }464 /* just assume the device is in reset */465 if (!st->hw_mode) {466 regcache_mark_dirty(st->map);467 regcache_cache_only(st->map, true);468 }469 470 return 0;471}472 473static int adau7118_parset_dt(const struct adau7118_data *st)474{475 int ret;476 u32 dec_ratio = 0;477 /* 4 inputs */478 u32 clk_map[4], regval;479 480 if (st->hw_mode)481 return 0;482 483 ret = device_property_read_u32(st->dev, "adi,decimation-ratio",484 &dec_ratio);485 if (!ret) {486 switch (dec_ratio) {487 case 64:488 regval = ADAU7118_DEC_RATIO(0);489 break;490 case 32:491 regval = ADAU7118_DEC_RATIO(1);492 break;493 case 16:494 regval = ADAU7118_DEC_RATIO(2);495 break;496 default:497 dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);498 return -EINVAL;499 }500 501 ret = regmap_update_bits(st->map,502 ADAU7118_REG_DEC_RATIO_CLK_MAP,503 ADAU7118_DEC_RATIO_MASK, regval);504 if (ret)505 return ret;506 }507 508 ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",509 clk_map, ARRAY_SIZE(clk_map));510 if (!ret) {511 int pdm;512 u32 _clk_map = 0;513 514 for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)515 _clk_map |= (clk_map[pdm] << (pdm + 4));516 517 ret = regmap_update_bits(st->map,518 ADAU7118_REG_DEC_RATIO_CLK_MAP,519 ADAU7118_CLK_MAP_MASK, _clk_map);520 if (ret)521 return ret;522 }523 524 return 0;525}526 527int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)528{529 struct adau7118_data *st;530 int ret;531 532 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);533 if (!st)534 return -ENOMEM;535 536 st->dev = dev;537 st->hw_mode = hw_mode;538 dev_set_drvdata(dev, st);539 540 if (!hw_mode) {541 st->map = map;542 adau7118_dai.ops = &adau7118_ops;543 /*544 * Perform a full soft reset. This will set all register's545 * with their reset values.546 */547 ret = regmap_update_bits(map, ADAU7118_REG_RESET,548 ADAU7118_FULL_SOFT_R_MASK,549 ADAU7118_FULL_SOFT_R(1));550 if (ret)551 return ret;552 }553 554 ret = adau7118_parset_dt(st);555 if (ret)556 return ret;557 558 ret = adau7118_regulator_setup(st);559 if (ret)560 return ret;561 562 return devm_snd_soc_register_component(dev,563 &adau7118_component_driver,564 &adau7118_dai, 1);565}566EXPORT_SYMBOL_GPL(adau7118_probe);567 568MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");569MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");570MODULE_LICENSE("GPL");571