.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2015 Andrea Venturi |
---|
3 | 4 | * Andrea Venturi <be17068@iperbole.bo.it> |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2016 Maxime Ripard |
---|
6 | 7 | * Maxime Ripard <maxime.ripard@free-electrons.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License as |
---|
10 | | - * published by the Free Software Foundation; either version 2 of |
---|
11 | | - * the License, or (at your option) any later version. |
---|
12 | 8 | */ |
---|
13 | 9 | |
---|
14 | 10 | #include <linux/clk.h> |
---|
.. | .. |
---|
50 | 46 | #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) |
---|
51 | 47 | #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) |
---|
52 | 48 | #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) |
---|
53 | | -#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1) |
---|
54 | | -#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0) |
---|
55 | 49 | |
---|
56 | 50 | #define SUN4I_I2S_FMT1_REG 0x08 |
---|
57 | 51 | #define SUN4I_I2S_FIFO_TX_REG 0x0c |
---|
.. | .. |
---|
84 | 78 | #define SUN4I_I2S_RX_CNT_REG 0x2c |
---|
85 | 79 | |
---|
86 | 80 | #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 |
---|
| 81 | +#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) |
---|
87 | 82 | #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) |
---|
88 | 83 | |
---|
89 | 84 | #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 |
---|
.. | .. |
---|
96 | 91 | #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) |
---|
97 | 92 | #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17) |
---|
98 | 93 | |
---|
| 94 | +#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) |
---|
| 95 | +#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) |
---|
| 96 | +#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) |
---|
| 97 | +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) |
---|
| 98 | + |
---|
| 99 | +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) |
---|
| 100 | +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) |
---|
| 101 | +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) |
---|
99 | 102 | #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) |
---|
100 | 103 | #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) |
---|
| 104 | +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) |
---|
| 105 | +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) |
---|
| 106 | +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) |
---|
101 | 107 | |
---|
102 | 108 | #define SUN8I_I2S_INT_STA_REG 0x0c |
---|
103 | 109 | #define SUN8I_I2S_FIFO_TX_REG 0x20 |
---|
.. | .. |
---|
118 | 124 | #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 |
---|
119 | 125 | #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58 |
---|
120 | 126 | |
---|
| 127 | +struct sun4i_i2s; |
---|
| 128 | + |
---|
121 | 129 | /** |
---|
122 | 130 | * struct sun4i_i2s_quirks - Differences between SoC variants. |
---|
123 | | - * |
---|
124 | 131 | * @has_reset: SoC needs reset deasserted. |
---|
125 | | - * @has_slave_select_bit: SoC has a bit to enable slave mode. |
---|
126 | | - * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. |
---|
127 | | - * @has_chcfg: tx and rx slot number need to be set. |
---|
128 | | - * @has_chsel_tx_chen: SoC requires that the tx channels are enabled. |
---|
129 | | - * @has_chsel_offset: SoC uses offset for selecting dai operational mode. |
---|
130 | 132 | * @reg_offset_txdata: offset of the tx fifo. |
---|
131 | 133 | * @sun4i_i2s_regmap: regmap config to use. |
---|
132 | | - * @mclk_offset: Value by which mclkdiv needs to be adjusted. |
---|
133 | | - * @bclk_offset: Value by which bclkdiv needs to be adjusted. |
---|
134 | | - * @fmt_offset: Value by which wss and sr needs to be adjusted. |
---|
135 | 134 | * @field_clkdiv_mclk_en: regmap field to enable mclk output. |
---|
136 | 135 | * @field_fmt_wss: regmap field to set word select size. |
---|
137 | 136 | * @field_fmt_sr: regmap field to set sample resolution. |
---|
138 | | - * @field_fmt_bclk: regmap field to set clk polarity. |
---|
139 | | - * @field_fmt_lrclk: regmap field to set frame polarity. |
---|
140 | | - * @field_fmt_mode: regmap field to set the operational mode. |
---|
141 | | - * @field_txchanmap: location of the tx channel mapping register. |
---|
142 | | - * @field_rxchanmap: location of the rx channel mapping register. |
---|
143 | | - * @field_txchansel: location of the tx channel select bit fields. |
---|
144 | | - * @field_rxchansel: location of the rx channel select bit fields. |
---|
| 137 | + * @bclk_dividers: bit clock dividers array |
---|
| 138 | + * @num_bclk_dividers: number of bit clock dividers |
---|
| 139 | + * @mclk_dividers: mclk dividers array |
---|
| 140 | + * @num_mclk_dividers: number of mclk dividers |
---|
| 141 | + * @get_bclk_parent_rate: callback to get bclk parent rate |
---|
| 142 | + * @get_sr: callback to get sample resolution |
---|
| 143 | + * @get_wss: callback to get word select size |
---|
| 144 | + * @set_chan_cfg: callback to set channel configuration |
---|
| 145 | + * @set_fmt: callback to set format |
---|
145 | 146 | */ |
---|
146 | 147 | struct sun4i_i2s_quirks { |
---|
147 | 148 | bool has_reset; |
---|
148 | | - bool has_slave_select_bit; |
---|
149 | | - bool has_fmt_set_lrck_period; |
---|
150 | | - bool has_chcfg; |
---|
151 | | - bool has_chsel_tx_chen; |
---|
152 | | - bool has_chsel_offset; |
---|
153 | 149 | unsigned int reg_offset_txdata; /* TX FIFO */ |
---|
154 | 150 | const struct regmap_config *sun4i_i2s_regmap; |
---|
155 | | - unsigned int mclk_offset; |
---|
156 | | - unsigned int bclk_offset; |
---|
157 | | - unsigned int fmt_offset; |
---|
158 | 151 | |
---|
159 | 152 | /* Register fields for i2s */ |
---|
160 | 153 | struct reg_field field_clkdiv_mclk_en; |
---|
161 | 154 | struct reg_field field_fmt_wss; |
---|
162 | 155 | struct reg_field field_fmt_sr; |
---|
163 | | - struct reg_field field_fmt_bclk; |
---|
164 | | - struct reg_field field_fmt_lrclk; |
---|
165 | | - struct reg_field field_fmt_mode; |
---|
166 | | - struct reg_field field_txchanmap; |
---|
167 | | - struct reg_field field_rxchanmap; |
---|
168 | | - struct reg_field field_txchansel; |
---|
169 | | - struct reg_field field_rxchansel; |
---|
| 156 | + |
---|
| 157 | + const struct sun4i_i2s_clk_div *bclk_dividers; |
---|
| 158 | + unsigned int num_bclk_dividers; |
---|
| 159 | + const struct sun4i_i2s_clk_div *mclk_dividers; |
---|
| 160 | + unsigned int num_mclk_dividers; |
---|
| 161 | + |
---|
| 162 | + unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); |
---|
| 163 | + s8 (*get_sr)(const struct sun4i_i2s *, int); |
---|
| 164 | + s8 (*get_wss)(const struct sun4i_i2s *, int); |
---|
| 165 | + int (*set_chan_cfg)(const struct sun4i_i2s *, |
---|
| 166 | + const struct snd_pcm_hw_params *); |
---|
| 167 | + int (*set_fmt)(const struct sun4i_i2s *, unsigned int); |
---|
170 | 168 | }; |
---|
171 | 169 | |
---|
172 | 170 | struct sun4i_i2s { |
---|
.. | .. |
---|
175 | 173 | struct regmap *regmap; |
---|
176 | 174 | struct reset_control *rst; |
---|
177 | 175 | |
---|
| 176 | + unsigned int format; |
---|
178 | 177 | unsigned int mclk_freq; |
---|
| 178 | + unsigned int slots; |
---|
| 179 | + unsigned int slot_width; |
---|
179 | 180 | |
---|
180 | 181 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
---|
181 | 182 | struct snd_dmaengine_dai_dma_data playback_dma_data; |
---|
.. | .. |
---|
184 | 185 | struct regmap_field *field_clkdiv_mclk_en; |
---|
185 | 186 | struct regmap_field *field_fmt_wss; |
---|
186 | 187 | struct regmap_field *field_fmt_sr; |
---|
187 | | - struct regmap_field *field_fmt_bclk; |
---|
188 | | - struct regmap_field *field_fmt_lrclk; |
---|
189 | | - struct regmap_field *field_fmt_mode; |
---|
190 | | - struct regmap_field *field_txchanmap; |
---|
191 | | - struct regmap_field *field_rxchanmap; |
---|
192 | | - struct regmap_field *field_txchansel; |
---|
193 | | - struct regmap_field *field_rxchansel; |
---|
194 | 188 | |
---|
195 | 189 | const struct sun4i_i2s_quirks *variant; |
---|
196 | 190 | }; |
---|
.. | .. |
---|
222 | 216 | /* TODO - extend divide ratio supported by newer SoCs */ |
---|
223 | 217 | }; |
---|
224 | 218 | |
---|
| 219 | +static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { |
---|
| 220 | + { .div = 1, .val = 1 }, |
---|
| 221 | + { .div = 2, .val = 2 }, |
---|
| 222 | + { .div = 4, .val = 3 }, |
---|
| 223 | + { .div = 6, .val = 4 }, |
---|
| 224 | + { .div = 8, .val = 5 }, |
---|
| 225 | + { .div = 12, .val = 6 }, |
---|
| 226 | + { .div = 16, .val = 7 }, |
---|
| 227 | + { .div = 24, .val = 8 }, |
---|
| 228 | + { .div = 32, .val = 9 }, |
---|
| 229 | + { .div = 48, .val = 10 }, |
---|
| 230 | + { .div = 64, .val = 11 }, |
---|
| 231 | + { .div = 96, .val = 12 }, |
---|
| 232 | + { .div = 128, .val = 13 }, |
---|
| 233 | + { .div = 176, .val = 14 }, |
---|
| 234 | + { .div = 192, .val = 15 }, |
---|
| 235 | +}; |
---|
| 236 | + |
---|
| 237 | +static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) |
---|
| 238 | +{ |
---|
| 239 | + return i2s->mclk_freq; |
---|
| 240 | +} |
---|
| 241 | + |
---|
| 242 | +static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) |
---|
| 243 | +{ |
---|
| 244 | + return clk_get_rate(i2s->mod_clk); |
---|
| 245 | +} |
---|
| 246 | + |
---|
225 | 247 | static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, |
---|
226 | 248 | unsigned long parent_rate, |
---|
227 | 249 | unsigned int sampling_rate, |
---|
| 250 | + unsigned int channels, |
---|
228 | 251 | unsigned int word_size) |
---|
229 | 252 | { |
---|
230 | | - int div = parent_rate / sampling_rate / word_size / 2; |
---|
| 253 | + const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; |
---|
| 254 | + int div = parent_rate / sampling_rate / word_size / channels; |
---|
231 | 255 | int i; |
---|
232 | 256 | |
---|
233 | | - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { |
---|
234 | | - const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; |
---|
| 257 | + for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { |
---|
| 258 | + const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; |
---|
235 | 259 | |
---|
236 | 260 | if (bdiv->div == div) |
---|
237 | 261 | return bdiv->val; |
---|
.. | .. |
---|
241 | 265 | } |
---|
242 | 266 | |
---|
243 | 267 | static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, |
---|
244 | | - unsigned int oversample_rate, |
---|
245 | | - unsigned int module_rate, |
---|
246 | | - unsigned int sampling_rate) |
---|
| 268 | + unsigned long parent_rate, |
---|
| 269 | + unsigned long mclk_rate) |
---|
247 | 270 | { |
---|
248 | | - int div = module_rate / sampling_rate / oversample_rate; |
---|
| 271 | + const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; |
---|
| 272 | + int div = parent_rate / mclk_rate; |
---|
249 | 273 | int i; |
---|
250 | 274 | |
---|
251 | | - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { |
---|
252 | | - const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; |
---|
| 275 | + for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { |
---|
| 276 | + const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; |
---|
253 | 277 | |
---|
254 | 278 | if (mdiv->div == div) |
---|
255 | 279 | return mdiv->val; |
---|
.. | .. |
---|
272 | 296 | |
---|
273 | 297 | static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, |
---|
274 | 298 | unsigned int rate, |
---|
275 | | - unsigned int word_size) |
---|
| 299 | + unsigned int slots, |
---|
| 300 | + unsigned int slot_width) |
---|
276 | 301 | { |
---|
277 | 302 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
278 | | - unsigned int oversample_rate, clk_rate; |
---|
| 303 | + unsigned int oversample_rate, clk_rate, bclk_parent_rate; |
---|
279 | 304 | int bclk_div, mclk_div; |
---|
280 | 305 | int ret; |
---|
281 | 306 | |
---|
.. | .. |
---|
317 | 342 | return -EINVAL; |
---|
318 | 343 | } |
---|
319 | 344 | |
---|
320 | | - bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq, |
---|
321 | | - rate, word_size); |
---|
| 345 | + bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); |
---|
| 346 | + bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, |
---|
| 347 | + rate, slots, slot_width); |
---|
322 | 348 | if (bclk_div < 0) { |
---|
323 | 349 | dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); |
---|
324 | 350 | return -EINVAL; |
---|
325 | 351 | } |
---|
326 | 352 | |
---|
327 | | - mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, |
---|
328 | | - clk_rate, rate); |
---|
| 353 | + mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); |
---|
329 | 354 | if (mclk_div < 0) { |
---|
330 | 355 | dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); |
---|
331 | 356 | return -EINVAL; |
---|
332 | 357 | } |
---|
333 | | - |
---|
334 | | - /* Adjust the clock division values if needed */ |
---|
335 | | - bclk_div += i2s->variant->bclk_offset; |
---|
336 | | - mclk_div += i2s->variant->mclk_offset; |
---|
337 | 358 | |
---|
338 | 359 | regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, |
---|
339 | 360 | SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | |
---|
.. | .. |
---|
341 | 362 | |
---|
342 | 363 | regmap_field_write(i2s->field_clkdiv_mclk_en, 1); |
---|
343 | 364 | |
---|
344 | | - /* Set sync period */ |
---|
345 | | - if (i2s->variant->has_fmt_set_lrck_period) |
---|
346 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, |
---|
347 | | - SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, |
---|
348 | | - SUN8I_I2S_FMT0_LRCK_PERIOD(32)); |
---|
| 365 | + return 0; |
---|
| 366 | +} |
---|
| 367 | + |
---|
| 368 | +static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width) |
---|
| 369 | +{ |
---|
| 370 | + if (width < 16 || width > 24) |
---|
| 371 | + return -EINVAL; |
---|
| 372 | + |
---|
| 373 | + if (width % 4) |
---|
| 374 | + return -EINVAL; |
---|
| 375 | + |
---|
| 376 | + return (width - 16) / 4; |
---|
| 377 | +} |
---|
| 378 | + |
---|
| 379 | +static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width) |
---|
| 380 | +{ |
---|
| 381 | + if (width < 16 || width > 32) |
---|
| 382 | + return -EINVAL; |
---|
| 383 | + |
---|
| 384 | + if (width % 4) |
---|
| 385 | + return -EINVAL; |
---|
| 386 | + |
---|
| 387 | + return (width - 16) / 4; |
---|
| 388 | +} |
---|
| 389 | + |
---|
| 390 | +static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) |
---|
| 391 | +{ |
---|
| 392 | + if (width % 4) |
---|
| 393 | + return -EINVAL; |
---|
| 394 | + |
---|
| 395 | + if (width < 8 || width > 32) |
---|
| 396 | + return -EINVAL; |
---|
| 397 | + |
---|
| 398 | + return (width - 8) / 4 + 1; |
---|
| 399 | +} |
---|
| 400 | + |
---|
| 401 | +static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, |
---|
| 402 | + const struct snd_pcm_hw_params *params) |
---|
| 403 | +{ |
---|
| 404 | + unsigned int channels = params_channels(params); |
---|
| 405 | + |
---|
| 406 | + /* Map the channels for playback and capture */ |
---|
| 407 | + regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); |
---|
| 408 | + regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); |
---|
| 409 | + |
---|
| 410 | + /* Configure the channels */ |
---|
| 411 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, |
---|
| 412 | + SUN4I_I2S_CHAN_SEL_MASK, |
---|
| 413 | + SUN4I_I2S_CHAN_SEL(channels)); |
---|
| 414 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, |
---|
| 415 | + SUN4I_I2S_CHAN_SEL_MASK, |
---|
| 416 | + SUN4I_I2S_CHAN_SEL(channels)); |
---|
| 417 | + |
---|
| 418 | + return 0; |
---|
| 419 | +} |
---|
| 420 | + |
---|
| 421 | +static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, |
---|
| 422 | + const struct snd_pcm_hw_params *params) |
---|
| 423 | +{ |
---|
| 424 | + unsigned int channels = params_channels(params); |
---|
| 425 | + unsigned int slots = channels; |
---|
| 426 | + unsigned int lrck_period; |
---|
| 427 | + |
---|
| 428 | + if (i2s->slots) |
---|
| 429 | + slots = i2s->slots; |
---|
| 430 | + |
---|
| 431 | + /* Map the channels for playback and capture */ |
---|
| 432 | + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); |
---|
| 433 | + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); |
---|
| 434 | + |
---|
| 435 | + /* Configure the channels */ |
---|
| 436 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
---|
| 437 | + SUN4I_I2S_CHAN_SEL_MASK, |
---|
| 438 | + SUN4I_I2S_CHAN_SEL(channels)); |
---|
| 439 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
---|
| 440 | + SUN4I_I2S_CHAN_SEL_MASK, |
---|
| 441 | + SUN4I_I2S_CHAN_SEL(channels)); |
---|
| 442 | + |
---|
| 443 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
---|
| 444 | + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, |
---|
| 445 | + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); |
---|
| 446 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
---|
| 447 | + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, |
---|
| 448 | + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); |
---|
| 449 | + |
---|
| 450 | + switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
---|
| 451 | + case SND_SOC_DAIFMT_DSP_A: |
---|
| 452 | + case SND_SOC_DAIFMT_DSP_B: |
---|
| 453 | + lrck_period = params_physical_width(params) * slots; |
---|
| 454 | + break; |
---|
| 455 | + |
---|
| 456 | + case SND_SOC_DAIFMT_LEFT_J: |
---|
| 457 | + case SND_SOC_DAIFMT_RIGHT_J: |
---|
| 458 | + case SND_SOC_DAIFMT_I2S: |
---|
| 459 | + lrck_period = params_physical_width(params); |
---|
| 460 | + break; |
---|
| 461 | + |
---|
| 462 | + default: |
---|
| 463 | + return -EINVAL; |
---|
| 464 | + } |
---|
| 465 | + |
---|
| 466 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, |
---|
| 467 | + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, |
---|
| 468 | + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); |
---|
| 469 | + |
---|
| 470 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
---|
| 471 | + SUN8I_I2S_TX_CHAN_EN_MASK, |
---|
| 472 | + SUN8I_I2S_TX_CHAN_EN(channels)); |
---|
349 | 473 | |
---|
350 | 474 | return 0; |
---|
351 | 475 | } |
---|
.. | .. |
---|
355 | 479 | struct snd_soc_dai *dai) |
---|
356 | 480 | { |
---|
357 | 481 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
358 | | - int sr, wss, channels; |
---|
| 482 | + unsigned int word_size = params_width(params); |
---|
| 483 | + unsigned int slot_width = params_physical_width(params); |
---|
| 484 | + unsigned int channels = params_channels(params); |
---|
| 485 | + unsigned int slots = channels; |
---|
| 486 | + int ret, sr, wss; |
---|
359 | 487 | u32 width; |
---|
360 | 488 | |
---|
361 | | - channels = params_channels(params); |
---|
362 | | - if (channels != 2) { |
---|
363 | | - dev_err(dai->dev, "Unsupported number of channels: %d\n", |
---|
364 | | - channels); |
---|
365 | | - return -EINVAL; |
---|
| 489 | + if (i2s->slots) |
---|
| 490 | + slots = i2s->slots; |
---|
| 491 | + |
---|
| 492 | + if (i2s->slot_width) |
---|
| 493 | + slot_width = i2s->slot_width; |
---|
| 494 | + |
---|
| 495 | + ret = i2s->variant->set_chan_cfg(i2s, params); |
---|
| 496 | + if (ret < 0) { |
---|
| 497 | + dev_err(dai->dev, "Invalid channel configuration\n"); |
---|
| 498 | + return ret; |
---|
366 | 499 | } |
---|
367 | | - |
---|
368 | | - if (i2s->variant->has_chcfg) { |
---|
369 | | - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
---|
370 | | - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, |
---|
371 | | - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); |
---|
372 | | - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
---|
373 | | - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, |
---|
374 | | - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); |
---|
375 | | - } |
---|
376 | | - |
---|
377 | | - /* Map the channels for playback and capture */ |
---|
378 | | - regmap_field_write(i2s->field_txchanmap, 0x76543210); |
---|
379 | | - regmap_field_write(i2s->field_rxchanmap, 0x00003210); |
---|
380 | | - |
---|
381 | | - /* Configure the channels */ |
---|
382 | | - regmap_field_write(i2s->field_txchansel, |
---|
383 | | - SUN4I_I2S_CHAN_SEL(params_channels(params))); |
---|
384 | | - |
---|
385 | | - regmap_field_write(i2s->field_rxchansel, |
---|
386 | | - SUN4I_I2S_CHAN_SEL(params_channels(params))); |
---|
387 | | - |
---|
388 | | - if (i2s->variant->has_chsel_tx_chen) |
---|
389 | | - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
---|
390 | | - SUN8I_I2S_TX_CHAN_EN_MASK, |
---|
391 | | - SUN8I_I2S_TX_CHAN_EN(channels)); |
---|
392 | 500 | |
---|
393 | 501 | switch (params_physical_width(params)) { |
---|
394 | 502 | case 16: |
---|
.. | .. |
---|
401 | 509 | } |
---|
402 | 510 | i2s->playback_dma_data.addr_width = width; |
---|
403 | 511 | |
---|
404 | | - switch (params_width(params)) { |
---|
405 | | - case 16: |
---|
406 | | - sr = 0; |
---|
407 | | - wss = 0; |
---|
408 | | - break; |
---|
409 | | - |
---|
410 | | - default: |
---|
411 | | - dev_err(dai->dev, "Unsupported sample width: %d\n", |
---|
412 | | - params_width(params)); |
---|
| 512 | + sr = i2s->variant->get_sr(i2s, word_size); |
---|
| 513 | + if (sr < 0) |
---|
413 | 514 | return -EINVAL; |
---|
414 | | - } |
---|
415 | 515 | |
---|
416 | | - regmap_field_write(i2s->field_fmt_wss, |
---|
417 | | - wss + i2s->variant->fmt_offset); |
---|
418 | | - regmap_field_write(i2s->field_fmt_sr, |
---|
419 | | - sr + i2s->variant->fmt_offset); |
---|
| 516 | + wss = i2s->variant->get_wss(i2s, slot_width); |
---|
| 517 | + if (wss < 0) |
---|
| 518 | + return -EINVAL; |
---|
| 519 | + |
---|
| 520 | + regmap_field_write(i2s->field_fmt_wss, wss); |
---|
| 521 | + regmap_field_write(i2s->field_fmt_sr, sr); |
---|
420 | 522 | |
---|
421 | 523 | return sun4i_i2s_set_clk_rate(dai, params_rate(params), |
---|
422 | | - params_width(params)); |
---|
| 524 | + slots, slot_width); |
---|
423 | 525 | } |
---|
424 | 526 | |
---|
425 | | -static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
---|
| 527 | +static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
---|
| 528 | + unsigned int fmt) |
---|
426 | 529 | { |
---|
427 | | - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
428 | 530 | u32 val; |
---|
429 | | - u32 offset = 0; |
---|
430 | | - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; |
---|
431 | | - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; |
---|
432 | | - |
---|
433 | | - /* DAI Mode */ |
---|
434 | | - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
---|
435 | | - case SND_SOC_DAIFMT_I2S: |
---|
436 | | - val = SUN4I_I2S_FMT0_FMT_I2S; |
---|
437 | | - offset = 1; |
---|
438 | | - break; |
---|
439 | | - case SND_SOC_DAIFMT_LEFT_J: |
---|
440 | | - val = SUN4I_I2S_FMT0_FMT_LEFT_J; |
---|
441 | | - break; |
---|
442 | | - case SND_SOC_DAIFMT_RIGHT_J: |
---|
443 | | - val = SUN4I_I2S_FMT0_FMT_RIGHT_J; |
---|
444 | | - break; |
---|
445 | | - default: |
---|
446 | | - dev_err(dai->dev, "Unsupported format: %d\n", |
---|
447 | | - fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
---|
448 | | - return -EINVAL; |
---|
449 | | - } |
---|
450 | | - |
---|
451 | | - if (i2s->variant->has_chsel_offset) { |
---|
452 | | - /* |
---|
453 | | - * offset being set indicates that we're connected to an i2s |
---|
454 | | - * device, however offset is only used on the sun8i block and |
---|
455 | | - * i2s shares the same setting with the LJ format. Increment |
---|
456 | | - * val so that the bit to value to write is correct. |
---|
457 | | - */ |
---|
458 | | - if (offset > 0) |
---|
459 | | - val++; |
---|
460 | | - /* blck offset determines whether i2s or LJ */ |
---|
461 | | - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
---|
462 | | - SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
---|
463 | | - SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
---|
464 | | - |
---|
465 | | - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
---|
466 | | - SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
---|
467 | | - SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
---|
468 | | - } |
---|
469 | | - |
---|
470 | | - regmap_field_write(i2s->field_fmt_mode, val); |
---|
471 | 531 | |
---|
472 | 532 | /* DAI clock polarity */ |
---|
473 | 533 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
---|
474 | 534 | case SND_SOC_DAIFMT_IB_IF: |
---|
475 | 535 | /* Invert both clocks */ |
---|
476 | | - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; |
---|
477 | | - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; |
---|
| 536 | + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | |
---|
| 537 | + SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
---|
478 | 538 | break; |
---|
479 | 539 | case SND_SOC_DAIFMT_IB_NF: |
---|
480 | 540 | /* Invert bit clock */ |
---|
481 | | - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; |
---|
| 541 | + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; |
---|
482 | 542 | break; |
---|
483 | 543 | case SND_SOC_DAIFMT_NB_IF: |
---|
484 | 544 | /* Invert frame clock */ |
---|
485 | | - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; |
---|
| 545 | + val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
---|
486 | 546 | break; |
---|
487 | 547 | case SND_SOC_DAIFMT_NB_NF: |
---|
| 548 | + val = 0; |
---|
488 | 549 | break; |
---|
489 | 550 | default: |
---|
490 | | - dev_err(dai->dev, "Unsupported clock polarity: %d\n", |
---|
491 | | - fmt & SND_SOC_DAIFMT_INV_MASK); |
---|
492 | 551 | return -EINVAL; |
---|
493 | 552 | } |
---|
494 | 553 | |
---|
495 | | - regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); |
---|
496 | | - regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); |
---|
| 554 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, |
---|
| 555 | + SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | |
---|
| 556 | + SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, |
---|
| 557 | + val); |
---|
497 | 558 | |
---|
498 | | - if (i2s->variant->has_slave_select_bit) { |
---|
499 | | - /* DAI clock master masks */ |
---|
500 | | - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
---|
501 | | - case SND_SOC_DAIFMT_CBS_CFS: |
---|
502 | | - /* BCLK and LRCLK master */ |
---|
503 | | - val = SUN4I_I2S_CTRL_MODE_MASTER; |
---|
504 | | - break; |
---|
505 | | - case SND_SOC_DAIFMT_CBM_CFM: |
---|
506 | | - /* BCLK and LRCLK slave */ |
---|
507 | | - val = SUN4I_I2S_CTRL_MODE_SLAVE; |
---|
508 | | - break; |
---|
509 | | - default: |
---|
510 | | - dev_err(dai->dev, "Unsupported slave setting: %d\n", |
---|
511 | | - fmt & SND_SOC_DAIFMT_MASTER_MASK); |
---|
512 | | - return -EINVAL; |
---|
513 | | - } |
---|
514 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
515 | | - SUN4I_I2S_CTRL_MODE_MASK, |
---|
516 | | - val); |
---|
517 | | - } else { |
---|
518 | | - /* |
---|
519 | | - * The newer i2s block does not have a slave select bit, |
---|
520 | | - * instead the clk pins are configured as inputs. |
---|
521 | | - */ |
---|
522 | | - /* DAI clock master masks */ |
---|
523 | | - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
---|
524 | | - case SND_SOC_DAIFMT_CBS_CFS: |
---|
525 | | - /* BCLK and LRCLK master */ |
---|
526 | | - val = SUN8I_I2S_CTRL_BCLK_OUT | |
---|
527 | | - SUN8I_I2S_CTRL_LRCK_OUT; |
---|
528 | | - break; |
---|
529 | | - case SND_SOC_DAIFMT_CBM_CFM: |
---|
530 | | - /* BCLK and LRCLK slave */ |
---|
531 | | - val = 0; |
---|
532 | | - break; |
---|
533 | | - default: |
---|
534 | | - dev_err(dai->dev, "Unsupported slave setting: %d\n", |
---|
535 | | - fmt & SND_SOC_DAIFMT_MASTER_MASK); |
---|
536 | | - return -EINVAL; |
---|
537 | | - } |
---|
538 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
539 | | - SUN8I_I2S_CTRL_BCLK_OUT | |
---|
540 | | - SUN8I_I2S_CTRL_LRCK_OUT, |
---|
541 | | - val); |
---|
| 559 | + /* DAI Mode */ |
---|
| 560 | + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
---|
| 561 | + case SND_SOC_DAIFMT_I2S: |
---|
| 562 | + val = SUN4I_I2S_FMT0_FMT_I2S; |
---|
| 563 | + break; |
---|
| 564 | + |
---|
| 565 | + case SND_SOC_DAIFMT_LEFT_J: |
---|
| 566 | + val = SUN4I_I2S_FMT0_FMT_LEFT_J; |
---|
| 567 | + break; |
---|
| 568 | + |
---|
| 569 | + case SND_SOC_DAIFMT_RIGHT_J: |
---|
| 570 | + val = SUN4I_I2S_FMT0_FMT_RIGHT_J; |
---|
| 571 | + break; |
---|
| 572 | + |
---|
| 573 | + default: |
---|
| 574 | + return -EINVAL; |
---|
| 575 | + } |
---|
| 576 | + |
---|
| 577 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, |
---|
| 578 | + SUN4I_I2S_FMT0_FMT_MASK, val); |
---|
| 579 | + |
---|
| 580 | + /* DAI clock master masks */ |
---|
| 581 | + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
---|
| 582 | + case SND_SOC_DAIFMT_CBS_CFS: |
---|
| 583 | + /* BCLK and LRCLK master */ |
---|
| 584 | + val = SUN4I_I2S_CTRL_MODE_MASTER; |
---|
| 585 | + break; |
---|
| 586 | + |
---|
| 587 | + case SND_SOC_DAIFMT_CBM_CFM: |
---|
| 588 | + /* BCLK and LRCLK slave */ |
---|
| 589 | + val = SUN4I_I2S_CTRL_MODE_SLAVE; |
---|
| 590 | + break; |
---|
| 591 | + |
---|
| 592 | + default: |
---|
| 593 | + return -EINVAL; |
---|
| 594 | + } |
---|
| 595 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 596 | + SUN4I_I2S_CTRL_MODE_MASK, val); |
---|
| 597 | + return 0; |
---|
| 598 | +} |
---|
| 599 | + |
---|
| 600 | +static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
---|
| 601 | + unsigned int fmt) |
---|
| 602 | +{ |
---|
| 603 | + u32 mode, val; |
---|
| 604 | + u8 offset; |
---|
| 605 | + |
---|
| 606 | + /* |
---|
| 607 | + * DAI clock polarity |
---|
| 608 | + * |
---|
| 609 | + * The setup for LRCK contradicts the datasheet, but under a |
---|
| 610 | + * scope it's clear that the LRCK polarity is reversed |
---|
| 611 | + * compared to the expected polarity on the bus. |
---|
| 612 | + */ |
---|
| 613 | + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
---|
| 614 | + case SND_SOC_DAIFMT_IB_IF: |
---|
| 615 | + /* Invert both clocks */ |
---|
| 616 | + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; |
---|
| 617 | + break; |
---|
| 618 | + case SND_SOC_DAIFMT_IB_NF: |
---|
| 619 | + /* Invert bit clock */ |
---|
| 620 | + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | |
---|
| 621 | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
---|
| 622 | + break; |
---|
| 623 | + case SND_SOC_DAIFMT_NB_IF: |
---|
| 624 | + /* Invert frame clock */ |
---|
| 625 | + val = 0; |
---|
| 626 | + break; |
---|
| 627 | + case SND_SOC_DAIFMT_NB_NF: |
---|
| 628 | + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
---|
| 629 | + break; |
---|
| 630 | + default: |
---|
| 631 | + return -EINVAL; |
---|
| 632 | + } |
---|
| 633 | + |
---|
| 634 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, |
---|
| 635 | + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | |
---|
| 636 | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, |
---|
| 637 | + val); |
---|
| 638 | + |
---|
| 639 | + /* DAI Mode */ |
---|
| 640 | + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
---|
| 641 | + case SND_SOC_DAIFMT_DSP_A: |
---|
| 642 | + mode = SUN8I_I2S_CTRL_MODE_PCM; |
---|
| 643 | + offset = 1; |
---|
| 644 | + break; |
---|
| 645 | + |
---|
| 646 | + case SND_SOC_DAIFMT_DSP_B: |
---|
| 647 | + mode = SUN8I_I2S_CTRL_MODE_PCM; |
---|
| 648 | + offset = 0; |
---|
| 649 | + break; |
---|
| 650 | + |
---|
| 651 | + case SND_SOC_DAIFMT_I2S: |
---|
| 652 | + mode = SUN8I_I2S_CTRL_MODE_LEFT; |
---|
| 653 | + offset = 1; |
---|
| 654 | + break; |
---|
| 655 | + |
---|
| 656 | + case SND_SOC_DAIFMT_LEFT_J: |
---|
| 657 | + mode = SUN8I_I2S_CTRL_MODE_LEFT; |
---|
| 658 | + offset = 0; |
---|
| 659 | + break; |
---|
| 660 | + |
---|
| 661 | + case SND_SOC_DAIFMT_RIGHT_J: |
---|
| 662 | + mode = SUN8I_I2S_CTRL_MODE_RIGHT; |
---|
| 663 | + offset = 0; |
---|
| 664 | + break; |
---|
| 665 | + |
---|
| 666 | + default: |
---|
| 667 | + return -EINVAL; |
---|
| 668 | + } |
---|
| 669 | + |
---|
| 670 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 671 | + SUN8I_I2S_CTRL_MODE_MASK, mode); |
---|
| 672 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
---|
| 673 | + SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
---|
| 674 | + SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
---|
| 675 | + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
---|
| 676 | + SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
---|
| 677 | + SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
---|
| 678 | + |
---|
| 679 | + /* DAI clock master masks */ |
---|
| 680 | + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
---|
| 681 | + case SND_SOC_DAIFMT_CBS_CFS: |
---|
| 682 | + /* BCLK and LRCLK master */ |
---|
| 683 | + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; |
---|
| 684 | + break; |
---|
| 685 | + |
---|
| 686 | + case SND_SOC_DAIFMT_CBM_CFM: |
---|
| 687 | + /* BCLK and LRCLK slave */ |
---|
| 688 | + val = 0; |
---|
| 689 | + break; |
---|
| 690 | + |
---|
| 691 | + default: |
---|
| 692 | + return -EINVAL; |
---|
| 693 | + } |
---|
| 694 | + |
---|
| 695 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 696 | + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, |
---|
| 697 | + val); |
---|
| 698 | + |
---|
| 699 | + return 0; |
---|
| 700 | +} |
---|
| 701 | + |
---|
| 702 | +static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
---|
| 703 | +{ |
---|
| 704 | + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 705 | + int ret; |
---|
| 706 | + |
---|
| 707 | + ret = i2s->variant->set_fmt(i2s, fmt); |
---|
| 708 | + if (ret) { |
---|
| 709 | + dev_err(dai->dev, "Unsupported format configuration\n"); |
---|
| 710 | + return ret; |
---|
542 | 711 | } |
---|
543 | 712 | |
---|
544 | 713 | /* Set significant bits in our FIFOs */ |
---|
.. | .. |
---|
547 | 716 | SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, |
---|
548 | 717 | SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | |
---|
549 | 718 | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); |
---|
| 719 | + |
---|
| 720 | + i2s->format = fmt; |
---|
| 721 | + |
---|
550 | 722 | return 0; |
---|
551 | 723 | } |
---|
552 | 724 | |
---|
.. | .. |
---|
649 | 821 | return 0; |
---|
650 | 822 | } |
---|
651 | 823 | |
---|
652 | | -static int sun4i_i2s_startup(struct snd_pcm_substream *substream, |
---|
653 | | - struct snd_soc_dai *dai) |
---|
654 | | -{ |
---|
655 | | - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
656 | | - |
---|
657 | | - /* Enable the whole hardware block */ |
---|
658 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
659 | | - SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); |
---|
660 | | - |
---|
661 | | - /* Enable the first output line */ |
---|
662 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
663 | | - SUN4I_I2S_CTRL_SDO_EN_MASK, |
---|
664 | | - SUN4I_I2S_CTRL_SDO_EN(0)); |
---|
665 | | - |
---|
666 | | - |
---|
667 | | - return clk_prepare_enable(i2s->mod_clk); |
---|
668 | | -} |
---|
669 | | - |
---|
670 | | -static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream, |
---|
671 | | - struct snd_soc_dai *dai) |
---|
672 | | -{ |
---|
673 | | - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
674 | | - |
---|
675 | | - clk_disable_unprepare(i2s->mod_clk); |
---|
676 | | - |
---|
677 | | - /* Disable our output lines */ |
---|
678 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
679 | | - SUN4I_I2S_CTRL_SDO_EN_MASK, 0); |
---|
680 | | - |
---|
681 | | - /* Disable the whole hardware block */ |
---|
682 | | - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
683 | | - SUN4I_I2S_CTRL_GL_EN, 0); |
---|
684 | | -} |
---|
685 | | - |
---|
686 | 824 | static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
---|
687 | 825 | unsigned int freq, int dir) |
---|
688 | 826 | { |
---|
.. | .. |
---|
696 | 834 | return 0; |
---|
697 | 835 | } |
---|
698 | 836 | |
---|
| 837 | +static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, |
---|
| 838 | + unsigned int tx_mask, unsigned int rx_mask, |
---|
| 839 | + int slots, int slot_width) |
---|
| 840 | +{ |
---|
| 841 | + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 842 | + |
---|
| 843 | + if (slots > 8) |
---|
| 844 | + return -EINVAL; |
---|
| 845 | + |
---|
| 846 | + i2s->slots = slots; |
---|
| 847 | + i2s->slot_width = slot_width; |
---|
| 848 | + |
---|
| 849 | + return 0; |
---|
| 850 | +} |
---|
| 851 | + |
---|
699 | 852 | static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { |
---|
700 | 853 | .hw_params = sun4i_i2s_hw_params, |
---|
701 | 854 | .set_fmt = sun4i_i2s_set_fmt, |
---|
702 | 855 | .set_sysclk = sun4i_i2s_set_sysclk, |
---|
703 | | - .shutdown = sun4i_i2s_shutdown, |
---|
704 | | - .startup = sun4i_i2s_startup, |
---|
| 856 | + .set_tdm_slot = sun4i_i2s_set_tdm_slot, |
---|
705 | 857 | .trigger = sun4i_i2s_trigger, |
---|
706 | 858 | }; |
---|
707 | 859 | |
---|
.. | .. |
---|
722 | 874 | .probe = sun4i_i2s_dai_probe, |
---|
723 | 875 | .capture = { |
---|
724 | 876 | .stream_name = "Capture", |
---|
725 | | - .channels_min = 2, |
---|
726 | | - .channels_max = 2, |
---|
| 877 | + .channels_min = 1, |
---|
| 878 | + .channels_max = 8, |
---|
727 | 879 | .rates = SNDRV_PCM_RATE_8000_192000, |
---|
728 | 880 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
---|
729 | 881 | }, |
---|
730 | 882 | .playback = { |
---|
731 | 883 | .stream_name = "Playback", |
---|
732 | | - .channels_min = 2, |
---|
733 | | - .channels_max = 2, |
---|
| 884 | + .channels_min = 1, |
---|
| 885 | + .channels_max = 8, |
---|
734 | 886 | .rates = SNDRV_PCM_RATE_8000_192000, |
---|
735 | 887 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
---|
736 | 888 | }, |
---|
.. | .. |
---|
874 | 1026 | goto err_disable_clk; |
---|
875 | 1027 | } |
---|
876 | 1028 | |
---|
| 1029 | + /* Enable the whole hardware block */ |
---|
| 1030 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 1031 | + SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); |
---|
| 1032 | + |
---|
| 1033 | + /* Enable the first output line */ |
---|
| 1034 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 1035 | + SUN4I_I2S_CTRL_SDO_EN_MASK, |
---|
| 1036 | + SUN4I_I2S_CTRL_SDO_EN(0)); |
---|
| 1037 | + |
---|
| 1038 | + ret = clk_prepare_enable(i2s->mod_clk); |
---|
| 1039 | + if (ret) { |
---|
| 1040 | + dev_err(dev, "Failed to enable module clock\n"); |
---|
| 1041 | + goto err_disable_clk; |
---|
| 1042 | + } |
---|
| 1043 | + |
---|
877 | 1044 | return 0; |
---|
878 | 1045 | |
---|
879 | 1046 | err_disable_clk: |
---|
.. | .. |
---|
884 | 1051 | static int sun4i_i2s_runtime_suspend(struct device *dev) |
---|
885 | 1052 | { |
---|
886 | 1053 | struct sun4i_i2s *i2s = dev_get_drvdata(dev); |
---|
| 1054 | + |
---|
| 1055 | + clk_disable_unprepare(i2s->mod_clk); |
---|
| 1056 | + |
---|
| 1057 | + /* Disable our output lines */ |
---|
| 1058 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 1059 | + SUN4I_I2S_CTRL_SDO_EN_MASK, 0); |
---|
| 1060 | + |
---|
| 1061 | + /* Disable the whole hardware block */ |
---|
| 1062 | + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, |
---|
| 1063 | + SUN4I_I2S_CTRL_GL_EN, 0); |
---|
887 | 1064 | |
---|
888 | 1065 | regcache_cache_only(i2s->regmap, true); |
---|
889 | 1066 | |
---|
.. | .. |
---|
899 | 1076 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
---|
900 | 1077 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
---|
901 | 1078 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
---|
902 | | - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
---|
903 | | - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
---|
904 | | - .has_slave_select_bit = true, |
---|
905 | | - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), |
---|
906 | | - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), |
---|
907 | | - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), |
---|
908 | | - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), |
---|
909 | | - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), |
---|
| 1079 | + .bclk_dividers = sun4i_i2s_bclk_div, |
---|
| 1080 | + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
---|
| 1081 | + .mclk_dividers = sun4i_i2s_mclk_div, |
---|
| 1082 | + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
---|
| 1083 | + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
---|
| 1084 | + .get_sr = sun4i_i2s_get_sr, |
---|
| 1085 | + .get_wss = sun4i_i2s_get_wss, |
---|
| 1086 | + .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
---|
| 1087 | + .set_fmt = sun4i_i2s_set_soc_fmt, |
---|
910 | 1088 | }; |
---|
911 | 1089 | |
---|
912 | 1090 | static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { |
---|
.. | .. |
---|
916 | 1094 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
---|
917 | 1095 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
---|
918 | 1096 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
---|
919 | | - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
---|
920 | | - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
---|
921 | | - .has_slave_select_bit = true, |
---|
922 | | - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), |
---|
923 | | - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), |
---|
924 | | - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), |
---|
925 | | - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), |
---|
926 | | - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), |
---|
| 1097 | + .bclk_dividers = sun4i_i2s_bclk_div, |
---|
| 1098 | + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
---|
| 1099 | + .mclk_dividers = sun4i_i2s_mclk_div, |
---|
| 1100 | + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
---|
| 1101 | + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
---|
| 1102 | + .get_sr = sun4i_i2s_get_sr, |
---|
| 1103 | + .get_wss = sun4i_i2s_get_wss, |
---|
| 1104 | + .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
---|
| 1105 | + .set_fmt = sun4i_i2s_set_soc_fmt, |
---|
927 | 1106 | }; |
---|
928 | 1107 | |
---|
| 1108 | +/* |
---|
| 1109 | + * This doesn't describe the TDM controller documented in the A83t |
---|
| 1110 | + * datasheet, but the three undocumented I2S controller that use the |
---|
| 1111 | + * older design. |
---|
| 1112 | + */ |
---|
929 | 1113 | static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { |
---|
930 | 1114 | .has_reset = true, |
---|
931 | 1115 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
---|
.. | .. |
---|
933 | 1117 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
---|
934 | 1118 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
---|
935 | 1119 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
---|
936 | | - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), |
---|
937 | | - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
---|
938 | | - .has_slave_select_bit = true, |
---|
939 | | - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), |
---|
940 | | - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), |
---|
941 | | - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), |
---|
942 | | - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), |
---|
943 | | - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), |
---|
| 1120 | + .bclk_dividers = sun4i_i2s_bclk_div, |
---|
| 1121 | + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
---|
| 1122 | + .mclk_dividers = sun4i_i2s_mclk_div, |
---|
| 1123 | + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
---|
| 1124 | + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
---|
| 1125 | + .get_sr = sun4i_i2s_get_sr, |
---|
| 1126 | + .get_wss = sun4i_i2s_get_wss, |
---|
| 1127 | + .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
---|
| 1128 | + .set_fmt = sun4i_i2s_set_soc_fmt, |
---|
944 | 1129 | }; |
---|
945 | 1130 | |
---|
946 | 1131 | static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { |
---|
947 | 1132 | .has_reset = true, |
---|
948 | 1133 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
---|
949 | 1134 | .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, |
---|
950 | | - .mclk_offset = 1, |
---|
951 | | - .bclk_offset = 2, |
---|
952 | | - .fmt_offset = 3, |
---|
953 | | - .has_fmt_set_lrck_period = true, |
---|
954 | | - .has_chcfg = true, |
---|
955 | | - .has_chsel_tx_chen = true, |
---|
956 | | - .has_chsel_offset = true, |
---|
957 | 1135 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), |
---|
958 | 1136 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), |
---|
959 | 1137 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), |
---|
960 | | - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), |
---|
961 | | - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), |
---|
962 | | - .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), |
---|
963 | | - .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31), |
---|
964 | | - .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31), |
---|
965 | | - .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2), |
---|
966 | | - .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), |
---|
| 1138 | + .bclk_dividers = sun8i_i2s_clk_div, |
---|
| 1139 | + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
---|
| 1140 | + .mclk_dividers = sun8i_i2s_clk_div, |
---|
| 1141 | + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
---|
| 1142 | + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
---|
| 1143 | + .get_sr = sun8i_i2s_get_sr_wss, |
---|
| 1144 | + .get_wss = sun8i_i2s_get_sr_wss, |
---|
| 1145 | + .set_chan_cfg = sun8i_i2s_set_chan_cfg, |
---|
| 1146 | + .set_fmt = sun8i_i2s_set_soc_fmt, |
---|
| 1147 | +}; |
---|
| 1148 | + |
---|
| 1149 | +static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { |
---|
| 1150 | + .has_reset = true, |
---|
| 1151 | + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
---|
| 1152 | + .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, |
---|
| 1153 | + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
---|
| 1154 | + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
---|
| 1155 | + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
---|
| 1156 | + .bclk_dividers = sun4i_i2s_bclk_div, |
---|
| 1157 | + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
---|
| 1158 | + .mclk_dividers = sun4i_i2s_mclk_div, |
---|
| 1159 | + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
---|
| 1160 | + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
---|
| 1161 | + .get_sr = sun4i_i2s_get_sr, |
---|
| 1162 | + .get_wss = sun4i_i2s_get_wss, |
---|
| 1163 | + .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
---|
| 1164 | + .set_fmt = sun4i_i2s_set_soc_fmt, |
---|
967 | 1165 | }; |
---|
968 | 1166 | |
---|
969 | 1167 | static int sun4i_i2s_init_regmap_fields(struct device *dev, |
---|
.. | .. |
---|
987 | 1185 | if (IS_ERR(i2s->field_fmt_sr)) |
---|
988 | 1186 | return PTR_ERR(i2s->field_fmt_sr); |
---|
989 | 1187 | |
---|
990 | | - i2s->field_fmt_bclk = |
---|
991 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
992 | | - i2s->variant->field_fmt_bclk); |
---|
993 | | - if (IS_ERR(i2s->field_fmt_bclk)) |
---|
994 | | - return PTR_ERR(i2s->field_fmt_bclk); |
---|
995 | | - |
---|
996 | | - i2s->field_fmt_lrclk = |
---|
997 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
998 | | - i2s->variant->field_fmt_lrclk); |
---|
999 | | - if (IS_ERR(i2s->field_fmt_lrclk)) |
---|
1000 | | - return PTR_ERR(i2s->field_fmt_lrclk); |
---|
1001 | | - |
---|
1002 | | - i2s->field_fmt_mode = |
---|
1003 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
1004 | | - i2s->variant->field_fmt_mode); |
---|
1005 | | - if (IS_ERR(i2s->field_fmt_mode)) |
---|
1006 | | - return PTR_ERR(i2s->field_fmt_mode); |
---|
1007 | | - |
---|
1008 | | - i2s->field_txchanmap = |
---|
1009 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
1010 | | - i2s->variant->field_txchanmap); |
---|
1011 | | - if (IS_ERR(i2s->field_txchanmap)) |
---|
1012 | | - return PTR_ERR(i2s->field_txchanmap); |
---|
1013 | | - |
---|
1014 | | - i2s->field_rxchanmap = |
---|
1015 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
1016 | | - i2s->variant->field_rxchanmap); |
---|
1017 | | - if (IS_ERR(i2s->field_rxchanmap)) |
---|
1018 | | - return PTR_ERR(i2s->field_rxchanmap); |
---|
1019 | | - |
---|
1020 | | - i2s->field_txchansel = |
---|
1021 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
1022 | | - i2s->variant->field_txchansel); |
---|
1023 | | - if (IS_ERR(i2s->field_txchansel)) |
---|
1024 | | - return PTR_ERR(i2s->field_txchansel); |
---|
1025 | | - |
---|
1026 | | - i2s->field_rxchansel = |
---|
1027 | | - devm_regmap_field_alloc(dev, i2s->regmap, |
---|
1028 | | - i2s->variant->field_rxchansel); |
---|
1029 | | - return PTR_ERR_OR_ZERO(i2s->field_rxchansel); |
---|
| 1188 | + return 0; |
---|
1030 | 1189 | } |
---|
1031 | 1190 | |
---|
1032 | 1191 | static int sun4i_i2s_probe(struct platform_device *pdev) |
---|
.. | .. |
---|
1047 | 1206 | return PTR_ERR(regs); |
---|
1048 | 1207 | |
---|
1049 | 1208 | irq = platform_get_irq(pdev, 0); |
---|
1050 | | - if (irq < 0) { |
---|
1051 | | - dev_err(&pdev->dev, "Can't retrieve our interrupt\n"); |
---|
| 1209 | + if (irq < 0) |
---|
1052 | 1210 | return irq; |
---|
1053 | | - } |
---|
1054 | 1211 | |
---|
1055 | 1212 | i2s->variant = of_device_get_match_data(&pdev->dev); |
---|
1056 | 1213 | if (!i2s->variant) { |
---|
.. | .. |
---|
1108 | 1265 | goto err_pm_disable; |
---|
1109 | 1266 | } |
---|
1110 | 1267 | |
---|
1111 | | - ret = devm_snd_soc_register_component(&pdev->dev, |
---|
1112 | | - &sun4i_i2s_component, |
---|
1113 | | - &sun4i_i2s_dai, 1); |
---|
| 1268 | + ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); |
---|
1114 | 1269 | if (ret) { |
---|
1115 | | - dev_err(&pdev->dev, "Could not register DAI\n"); |
---|
| 1270 | + dev_err(&pdev->dev, "Could not initialise regmap fields\n"); |
---|
1116 | 1271 | goto err_suspend; |
---|
1117 | 1272 | } |
---|
1118 | 1273 | |
---|
1119 | | - ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
| 1274 | + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
1120 | 1275 | if (ret) { |
---|
1121 | 1276 | dev_err(&pdev->dev, "Could not register PCM\n"); |
---|
1122 | 1277 | goto err_suspend; |
---|
1123 | 1278 | } |
---|
1124 | 1279 | |
---|
1125 | | - ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); |
---|
| 1280 | + ret = devm_snd_soc_register_component(&pdev->dev, |
---|
| 1281 | + &sun4i_i2s_component, |
---|
| 1282 | + &sun4i_i2s_dai, 1); |
---|
1126 | 1283 | if (ret) { |
---|
1127 | | - dev_err(&pdev->dev, "Could not initialise regmap fields\n"); |
---|
| 1284 | + dev_err(&pdev->dev, "Could not register DAI\n"); |
---|
1128 | 1285 | goto err_suspend; |
---|
1129 | 1286 | } |
---|
1130 | 1287 | |
---|
.. | .. |
---|
1144 | 1301 | static int sun4i_i2s_remove(struct platform_device *pdev) |
---|
1145 | 1302 | { |
---|
1146 | 1303 | struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); |
---|
1147 | | - |
---|
1148 | | - snd_dmaengine_pcm_unregister(&pdev->dev); |
---|
1149 | 1304 | |
---|
1150 | 1305 | pm_runtime_disable(&pdev->dev); |
---|
1151 | 1306 | if (!pm_runtime_status_suspended(&pdev->dev)) |
---|
.. | .. |
---|
1174 | 1329 | .compatible = "allwinner,sun8i-h3-i2s", |
---|
1175 | 1330 | .data = &sun8i_h3_i2s_quirks, |
---|
1176 | 1331 | }, |
---|
| 1332 | + { |
---|
| 1333 | + .compatible = "allwinner,sun50i-a64-codec-i2s", |
---|
| 1334 | + .data = &sun50i_a64_codec_i2s_quirks, |
---|
| 1335 | + }, |
---|
1177 | 1336 | {} |
---|
1178 | 1337 | }; |
---|
1179 | 1338 | MODULE_DEVICE_TABLE(of, sun4i_i2s_match); |
---|