| .. | .. |
|---|
| 24 | 24 | #define TDMOUT_CTRL1 0x04 |
|---|
| 25 | 25 | #define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4) |
|---|
| 26 | 26 | #define TDMOUT_CTRL1_TYPE(x) ((x) << 4) |
|---|
| 27 | +#define SM1_TDMOUT_CTRL1_GAIN_EN 7 |
|---|
| 27 | 28 | #define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8) |
|---|
| 28 | 29 | #define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8) |
|---|
| 29 | 30 | #define TDMOUT_CTRL1_SEL_SHIFT 24 |
|---|
| .. | .. |
|---|
| 50 | 51 | .reg_stride = 4, |
|---|
| 51 | 52 | .max_register = TDMOUT_MASK_VAL, |
|---|
| 52 | 53 | }; |
|---|
| 53 | | - |
|---|
| 54 | | -static const struct snd_kcontrol_new axg_tdmout_controls[] = { |
|---|
| 55 | | - SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), |
|---|
| 56 | | - SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), |
|---|
| 57 | | - SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), |
|---|
| 58 | | - SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), |
|---|
| 59 | | - SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, |
|---|
| 60 | | - TDMOUT_CTRL1_GAIN_EN, 1, 0), |
|---|
| 61 | | -}; |
|---|
| 62 | | - |
|---|
| 63 | | -static const char * const tdmout_sel_texts[] = { |
|---|
| 64 | | - "IN 0", "IN 1", "IN 2", |
|---|
| 65 | | -}; |
|---|
| 66 | | - |
|---|
| 67 | | -static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, |
|---|
| 68 | | - TDMOUT_CTRL1_SEL_SHIFT, tdmout_sel_texts); |
|---|
| 69 | | - |
|---|
| 70 | | -static const struct snd_kcontrol_new axg_tdmout_in_mux = |
|---|
| 71 | | - SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); |
|---|
| 72 | 54 | |
|---|
| 73 | 55 | static struct snd_soc_dai * |
|---|
| 74 | 56 | axg_tdmout_get_be(struct snd_soc_dapm_widget *w) |
|---|
| .. | .. |
|---|
| 124 | 106 | regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0); |
|---|
| 125 | 107 | } |
|---|
| 126 | 108 | |
|---|
| 127 | | -static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) |
|---|
| 109 | +static int axg_tdmout_prepare(struct regmap *map, |
|---|
| 110 | + const struct axg_tdm_formatter_hw *quirks, |
|---|
| 111 | + struct axg_tdm_stream *ts) |
|---|
| 128 | 112 | { |
|---|
| 129 | | - unsigned int val = 0; |
|---|
| 113 | + unsigned int val, skew = quirks->skew_offset; |
|---|
| 130 | 114 | |
|---|
| 131 | 115 | /* Set the stream skew */ |
|---|
| 132 | 116 | switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
|---|
| 133 | 117 | case SND_SOC_DAIFMT_I2S: |
|---|
| 134 | 118 | case SND_SOC_DAIFMT_DSP_A: |
|---|
| 135 | | - val |= TDMOUT_CTRL0_INIT_BITNUM(1); |
|---|
| 136 | 119 | break; |
|---|
| 137 | 120 | |
|---|
| 138 | 121 | case SND_SOC_DAIFMT_LEFT_J: |
|---|
| 139 | 122 | case SND_SOC_DAIFMT_DSP_B: |
|---|
| 140 | | - val |= TDMOUT_CTRL0_INIT_BITNUM(2); |
|---|
| 123 | + skew += 1; |
|---|
| 141 | 124 | break; |
|---|
| 142 | 125 | |
|---|
| 143 | 126 | default: |
|---|
| .. | .. |
|---|
| 145 | 128 | ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
|---|
| 146 | 129 | return -EINVAL; |
|---|
| 147 | 130 | } |
|---|
| 131 | + |
|---|
| 132 | + val = TDMOUT_CTRL0_INIT_BITNUM(skew); |
|---|
| 148 | 133 | |
|---|
| 149 | 134 | /* Set the slot width */ |
|---|
| 150 | 135 | val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1); |
|---|
| .. | .. |
|---|
| 194 | 179 | return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0); |
|---|
| 195 | 180 | } |
|---|
| 196 | 181 | |
|---|
| 182 | +static const struct snd_kcontrol_new axg_tdmout_controls[] = { |
|---|
| 183 | + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), |
|---|
| 184 | + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), |
|---|
| 185 | + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), |
|---|
| 186 | + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), |
|---|
| 187 | + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, |
|---|
| 188 | + TDMOUT_CTRL1_GAIN_EN, 1, 0), |
|---|
| 189 | +}; |
|---|
| 190 | + |
|---|
| 191 | +static const char * const axg_tdmout_sel_texts[] = { |
|---|
| 192 | + "IN 0", "IN 1", "IN 2", |
|---|
| 193 | +}; |
|---|
| 194 | + |
|---|
| 195 | +static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, |
|---|
| 196 | + TDMOUT_CTRL1_SEL_SHIFT, axg_tdmout_sel_texts); |
|---|
| 197 | + |
|---|
| 198 | +static const struct snd_kcontrol_new axg_tdmout_in_mux = |
|---|
| 199 | + SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); |
|---|
| 200 | + |
|---|
| 197 | 201 | static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = { |
|---|
| 198 | 202 | SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 199 | 203 | SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| .. | .. |
|---|
| 233 | 237 | .component_drv = &axg_tdmout_component_drv, |
|---|
| 234 | 238 | .regmap_cfg = &axg_tdmout_regmap_cfg, |
|---|
| 235 | 239 | .ops = &axg_tdmout_ops, |
|---|
| 236 | | - .invert_sclk = true, |
|---|
| 240 | + .quirks = &(const struct axg_tdm_formatter_hw) { |
|---|
| 241 | + .skew_offset = 1, |
|---|
| 242 | + }, |
|---|
| 243 | +}; |
|---|
| 244 | + |
|---|
| 245 | +static const struct axg_tdm_formatter_driver g12a_tdmout_drv = { |
|---|
| 246 | + .component_drv = &axg_tdmout_component_drv, |
|---|
| 247 | + .regmap_cfg = &axg_tdmout_regmap_cfg, |
|---|
| 248 | + .ops = &axg_tdmout_ops, |
|---|
| 249 | + .quirks = &(const struct axg_tdm_formatter_hw) { |
|---|
| 250 | + .skew_offset = 2, |
|---|
| 251 | + }, |
|---|
| 252 | +}; |
|---|
| 253 | + |
|---|
| 254 | +static const struct snd_kcontrol_new sm1_tdmout_controls[] = { |
|---|
| 255 | + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), |
|---|
| 256 | + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), |
|---|
| 257 | + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), |
|---|
| 258 | + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), |
|---|
| 259 | + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, |
|---|
| 260 | + SM1_TDMOUT_CTRL1_GAIN_EN, 1, 0), |
|---|
| 261 | +}; |
|---|
| 262 | + |
|---|
| 263 | +static const char * const sm1_tdmout_sel_texts[] = { |
|---|
| 264 | + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", |
|---|
| 265 | +}; |
|---|
| 266 | + |
|---|
| 267 | +static SOC_ENUM_SINGLE_DECL(sm1_tdmout_sel_enum, TDMOUT_CTRL1, |
|---|
| 268 | + TDMOUT_CTRL1_SEL_SHIFT, sm1_tdmout_sel_texts); |
|---|
| 269 | + |
|---|
| 270 | +static const struct snd_kcontrol_new sm1_tdmout_in_mux = |
|---|
| 271 | + SOC_DAPM_ENUM("Input Source", sm1_tdmout_sel_enum); |
|---|
| 272 | + |
|---|
| 273 | +static const struct snd_soc_dapm_widget sm1_tdmout_dapm_widgets[] = { |
|---|
| 274 | + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 275 | + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 276 | + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 277 | + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 278 | + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 279 | + SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_tdmout_in_mux), |
|---|
| 280 | + SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0, |
|---|
| 281 | + axg_tdm_formatter_event, |
|---|
| 282 | + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), |
|---|
| 283 | + SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0), |
|---|
| 284 | +}; |
|---|
| 285 | + |
|---|
| 286 | +static const struct snd_soc_dapm_route sm1_tdmout_dapm_routes[] = { |
|---|
| 287 | + { "SRC SEL", "IN 0", "IN 0" }, |
|---|
| 288 | + { "SRC SEL", "IN 1", "IN 1" }, |
|---|
| 289 | + { "SRC SEL", "IN 2", "IN 2" }, |
|---|
| 290 | + { "SRC SEL", "IN 3", "IN 3" }, |
|---|
| 291 | + { "SRC SEL", "IN 4", "IN 4" }, |
|---|
| 292 | + { "ENC", NULL, "SRC SEL" }, |
|---|
| 293 | + { "OUT", NULL, "ENC" }, |
|---|
| 294 | +}; |
|---|
| 295 | + |
|---|
| 296 | +static const struct snd_soc_component_driver sm1_tdmout_component_drv = { |
|---|
| 297 | + .controls = sm1_tdmout_controls, |
|---|
| 298 | + .num_controls = ARRAY_SIZE(sm1_tdmout_controls), |
|---|
| 299 | + .dapm_widgets = sm1_tdmout_dapm_widgets, |
|---|
| 300 | + .num_dapm_widgets = ARRAY_SIZE(sm1_tdmout_dapm_widgets), |
|---|
| 301 | + .dapm_routes = sm1_tdmout_dapm_routes, |
|---|
| 302 | + .num_dapm_routes = ARRAY_SIZE(sm1_tdmout_dapm_routes), |
|---|
| 303 | +}; |
|---|
| 304 | + |
|---|
| 305 | +static const struct axg_tdm_formatter_driver sm1_tdmout_drv = { |
|---|
| 306 | + .component_drv = &sm1_tdmout_component_drv, |
|---|
| 307 | + .regmap_cfg = &axg_tdmout_regmap_cfg, |
|---|
| 308 | + .ops = &axg_tdmout_ops, |
|---|
| 309 | + .quirks = &(const struct axg_tdm_formatter_hw) { |
|---|
| 310 | + .skew_offset = 2, |
|---|
| 311 | + }, |
|---|
| 237 | 312 | }; |
|---|
| 238 | 313 | |
|---|
| 239 | 314 | static const struct of_device_id axg_tdmout_of_match[] = { |
|---|
| 240 | 315 | { |
|---|
| 241 | 316 | .compatible = "amlogic,axg-tdmout", |
|---|
| 242 | 317 | .data = &axg_tdmout_drv, |
|---|
| 318 | + }, { |
|---|
| 319 | + .compatible = "amlogic,g12a-tdmout", |
|---|
| 320 | + .data = &g12a_tdmout_drv, |
|---|
| 321 | + }, { |
|---|
| 322 | + .compatible = "amlogic,sm1-tdmout", |
|---|
| 323 | + .data = &sm1_tdmout_drv, |
|---|
| 243 | 324 | }, {} |
|---|
| 244 | 325 | }; |
|---|
| 245 | 326 | MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); |
|---|