File Index
Files and directories
Sign in
FILE

cs530x.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/codecs/cs530x.c C
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// CS530x CODEC driver
   4//
   5// Copyright (C) 2024-2025 Cirrus Logic, Inc. and
   6//                         Cirrus Logic International Semiconductor Ltd.
   7
   8#include <linux/delay.h>
   9#include <linux/i2c.h>
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/pm.h>
  13#include <linux/property.h>
  14#include <linux/slab.h>
  15#include <linux/spi/spi.h>
  16#include <sound/core.h>
  17#include <sound/initval.h>
  18#include <sound/pcm.h>
  19#include <sound/pcm_params.h>
  20#include <sound/soc.h>
  21#include <sound/tlv.h>
  22
  23#include "cs530x.h"
  24
  25static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = {
  26	"vdd-a",
  27	"vdd-io",
  28};
  29
  30static const struct reg_default cs530x_reg_defaults[] = {
  31	{ CS530X_CLK_CFG_0, 0x30 },
  32	{ CS530X_CLK_CFG_1, 0x0001 },
  33	{ CS530X_CHIP_ENABLE, 0 },
  34	{ CS530X_ASP_CFG, 0 },
  35	{ CS530X_SIGNAL_PATH_CFG, 0 },
  36	{ CS530X_IN_ENABLES, 0 },
  37	{ CS530X_IN_RAMP_SUM, 0x0022 },
  38	{ CS530X_IN_FILTER, 0 },
  39	{ CS530X_IN_HIZ, 0 },
  40	{ CS530X_IN_INV, 0 },
  41	{ CS530X_IN_VOL_CTRL1_0, 0x8000 },
  42	{ CS530X_IN_VOL_CTRL1_1, 0x8000 },
  43	{ CS530X_IN_VOL_CTRL2_0, 0x8000 },
  44	{ CS530X_IN_VOL_CTRL2_1, 0x8000 },
  45	{ CS530X_IN_VOL_CTRL3_0, 0x8000 },
  46	{ CS530X_IN_VOL_CTRL3_1, 0x8000 },
  47	{ CS530X_IN_VOL_CTRL4_0, 0x8000 },
  48	{ CS530X_IN_VOL_CTRL4_1, 0x8000 },
  49	{ CS530X_OUT_ENABLES, 0 },
  50	{ CS530X_OUT_RAMP_SUM, 0x0022 },
  51	{ CS530X_OUT_FILTER, 0 },
  52	{ CS530X_OUT_INV, 0 },
  53	{ CS530X_OUT_VOL_CTRL1_0, 0x8000 },
  54	{ CS530X_OUT_VOL_CTRL1_1, 0x8000 },
  55	{ CS530X_OUT_VOL_CTRL2_0, 0x8000 },
  56	{ CS530X_OUT_VOL_CTRL2_1, 0x8000 },
  57	{ CS530X_OUT_VOL_CTRL3_0, 0x8000 },
  58	{ CS530X_OUT_VOL_CTRL3_1, 0x8000 },
  59	{ CS530X_OUT_VOL_CTRL4_0, 0x8000 },
  60	{ CS530X_OUT_VOL_CTRL4_1, 0x8000 },
  61	{ CS530X_PAD_FN, 0 },
  62	{ CS530X_PAD_LVL, 0 },
  63};
  64
  65static bool cs530x_read_and_write_regs(unsigned int reg)
  66{
  67	switch (reg) {
  68	case CS530X_CLK_CFG_0:
  69	case CS530X_CLK_CFG_1:
  70	case CS530X_CHIP_ENABLE:
  71	case CS530X_ASP_CFG:
  72	case CS530X_SIGNAL_PATH_CFG:
  73	case CS530X_IN_ENABLES:
  74	case CS530X_IN_RAMP_SUM:
  75	case CS530X_IN_FILTER:
  76	case CS530X_IN_HIZ:
  77	case CS530X_IN_INV:
  78	case CS530X_IN_VOL_CTRL1_0:
  79	case CS530X_IN_VOL_CTRL1_1:
  80	case CS530X_IN_VOL_CTRL2_0:
  81	case CS530X_IN_VOL_CTRL2_1:
  82	case CS530X_IN_VOL_CTRL3_0:
  83	case CS530X_IN_VOL_CTRL3_1:
  84	case CS530X_IN_VOL_CTRL4_0:
  85	case CS530X_IN_VOL_CTRL4_1:
  86	case CS530X_OUT_ENABLES:
  87	case CS530X_OUT_RAMP_SUM:
  88	case CS530X_OUT_DEEMPH:
  89	case CS530X_OUT_FILTER:
  90	case CS530X_OUT_INV:
  91	case CS530X_OUT_VOL_CTRL1_0:
  92	case CS530X_OUT_VOL_CTRL1_1:
  93	case CS530X_OUT_VOL_CTRL2_0:
  94	case CS530X_OUT_VOL_CTRL2_1:
  95	case CS530X_OUT_VOL_CTRL3_0:
  96	case CS530X_OUT_VOL_CTRL3_1:
  97	case CS530X_OUT_VOL_CTRL4_0:
  98	case CS530X_OUT_VOL_CTRL4_1:
  99	case CS530X_PAD_FN:
 100	case CS530X_PAD_LVL:
 101		return true;
 102	default:
 103		return false;
 104	}
 105}
 106
 107static bool cs530x_readable_register(struct device *dev, unsigned int reg)
 108{
 109	switch (reg) {
 110	case CS530X_DEVID:
 111	case CS530X_REVID:
 112		return true;
 113	default:
 114		return cs530x_read_and_write_regs(reg);
 115	}
 116}
 117
 118static bool cs530x_writeable_register(struct device *dev, unsigned int reg)
 119{
 120	switch (reg) {
 121	case CS530X_SW_RESET:
 122	case CS530X_IN_VOL_CTRL5:
 123	case CS530X_OUT_VOL_CTRL5:
 124		return true;
 125	default:
 126		return cs530x_read_and_write_regs(reg);
 127	}
 128}
 129
 130static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol,
 131			       struct snd_ctl_elem_value *ucontrol)
 132{
 133	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 134	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 135	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 136	struct regmap *regmap = cs530x->regmap;
 137	int ret;
 138
 139	snd_soc_dapm_mutex_lock(dapm);
 140
 141	ret = snd_soc_put_volsw(kcontrol, ucontrol);
 142	if (ret)
 143		goto volsw_err;
 144
 145	/* Write INOUT_VU bit for the volume change to take effect */
 146	regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_INOUT_VU);
 147
 148volsw_err:
 149	snd_soc_dapm_mutex_unlock(dapm);
 150
 151	return ret;
 152}
 153
 154static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0);
 155
 156static const char * const cs530x_inout_filter_text[] = {
 157	"Min Phase Slow Roll-off",
 158	"Min Phase Fast Roll-off",
 159	"Linear Phase Slow Roll-off",
 160	"Linear Phase Fast Roll-off",
 161};
 162
 163static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER,
 164			    CS530X_INOUT_FILTER_SHIFT,
 165			    cs530x_inout_filter_text);
 166
 167static SOC_ENUM_SINGLE_DECL(cs530x_out_filter_enum, CS530X_OUT_FILTER,
 168			    CS530X_INOUT_FILTER_SHIFT,
 169			    cs530x_inout_filter_text);
 170
 171static const char * const cs530x_4ch_sum_text[] = {
 172	"None",
 173	"Groups of 2",
 174	"Groups of 4",
 175};
 176
 177static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM,
 178			    CS530X_INOUT_SUM_MODE_SHIFT,
 179			    cs530x_4ch_sum_text);
 180
 181static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = {
 182SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum),
 183};
 184
 185static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch4_enum, CS530X_OUT_RAMP_SUM,
 186			    CS530X_INOUT_SUM_MODE_SHIFT,
 187			    cs530x_4ch_sum_text);
 188
 189static const struct snd_kcontrol_new cs530x_out_sum_4ch_controls[] = {
 190SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch4_enum),
 191};
 192
 193static const char * const cs530x_8ch_sum_text[] = {
 194	"None",
 195	"Groups of 2",
 196	"Groups of 4",
 197	"Groups of 8",
 198};
 199
 200static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM,
 201			    CS530X_INOUT_SUM_MODE_SHIFT,
 202			    cs530x_8ch_sum_text);
 203
 204static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = {
 205SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum),
 206};
 207
 208static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch8_enum, CS530X_OUT_RAMP_SUM,
 209			    CS530X_INOUT_SUM_MODE_SHIFT,
 210			    cs530x_8ch_sum_text);
 211
 212static const struct snd_kcontrol_new cs530x_out_sum_8ch_controls[] = {
 213SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch8_enum),
 214};
 215
 216static const char * const cs530x_vol_ramp_text[] = {
 217	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
 218	"15ms/6dB", "30ms/6dB",
 219};
 220
 221static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM,
 222			    CS530X_RAMP_RATE_INC_SHIFT,
 223			    cs530x_vol_ramp_text);
 224
 225static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM,
 226			    CS530X_RAMP_RATE_DEC_SHIFT,
 227			    cs530x_vol_ramp_text);
 228
 229static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = {
 230SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1,
 231		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 232SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1,
 233		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 234
 235SOC_ENUM("IN DEC Filter Select", cs530x_in_filter_enum),
 236SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum),
 237SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum),
 238
 239SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_INOUT1_INV_SHIFT, 1, 0),
 240SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_INOUT2_INV_SHIFT, 1, 0),
 241};
 242
 243static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = {
 244SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1,
 245		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 246SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1,
 247		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 248
 249SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_INOUT3_INV_SHIFT, 1, 0),
 250SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_INOUT4_INV_SHIFT, 1, 0),
 251};
 252
 253static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = {
 254SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1,
 255		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 256SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1,
 257		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 258SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1,
 259		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 260SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1,
 261		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 262
 263SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_INOUT5_INV_SHIFT, 1, 0),
 264SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_INOUT6_INV_SHIFT, 1, 0),
 265SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_INOUT7_INV_SHIFT, 1, 0),
 266SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_INOUT8_INV_SHIFT, 1, 0),
 267};
 268
 269static int cs530x_adc_event(struct snd_soc_dapm_widget *w,
 270			    struct snd_kcontrol *kcontrol, int event)
 271{
 272	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 273	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 274	struct regmap *regmap = cs530x->regmap;
 275
 276	switch (event) {
 277	case SND_SOC_DAPM_PRE_PMU:
 278		cs530x->adc_pairs_count++;
 279		break;
 280	case SND_SOC_DAPM_POST_PMU:
 281		regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
 282				  (w->shift * 2), CS530X_INOUT_MUTE);
 283		regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
 284				  ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
 285
 286		cs530x->adc_pairs_count--;
 287		if (!cs530x->adc_pairs_count) {
 288			usleep_range(1000, 1100);
 289			return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
 290					    CS530X_INOUT_VU);
 291		}
 292		break;
 293	case SND_SOC_DAPM_PRE_PMD:
 294		regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
 295				(w->shift * 2), CS530X_INOUT_MUTE);
 296		regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
 297				((w->shift + 1) * 2), CS530X_INOUT_MUTE);
 298		return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
 299				    CS530X_INOUT_VU);
 300	default:
 301		return -EINVAL;
 302	}
 303
 304	return 0;
 305}
 306
 307static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_inc_enum, CS530X_OUT_RAMP_SUM,
 308			    CS530X_RAMP_RATE_INC_SHIFT,
 309			    cs530x_vol_ramp_text);
 310
 311static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_dec_enum, CS530X_OUT_RAMP_SUM,
 312			    CS530X_RAMP_RATE_DEC_SHIFT,
 313			    cs530x_vol_ramp_text);
 314
 315static const struct snd_kcontrol_new cs530x_out_1_to_2_controls[] = {
 316SOC_SINGLE_EXT_TLV("OUT1 Volume", CS530X_OUT_VOL_CTRL1_0, 0, 255, 1,
 317		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 318SOC_SINGLE_EXT_TLV("OUT2 Volume", CS530X_OUT_VOL_CTRL1_1, 0, 255, 1,
 319		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 320
 321SOC_ENUM("OUT DEC Filter Select", cs530x_out_filter_enum),
 322SOC_ENUM("Output Ramp Up", cs530x_ramp_out_inc_enum),
 323SOC_ENUM("Output Ramp Down", cs530x_ramp_out_dec_enum),
 324
 325SOC_SINGLE("DAC1 Invert Switch", CS530X_OUT_INV, CS530X_INOUT1_INV_SHIFT, 1, 0),
 326SOC_SINGLE("DAC2 Invert Switch", CS530X_OUT_INV, CS530X_INOUT2_INV_SHIFT, 1, 0),
 327};
 328
 329static const struct snd_kcontrol_new cs530x_out_3_to_4_controls[] = {
 330SOC_SINGLE_EXT_TLV("OUT3 Volume", CS530X_OUT_VOL_CTRL2_0, 0, 255, 1,
 331		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 332SOC_SINGLE_EXT_TLV("OUT4 Volume", CS530X_OUT_VOL_CTRL2_1, 0, 255, 1,
 333		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 334
 335SOC_SINGLE("DAC3 Invert Switch", CS530X_OUT_INV, CS530X_INOUT3_INV_SHIFT, 1, 0),
 336SOC_SINGLE("DAC4 Invert Switch", CS530X_OUT_INV, CS530X_INOUT4_INV_SHIFT, 1, 0),
 337};
 338
 339static const struct snd_kcontrol_new cs530x_out_5_to_8_controls[] = {
 340SOC_SINGLE_EXT_TLV("OUT5 Volume", CS530X_OUT_VOL_CTRL3_0, 0, 255, 1,
 341		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 342SOC_SINGLE_EXT_TLV("OUT6 Volume", CS530X_OUT_VOL_CTRL3_1, 0, 255, 1,
 343		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 344SOC_SINGLE_EXT_TLV("OUT7 Volume", CS530X_OUT_VOL_CTRL4_0, 0, 255, 1,
 345		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 346SOC_SINGLE_EXT_TLV("OUT8 Volume", CS530X_OUT_VOL_CTRL4_1, 0, 255, 1,
 347		    snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
 348
 349SOC_SINGLE("DAC5 Invert Switch", CS530X_OUT_INV, CS530X_INOUT5_INV_SHIFT, 1, 0),
 350SOC_SINGLE("DAC6 Invert Switch", CS530X_OUT_INV, CS530X_INOUT6_INV_SHIFT, 1, 0),
 351SOC_SINGLE("DAC7 Invert Switch", CS530X_OUT_INV, CS530X_INOUT7_INV_SHIFT, 1, 0),
 352SOC_SINGLE("DAC8 Invert Switch", CS530X_OUT_INV, CS530X_INOUT8_INV_SHIFT, 1, 0),
 353};
 354
 355static int cs530x_dac_event(struct snd_soc_dapm_widget *w,
 356			    struct snd_kcontrol *kcontrol, int event)
 357{
 358	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 359	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 360	struct regmap *regmap = cs530x->regmap;
 361
 362	switch (event) {
 363	case SND_SOC_DAPM_PRE_PMU:
 364		cs530x->dac_pairs_count++;
 365		break;
 366	case SND_SOC_DAPM_POST_PMU:
 367		regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
 368				 (w->shift * 2), CS530X_INOUT_MUTE);
 369		regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
 370				 ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
 371
 372		cs530x->dac_pairs_count--;
 373		if (!cs530x->dac_pairs_count) {
 374			usleep_range(1000, 1100);
 375			return regmap_write(regmap, CS530X_OUT_VOL_CTRL5,
 376					    CS530X_INOUT_VU);
 377		}
 378		break;
 379	case SND_SOC_DAPM_PRE_PMD:
 380		regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
 381			       (w->shift * 2), CS530X_INOUT_MUTE);
 382		regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
 383			       ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
 384		return regmap_write(regmap, CS530X_OUT_VOL_CTRL5,
 385				    CS530X_INOUT_VU);
 386	default:
 387		return -EINVAL;
 388	}
 389
 390	return 0;
 391}
 392
 393static const struct snd_kcontrol_new adc12_ctrl =
 394	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 395static const struct snd_kcontrol_new adc34_ctrl =
 396	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 397static const struct snd_kcontrol_new adc56_ctrl =
 398	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 399static const struct snd_kcontrol_new adc78_ctrl =
 400	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 401static const struct snd_kcontrol_new dac12_ctrl =
 402	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 403static const struct snd_kcontrol_new dac34_ctrl =
 404	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 405static const struct snd_kcontrol_new dac56_ctrl =
 406	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 407static const struct snd_kcontrol_new dac78_ctrl =
 408	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 409static const struct snd_kcontrol_new in_hpf_ctrl =
 410	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 411static const struct snd_kcontrol_new out_hpf_ctrl =
 412	SOC_DAPM_SINGLE_VIRT("Switch", 1);
 413
 414/* General DAPM widgets for all devices */
 415static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = {
 416SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0),
 417};
 418
 419/* ADC's Channels 1 and 2 plus generic ADC DAPM events */
 420static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = {
 421SND_SOC_DAPM_INPUT("IN1"),
 422SND_SOC_DAPM_INPUT("IN2"),
 423SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0,
 424		   cs530x_adc_event,
 425		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 426		   SND_SOC_DAPM_PRE_PMU),
 427SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0),
 428SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl),
 429SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_INOUT_HPF_EN_SHIFT,
 430		    0, &in_hpf_ctrl),
 431};
 432
 433/* ADC's Channels 3 and 4 */
 434static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = {
 435SND_SOC_DAPM_INPUT("IN3"),
 436SND_SOC_DAPM_INPUT("IN4"),
 437SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0,
 438		   cs530x_adc_event,
 439		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 440		   SND_SOC_DAPM_PRE_PMU),
 441SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0),
 442SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl),
 443};
 444
 445/* ADC's Channels 5 to 8 */
 446static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = {
 447SND_SOC_DAPM_INPUT("IN5"),
 448SND_SOC_DAPM_INPUT("IN6"),
 449SND_SOC_DAPM_INPUT("IN7"),
 450SND_SOC_DAPM_INPUT("IN8"),
 451SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0,
 452		   cs530x_adc_event,
 453		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 454		   SND_SOC_DAPM_PRE_PMU),
 455SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0),
 456SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl),
 457SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0,
 458		   cs530x_adc_event,
 459		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 460		   SND_SOC_DAPM_PRE_PMU),
 461SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0),
 462SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl),
 463};
 464
 465static const struct snd_soc_dapm_route adc_ch1_2_routes[] = {
 466	{ "ADC1", NULL, "Global Enable" },
 467	{ "ADC2", NULL, "Global Enable" },
 468
 469	{ "ADC12 Enable", "Switch", "IN1" },
 470	{ "ADC12 Enable", "Switch", "IN2" },
 471	{ "ADC1", NULL, "ADC12 Enable" },
 472	{ "ADC2", NULL, "ADC12 Enable" },
 473	{ "IN HPF", "Switch", "ADC1" },
 474	{ "IN HPF", "Switch", "ADC2" },
 475
 476	{ "AIF Capture", NULL, "IN HPF" },
 477	{ "AIF Capture", NULL, "ADC1" },
 478	{ "AIF Capture", NULL, "ADC2" },
 479};
 480
 481static const struct snd_soc_dapm_route adc_ch3_4_routes[] = {
 482	{ "ADC3", NULL, "Global Enable" },
 483	{ "ADC4", NULL, "Global Enable" },
 484
 485	{ "ADC34 Enable", "Switch", "IN3" },
 486	{ "ADC34 Enable", "Switch", "IN4" },
 487	{ "ADC3", NULL, "ADC34 Enable" },
 488	{ "ADC4", NULL, "ADC34 Enable" },
 489	{ "IN HPF", "Switch", "ADC3" },
 490	{ "IN HPF", "Switch", "ADC4" },
 491
 492	{ "AIF Capture", NULL, "ADC3" },
 493	{ "AIF Capture", NULL, "ADC4" },
 494};
 495
 496static const struct snd_soc_dapm_route adc_ch5_8_routes[] = {
 497	{ "ADC5", NULL, "Global Enable" },
 498	{ "ADC6", NULL, "Global Enable" },
 499	{ "ADC7", NULL, "Global Enable" },
 500	{ "ADC8", NULL, "Global Enable" },
 501
 502	{ "ADC56 Enable", "Switch", "IN5" },
 503	{ "ADC56 Enable", "Switch", "IN6" },
 504	{ "ADC5", NULL, "ADC56 Enable" },
 505	{ "ADC6", NULL, "ADC56 Enable" },
 506	{ "IN HPF", "Switch", "ADC5" },
 507	{ "IN HPF", "Switch", "ADC6" },
 508
 509	{ "AIF Capture", NULL, "ADC5" },
 510	{ "AIF Capture", NULL, "ADC6" },
 511
 512	{ "ADC78 Enable", "Switch", "IN7" },
 513	{ "ADC78 Enable", "Switch", "IN8" },
 514	{ "ADC7", NULL, "ADC78 Enable" },
 515	{ "ADC8", NULL, "ADC78 Enable" },
 516	{ "IN HPF", "Switch", "ADC7" },
 517	{ "IN HPF", "Switch", "ADC8" },
 518
 519	{ "AIF Capture", NULL, "ADC7" },
 520	{ "AIF Capture", NULL, "ADC8" },
 521};
 522
 523static void cs530x_add_12_adc_widgets(struct snd_soc_component *component)
 524{
 525	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 526
 527	snd_soc_add_component_controls(component,
 528				       cs530x_in_1_to_2_controls,
 529				       ARRAY_SIZE(cs530x_in_1_to_2_controls));
 530
 531	snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets,
 532				  ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets));
 533
 534	snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes,
 535				ARRAY_SIZE(adc_ch1_2_routes));
 536}
 537
 538static void cs530x_add_34_adc_widgets(struct snd_soc_component *component)
 539{
 540	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 541
 542	snd_soc_add_component_controls(component,
 543				       cs530x_in_3_to_4_controls,
 544				       ARRAY_SIZE(cs530x_in_3_to_4_controls));
 545
 546	snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets,
 547				  ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets));
 548
 549	snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes,
 550				ARRAY_SIZE(adc_ch3_4_routes));
 551}
 552
 553/* DAC's Channels 1 and 2 plus generic DAC DAPM events */
 554static const struct snd_soc_dapm_widget cs530x_dac_ch12_dapm_widgets[] = {
 555SND_SOC_DAPM_OUTPUT("OUT1"),
 556SND_SOC_DAPM_OUTPUT("OUT2"),
 557SND_SOC_DAPM_DAC_E("DAC1", NULL, CS530X_OUT_ENABLES, 0, 0,
 558		   cs530x_dac_event,
 559		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 560		   SND_SOC_DAPM_PRE_PMU),
 561SND_SOC_DAPM_DAC("DAC2", NULL, CS530X_OUT_ENABLES, 1, 0),
 562SND_SOC_DAPM_SWITCH("DAC12 Enable", SND_SOC_NOPM, 0, 0, &dac12_ctrl),
 563SND_SOC_DAPM_SWITCH("OUT HPF", CS530X_OUT_FILTER, CS530X_INOUT_HPF_EN_SHIFT,
 564		    0, &out_hpf_ctrl),
 565};
 566
 567/* DAC's Channels 3 and 4 */
 568static const struct snd_soc_dapm_widget cs530x_dac_ch34_dapm_widgets[] = {
 569SND_SOC_DAPM_OUTPUT("OUT3"),
 570SND_SOC_DAPM_OUTPUT("OUT4"),
 571SND_SOC_DAPM_DAC_E("DAC3", NULL, CS530X_OUT_ENABLES, 2, 0,
 572		   cs530x_dac_event,
 573		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 574		   SND_SOC_DAPM_PRE_PMU),
 575SND_SOC_DAPM_DAC("DAC4", NULL, CS530X_OUT_ENABLES, 3, 0),
 576SND_SOC_DAPM_SWITCH("DAC34 Enable", SND_SOC_NOPM, 0, 0, &dac34_ctrl),
 577};
 578
 579/* DAC's Channels 5 to 8 */
 580static const struct snd_soc_dapm_widget cs530x_dac_ch58_dapm_widgets[] = {
 581SND_SOC_DAPM_OUTPUT("OUT5"),
 582SND_SOC_DAPM_OUTPUT("OUT6"),
 583SND_SOC_DAPM_OUTPUT("OUT7"),
 584SND_SOC_DAPM_OUTPUT("OUT8"),
 585SND_SOC_DAPM_DAC_E("DAC5", NULL, CS530X_OUT_ENABLES, 4, 0,
 586		   cs530x_dac_event,
 587		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 588		   SND_SOC_DAPM_PRE_PMU),
 589SND_SOC_DAPM_DAC("DAC6", NULL, CS530X_OUT_ENABLES, 5, 0),
 590SND_SOC_DAPM_SWITCH("DAC56 Enable", SND_SOC_NOPM, 0, 0, &dac56_ctrl),
 591SND_SOC_DAPM_DAC_E("DAC7", NULL, CS530X_OUT_ENABLES, 6, 0,
 592		   cs530x_dac_event,
 593		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
 594		   SND_SOC_DAPM_PRE_PMU),
 595SND_SOC_DAPM_DAC("DAC8", NULL, CS530X_OUT_ENABLES, 7, 0),
 596SND_SOC_DAPM_SWITCH("DAC78 Enable", SND_SOC_NOPM, 0, 0, &dac78_ctrl),
 597};
 598
 599static const struct snd_soc_dapm_route dac_ch1_2_routes[] = {
 600	{ "DAC1", NULL, "Global Enable" },
 601	{ "DAC2", NULL, "Global Enable" },
 602
 603	{ "DAC12 Enable", "Switch", "OUT1" },
 604	{ "DAC12 Enable", "Switch", "OUT2" },
 605	{ "DAC1", NULL, "DAC12 Enable" },
 606	{ "DAC2", NULL, "DAC12 Enable" },
 607	{ "OUT HPF", "Switch", "DAC1" },
 608	{ "OUT HPF", "Switch", "DAC2" },
 609
 610	{ "OUT HPF", NULL, "AIF Playback" },
 611	{ "DAC1", NULL, "AIF Playback" },
 612	{ "DAC2", NULL, "AIF Playback" },
 613
 614	{ "OUT1", NULL, "DAC1" },
 615	{ "OUT2", NULL, "DAC2" },
 616};
 617
 618static const struct snd_soc_dapm_route dac_ch3_4_routes[] = {
 619	{ "DAC3", NULL, "Global Enable" },
 620	{ "DAC4", NULL, "Global Enable" },
 621
 622	{ "DAC34 Enable", "Switch", "OUT3" },
 623	{ "DAC34 Enable", "Switch", "OUT4" },
 624	{ "DAC3", NULL, "DAC34 Enable" },
 625	{ "DAC4", NULL, "DAC34 Enable" },
 626	{ "OUT HPF", "Switch", "DAC3" },
 627	{ "OUT HPF", "Switch", "DAC4" },
 628
 629	{ "DAC3", NULL, "AIF Playback" },
 630	{ "DAC4", NULL, "AIF Playback" },
 631
 632	{ "OUT3", NULL, "DAC3" },
 633	{ "OUT4", NULL, "DAC4" },
 634};
 635
 636static const struct snd_soc_dapm_route dac_ch5_8_routes[] = {
 637	{ "DAC5", NULL, "Global Enable" },
 638	{ "DAC6", NULL, "Global Enable" },
 639
 640	{ "DAC56 Enable", "Switch", "OUT5" },
 641	{ "DAC56 Enable", "Switch", "OUT6" },
 642	{ "DAC5", NULL, "DAC56 Enable" },
 643	{ "DAC6", NULL, "DAC56 Enable" },
 644	{ "OUT HPF", "Switch", "DAC5" },
 645	{ "OUT HPF", "Switch", "DAC6" },
 646
 647	{ "DAC5", NULL, "AIF Playback" },
 648	{ "DAC6", NULL, "AIF Playback" },
 649
 650	{ "OUT5", NULL, "DAC5" },
 651	{ "OUT6", NULL, "DAC6" },
 652
 653	{ "DAC7", NULL, "Global Enable" },
 654	{ "DAC8", NULL, "Global Enable" },
 655
 656	{ "DAC78 Enable", "Switch", "OUT7" },
 657	{ "DAC78 Enable", "Switch", "OUT8" },
 658	{ "DAC7", NULL, "DAC78 Enable" },
 659	{ "DAC8", NULL, "DAC78 Enable" },
 660	{ "OUT HPF", "Switch", "DAC7" },
 661	{ "OUT HPF", "Switch", "DAC8" },
 662
 663	{ "DAC7", NULL, "AIF Playback" },
 664	{ "DAC8", NULL, "AIF Playback" },
 665
 666	{ "OUT7", NULL, "DAC7" },
 667	{ "OUT8", NULL, "DAC8" },
 668};
 669
 670static void cs530x_add_12_dac_widgets(struct snd_soc_component *component)
 671{
 672	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 673
 674	snd_soc_add_component_controls(component,
 675				       cs530x_out_1_to_2_controls,
 676				       ARRAY_SIZE(cs530x_out_1_to_2_controls));
 677
 678	snd_soc_dapm_new_controls(dapm, cs530x_dac_ch12_dapm_widgets,
 679				  ARRAY_SIZE(cs530x_dac_ch12_dapm_widgets));
 680
 681	snd_soc_dapm_add_routes(dapm, dac_ch1_2_routes,
 682				ARRAY_SIZE(dac_ch1_2_routes));
 683}
 684
 685static void cs530x_add_34_dac_widgets(struct snd_soc_component *component)
 686{
 687	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 688
 689	snd_soc_add_component_controls(component,
 690				       cs530x_out_3_to_4_controls,
 691				       ARRAY_SIZE(cs530x_out_3_to_4_controls));
 692
 693	snd_soc_dapm_new_controls(dapm, cs530x_dac_ch34_dapm_widgets,
 694				  ARRAY_SIZE(cs530x_dac_ch34_dapm_widgets));
 695
 696	snd_soc_dapm_add_routes(dapm, dac_ch3_4_routes,
 697				ARRAY_SIZE(dac_ch3_4_routes));
 698}
 699
 700static int cs530x_set_bclk(struct snd_soc_component *component, const int freq)
 701{
 702	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 703	struct regmap *regmap = cs530x->regmap;
 704	unsigned int bclk_val;
 705
 706	switch (freq) {
 707	case 2822400:
 708	case 3072000:
 709		bclk_val = CS530X_BCLK_2P822_3P072;
 710		break;
 711	case 5644800:
 712	case 6144000:
 713		bclk_val = CS530X_BCLK_5P6448_6P144;
 714		break;
 715	case 11289600:
 716	case 12288000:
 717		bclk_val = CS530X_BCLK_11P2896_12P288;
 718		break;
 719	case 22579200:
 720	case 24576000:
 721		bclk_val = CS530X_BCLK_24P5792_24P576;
 722		break;
 723	default:
 724		dev_err(component->dev, "Invalid BCLK frequency %d\n", freq);
 725		return -EINVAL;
 726	}
 727
 728	dev_dbg(component->dev, "BCLK frequency is %d\n", freq);
 729
 730	return regmap_update_bits(regmap, CS530X_ASP_CFG,
 731				  CS530X_ASP_BCLK_FREQ_MASK, bclk_val);
 732}
 733
 734static int cs530x_set_pll_refclk(struct snd_soc_component *component,
 735				 const unsigned int freq)
 736{
 737	struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
 738	struct regmap *regmap = priv->regmap;
 739	unsigned int refclk;
 740
 741	switch (freq) {
 742	case 2822400:
 743	case 3072000:
 744		refclk = CS530X_REFCLK_2P822_3P072;
 745		break;
 746	case 5644800:
 747	case 6144000:
 748		refclk = CS530X_REFCLK_5P6448_6P144;
 749		break;
 750	case 11289600:
 751	case 12288000:
 752		refclk = CS530X_REFCLK_11P2896_12P288;
 753		break;
 754	case 22579200:
 755	case 24576000:
 756		refclk = CS530X_REFCLK_24P5792_24P576;
 757		break;
 758	default:
 759		dev_err(component->dev, "Invalid PLL refclk %d\n", freq);
 760		return -EINVAL;
 761	}
 762
 763	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
 764				  CS530X_PLL_REFCLK_FREQ_MASK, refclk);
 765}
 766
 767static int cs530x_hw_params(struct snd_pcm_substream *substream,
 768			    struct snd_pcm_hw_params *params,
 769			    struct snd_soc_dai *dai)
 770{
 771	struct snd_soc_component *component = dai->component;
 772	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 773	struct regmap *regmap = cs530x->regmap;
 774	int ret = 0, fs = params_rate(params), bclk;
 775	unsigned int fs_val;
 776
 777	switch (fs) {
 778	case 32000:
 779		fs_val = CS530X_FS_32K;
 780		break;
 781	case 44100:
 782	case 48000:
 783		fs_val = CS530X_FS_44P1K_48K;
 784		break;
 785	case 88200:
 786	case 96000:
 787		fs_val = CS530X_FS_88P2K_96K;
 788		break;
 789	case 176400:
 790	case 192000:
 791		fs_val = CS530X_FS_176P4K_192K;
 792		break;
 793	case 356800:
 794	case 384000:
 795		fs_val = CS530X_FS_356P8K_384K;
 796		break;
 797	case 705600:
 798	case 768000:
 799		fs_val = CS530X_FS_705P6K_768K;
 800		break;
 801	default:
 802		dev_err(component->dev, "Invalid sample rate %d\n", fs);
 803		return -EINVAL;
 804	}
 805
 806	regmap_update_bits(regmap, CS530X_CLK_CFG_1,
 807			   CS530X_SAMPLE_RATE_MASK, fs_val);
 808
 809
 810	if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG,
 811			     CS530X_TDM_EN_MASK)) {
 812		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
 813			cs530x->tdm_slots, cs530x->tdm_width);
 814		bclk = snd_soc_tdm_params_to_bclk(params,
 815						  cs530x->tdm_width,
 816						  cs530x->tdm_slots,
 817						  1);
 818	} else {
 819		bclk = snd_soc_params_to_bclk(params);
 820	}
 821
 822	if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0,
 823			      CS530X_PLL_REFCLK_SRC_MASK)) {
 824		ret = cs530x_set_pll_refclk(component, bclk);
 825		if (ret)
 826			return ret;
 827	}
 828
 829	return cs530x_set_bclk(component, bclk);
 830}
 831
 832static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 833{
 834	struct snd_soc_component *component = dai->component;
 835	struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
 836	struct regmap *regmap = priv->regmap;
 837	unsigned int asp_fmt, asp_cfg = 0;
 838
 839	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 840	case SND_SOC_DAIFMT_CBC_CFC:
 841		break;
 842	case SND_SOC_DAIFMT_CBP_CFP:
 843		asp_cfg = CS530X_ASP_PRIMARY;
 844		break;
 845	default:
 846		return -EINVAL;
 847	}
 848
 849	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 850	case SND_SOC_DAIFMT_DSP_A:
 851		asp_fmt = CS530X_ASP_FMT_DSP_A;
 852		break;
 853	case SND_SOC_DAIFMT_I2S:
 854		asp_fmt = CS530X_ASP_FMT_I2S;
 855		break;
 856	case SND_SOC_DAIFMT_LEFT_J:
 857		asp_fmt = CS530X_ASP_FMT_LJ;
 858		break;
 859	default:
 860		return -EINVAL;
 861	}
 862
 863	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 864	case SND_SOC_DAIFMT_NB_NF:
 865		break;
 866	case SND_SOC_DAIFMT_IB_IF:
 867		asp_cfg |= CS530X_ASP_BCLK_INV;
 868		break;
 869	default:
 870		return -EINVAL;
 871	}
 872
 873	regmap_update_bits(regmap, CS530X_ASP_CFG,
 874			   CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV,
 875			   asp_cfg);
 876
 877	return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
 878				  CS530X_ASP_FMT_MASK, asp_fmt);
 879}
 880
 881static bool cs530x_check_mclk_freq(struct snd_soc_component *component,
 882				   const unsigned int freq)
 883{
 884	switch (freq) {
 885	case 24576000:
 886	case 22579200:
 887	case 12288000:
 888	case 11289600:
 889		return true;
 890	default:
 891		dev_err(component->dev, "Invalid MCLK %d\n", freq);
 892		return false;
 893	}
 894}
 895
 896static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 897			       unsigned int rx_mask, int slots, int slot_width)
 898{
 899	struct snd_soc_component *component = dai->component;
 900	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 901	struct regmap *regmap = cs530x->regmap;
 902	unsigned int val;
 903
 904	switch (tx_mask) {
 905	case CS530X_0_1_TDM_SLOT_MASK:
 906	case CS530X_0_3_TDM_SLOT_MASK:
 907	case CS530X_0_7_TDM_SLOT_MASK:
 908		val = CS530X_0_7_TDM_SLOT_VAL;
 909		break;
 910	case CS530X_2_3_TDM_SLOT_MASK:
 911		val = CS530X_2_3_TDM_SLOT_VAL;
 912		break;
 913	case CS530X_4_5_TDM_SLOT_MASK:
 914	case CS530X_4_7_TDM_SLOT_MASK:
 915		val = CS530X_4_7_TDM_SLOT_VAL;
 916		break;
 917	case CS530X_6_7_TDM_SLOT_MASK:
 918		val = CS530X_6_7_TDM_SLOT_VAL;
 919		break;
 920	case CS530X_8_9_TDM_SLOT_MASK:
 921	case CS530X_8_11_TDM_SLOT_MASK:
 922	case CS530X_8_15_TDM_SLOT_MASK:
 923		val = CS530X_8_15_TDM_SLOT_VAL;
 924		break;
 925	case CS530X_10_11_TDM_SLOT_MASK:
 926		val = CS530X_10_11_TDM_SLOT_VAL;
 927		break;
 928	case CS530X_12_13_TDM_SLOT_MASK:
 929	case CS530X_12_15_TDM_SLOT_MASK:
 930		val = CS530X_12_15_TDM_SLOT_VAL;
 931		break;
 932	case CS530X_14_15_TDM_SLOT_MASK:
 933		val = CS530X_14_15_TDM_SLOT_VAL;
 934		break;
 935	default:
 936		dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask);
 937		return -EINVAL;
 938	}
 939
 940	cs530x->tdm_width = slot_width;
 941	cs530x->tdm_slots = slots;
 942
 943	return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
 944				  CS530X_ASP_TDM_SLOT_MASK,
 945				  val << CS530X_ASP_TDM_SLOT_SHIFT);
 946}
 947
 948static const struct snd_soc_dai_ops cs530x_dai_ops = {
 949	.set_fmt = cs530x_set_fmt,
 950	.hw_params = cs530x_hw_params,
 951	.set_tdm_slot = cs530x_set_tdm_slot,
 952};
 953
 954static const struct snd_soc_dai_driver cs530x_dai = {
 955	.name = "cs530x-dai",
 956	.capture = {
 957		.stream_name = "AIF Capture",
 958		.rates = SNDRV_PCM_RATE_KNOT,
 959		.formats = SNDRV_PCM_FMTBIT_S32_LE,
 960	},
 961	.playback = {
 962		.stream_name = "AIF Playback",
 963		.rates = SNDRV_PCM_RATE_KNOT,
 964		.formats = SNDRV_PCM_FMTBIT_S32_LE,
 965	},
 966	.ops = &cs530x_dai_ops,
 967	.symmetric_rate = 1,
 968	.symmetric_sample_bits = 1,
 969};
 970
 971static int cs530x_set_pll(struct snd_soc_component *component, int pll_id,
 972			  int source, unsigned int freq_in,
 973			  unsigned int freq_out)
 974{
 975	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
 976	struct regmap *regmap = cs530x->regmap;
 977	unsigned int sysclk_src;
 978	int ret;
 979
 980	regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src);
 981
 982	/* Check if the source is the PLL  */
 983	if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0)
 984		return 0;
 985
 986	switch (source) {
 987	case CS530X_PLL_SRC_MCLK:
 988		if (!cs530x_check_mclk_freq(component, freq_in))
 989			return -EINVAL;
 990
 991		ret = cs530x_set_pll_refclk(component, freq_in);
 992		if (ret)
 993			return ret;
 994
 995		break;
 996	case CS530X_PLL_SRC_BCLK:
 997		break;
 998	default:
 999		dev_err(component->dev, "Invalid PLL source %d\n", source);
1000		return -EINVAL;
1001	}
1002
1003	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
1004				  CS530X_PLL_REFCLK_SRC_MASK, source);
1005}
1006
1007static int cs530x_component_probe(struct snd_soc_component *component)
1008{
1009	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
1010	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
1011	int num_widgets;
1012
1013	snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets,
1014				  ARRAY_SIZE(cs530x_gen_dapm_widgets));
1015
1016	switch (cs530x->devtype) {
1017	case CS4282:
1018		cs530x_add_12_adc_widgets(component);
1019		cs530x_add_12_dac_widgets(component);
1020		break;
1021	case CS4302:
1022		cs530x_add_12_dac_widgets(component);
1023		break;
1024	case CS4304:
1025		cs530x_add_12_dac_widgets(component);
1026		cs530x_add_34_dac_widgets(component);
1027
1028		num_widgets = ARRAY_SIZE(cs530x_out_sum_4ch_controls);
1029		snd_soc_add_component_controls(component,
1030					       cs530x_out_sum_4ch_controls,
1031					       num_widgets);
1032		break;
1033	case CS4308:
1034		cs530x_add_12_dac_widgets(component);
1035		cs530x_add_34_dac_widgets(component);
1036
1037		num_widgets = ARRAY_SIZE(cs530x_out_5_to_8_controls);
1038		snd_soc_add_component_controls(component,
1039					       cs530x_out_5_to_8_controls,
1040					       num_widgets);
1041
1042		num_widgets = ARRAY_SIZE(cs530x_out_sum_8ch_controls);
1043		snd_soc_add_component_controls(component,
1044					       cs530x_out_sum_8ch_controls,
1045					       num_widgets);
1046
1047		num_widgets = ARRAY_SIZE(cs530x_dac_ch58_dapm_widgets);
1048		snd_soc_dapm_new_controls(dapm, cs530x_dac_ch58_dapm_widgets,
1049					  num_widgets);
1050
1051		snd_soc_dapm_add_routes(dapm, dac_ch5_8_routes,
1052					ARRAY_SIZE(dac_ch5_8_routes));
1053		break;
1054	case CS5302:
1055		cs530x_add_12_adc_widgets(component);
1056		break;
1057	case CS5304:
1058		cs530x_add_12_adc_widgets(component);
1059		cs530x_add_34_adc_widgets(component);
1060
1061		num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls);
1062		snd_soc_add_component_controls(component,
1063					       cs530x_in_sum_4ch_controls,
1064					       num_widgets);
1065		break;
1066	case CS5308:
1067		cs530x_add_12_adc_widgets(component);
1068		cs530x_add_34_adc_widgets(component);
1069
1070		num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls);
1071		snd_soc_add_component_controls(component,
1072					       cs530x_in_5_to_8_controls,
1073					       num_widgets);
1074
1075		num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls);
1076		snd_soc_add_component_controls(component,
1077					       cs530x_in_sum_8ch_controls,
1078					       num_widgets);
1079
1080		num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets);
1081		snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets,
1082					  num_widgets);
1083
1084		snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes,
1085					ARRAY_SIZE(adc_ch5_8_routes));
1086		break;
1087	default:
1088		dev_err(component->dev, "Invalid device type %d\n",
1089			cs530x->devtype);
1090		return -EINVAL;
1091	}
1092
1093	return 0;
1094}
1095
1096static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
1097			     int source, unsigned int freq, int dir)
1098{
1099	struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
1100	struct regmap *regmap = cs530x->regmap;
1101
1102	switch (source) {
1103	case CS530X_SYSCLK_SRC_MCLK:
1104		switch (freq) {
1105		case CS530X_SYSCLK_REF_45_1MHZ:
1106		case CS530X_SYSCLK_REF_49_1MHZ:
1107			break;
1108		default:
1109			dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
1110			return -EINVAL;
1111		}
1112		break;
1113	case CS530X_SYSCLK_SRC_PLL:
1114		break;
1115	default:
1116		dev_err(component->dev, "Invalid sysclk source: %d\n", source);
1117		return -EINVAL;
1118	}
1119
1120	return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
1121				  CS530X_SYSCLK_SRC_MASK,
1122				  source << CS530X_SYSCLK_SRC_SHIFT);
1123}
1124
1125static const struct snd_soc_component_driver soc_component_dev_cs530x = {
1126	.probe			= cs530x_component_probe,
1127	.set_sysclk		= cs530x_set_sysclk,
1128	.set_pll		= cs530x_set_pll,
1129	.endianness		= 1,
1130};
1131
1132const struct regmap_config cs530x_regmap_i2c = {
1133	.reg_bits = 16,
1134	.val_bits = 16,
1135
1136	.max_register = CS530X_MAX_REGISTER,
1137	.readable_reg = cs530x_readable_register,
1138	.writeable_reg = cs530x_writeable_register,
1139
1140	.cache_type = REGCACHE_MAPLE,
1141	.reg_defaults = cs530x_reg_defaults,
1142	.num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
1143};
1144EXPORT_SYMBOL_NS_GPL(cs530x_regmap_i2c, "SND_SOC_CS530X");
1145
1146const struct regmap_config cs530x_regmap_spi = {
1147	.reg_bits = 16,
1148	.pad_bits = 16,
1149	.val_bits = 16,
1150
1151	.reg_stride = 2,
1152
1153	.reg_format_endian = REGMAP_ENDIAN_BIG,
1154	.val_format_endian = REGMAP_ENDIAN_BIG,
1155
1156	.max_register = CS530X_MAX_REGISTER,
1157	.writeable_reg = cs530x_writeable_register,
1158	.readable_reg = cs530x_readable_register,
1159
1160	.cache_type = REGCACHE_MAPLE,
1161	.reg_defaults = cs530x_reg_defaults,
1162	.num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
1163};
1164EXPORT_SYMBOL_NS_GPL(cs530x_regmap_spi, "SND_SOC_CS530X");
1165
1166static int cs530x_check_device_id(struct cs530x_priv *cs530x)
1167{
1168	struct device *dev = cs530x->dev;
1169	unsigned int dev_id, rev;
1170	int ret;
1171
1172	ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id);
1173	if (ret)
1174		return dev_err_probe(dev, ret, "Can't read device ID\n");
1175
1176	ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev);
1177	if (ret)
1178		return dev_err_probe(dev, ret, "Can't read REV ID\n");
1179
1180	switch (dev_id) {
1181	case CS530X_2CH_CODEC_DEV_ID:
1182		cs530x->num_dacs = 2;
1183		cs530x->num_adcs = 2;
1184		break;
1185	case CS530X_2CH_DAC_DEV_ID:
1186		cs530x->num_dacs = 2;
1187		break;
1188	case CS530X_4CH_DAC_DEV_ID:
1189		cs530x->num_dacs = 4;
1190		break;
1191	case CS530X_8CH_DAC_DEV_ID:
1192		cs530x->num_dacs = 8;
1193		break;
1194	case CS530X_2CH_ADC_DEV_ID:
1195		cs530x->num_adcs = 2;
1196		break;
1197	case CS530X_4CH_ADC_DEV_ID:
1198		cs530x->num_adcs = 4;
1199		break;
1200	case CS530X_8CH_ADC_DEV_ID:
1201		cs530x->num_adcs = 8;
1202		break;
1203	default:
1204		return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n",
1205				     dev_id);
1206	}
1207
1208	if (cs530x->devtype != dev_id) {
1209		dev_err(dev, "Read device ID 0x%x is not the expected devtype 0x%x\n",
1210			dev_id, cs530x->devtype);
1211		return -EINVAL;
1212	}
1213
1214	dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x (%d in %d out)\n", dev_id, rev,
1215		cs530x->num_adcs, cs530x->num_dacs);
1216
1217	return 0;
1218}
1219
1220static int cs530x_parse_device_properties(struct cs530x_priv *cs530x)
1221{
1222	struct regmap *regmap = cs530x->regmap;
1223	struct device *dev = cs530x->dev;
1224	unsigned int val = 0;
1225
1226	switch (cs530x->num_adcs) {
1227	case 8:
1228		if (device_property_read_bool(dev, "cirrus,in-hiz-pin78"))
1229			val = CS530X_IN78_HIZ;
1230
1231		if (device_property_read_bool(dev, "cirrus,in-hiz-pin56"))
1232			val |= CS530X_IN56_HIZ;
1233
1234		fallthrough;
1235	case 4:
1236		if (device_property_read_bool(dev, "cirrus,in-hiz-pin34"))
1237			val |= CS530X_IN34_HIZ;
1238
1239		fallthrough;
1240	case 2:
1241		if (device_property_read_bool(dev, "cirrus,in-hiz-pin12"))
1242			val |= CS530X_IN12_HIZ;
1243
1244		return regmap_set_bits(regmap, CS530X_IN_HIZ, val);
1245	case 0:
1246		/* No ADCs */
1247		return 0;
1248	default:
1249		return dev_err_probe(dev, -EINVAL,
1250				     "Invalid number of adcs %d\n",
1251				     cs530x->num_adcs);
1252	}
1253}
1254
1255int cs530x_probe(struct cs530x_priv *cs530x)
1256{
1257	struct device *dev = cs530x->dev;
1258	int ret, i;
1259
1260	cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai,
1261				       sizeof(*(cs530x->dev_dai)),
1262				       GFP_KERNEL);
1263	if (!cs530x->dev_dai)
1264		return -ENOMEM;
1265
1266	for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++)
1267		cs530x->supplies[i].supply = cs530x_supply_names[i];
1268
1269	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies),
1270				      cs530x->supplies);
1271	if (ret != 0)
1272		return dev_err_probe(dev, ret, "Failed to request supplies");
1273
1274	ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies),
1275				    cs530x->supplies);
1276	if (ret != 0)
1277		return dev_err_probe(dev, ret, "Failed to enable supplies");
1278
1279	cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
1280						     GPIOD_OUT_HIGH);
1281	if (IS_ERR(cs530x->reset_gpio)) {
1282		ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio),
1283				    "Reset gpio not available\n");
1284		goto err_regulator;
1285	}
1286
1287	if (cs530x->reset_gpio) {
1288		usleep_range(2000, 2100);
1289		gpiod_set_value_cansleep(cs530x->reset_gpio, 0);
1290	}
1291
1292	usleep_range(5000, 5100);
1293	ret = cs530x_check_device_id(cs530x);
1294	if (ret)
1295		goto err_reset;
1296
1297	if (!cs530x->reset_gpio) {
1298		ret = regmap_write(cs530x->regmap, CS530X_SW_RESET,
1299				   CS530X_SW_RST_VAL);
1300		if (ret) {
1301			dev_err_probe(dev, ret, "Soft Reset Failed\n");
1302			goto err_reset;
1303		}
1304	}
1305
1306	ret = cs530x_parse_device_properties(cs530x);
1307	if (ret)
1308		goto err_reset;
1309
1310	if (cs530x->num_adcs) {
1311		cs530x->dev_dai->capture.channels_min = 2;
1312		cs530x->dev_dai->capture.channels_max = cs530x->num_adcs;
1313	}
1314
1315	if (cs530x->num_dacs) {
1316		cs530x->dev_dai->playback.channels_min = 2;
1317		cs530x->dev_dai->playback.channels_max = cs530x->num_dacs;
1318	}
1319
1320	ret = devm_snd_soc_register_component(dev,
1321					      &soc_component_dev_cs530x,
1322					      cs530x->dev_dai, 1);
1323	if (ret) {
1324		dev_err_probe(dev, ret, "Can't register cs530x component\n");
1325		goto err_reset;
1326	}
1327
1328	return 0;
1329
1330err_reset:
1331	gpiod_set_value_cansleep(cs530x->reset_gpio, 1);
1332
1333err_regulator:
1334	regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies),
1335			       cs530x->supplies);
1336
1337	return ret;
1338}
1339EXPORT_SYMBOL_NS_GPL(cs530x_probe, "SND_SOC_CS530X");
1340
1341MODULE_DESCRIPTION("CS530X CODEC Driver");
1342MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>");
1343MODULE_LICENSE("GPL");
~/ Read-only file preview.