.. | .. |
---|
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); |
---|