1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // peb2466.c -- Infineon PEB2466 ALSA SoC driver |
4 | // |
5 | // Copyright 2023 CS GROUP France |
6 | // |
7 | // Author: Herve Codina <herve.codina@bootlin.com> |
8 | |
9 | #include <asm/unaligned.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/firmware.h> |
12 | #include <linux/gpio/consumer.h> |
13 | #include <linux/gpio/driver.h> |
14 | #include <linux/module.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/spi/spi.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/soc.h> |
20 | #include <sound/tlv.h> |
21 | |
22 | #define PEB2466_NB_CHANNEL 4 |
23 | |
24 | struct peb2466_lookup { |
25 | u8 (*table)[4]; |
26 | unsigned int count; |
27 | }; |
28 | |
29 | #define PEB2466_TLV_SIZE (sizeof((unsigned int []){TLV_DB_SCALE_ITEM(0, 0, 0)}) / \ |
30 | sizeof(unsigned int)) |
31 | |
32 | struct peb2466_lkup_ctrl { |
33 | int reg; |
34 | unsigned int index; |
35 | const struct peb2466_lookup *lookup; |
36 | unsigned int tlv_array[PEB2466_TLV_SIZE]; |
37 | }; |
38 | |
39 | struct peb2466 { |
40 | struct spi_device *spi; |
41 | struct clk *mclk; |
42 | struct gpio_desc *reset_gpio; |
43 | u8 spi_tx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ |
44 | u8 spi_rx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ |
45 | struct regmap *regmap; |
46 | struct { |
47 | struct peb2466_lookup ax_lookup; |
48 | struct peb2466_lookup ar_lookup; |
49 | struct peb2466_lkup_ctrl ax_lkup_ctrl; |
50 | struct peb2466_lkup_ctrl ar_lkup_ctrl; |
51 | unsigned int tg1_freq_item; |
52 | unsigned int tg2_freq_item; |
53 | } ch[PEB2466_NB_CHANNEL]; |
54 | int max_chan_playback; |
55 | int max_chan_capture; |
56 | struct { |
57 | struct gpio_chip gpio_chip; |
58 | struct mutex lock; |
59 | struct { |
60 | unsigned int xr0; |
61 | unsigned int xr1; |
62 | unsigned int xr2; |
63 | unsigned int xr3; |
64 | } cache; |
65 | } gpio; |
66 | }; |
67 | |
68 | #define PEB2466_CMD_R (1 << 5) |
69 | #define PEB2466_CMD_W (0 << 5) |
70 | |
71 | #define PEB2466_CMD_MASK 0x18 |
72 | #define PEB2466_CMD_XOP 0x18 /* XOP is 0bxxx11xxx */ |
73 | #define PEB2466_CMD_SOP 0x10 /* SOP is 0bxxx10xxx */ |
74 | #define PEB2466_CMD_COP 0x00 /* COP is 0bxxx0xxxx, handle 0bxxx00xxx */ |
75 | #define PEB2466_CMD_COP1 0x08 /* COP is 0bxxx0xxxx, handle 0bxxx01xxx */ |
76 | |
77 | #define PEB2466_MAKE_XOP(_lsel) (PEB2466_CMD_XOP | (_lsel)) |
78 | #define PEB2466_MAKE_SOP(_ad, _lsel) (PEB2466_CMD_SOP | ((_ad) << 6) | (_lsel)) |
79 | #define PEB2466_MAKE_COP(_ad, _code) (PEB2466_CMD_COP | ((_ad) << 6) | (_code)) |
80 | |
81 | #define PEB2466_CR0(_ch) PEB2466_MAKE_SOP(_ch, 0x0) |
82 | #define PEB2466_CR0_TH (1 << 7) |
83 | #define PEB2466_CR0_IMR1 (1 << 6) |
84 | #define PEB2466_CR0_FRX (1 << 5) |
85 | #define PEB2466_CR0_FRR (1 << 4) |
86 | #define PEB2466_CR0_AX (1 << 3) |
87 | #define PEB2466_CR0_AR (1 << 2) |
88 | #define PEB2466_CR0_THSEL_MASK (0x3 << 0) |
89 | #define PEB2466_CR0_THSEL(_set) ((_set) << 0) |
90 | |
91 | #define PEB2466_CR1(_ch) PEB2466_MAKE_SOP(_ch, 0x1) |
92 | #define PEB2466_CR1_ETG2 (1 << 7) |
93 | #define PEB2466_CR1_ETG1 (1 << 6) |
94 | #define PEB2466_CR1_PTG2 (1 << 5) |
95 | #define PEB2466_CR1_PTG1 (1 << 4) |
96 | #define PEB2466_CR1_LAW_MASK (1 << 3) |
97 | #define PEB2466_CR1_LAW_ALAW (0 << 3) |
98 | #define PEB2466_CR1_LAW_MULAW (1 << 3) |
99 | #define PEB2466_CR1_PU (1 << 0) |
100 | |
101 | #define PEB2466_CR2(_ch) PEB2466_MAKE_SOP(_ch, 0x2) |
102 | #define PEB2466_CR3(_ch) PEB2466_MAKE_SOP(_ch, 0x3) |
103 | #define PEB2466_CR4(_ch) PEB2466_MAKE_SOP(_ch, 0x4) |
104 | #define PEB2466_CR5(_ch) PEB2466_MAKE_SOP(_ch, 0x5) |
105 | |
106 | #define PEB2466_XR0 PEB2466_MAKE_XOP(0x0) |
107 | #define PEB2466_XR1 PEB2466_MAKE_XOP(0x1) |
108 | #define PEB2466_XR2 PEB2466_MAKE_XOP(0x2) |
109 | #define PEB2466_XR3 PEB2466_MAKE_XOP(0x3) |
110 | #define PEB2466_XR4 PEB2466_MAKE_XOP(0x4) |
111 | #define PEB2466_XR5 PEB2466_MAKE_XOP(0x5) |
112 | #define PEB2466_XR5_MCLK_1536 (0x0 << 6) |
113 | #define PEB2466_XR5_MCLK_2048 (0x1 << 6) |
114 | #define PEB2466_XR5_MCLK_4096 (0x2 << 6) |
115 | #define PEB2466_XR5_MCLK_8192 (0x3 << 6) |
116 | |
117 | #define PEB2466_XR6 PEB2466_MAKE_XOP(0x6) |
118 | #define PEB2466_XR6_PCM_OFFSET(_off) ((_off) << 0) |
119 | |
120 | #define PEB2466_XR7 PEB2466_MAKE_XOP(0x7) |
121 | |
122 | #define PEB2466_TH_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x0) |
123 | #define PEB2466_TH_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x1) |
124 | #define PEB2466_TH_FILTER_P3(_ch) PEB2466_MAKE_COP(_ch, 0x2) |
125 | #define PEB2466_IMR1_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x4) |
126 | #define PEB2466_IMR1_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x5) |
127 | #define PEB2466_FRX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x6) |
128 | #define PEB2466_FRR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x7) |
129 | #define PEB2466_AX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x8) |
130 | #define PEB2466_AR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x9) |
131 | #define PEB2466_TG1(_ch) PEB2466_MAKE_COP(_ch, 0xc) |
132 | #define PEB2466_TG2(_ch) PEB2466_MAKE_COP(_ch, 0xd) |
133 | |
134 | static int peb2466_write_byte(struct peb2466 *peb2466, u8 cmd, u8 val) |
135 | { |
136 | struct spi_transfer xfer = { |
137 | .tx_buf = &peb2466->spi_tx_buf, |
138 | .len = 2, |
139 | }; |
140 | |
141 | peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; |
142 | peb2466->spi_tx_buf[1] = val; |
143 | |
144 | dev_dbg(&peb2466->spi->dev, "write byte (cmd %02x) %02x\n" , |
145 | peb2466->spi_tx_buf[0], peb2466->spi_tx_buf[1]); |
146 | |
147 | return spi_sync_transfer(spi: peb2466->spi, xfers: &xfer, num_xfers: 1); |
148 | } |
149 | |
150 | static int peb2466_read_byte(struct peb2466 *peb2466, u8 cmd, u8 *val) |
151 | { |
152 | struct spi_transfer xfer = { |
153 | .tx_buf = &peb2466->spi_tx_buf, |
154 | .rx_buf = &peb2466->spi_rx_buf, |
155 | .len = 3, |
156 | }; |
157 | int ret; |
158 | |
159 | peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_R; |
160 | |
161 | ret = spi_sync_transfer(spi: peb2466->spi, xfers: &xfer, num_xfers: 1); |
162 | if (ret) |
163 | return ret; |
164 | |
165 | if (peb2466->spi_rx_buf[1] != 0x81) { |
166 | dev_err(&peb2466->spi->dev, |
167 | "spi xfer rd (cmd %02x) invalid ident byte (0x%02x)\n" , |
168 | peb2466->spi_tx_buf[0], peb2466->spi_rx_buf[1]); |
169 | return -EILSEQ; |
170 | } |
171 | |
172 | *val = peb2466->spi_rx_buf[2]; |
173 | |
174 | dev_dbg(&peb2466->spi->dev, "read byte (cmd %02x) %02x\n" , |
175 | peb2466->spi_tx_buf[0], *val); |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | static int peb2466_write_buf(struct peb2466 *peb2466, u8 cmd, const u8 *buf, unsigned int len) |
181 | { |
182 | struct spi_transfer xfer = { |
183 | .tx_buf = &peb2466->spi_tx_buf, |
184 | .len = len + 1, |
185 | }; |
186 | |
187 | if (len > 8) |
188 | return -EINVAL; |
189 | |
190 | peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; |
191 | memcpy(&peb2466->spi_tx_buf[1], buf, len); |
192 | |
193 | dev_dbg(&peb2466->spi->dev, "write buf (cmd %02x, %u) %*ph\n" , |
194 | peb2466->spi_tx_buf[0], len, len, &peb2466->spi_tx_buf[1]); |
195 | |
196 | return spi_sync_transfer(spi: peb2466->spi, xfers: &xfer, num_xfers: 1); |
197 | } |
198 | |
199 | static int peb2466_reg_write(void *context, unsigned int reg, unsigned int val) |
200 | { |
201 | struct peb2466 *peb2466 = context; |
202 | int ret; |
203 | |
204 | /* |
205 | * Only XOP and SOP commands can be handled as registers. |
206 | * COP commands are handled using direct peb2466_write_buf() calls. |
207 | */ |
208 | switch (reg & PEB2466_CMD_MASK) { |
209 | case PEB2466_CMD_XOP: |
210 | case PEB2466_CMD_SOP: |
211 | ret = peb2466_write_byte(peb2466, cmd: reg, val); |
212 | break; |
213 | default: |
214 | dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n" ); |
215 | ret = -EINVAL; |
216 | break; |
217 | } |
218 | return ret; |
219 | } |
220 | |
221 | static int peb2466_reg_read(void *context, unsigned int reg, unsigned int *val) |
222 | { |
223 | struct peb2466 *peb2466 = context; |
224 | int ret; |
225 | u8 tmp; |
226 | |
227 | /* Only XOP and SOP commands can be handled as registers */ |
228 | switch (reg & PEB2466_CMD_MASK) { |
229 | case PEB2466_CMD_XOP: |
230 | case PEB2466_CMD_SOP: |
231 | ret = peb2466_read_byte(peb2466, cmd: reg, val: &tmp); |
232 | *val = tmp; |
233 | break; |
234 | default: |
235 | dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n" ); |
236 | ret = -EINVAL; |
237 | break; |
238 | } |
239 | return ret; |
240 | } |
241 | |
242 | static const struct regmap_config peb2466_regmap_config = { |
243 | .reg_bits = 8, |
244 | .val_bits = 8, |
245 | .max_register = 0xFF, |
246 | .reg_write = peb2466_reg_write, |
247 | .reg_read = peb2466_reg_read, |
248 | .cache_type = REGCACHE_NONE, |
249 | }; |
250 | |
251 | static int peb2466_lkup_ctrl_info(struct snd_kcontrol *kcontrol, |
252 | struct snd_ctl_elem_info *uinfo) |
253 | { |
254 | struct peb2466_lkup_ctrl *lkup_ctrl = |
255 | (struct peb2466_lkup_ctrl *)kcontrol->private_value; |
256 | |
257 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
258 | uinfo->count = 1; |
259 | uinfo->value.integer.min = 0; |
260 | uinfo->value.integer.max = lkup_ctrl->lookup->count - 1; |
261 | return 0; |
262 | } |
263 | |
264 | static int peb2466_lkup_ctrl_get(struct snd_kcontrol *kcontrol, |
265 | struct snd_ctl_elem_value *ucontrol) |
266 | { |
267 | struct peb2466_lkup_ctrl *lkup_ctrl = |
268 | (struct peb2466_lkup_ctrl *)kcontrol->private_value; |
269 | |
270 | ucontrol->value.integer.value[0] = lkup_ctrl->index; |
271 | return 0; |
272 | } |
273 | |
274 | static int peb2466_lkup_ctrl_put(struct snd_kcontrol *kcontrol, |
275 | struct snd_ctl_elem_value *ucontrol) |
276 | { |
277 | struct peb2466_lkup_ctrl *lkup_ctrl = |
278 | (struct peb2466_lkup_ctrl *)kcontrol->private_value; |
279 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
280 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
281 | unsigned int index; |
282 | int ret; |
283 | |
284 | index = ucontrol->value.integer.value[0]; |
285 | if (index >= lkup_ctrl->lookup->count) |
286 | return -EINVAL; |
287 | |
288 | if (index == lkup_ctrl->index) |
289 | return 0; |
290 | |
291 | ret = peb2466_write_buf(peb2466, cmd: lkup_ctrl->reg, |
292 | buf: lkup_ctrl->lookup->table[index], len: 4); |
293 | if (ret) |
294 | return ret; |
295 | |
296 | lkup_ctrl->index = index; |
297 | return 1; /* The value changed */ |
298 | } |
299 | |
300 | static int peb2466_add_lkup_ctrl(struct snd_soc_component *component, |
301 | struct peb2466_lkup_ctrl *lkup_ctrl, |
302 | const char *name, int min_val, int step) |
303 | { |
304 | DECLARE_TLV_DB_SCALE(tlv_array, min_val, step, 0); |
305 | struct snd_kcontrol_new control = {0}; |
306 | |
307 | BUILD_BUG_ON(sizeof(lkup_ctrl->tlv_array) < sizeof(tlv_array)); |
308 | memcpy(lkup_ctrl->tlv_array, tlv_array, sizeof(tlv_array)); |
309 | |
310 | control.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
311 | control.name = name; |
312 | control.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
313 | SNDRV_CTL_ELEM_ACCESS_READWRITE; |
314 | control.tlv.p = lkup_ctrl->tlv_array; |
315 | control.info = peb2466_lkup_ctrl_info; |
316 | control.get = peb2466_lkup_ctrl_get; |
317 | control.put = peb2466_lkup_ctrl_put; |
318 | control.private_value = (unsigned long)lkup_ctrl; |
319 | |
320 | return snd_soc_add_component_controls(component, controls: &control, num_controls: 1); |
321 | } |
322 | |
323 | enum peb2466_tone_freq { |
324 | PEB2466_TONE_697HZ, |
325 | PEB2466_TONE_800HZ, |
326 | PEB2466_TONE_950HZ, |
327 | PEB2466_TONE_1000HZ, |
328 | PEB2466_TONE_1008HZ, |
329 | PEB2466_TONE_2000HZ, |
330 | }; |
331 | |
332 | static const u8 peb2466_tone_lookup[][4] = { |
333 | [PEB2466_TONE_697HZ] = {0x0a, 0x33, 0x5a, 0x2c}, |
334 | [PEB2466_TONE_800HZ] = {0x12, 0xD6, 0x5a, 0xc0}, |
335 | [PEB2466_TONE_950HZ] = {0x1c, 0xf0, 0x5c, 0xc0}, |
336 | [PEB2466_TONE_1000HZ] = {0}, /* lookup value not used for 1000Hz */ |
337 | [PEB2466_TONE_1008HZ] = {0x1a, 0xae, 0x57, 0x70}, |
338 | [PEB2466_TONE_2000HZ] = {0x00, 0x80, 0x50, 0x09}, |
339 | }; |
340 | |
341 | static const char * const peb2466_tone_freq_txt[] = { |
342 | [PEB2466_TONE_697HZ] = "697Hz" , |
343 | [PEB2466_TONE_800HZ] = "800Hz" , |
344 | [PEB2466_TONE_950HZ] = "950Hz" , |
345 | [PEB2466_TONE_1000HZ] = "1000Hz" , |
346 | [PEB2466_TONE_1008HZ] = "1008Hz" , |
347 | [PEB2466_TONE_2000HZ] = "2000Hz" |
348 | }; |
349 | |
350 | static const struct soc_enum peb2466_tg_freq[][2] = { |
351 | [0] = { |
352 | SOC_ENUM_SINGLE(PEB2466_TG1(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
353 | peb2466_tone_freq_txt), |
354 | SOC_ENUM_SINGLE(PEB2466_TG2(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
355 | peb2466_tone_freq_txt) |
356 | }, |
357 | [1] = { |
358 | SOC_ENUM_SINGLE(PEB2466_TG1(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
359 | peb2466_tone_freq_txt), |
360 | SOC_ENUM_SINGLE(PEB2466_TG2(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
361 | peb2466_tone_freq_txt) |
362 | }, |
363 | [2] = { |
364 | SOC_ENUM_SINGLE(PEB2466_TG1(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
365 | peb2466_tone_freq_txt), |
366 | SOC_ENUM_SINGLE(PEB2466_TG2(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
367 | peb2466_tone_freq_txt) |
368 | }, |
369 | [3] = { |
370 | SOC_ENUM_SINGLE(PEB2466_TG1(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
371 | peb2466_tone_freq_txt), |
372 | SOC_ENUM_SINGLE(PEB2466_TG2(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), |
373 | peb2466_tone_freq_txt) |
374 | } |
375 | }; |
376 | |
377 | static int peb2466_tg_freq_get(struct snd_kcontrol *kcontrol, |
378 | struct snd_ctl_elem_value *ucontrol) |
379 | { |
380 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
381 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
382 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
383 | |
384 | switch (e->reg) { |
385 | case PEB2466_TG1(0): |
386 | ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg1_freq_item; |
387 | break; |
388 | case PEB2466_TG2(0): |
389 | ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg2_freq_item; |
390 | break; |
391 | case PEB2466_TG1(1): |
392 | ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg1_freq_item; |
393 | break; |
394 | case PEB2466_TG2(1): |
395 | ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg2_freq_item; |
396 | break; |
397 | case PEB2466_TG1(2): |
398 | ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg1_freq_item; |
399 | break; |
400 | case PEB2466_TG2(2): |
401 | ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg2_freq_item; |
402 | break; |
403 | case PEB2466_TG1(3): |
404 | ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg1_freq_item; |
405 | break; |
406 | case PEB2466_TG2(3): |
407 | ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg2_freq_item; |
408 | break; |
409 | default: |
410 | return -EINVAL; |
411 | } |
412 | return 0; |
413 | } |
414 | |
415 | static int peb2466_tg_freq_put(struct snd_kcontrol *kcontrol, |
416 | struct snd_ctl_elem_value *ucontrol) |
417 | { |
418 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
419 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
420 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
421 | unsigned int *tg_freq_item; |
422 | u8 cr1_reg, cr1_mask; |
423 | unsigned int index; |
424 | int ret; |
425 | |
426 | index = ucontrol->value.enumerated.item[0]; |
427 | |
428 | if (index >= ARRAY_SIZE(peb2466_tone_lookup)) |
429 | return -EINVAL; |
430 | |
431 | switch (e->reg) { |
432 | case PEB2466_TG1(0): |
433 | tg_freq_item = &peb2466->ch[0].tg1_freq_item; |
434 | cr1_reg = PEB2466_CR1(0); |
435 | cr1_mask = PEB2466_CR1_PTG1; |
436 | break; |
437 | case PEB2466_TG2(0): |
438 | tg_freq_item = &peb2466->ch[0].tg2_freq_item; |
439 | cr1_reg = PEB2466_CR1(0); |
440 | cr1_mask = PEB2466_CR1_PTG2; |
441 | break; |
442 | case PEB2466_TG1(1): |
443 | tg_freq_item = &peb2466->ch[1].tg1_freq_item; |
444 | cr1_reg = PEB2466_CR1(1); |
445 | cr1_mask = PEB2466_CR1_PTG1; |
446 | break; |
447 | case PEB2466_TG2(1): |
448 | tg_freq_item = &peb2466->ch[1].tg2_freq_item; |
449 | cr1_reg = PEB2466_CR1(1); |
450 | cr1_mask = PEB2466_CR1_PTG2; |
451 | break; |
452 | case PEB2466_TG1(2): |
453 | tg_freq_item = &peb2466->ch[2].tg1_freq_item; |
454 | cr1_reg = PEB2466_CR1(2); |
455 | cr1_mask = PEB2466_CR1_PTG1; |
456 | break; |
457 | case PEB2466_TG2(2): |
458 | tg_freq_item = &peb2466->ch[2].tg2_freq_item; |
459 | cr1_reg = PEB2466_CR1(2); |
460 | cr1_mask = PEB2466_CR1_PTG2; |
461 | break; |
462 | case PEB2466_TG1(3): |
463 | tg_freq_item = &peb2466->ch[3].tg1_freq_item; |
464 | cr1_reg = PEB2466_CR1(3); |
465 | cr1_mask = PEB2466_CR1_PTG1; |
466 | break; |
467 | case PEB2466_TG2(3): |
468 | tg_freq_item = &peb2466->ch[3].tg2_freq_item; |
469 | cr1_reg = PEB2466_CR1(3); |
470 | cr1_mask = PEB2466_CR1_PTG2; |
471 | break; |
472 | default: |
473 | return -EINVAL; |
474 | } |
475 | |
476 | if (index == *tg_freq_item) |
477 | return 0; |
478 | |
479 | if (index == PEB2466_TONE_1000HZ) { |
480 | ret = regmap_update_bits(map: peb2466->regmap, reg: cr1_reg, mask: cr1_mask, val: 0); |
481 | if (ret) |
482 | return ret; |
483 | } else { |
484 | ret = peb2466_write_buf(peb2466, cmd: e->reg, buf: peb2466_tone_lookup[index], len: 4); |
485 | if (ret) |
486 | return ret; |
487 | ret = regmap_update_bits(map: peb2466->regmap, reg: cr1_reg, mask: cr1_mask, val: cr1_mask); |
488 | if (ret) |
489 | return ret; |
490 | } |
491 | |
492 | *tg_freq_item = index; |
493 | return 1; /* The value changed */ |
494 | } |
495 | |
496 | static const struct snd_kcontrol_new peb2466_ch0_out_mix_controls[] = { |
497 | SOC_DAPM_SINGLE("TG1 Switch" , PEB2466_CR1(0), 6, 1, 0), |
498 | SOC_DAPM_SINGLE("TG2 Switch" , PEB2466_CR1(0), 7, 1, 0), |
499 | SOC_DAPM_SINGLE("Voice Switch" , PEB2466_CR2(0), 0, 1, 0) |
500 | }; |
501 | |
502 | static const struct snd_kcontrol_new peb2466_ch1_out_mix_controls[] = { |
503 | SOC_DAPM_SINGLE("TG1 Switch" , PEB2466_CR1(1), 6, 1, 0), |
504 | SOC_DAPM_SINGLE("TG2 Switch" , PEB2466_CR1(1), 7, 1, 0), |
505 | SOC_DAPM_SINGLE("Voice Switch" , PEB2466_CR2(1), 0, 1, 0) |
506 | }; |
507 | |
508 | static const struct snd_kcontrol_new peb2466_ch2_out_mix_controls[] = { |
509 | SOC_DAPM_SINGLE("TG1 Switch" , PEB2466_CR1(2), 6, 1, 0), |
510 | SOC_DAPM_SINGLE("TG2 Switch" , PEB2466_CR1(2), 7, 1, 0), |
511 | SOC_DAPM_SINGLE("Voice Switch" , PEB2466_CR2(2), 0, 1, 0) |
512 | }; |
513 | |
514 | static const struct snd_kcontrol_new peb2466_ch3_out_mix_controls[] = { |
515 | SOC_DAPM_SINGLE("TG1 Switch" , PEB2466_CR1(3), 6, 1, 0), |
516 | SOC_DAPM_SINGLE("TG2 Switch" , PEB2466_CR1(3), 7, 1, 0), |
517 | SOC_DAPM_SINGLE("Voice Switch" , PEB2466_CR2(3), 0, 1, 0) |
518 | }; |
519 | |
520 | static const struct snd_kcontrol_new peb2466_controls[] = { |
521 | /* Attenuators */ |
522 | SOC_SINGLE("DAC0 -6dB Playback Switch" , PEB2466_CR3(0), 2, 1, 0), |
523 | SOC_SINGLE("DAC1 -6dB Playback Switch" , PEB2466_CR3(1), 2, 1, 0), |
524 | SOC_SINGLE("DAC2 -6dB Playback Switch" , PEB2466_CR3(2), 2, 1, 0), |
525 | SOC_SINGLE("DAC3 -6dB Playback Switch" , PEB2466_CR3(3), 2, 1, 0), |
526 | |
527 | /* Amplifiers */ |
528 | SOC_SINGLE("ADC0 +6dB Capture Switch" , PEB2466_CR3(0), 3, 1, 0), |
529 | SOC_SINGLE("ADC1 +6dB Capture Switch" , PEB2466_CR3(1), 3, 1, 0), |
530 | SOC_SINGLE("ADC2 +6dB Capture Switch" , PEB2466_CR3(2), 3, 1, 0), |
531 | SOC_SINGLE("ADC3 +6dB Capture Switch" , PEB2466_CR3(3), 3, 1, 0), |
532 | |
533 | /* Tone generators */ |
534 | SOC_ENUM_EXT("DAC0 TG1 Freq" , peb2466_tg_freq[0][0], |
535 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
536 | SOC_ENUM_EXT("DAC1 TG1 Freq" , peb2466_tg_freq[1][0], |
537 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
538 | SOC_ENUM_EXT("DAC2 TG1 Freq" , peb2466_tg_freq[2][0], |
539 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
540 | SOC_ENUM_EXT("DAC3 TG1 Freq" , peb2466_tg_freq[3][0], |
541 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
542 | |
543 | SOC_ENUM_EXT("DAC0 TG2 Freq" , peb2466_tg_freq[0][1], |
544 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
545 | SOC_ENUM_EXT("DAC1 TG2 Freq" , peb2466_tg_freq[1][1], |
546 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
547 | SOC_ENUM_EXT("DAC2 TG2 Freq" , peb2466_tg_freq[2][1], |
548 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
549 | SOC_ENUM_EXT("DAC3 TG2 Freq" , peb2466_tg_freq[3][1], |
550 | peb2466_tg_freq_get, peb2466_tg_freq_put), |
551 | }; |
552 | |
553 | static const struct snd_soc_dapm_widget peb2466_dapm_widgets[] = { |
554 | SND_SOC_DAPM_SUPPLY("CH0 PWR" , PEB2466_CR1(0), 0, 0, NULL, 0), |
555 | SND_SOC_DAPM_SUPPLY("CH1 PWR" , PEB2466_CR1(1), 0, 0, NULL, 0), |
556 | SND_SOC_DAPM_SUPPLY("CH2 PWR" , PEB2466_CR1(2), 0, 0, NULL, 0), |
557 | SND_SOC_DAPM_SUPPLY("CH3 PWR" , PEB2466_CR1(3), 0, 0, NULL, 0), |
558 | |
559 | SND_SOC_DAPM_DAC("CH0 DIN" , "Playback" , SND_SOC_NOPM, 0, 0), |
560 | SND_SOC_DAPM_DAC("CH1 DIN" , "Playback" , SND_SOC_NOPM, 0, 0), |
561 | SND_SOC_DAPM_DAC("CH2 DIN" , "Playback" , SND_SOC_NOPM, 0, 0), |
562 | SND_SOC_DAPM_DAC("CH3 DIN" , "Playback" , SND_SOC_NOPM, 0, 0), |
563 | |
564 | SND_SOC_DAPM_SIGGEN("CH0 TG1" ), |
565 | SND_SOC_DAPM_SIGGEN("CH1 TG1" ), |
566 | SND_SOC_DAPM_SIGGEN("CH2 TG1" ), |
567 | SND_SOC_DAPM_SIGGEN("CH3 TG1" ), |
568 | |
569 | SND_SOC_DAPM_SIGGEN("CH0 TG2" ), |
570 | SND_SOC_DAPM_SIGGEN("CH1 TG2" ), |
571 | SND_SOC_DAPM_SIGGEN("CH2 TG2" ), |
572 | SND_SOC_DAPM_SIGGEN("CH3 TG2" ), |
573 | |
574 | SND_SOC_DAPM_MIXER("DAC0 Mixer" , SND_SOC_NOPM, 0, 0, |
575 | peb2466_ch0_out_mix_controls, |
576 | ARRAY_SIZE(peb2466_ch0_out_mix_controls)), |
577 | SND_SOC_DAPM_MIXER("DAC1 Mixer" , SND_SOC_NOPM, 0, 0, |
578 | peb2466_ch1_out_mix_controls, |
579 | ARRAY_SIZE(peb2466_ch1_out_mix_controls)), |
580 | SND_SOC_DAPM_MIXER("DAC2 Mixer" , SND_SOC_NOPM, 0, 0, |
581 | peb2466_ch2_out_mix_controls, |
582 | ARRAY_SIZE(peb2466_ch2_out_mix_controls)), |
583 | SND_SOC_DAPM_MIXER("DAC3 Mixer" , SND_SOC_NOPM, 0, 0, |
584 | peb2466_ch3_out_mix_controls, |
585 | ARRAY_SIZE(peb2466_ch3_out_mix_controls)), |
586 | |
587 | SND_SOC_DAPM_PGA("DAC0 PGA" , SND_SOC_NOPM, 0, 0, NULL, 0), |
588 | SND_SOC_DAPM_PGA("DAC1 PGA" , SND_SOC_NOPM, 0, 0, NULL, 0), |
589 | SND_SOC_DAPM_PGA("DAC2 PGA" , SND_SOC_NOPM, 0, 0, NULL, 0), |
590 | SND_SOC_DAPM_PGA("DAC3 PGA" , SND_SOC_NOPM, 0, 0, NULL, 0), |
591 | |
592 | SND_SOC_DAPM_OUTPUT("OUT0" ), |
593 | SND_SOC_DAPM_OUTPUT("OUT1" ), |
594 | SND_SOC_DAPM_OUTPUT("OUT2" ), |
595 | SND_SOC_DAPM_OUTPUT("OUT3" ), |
596 | |
597 | SND_SOC_DAPM_INPUT("IN0" ), |
598 | SND_SOC_DAPM_INPUT("IN1" ), |
599 | SND_SOC_DAPM_INPUT("IN2" ), |
600 | SND_SOC_DAPM_INPUT("IN3" ), |
601 | |
602 | SND_SOC_DAPM_DAC("ADC0" , "Capture" , SND_SOC_NOPM, 0, 0), |
603 | SND_SOC_DAPM_DAC("ADC1" , "Capture" , SND_SOC_NOPM, 0, 0), |
604 | SND_SOC_DAPM_DAC("ADC2" , "Capture" , SND_SOC_NOPM, 0, 0), |
605 | SND_SOC_DAPM_DAC("ADC3" , "Capture" , SND_SOC_NOPM, 0, 0), |
606 | }; |
607 | |
608 | static const struct snd_soc_dapm_route peb2466_dapm_routes[] = { |
609 | { "CH0 DIN" , NULL, "CH0 PWR" }, |
610 | { "CH1 DIN" , NULL, "CH1 PWR" }, |
611 | { "CH2 DIN" , NULL, "CH2 PWR" }, |
612 | { "CH3 DIN" , NULL, "CH3 PWR" }, |
613 | |
614 | { "CH0 TG1" , NULL, "CH0 PWR" }, |
615 | { "CH1 TG1" , NULL, "CH1 PWR" }, |
616 | { "CH2 TG1" , NULL, "CH2 PWR" }, |
617 | { "CH3 TG1" , NULL, "CH3 PWR" }, |
618 | |
619 | { "CH0 TG2" , NULL, "CH0 PWR" }, |
620 | { "CH1 TG2" , NULL, "CH1 PWR" }, |
621 | { "CH2 TG2" , NULL, "CH2 PWR" }, |
622 | { "CH3 TG2" , NULL, "CH3 PWR" }, |
623 | |
624 | { "DAC0 Mixer" , "TG1 Switch" , "CH0 TG1" }, |
625 | { "DAC0 Mixer" , "TG2 Switch" , "CH0 TG2" }, |
626 | { "DAC0 Mixer" , "Voice Switch" , "CH0 DIN" }, |
627 | { "DAC0 Mixer" , NULL, "CH0 DIN" }, |
628 | |
629 | { "DAC1 Mixer" , "TG1 Switch" , "CH1 TG1" }, |
630 | { "DAC1 Mixer" , "TG2 Switch" , "CH1 TG2" }, |
631 | { "DAC1 Mixer" , "Voice Switch" , "CH1 DIN" }, |
632 | { "DAC1 Mixer" , NULL, "CH1 DIN" }, |
633 | |
634 | { "DAC2 Mixer" , "TG1 Switch" , "CH2 TG1" }, |
635 | { "DAC2 Mixer" , "TG2 Switch" , "CH2 TG2" }, |
636 | { "DAC2 Mixer" , "Voice Switch" , "CH2 DIN" }, |
637 | { "DAC2 Mixer" , NULL, "CH2 DIN" }, |
638 | |
639 | { "DAC3 Mixer" , "TG1 Switch" , "CH3 TG1" }, |
640 | { "DAC3 Mixer" , "TG2 Switch" , "CH3 TG2" }, |
641 | { "DAC3 Mixer" , "Voice Switch" , "CH3 DIN" }, |
642 | { "DAC3 Mixer" , NULL, "CH3 DIN" }, |
643 | |
644 | { "DAC0 PGA" , NULL, "DAC0 Mixer" }, |
645 | { "DAC1 PGA" , NULL, "DAC1 Mixer" }, |
646 | { "DAC2 PGA" , NULL, "DAC2 Mixer" }, |
647 | { "DAC3 PGA" , NULL, "DAC3 Mixer" }, |
648 | |
649 | { "OUT0" , NULL, "DAC0 PGA" }, |
650 | { "OUT1" , NULL, "DAC1 PGA" }, |
651 | { "OUT2" , NULL, "DAC2 PGA" }, |
652 | { "OUT3" , NULL, "DAC3 PGA" }, |
653 | |
654 | { "ADC0" , NULL, "IN0" }, |
655 | { "ADC1" , NULL, "IN1" }, |
656 | { "ADC2" , NULL, "IN2" }, |
657 | { "ADC3" , NULL, "IN3" }, |
658 | |
659 | { "ADC0" , NULL, "CH0 PWR" }, |
660 | { "ADC1" , NULL, "CH1 PWR" }, |
661 | { "ADC2" , NULL, "CH2 PWR" }, |
662 | { "ADC3" , NULL, "CH3 PWR" }, |
663 | }; |
664 | |
665 | static int peb2466_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
666 | unsigned int rx_mask, int slots, int width) |
667 | { |
668 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: dai->component); |
669 | unsigned int chan; |
670 | unsigned int mask; |
671 | u8 slot; |
672 | int ret; |
673 | |
674 | switch (width) { |
675 | case 0: |
676 | /* Not set -> default 8 */ |
677 | case 8: |
678 | break; |
679 | default: |
680 | dev_err(dai->dev, "tdm slot width %d not supported\n" , width); |
681 | return -EINVAL; |
682 | } |
683 | |
684 | mask = tx_mask; |
685 | slot = 0; |
686 | chan = 0; |
687 | while (mask && chan < PEB2466_NB_CHANNEL) { |
688 | if (mask & 0x1) { |
689 | ret = regmap_write(map: peb2466->regmap, PEB2466_CR5(chan), val: slot); |
690 | if (ret) { |
691 | dev_err(dai->dev, "chan %d set tx tdm slot failed (%d)\n" , |
692 | chan, ret); |
693 | return ret; |
694 | } |
695 | chan++; |
696 | } |
697 | mask >>= 1; |
698 | slot++; |
699 | } |
700 | if (mask) { |
701 | dev_err(dai->dev, "too much tx slots defined (mask = 0x%x) support max %d\n" , |
702 | tx_mask, PEB2466_NB_CHANNEL); |
703 | return -EINVAL; |
704 | } |
705 | peb2466->max_chan_playback = chan; |
706 | |
707 | mask = rx_mask; |
708 | slot = 0; |
709 | chan = 0; |
710 | while (mask && chan < PEB2466_NB_CHANNEL) { |
711 | if (mask & 0x1) { |
712 | ret = regmap_write(map: peb2466->regmap, PEB2466_CR4(chan), val: slot); |
713 | if (ret) { |
714 | dev_err(dai->dev, "chan %d set rx tdm slot failed (%d)\n" , |
715 | chan, ret); |
716 | return ret; |
717 | } |
718 | chan++; |
719 | } |
720 | mask >>= 1; |
721 | slot++; |
722 | } |
723 | if (mask) { |
724 | dev_err(dai->dev, "too much rx slots defined (mask = 0x%x) support max %d\n" , |
725 | rx_mask, PEB2466_NB_CHANNEL); |
726 | return -EINVAL; |
727 | } |
728 | peb2466->max_chan_capture = chan; |
729 | |
730 | return 0; |
731 | } |
732 | |
733 | static int peb2466_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
734 | { |
735 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: dai->component); |
736 | u8 xr6; |
737 | |
738 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
739 | case SND_SOC_DAIFMT_DSP_A: |
740 | xr6 = PEB2466_XR6_PCM_OFFSET(1); |
741 | break; |
742 | case SND_SOC_DAIFMT_DSP_B: |
743 | xr6 = PEB2466_XR6_PCM_OFFSET(0); |
744 | break; |
745 | default: |
746 | dev_err(dai->dev, "Unsupported format 0x%x\n" , |
747 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
748 | return -EINVAL; |
749 | } |
750 | return regmap_write(map: peb2466->regmap, PEB2466_XR6, val: xr6); |
751 | } |
752 | |
753 | static int peb2466_dai_hw_params(struct snd_pcm_substream *substream, |
754 | struct snd_pcm_hw_params *params, |
755 | struct snd_soc_dai *dai) |
756 | { |
757 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: dai->component); |
758 | unsigned int ch; |
759 | int ret; |
760 | u8 cr1; |
761 | |
762 | switch (params_format(p: params)) { |
763 | case SNDRV_PCM_FORMAT_MU_LAW: |
764 | cr1 = PEB2466_CR1_LAW_MULAW; |
765 | break; |
766 | case SNDRV_PCM_FORMAT_A_LAW: |
767 | cr1 = PEB2466_CR1_LAW_ALAW; |
768 | break; |
769 | default: |
770 | dev_err(&peb2466->spi->dev, "Unsupported format 0x%x\n" , |
771 | params_format(params)); |
772 | return -EINVAL; |
773 | } |
774 | |
775 | for (ch = 0; ch < PEB2466_NB_CHANNEL; ch++) { |
776 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR1(ch), |
777 | PEB2466_CR1_LAW_MASK, val: cr1); |
778 | if (ret) |
779 | return ret; |
780 | } |
781 | |
782 | return 0; |
783 | } |
784 | |
785 | static const unsigned int peb2466_sample_bits[] = {8}; |
786 | |
787 | static struct snd_pcm_hw_constraint_list peb2466_sample_bits_constr = { |
788 | .list = peb2466_sample_bits, |
789 | .count = ARRAY_SIZE(peb2466_sample_bits), |
790 | }; |
791 | |
792 | static int peb2466_dai_startup(struct snd_pcm_substream *substream, |
793 | struct snd_soc_dai *dai) |
794 | { |
795 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: dai->component); |
796 | unsigned int max_ch; |
797 | int ret; |
798 | |
799 | max_ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
800 | peb2466->max_chan_playback : peb2466->max_chan_capture; |
801 | |
802 | /* |
803 | * Disable stream support (min = 0, max = 0) if no timeslots were |
804 | * configured. |
805 | */ |
806 | ret = snd_pcm_hw_constraint_minmax(runtime: substream->runtime, |
807 | SNDRV_PCM_HW_PARAM_CHANNELS, |
808 | min: max_ch ? 1 : 0, max: max_ch); |
809 | if (ret < 0) |
810 | return ret; |
811 | |
812 | return snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, |
813 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, |
814 | l: &peb2466_sample_bits_constr); |
815 | } |
816 | |
817 | static u64 peb2466_dai_formats[] = { |
818 | SND_SOC_POSSIBLE_DAIFMT_DSP_A | |
819 | SND_SOC_POSSIBLE_DAIFMT_DSP_B, |
820 | }; |
821 | |
822 | static const struct snd_soc_dai_ops peb2466_dai_ops = { |
823 | .startup = peb2466_dai_startup, |
824 | .hw_params = peb2466_dai_hw_params, |
825 | .set_tdm_slot = peb2466_dai_set_tdm_slot, |
826 | .set_fmt = peb2466_dai_set_fmt, |
827 | .auto_selectable_formats = peb2466_dai_formats, |
828 | .num_auto_selectable_formats = ARRAY_SIZE(peb2466_dai_formats), |
829 | }; |
830 | |
831 | static struct snd_soc_dai_driver peb2466_dai_driver = { |
832 | .name = "peb2466" , |
833 | .playback = { |
834 | .stream_name = "Playback" , |
835 | .channels_min = 1, |
836 | .channels_max = PEB2466_NB_CHANNEL, |
837 | .rates = SNDRV_PCM_RATE_8000, |
838 | .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, |
839 | }, |
840 | .capture = { |
841 | .stream_name = "Capture" , |
842 | .channels_min = 1, |
843 | .channels_max = PEB2466_NB_CHANNEL, |
844 | .rates = SNDRV_PCM_RATE_8000, |
845 | .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, |
846 | }, |
847 | .ops = &peb2466_dai_ops, |
848 | }; |
849 | |
850 | static int peb2466_reset_audio(struct peb2466 *peb2466) |
851 | { |
852 | static const struct reg_sequence reg_reset[] = { |
853 | { .reg = PEB2466_XR6, .def = 0x00 }, |
854 | |
855 | { .reg = PEB2466_CR5(0), .def = 0x00 }, |
856 | { .reg = PEB2466_CR4(0), .def = 0x00 }, |
857 | { .reg = PEB2466_CR3(0), .def = 0x00 }, |
858 | { .reg = PEB2466_CR2(0), .def = 0x00 }, |
859 | { .reg = PEB2466_CR1(0), .def = 0x00 }, |
860 | { .reg = PEB2466_CR0(0), .def = PEB2466_CR0_IMR1 }, |
861 | |
862 | { .reg = PEB2466_CR5(1), .def = 0x00 }, |
863 | { .reg = PEB2466_CR4(1), .def = 0x00 }, |
864 | { .reg = PEB2466_CR3(1), .def = 0x00 }, |
865 | { .reg = PEB2466_CR2(1), .def = 0x00 }, |
866 | { .reg = PEB2466_CR1(1), .def = 0x00 }, |
867 | { .reg = PEB2466_CR0(1), .def = PEB2466_CR0_IMR1 }, |
868 | |
869 | { .reg = PEB2466_CR5(2), .def = 0x00 }, |
870 | { .reg = PEB2466_CR4(2), .def = 0x00 }, |
871 | { .reg = PEB2466_CR3(2), .def = 0x00 }, |
872 | { .reg = PEB2466_CR2(2), .def = 0x00 }, |
873 | { .reg = PEB2466_CR1(2), .def = 0x00 }, |
874 | { .reg = PEB2466_CR0(2), .def = PEB2466_CR0_IMR1 }, |
875 | |
876 | { .reg = PEB2466_CR5(3), .def = 0x00 }, |
877 | { .reg = PEB2466_CR4(3), .def = 0x00 }, |
878 | { .reg = PEB2466_CR3(3), .def = 0x00 }, |
879 | { .reg = PEB2466_CR2(3), .def = 0x00 }, |
880 | { .reg = PEB2466_CR1(3), .def = 0x00 }, |
881 | { .reg = PEB2466_CR0(3), .def = PEB2466_CR0_IMR1 }, |
882 | }; |
883 | static const u8 imr1_p1[8] = {0x00, 0x90, 0x09, 0x00, 0x90, 0x09, 0x00, 0x00}; |
884 | static const u8 imr1_p2[8] = {0x7F, 0xFF, 0x00, 0x00, 0x90, 0x14, 0x40, 0x08}; |
885 | static const u8 zero[8] = {0}; |
886 | int ret; |
887 | int i; |
888 | |
889 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
890 | peb2466->ch[i].tg1_freq_item = PEB2466_TONE_1000HZ; |
891 | peb2466->ch[i].tg2_freq_item = PEB2466_TONE_1000HZ; |
892 | |
893 | /* |
894 | * Even if not used, disabling IM/R1 filter is not recommended. |
895 | * Instead, we must configure it with default coefficients and |
896 | * enable it. |
897 | * The filter will be enabled right after (in the following |
898 | * regmap_multi_reg_write() call). |
899 | */ |
900 | ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), buf: imr1_p1, len: 8); |
901 | if (ret) |
902 | return ret; |
903 | ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), buf: imr1_p2, len: 8); |
904 | if (ret) |
905 | return ret; |
906 | |
907 | /* Set all other filters coefficients to zero */ |
908 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), buf: zero, len: 8); |
909 | if (ret) |
910 | return ret; |
911 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), buf: zero, len: 8); |
912 | if (ret) |
913 | return ret; |
914 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), buf: zero, len: 8); |
915 | if (ret) |
916 | return ret; |
917 | ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), buf: zero, len: 8); |
918 | if (ret) |
919 | return ret; |
920 | ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), buf: zero, len: 8); |
921 | if (ret) |
922 | return ret; |
923 | ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), buf: zero, len: 4); |
924 | if (ret) |
925 | return ret; |
926 | ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), buf: zero, len: 4); |
927 | if (ret) |
928 | return ret; |
929 | } |
930 | |
931 | return regmap_multi_reg_write(map: peb2466->regmap, regs: reg_reset, ARRAY_SIZE(reg_reset)); |
932 | } |
933 | |
934 | static int peb2466_fw_parse_thfilter(struct snd_soc_component *component, |
935 | u16 tag, u32 lng, const u8 *data) |
936 | { |
937 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
938 | u8 mask; |
939 | int ret; |
940 | int i; |
941 | |
942 | dev_info(component->dev, "fw TH filter: mask %x, %*phN\n" , *data, |
943 | lng - 1, data + 1); |
944 | |
945 | /* |
946 | * TH_FILTER TLV data: |
947 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
948 | * - @1 8 bytes: TH-Filter coefficients part1 |
949 | * - @9 8 bytes: TH-Filter coefficients part2 |
950 | * - @17 8 bytes: TH-Filter coefficients part3 |
951 | */ |
952 | mask = *data; |
953 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
954 | if (!(mask & (1 << i))) |
955 | continue; |
956 | |
957 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
958 | PEB2466_CR0_TH, val: 0); |
959 | if (ret) |
960 | return ret; |
961 | |
962 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), buf: data + 1, len: 8); |
963 | if (ret) |
964 | return ret; |
965 | |
966 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), buf: data + 9, len: 8); |
967 | if (ret) |
968 | return ret; |
969 | |
970 | ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), buf: data + 17, len: 8); |
971 | if (ret) |
972 | return ret; |
973 | |
974 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
975 | PEB2466_CR0_TH | PEB2466_CR0_THSEL_MASK, |
976 | PEB2466_CR0_TH | PEB2466_CR0_THSEL(i)); |
977 | if (ret) |
978 | return ret; |
979 | } |
980 | return 0; |
981 | } |
982 | |
983 | static int peb2466_fw_parse_imr1filter(struct snd_soc_component *component, |
984 | u16 tag, u32 lng, const u8 *data) |
985 | { |
986 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
987 | u8 mask; |
988 | int ret; |
989 | int i; |
990 | |
991 | dev_info(component->dev, "fw IM/R1 filter: mask %x, %*phN\n" , *data, |
992 | lng - 1, data + 1); |
993 | |
994 | /* |
995 | * IMR1_FILTER TLV data: |
996 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
997 | * - @1 8 bytes: IM/R1-Filter coefficients part1 |
998 | * - @9 8 bytes: IM/R1-Filter coefficients part2 |
999 | */ |
1000 | mask = *data; |
1001 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1002 | if (!(mask & (1 << i))) |
1003 | continue; |
1004 | |
1005 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1006 | PEB2466_CR0_IMR1, val: 0); |
1007 | if (ret) |
1008 | return ret; |
1009 | |
1010 | ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), buf: data + 1, len: 8); |
1011 | if (ret) |
1012 | return ret; |
1013 | |
1014 | ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), buf: data + 9, len: 8); |
1015 | if (ret) |
1016 | return ret; |
1017 | |
1018 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1019 | PEB2466_CR0_IMR1, PEB2466_CR0_IMR1); |
1020 | if (ret) |
1021 | return ret; |
1022 | } |
1023 | return 0; |
1024 | } |
1025 | |
1026 | static int peb2466_fw_parse_frxfilter(struct snd_soc_component *component, |
1027 | u16 tag, u32 lng, const u8 *data) |
1028 | { |
1029 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1030 | u8 mask; |
1031 | int ret; |
1032 | int i; |
1033 | |
1034 | dev_info(component->dev, "fw FRX filter: mask %x, %*phN\n" , *data, |
1035 | lng - 1, data + 1); |
1036 | |
1037 | /* |
1038 | * FRX_FILTER TLV data: |
1039 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1040 | * - @1 8 bytes: FRX-Filter coefficients |
1041 | */ |
1042 | mask = *data; |
1043 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1044 | if (!(mask & (1 << i))) |
1045 | continue; |
1046 | |
1047 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1048 | PEB2466_CR0_FRX, val: 0); |
1049 | if (ret) |
1050 | return ret; |
1051 | |
1052 | ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), buf: data + 1, len: 8); |
1053 | if (ret) |
1054 | return ret; |
1055 | |
1056 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1057 | PEB2466_CR0_FRX, PEB2466_CR0_FRX); |
1058 | if (ret) |
1059 | return ret; |
1060 | } |
1061 | return 0; |
1062 | } |
1063 | |
1064 | static int peb2466_fw_parse_frrfilter(struct snd_soc_component *component, |
1065 | u16 tag, u32 lng, const u8 *data) |
1066 | { |
1067 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1068 | u8 mask; |
1069 | int ret; |
1070 | int i; |
1071 | |
1072 | dev_info(component->dev, "fw FRR filter: mask %x, %*phN\n" , *data, |
1073 | lng - 1, data + 1); |
1074 | |
1075 | /* |
1076 | * FRR_FILTER TLV data: |
1077 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1078 | * - @1 8 bytes: FRR-Filter coefficients |
1079 | */ |
1080 | mask = *data; |
1081 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1082 | if (!(mask & (1 << i))) |
1083 | continue; |
1084 | |
1085 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1086 | PEB2466_CR0_FRR, val: 0); |
1087 | if (ret) |
1088 | return ret; |
1089 | |
1090 | ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), buf: data + 1, len: 8); |
1091 | if (ret) |
1092 | return ret; |
1093 | |
1094 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1095 | PEB2466_CR0_FRR, PEB2466_CR0_FRR); |
1096 | if (ret) |
1097 | return ret; |
1098 | } |
1099 | return 0; |
1100 | } |
1101 | |
1102 | static int peb2466_fw_parse_axfilter(struct snd_soc_component *component, |
1103 | u16 tag, u32 lng, const u8 *data) |
1104 | { |
1105 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1106 | u8 mask; |
1107 | int ret; |
1108 | int i; |
1109 | |
1110 | dev_info(component->dev, "fw AX filter: mask %x, %*phN\n" , *data, |
1111 | lng - 1, data + 1); |
1112 | |
1113 | /* |
1114 | * AX_FILTER TLV data: |
1115 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1116 | * - @1 4 bytes: AX-Filter coefficients |
1117 | */ |
1118 | mask = *data; |
1119 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1120 | if (!(mask & (1 << i))) |
1121 | continue; |
1122 | |
1123 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1124 | PEB2466_CR0_AX, val: 0); |
1125 | if (ret) |
1126 | return ret; |
1127 | |
1128 | ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), buf: data + 1, len: 4); |
1129 | if (ret) |
1130 | return ret; |
1131 | |
1132 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1133 | PEB2466_CR0_AX, PEB2466_CR0_AX); |
1134 | if (ret) |
1135 | return ret; |
1136 | } |
1137 | return 0; |
1138 | } |
1139 | |
1140 | static int peb2466_fw_parse_arfilter(struct snd_soc_component *component, |
1141 | u16 tag, u32 lng, const u8 *data) |
1142 | { |
1143 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1144 | u8 mask; |
1145 | int ret; |
1146 | int i; |
1147 | |
1148 | dev_info(component->dev, "fw AR filter: mask %x, %*phN\n" , *data, |
1149 | lng - 1, data + 1); |
1150 | |
1151 | /* |
1152 | * AR_FILTER TLV data: |
1153 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1154 | * - @1 4 bytes: AR-Filter coefficients |
1155 | */ |
1156 | mask = *data; |
1157 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1158 | if (!(mask & (1 << i))) |
1159 | continue; |
1160 | |
1161 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1162 | PEB2466_CR0_AR, val: 0); |
1163 | if (ret) |
1164 | return ret; |
1165 | |
1166 | ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), buf: data + 1, len: 4); |
1167 | if (ret) |
1168 | return ret; |
1169 | |
1170 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1171 | PEB2466_CR0_AR, PEB2466_CR0_AR); |
1172 | if (ret) |
1173 | return ret; |
1174 | } |
1175 | return 0; |
1176 | } |
1177 | |
1178 | static const char * const peb2466_ax_ctrl_names[] = { |
1179 | "ADC0 Capture Volume" , |
1180 | "ADC1 Capture Volume" , |
1181 | "ADC2 Capture Volume" , |
1182 | "ADC3 Capture Volume" , |
1183 | }; |
1184 | |
1185 | static int peb2466_fw_parse_axtable(struct snd_soc_component *component, |
1186 | u16 tag, u32 lng, const u8 *data) |
1187 | { |
1188 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1189 | struct peb2466_lkup_ctrl *lkup_ctrl; |
1190 | struct peb2466_lookup *lookup; |
1191 | u8 (*table)[4]; |
1192 | u32 table_size; |
1193 | u32 init_index; |
1194 | s32 min_val; |
1195 | s32 step; |
1196 | u8 mask; |
1197 | int ret; |
1198 | int i; |
1199 | |
1200 | /* |
1201 | * AX_TABLE TLV data: |
1202 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1203 | * - @1 32bits signed: Min table value in centi dB (MinVal) |
1204 | * ie -300 means -3.0 dB |
1205 | * - @5 32bits signed: Step from on item to other item in centi dB (Step) |
1206 | * ie 25 means 0.25 dB) |
1207 | * - @9 32bits unsigned: Item index in the table to use for the initial |
1208 | * value |
1209 | * - @13 N*4 bytes: Table composed of 4 bytes items. |
1210 | * Each item correspond to an AX filter value. |
1211 | * |
1212 | * The conversion from raw value item in the table to/from the value in |
1213 | * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. |
1214 | */ |
1215 | |
1216 | /* Check Lng and extract the table size. */ |
1217 | if (lng < 13 || ((lng - 13) % 4)) { |
1218 | dev_err(component->dev, "fw AX table lng %u invalid\n" , lng); |
1219 | return -EINVAL; |
1220 | } |
1221 | table_size = lng - 13; |
1222 | |
1223 | min_val = get_unaligned_be32(p: data + 1); |
1224 | step = get_unaligned_be32(p: data + 5); |
1225 | init_index = get_unaligned_be32(p: data + 9); |
1226 | if (init_index >= (table_size / 4)) { |
1227 | dev_err(component->dev, "fw AX table index %u out of table[%u]\n" , |
1228 | init_index, table_size / 4); |
1229 | return -EINVAL; |
1230 | } |
1231 | |
1232 | dev_info(component->dev, |
1233 | "fw AX table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n" , |
1234 | *data, min_val, step, table_size / 4, init_index, |
1235 | 4, data + 13 + (init_index * 4)); |
1236 | |
1237 | BUILD_BUG_ON(sizeof(*table) != 4); |
1238 | table = devm_kzalloc(dev: &peb2466->spi->dev, size: table_size, GFP_KERNEL); |
1239 | if (!table) |
1240 | return -ENOMEM; |
1241 | memcpy(table, data + 13, table_size); |
1242 | |
1243 | mask = *data; |
1244 | BUILD_BUG_ON(ARRAY_SIZE(peb2466_ax_ctrl_names) != ARRAY_SIZE(peb2466->ch)); |
1245 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1246 | if (!(mask & (1 << i))) |
1247 | continue; |
1248 | |
1249 | lookup = &peb2466->ch[i].ax_lookup; |
1250 | lookup->table = table; |
1251 | lookup->count = table_size / 4; |
1252 | |
1253 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1254 | PEB2466_CR0_AX, val: 0); |
1255 | if (ret) |
1256 | return ret; |
1257 | |
1258 | ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), |
1259 | buf: lookup->table[init_index], len: 4); |
1260 | if (ret) |
1261 | return ret; |
1262 | |
1263 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1264 | PEB2466_CR0_AX, PEB2466_CR0_AX); |
1265 | if (ret) |
1266 | return ret; |
1267 | |
1268 | lkup_ctrl = &peb2466->ch[i].ax_lkup_ctrl; |
1269 | lkup_ctrl->lookup = lookup; |
1270 | lkup_ctrl->reg = PEB2466_AX_FILTER(i); |
1271 | lkup_ctrl->index = init_index; |
1272 | |
1273 | ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, |
1274 | name: peb2466_ax_ctrl_names[i], |
1275 | min_val, step); |
1276 | if (ret) |
1277 | return ret; |
1278 | } |
1279 | return 0; |
1280 | } |
1281 | |
1282 | static const char * const peb2466_ar_ctrl_names[] = { |
1283 | "DAC0 Playback Volume" , |
1284 | "DAC1 Playback Volume" , |
1285 | "DAC2 Playback Volume" , |
1286 | "DAC3 Playback Volume" , |
1287 | }; |
1288 | |
1289 | static int peb2466_fw_parse_artable(struct snd_soc_component *component, |
1290 | u16 tag, u32 lng, const u8 *data) |
1291 | { |
1292 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1293 | struct peb2466_lkup_ctrl *lkup_ctrl; |
1294 | struct peb2466_lookup *lookup; |
1295 | u8 (*table)[4]; |
1296 | u32 table_size; |
1297 | u32 init_index; |
1298 | s32 min_val; |
1299 | s32 step; |
1300 | u8 mask; |
1301 | int ret; |
1302 | int i; |
1303 | |
1304 | /* |
1305 | * AR_TABLE TLV data: |
1306 | * - @0 1 byte: Chan mask (bit set means related channel is concerned) |
1307 | * - @1 32bits signed: Min table value in centi dB (MinVal) |
1308 | * ie -300 means -3.0 dB |
1309 | * - @5 32bits signed: Step from on item to other item in centi dB (Step) |
1310 | * ie 25 means 0.25 dB) |
1311 | * - @9 32bits unsigned: Item index in the table to use for the initial |
1312 | * value |
1313 | * - @13 N*4 bytes: Table composed of 4 bytes items. |
1314 | * Each item correspond to an AR filter value. |
1315 | * |
1316 | * The conversion from raw value item in the table to/from the value in |
1317 | * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. |
1318 | */ |
1319 | |
1320 | /* Check Lng and extract the table size. */ |
1321 | if (lng < 13 || ((lng - 13) % 4)) { |
1322 | dev_err(component->dev, "fw AR table lng %u invalid\n" , lng); |
1323 | return -EINVAL; |
1324 | } |
1325 | table_size = lng - 13; |
1326 | |
1327 | min_val = get_unaligned_be32(p: data + 1); |
1328 | step = get_unaligned_be32(p: data + 5); |
1329 | init_index = get_unaligned_be32(p: data + 9); |
1330 | if (init_index >= (table_size / 4)) { |
1331 | dev_err(component->dev, "fw AR table index %u out of table[%u]\n" , |
1332 | init_index, table_size / 4); |
1333 | return -EINVAL; |
1334 | } |
1335 | |
1336 | dev_info(component->dev, |
1337 | "fw AR table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n" , |
1338 | *data, min_val, step, table_size / 4, init_index, |
1339 | 4, data + 13 + (init_index * 4)); |
1340 | |
1341 | BUILD_BUG_ON(sizeof(*table) != 4); |
1342 | table = devm_kzalloc(dev: &peb2466->spi->dev, size: table_size, GFP_KERNEL); |
1343 | if (!table) |
1344 | return -ENOMEM; |
1345 | memcpy(table, data + 13, table_size); |
1346 | |
1347 | mask = *data; |
1348 | BUILD_BUG_ON(ARRAY_SIZE(peb2466_ar_ctrl_names) != ARRAY_SIZE(peb2466->ch)); |
1349 | for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { |
1350 | if (!(mask & (1 << i))) |
1351 | continue; |
1352 | |
1353 | lookup = &peb2466->ch[i].ar_lookup; |
1354 | lookup->table = table; |
1355 | lookup->count = table_size / 4; |
1356 | |
1357 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1358 | PEB2466_CR0_AR, val: 0); |
1359 | if (ret) |
1360 | return ret; |
1361 | |
1362 | ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), |
1363 | buf: lookup->table[init_index], len: 4); |
1364 | if (ret) |
1365 | return ret; |
1366 | |
1367 | ret = regmap_update_bits(map: peb2466->regmap, PEB2466_CR0(i), |
1368 | PEB2466_CR0_AR, PEB2466_CR0_AR); |
1369 | if (ret) |
1370 | return ret; |
1371 | |
1372 | lkup_ctrl = &peb2466->ch[i].ar_lkup_ctrl; |
1373 | lkup_ctrl->lookup = lookup; |
1374 | lkup_ctrl->reg = PEB2466_AR_FILTER(i); |
1375 | lkup_ctrl->index = init_index; |
1376 | |
1377 | ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, |
1378 | name: peb2466_ar_ctrl_names[i], |
1379 | min_val, step); |
1380 | if (ret) |
1381 | return ret; |
1382 | } |
1383 | return 0; |
1384 | } |
1385 | |
1386 | struct peb2466_fw_tag_def { |
1387 | u16 tag; |
1388 | u32 lng_min; |
1389 | u32 lng_max; |
1390 | int (*parse)(struct snd_soc_component *component, |
1391 | u16 tag, u32 lng, const u8 *data); |
1392 | }; |
1393 | |
1394 | #define PEB2466_TAG_DEF_LNG_EQ(__tag, __lng, __parse) { \ |
1395 | .tag = __tag, \ |
1396 | .lng_min = __lng, \ |
1397 | .lng_max = __lng, \ |
1398 | .parse = __parse, \ |
1399 | } |
1400 | |
1401 | #define PEB2466_TAG_DEF_LNG_MIN(__tag, __lng_min, __parse) { \ |
1402 | .tag = __tag, \ |
1403 | .lng_min = __lng_min, \ |
1404 | .lng_max = U32_MAX, \ |
1405 | .parse = __parse, \ |
1406 | } |
1407 | |
1408 | static const struct peb2466_fw_tag_def peb2466_fw_tag_defs[] = { |
1409 | /* TH FILTER */ |
1410 | PEB2466_TAG_DEF_LNG_EQ(0x0001, 1 + 3 * 8, peb2466_fw_parse_thfilter), |
1411 | /* IMR1 FILTER */ |
1412 | PEB2466_TAG_DEF_LNG_EQ(0x0002, 1 + 2 * 8, peb2466_fw_parse_imr1filter), |
1413 | /* FRX FILTER */ |
1414 | PEB2466_TAG_DEF_LNG_EQ(0x0003, 1 + 8, peb2466_fw_parse_frxfilter), |
1415 | /* FRR FILTER */ |
1416 | PEB2466_TAG_DEF_LNG_EQ(0x0004, 1 + 8, peb2466_fw_parse_frrfilter), |
1417 | /* AX FILTER */ |
1418 | PEB2466_TAG_DEF_LNG_EQ(0x0005, 1 + 4, peb2466_fw_parse_axfilter), |
1419 | /* AR FILTER */ |
1420 | PEB2466_TAG_DEF_LNG_EQ(0x0006, 1 + 4, peb2466_fw_parse_arfilter), |
1421 | /* AX TABLE */ |
1422 | PEB2466_TAG_DEF_LNG_MIN(0x0105, 1 + 3 * 4, peb2466_fw_parse_axtable), |
1423 | /* AR TABLE */ |
1424 | PEB2466_TAG_DEF_LNG_MIN(0x0106, 1 + 3 * 4, peb2466_fw_parse_artable), |
1425 | }; |
1426 | |
1427 | static const struct peb2466_fw_tag_def *peb2466_fw_get_tag_def(u16 tag) |
1428 | { |
1429 | int i; |
1430 | |
1431 | for (i = 0; i < ARRAY_SIZE(peb2466_fw_tag_defs); i++) { |
1432 | if (peb2466_fw_tag_defs[i].tag == tag) |
1433 | return &peb2466_fw_tag_defs[i]; |
1434 | } |
1435 | return NULL; |
1436 | } |
1437 | |
1438 | static int peb2466_fw_parse(struct snd_soc_component *component, |
1439 | const u8 *data, size_t size) |
1440 | { |
1441 | const struct peb2466_fw_tag_def *tag_def; |
1442 | size_t left; |
1443 | const u8 *buf; |
1444 | u16 val16; |
1445 | u16 tag; |
1446 | u32 lng; |
1447 | int ret; |
1448 | |
1449 | /* |
1450 | * Coefficients firmware binary structure (16bits and 32bits are |
1451 | * big-endian values). |
1452 | * |
1453 | * @0, 16bits: Magic (0x2466) |
1454 | * @2, 16bits: Version (0x0100 for version 1.0) |
1455 | * @4, 2+4+N bytes: TLV block |
1456 | * @4+(2+4+N) bytes: Next TLV block |
1457 | * ... |
1458 | * |
1459 | * Detail of a TLV block: |
1460 | * @0, 16bits: Tag |
1461 | * @2, 32bits: Lng |
1462 | * @6, lng bytes: Data |
1463 | * |
1464 | * The detail the Data for a given TLV Tag is provided in the related |
1465 | * parser. |
1466 | */ |
1467 | |
1468 | left = size; |
1469 | buf = data; |
1470 | |
1471 | if (left < 4) { |
1472 | dev_err(component->dev, "fw size %zu, exp at least 4\n" , left); |
1473 | return -EINVAL; |
1474 | } |
1475 | |
1476 | /* Check magic */ |
1477 | val16 = get_unaligned_be16(p: buf); |
1478 | if (val16 != 0x2466) { |
1479 | dev_err(component->dev, "fw magic 0x%04x exp 0x2466\n" , val16); |
1480 | return -EINVAL; |
1481 | } |
1482 | buf += 2; |
1483 | left -= 2; |
1484 | |
1485 | /* Check version */ |
1486 | val16 = get_unaligned_be16(p: buf); |
1487 | if (val16 != 0x0100) { |
1488 | dev_err(component->dev, "fw magic 0x%04x exp 0x0100\n" , val16); |
1489 | return -EINVAL; |
1490 | } |
1491 | buf += 2; |
1492 | left -= 2; |
1493 | |
1494 | while (left) { |
1495 | if (left < 6) { |
1496 | dev_err(component->dev, "fw %td/%zu left %zu, exp at least 6\n" , |
1497 | buf - data, size, left); |
1498 | return -EINVAL; |
1499 | } |
1500 | /* Check tag and lng */ |
1501 | tag = get_unaligned_be16(p: buf); |
1502 | lng = get_unaligned_be32(p: buf + 2); |
1503 | tag_def = peb2466_fw_get_tag_def(tag); |
1504 | if (!tag_def) { |
1505 | dev_err(component->dev, "fw %td/%zu tag 0x%04x unknown\n" , |
1506 | buf - data, size, tag); |
1507 | return -EINVAL; |
1508 | } |
1509 | if (lng < tag_def->lng_min || lng > tag_def->lng_max) { |
1510 | dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, exp [%u;%u]\n" , |
1511 | buf - data, size, tag, lng, tag_def->lng_min, tag_def->lng_max); |
1512 | return -EINVAL; |
1513 | } |
1514 | buf += 6; |
1515 | left -= 6; |
1516 | if (left < lng) { |
1517 | dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, left %zu\n" , |
1518 | buf - data, size, tag, lng, left); |
1519 | return -EINVAL; |
1520 | } |
1521 | |
1522 | /* TLV block is valid -> parse the data part */ |
1523 | ret = tag_def->parse(component, tag, lng, buf); |
1524 | if (ret) { |
1525 | dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u parse failed\n" , |
1526 | buf - data, size, tag, lng); |
1527 | return ret; |
1528 | } |
1529 | |
1530 | buf += lng; |
1531 | left -= lng; |
1532 | } |
1533 | return 0; |
1534 | } |
1535 | |
1536 | static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name) |
1537 | { |
1538 | const struct firmware *fw; |
1539 | int ret; |
1540 | |
1541 | ret = request_firmware(fw: &fw, name: fw_name, device: component->dev); |
1542 | if (ret) |
1543 | return ret; |
1544 | |
1545 | ret = peb2466_fw_parse(component, data: fw->data, size: fw->size); |
1546 | release_firmware(fw); |
1547 | |
1548 | return ret; |
1549 | } |
1550 | |
1551 | static int peb2466_component_probe(struct snd_soc_component *component) |
1552 | { |
1553 | struct peb2466 *peb2466 = snd_soc_component_get_drvdata(c: component); |
1554 | const char *firmware_name; |
1555 | int ret; |
1556 | |
1557 | /* reset peb2466 audio part */ |
1558 | ret = peb2466_reset_audio(peb2466); |
1559 | if (ret) |
1560 | return ret; |
1561 | |
1562 | ret = of_property_read_string(np: peb2466->spi->dev.of_node, |
1563 | propname: "firmware-name" , out_string: &firmware_name); |
1564 | if (ret) |
1565 | return (ret == -EINVAL) ? 0 : ret; |
1566 | |
1567 | return peb2466_load_coeffs(component, fw_name: firmware_name); |
1568 | } |
1569 | |
1570 | static const struct snd_soc_component_driver peb2466_component_driver = { |
1571 | .probe = peb2466_component_probe, |
1572 | .controls = peb2466_controls, |
1573 | .num_controls = ARRAY_SIZE(peb2466_controls), |
1574 | .dapm_widgets = peb2466_dapm_widgets, |
1575 | .num_dapm_widgets = ARRAY_SIZE(peb2466_dapm_widgets), |
1576 | .dapm_routes = peb2466_dapm_routes, |
1577 | .num_dapm_routes = ARRAY_SIZE(peb2466_dapm_routes), |
1578 | .endianness = 1, |
1579 | }; |
1580 | |
1581 | /* |
1582 | * The mapping used for the relationship between the gpio offset and the |
1583 | * physical pin is the following: |
1584 | * |
1585 | * offset pin |
1586 | * 0 SI1_0 |
1587 | * 1 SI1_1 |
1588 | * 2 SI2_0 |
1589 | * 3 SI2_1 |
1590 | * 4 SI3_0 |
1591 | * 5 SI3_1 |
1592 | * 6 SI4_0 |
1593 | * 7 SI4_1 |
1594 | * 8 SO1_0 |
1595 | * 9 SO1_1 |
1596 | * 10 SO2_0 |
1597 | * 11 SO2_1 |
1598 | * 12 SO3_0 |
1599 | * 13 SO3_1 |
1600 | * 14 SO4_0 |
1601 | * 15 SO4_1 |
1602 | * 16 SB1_0 |
1603 | * 17 SB1_1 |
1604 | * 18 SB2_0 |
1605 | * 19 SB2_1 |
1606 | * 20 SB3_0 |
1607 | * 21 SB3_1 |
1608 | * 22 SB4_0 |
1609 | * 23 SB4_1 |
1610 | * 24 SB1_2 |
1611 | * 25 SB2_2 |
1612 | * 26 SB3_2 |
1613 | * 27 SB4_2 |
1614 | */ |
1615 | |
1616 | static int peb2466_chip_gpio_offset_to_data_regmask(unsigned int offset, |
1617 | unsigned int *xr_reg, |
1618 | unsigned int *mask) |
1619 | { |
1620 | if (offset < 16) { |
1621 | /* |
1622 | * SIx_{0,1} and SOx_{0,1} |
1623 | * Read accesses read SIx_{0,1} values |
1624 | * Write accesses write SOx_{0,1} values |
1625 | */ |
1626 | *xr_reg = PEB2466_XR0; |
1627 | *mask = (1 << (offset % 8)); |
1628 | return 0; |
1629 | } |
1630 | if (offset < 24) { |
1631 | /* SBx_{0,1} */ |
1632 | *xr_reg = PEB2466_XR1; |
1633 | *mask = (1 << (offset - 16)); |
1634 | return 0; |
1635 | } |
1636 | if (offset < 28) { |
1637 | /* SBx_2 */ |
1638 | *xr_reg = PEB2466_XR3; |
1639 | *mask = (1 << (offset - 24 + 4)); |
1640 | return 0; |
1641 | } |
1642 | return -EINVAL; |
1643 | } |
1644 | |
1645 | static int peb2466_chip_gpio_offset_to_dir_regmask(unsigned int offset, |
1646 | unsigned int *xr_reg, |
1647 | unsigned int *mask) |
1648 | { |
1649 | if (offset < 16) { |
1650 | /* Direction cannot be changed for these GPIOs */ |
1651 | return -EINVAL; |
1652 | } |
1653 | if (offset < 24) { |
1654 | *xr_reg = PEB2466_XR2; |
1655 | *mask = (1 << (offset - 16)); |
1656 | return 0; |
1657 | } |
1658 | if (offset < 28) { |
1659 | *xr_reg = PEB2466_XR3; |
1660 | *mask = (1 << (offset - 24)); |
1661 | return 0; |
1662 | } |
1663 | return -EINVAL; |
1664 | } |
1665 | |
1666 | static unsigned int *peb2466_chip_gpio_get_cache(struct peb2466 *peb2466, |
1667 | unsigned int xr_reg) |
1668 | { |
1669 | unsigned int *cache; |
1670 | |
1671 | switch (xr_reg) { |
1672 | case PEB2466_XR0: |
1673 | cache = &peb2466->gpio.cache.xr0; |
1674 | break; |
1675 | case PEB2466_XR1: |
1676 | cache = &peb2466->gpio.cache.xr1; |
1677 | break; |
1678 | case PEB2466_XR2: |
1679 | cache = &peb2466->gpio.cache.xr2; |
1680 | break; |
1681 | case PEB2466_XR3: |
1682 | cache = &peb2466->gpio.cache.xr3; |
1683 | break; |
1684 | default: |
1685 | cache = NULL; |
1686 | break; |
1687 | } |
1688 | return cache; |
1689 | } |
1690 | |
1691 | static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int xr_reg, |
1692 | unsigned int mask, unsigned int val) |
1693 | { |
1694 | unsigned int tmp; |
1695 | unsigned int *cache; |
1696 | int ret; |
1697 | |
1698 | /* |
1699 | * Read and write accesses use different peb2466 internal signals (input |
1700 | * signals on reads and output signals on writes). regmap_update_bits |
1701 | * cannot be used to read/modify/write the value. |
1702 | * So, a specific cache value is used. |
1703 | */ |
1704 | |
1705 | mutex_lock(&peb2466->gpio.lock); |
1706 | |
1707 | cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); |
1708 | if (!cache) { |
1709 | ret = -EINVAL; |
1710 | goto end; |
1711 | } |
1712 | |
1713 | tmp = *cache; |
1714 | tmp &= ~mask; |
1715 | tmp |= val; |
1716 | |
1717 | ret = regmap_write(map: peb2466->regmap, reg: xr_reg, val: tmp); |
1718 | if (ret) |
1719 | goto end; |
1720 | |
1721 | *cache = tmp; |
1722 | ret = 0; |
1723 | |
1724 | end: |
1725 | mutex_unlock(lock: &peb2466->gpio.lock); |
1726 | return ret; |
1727 | } |
1728 | |
1729 | static void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) |
1730 | { |
1731 | struct peb2466 *peb2466 = gpiochip_get_data(gc: c); |
1732 | unsigned int xr_reg; |
1733 | unsigned int mask; |
1734 | int ret; |
1735 | |
1736 | if (offset < 8) { |
1737 | /* |
1738 | * SIx_{0,1} signals cannot be set and writing the related |
1739 | * register will change the SOx_{0,1} signals |
1740 | */ |
1741 | dev_warn(&peb2466->spi->dev, "cannot set gpio %d (read-only)\n" , |
1742 | offset); |
1743 | return; |
1744 | } |
1745 | |
1746 | ret = peb2466_chip_gpio_offset_to_data_regmask(offset, xr_reg: &xr_reg, mask: &mask); |
1747 | if (ret) { |
1748 | dev_err(&peb2466->spi->dev, "cannot set gpio %d (%d)\n" , |
1749 | offset, ret); |
1750 | return; |
1751 | } |
1752 | |
1753 | ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val: val ? mask : 0); |
1754 | if (ret) { |
1755 | dev_err(&peb2466->spi->dev, "set gpio %d (0x%x, 0x%x) failed (%d)\n" , |
1756 | offset, xr_reg, mask, ret); |
1757 | } |
1758 | } |
1759 | |
1760 | static int peb2466_chip_gpio_get(struct gpio_chip *c, unsigned int offset) |
1761 | { |
1762 | struct peb2466 *peb2466 = gpiochip_get_data(gc: c); |
1763 | bool use_cache = false; |
1764 | unsigned int *cache; |
1765 | unsigned int xr_reg; |
1766 | unsigned int mask; |
1767 | unsigned int val; |
1768 | int ret; |
1769 | |
1770 | if (offset >= 8 && offset < 16) { |
1771 | /* |
1772 | * SOx_{0,1} signals cannot be read. Reading the related |
1773 | * register will read the SIx_{0,1} signals. |
1774 | * Use the cache to get value; |
1775 | */ |
1776 | use_cache = true; |
1777 | } |
1778 | |
1779 | ret = peb2466_chip_gpio_offset_to_data_regmask(offset, xr_reg: &xr_reg, mask: &mask); |
1780 | if (ret) { |
1781 | dev_err(&peb2466->spi->dev, "cannot get gpio %d (%d)\n" , |
1782 | offset, ret); |
1783 | return -EINVAL; |
1784 | } |
1785 | |
1786 | if (use_cache) { |
1787 | cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); |
1788 | if (!cache) |
1789 | return -EINVAL; |
1790 | val = *cache; |
1791 | } else { |
1792 | ret = regmap_read(map: peb2466->regmap, reg: xr_reg, val: &val); |
1793 | if (ret) { |
1794 | dev_err(&peb2466->spi->dev, "get gpio %d (0x%x, 0x%x) failed (%d)\n" , |
1795 | offset, xr_reg, mask, ret); |
1796 | return ret; |
1797 | } |
1798 | } |
1799 | |
1800 | return !!(val & mask); |
1801 | } |
1802 | |
1803 | static int peb2466_chip_get_direction(struct gpio_chip *c, unsigned int offset) |
1804 | { |
1805 | struct peb2466 *peb2466 = gpiochip_get_data(gc: c); |
1806 | unsigned int xr_reg; |
1807 | unsigned int mask; |
1808 | unsigned int val; |
1809 | int ret; |
1810 | |
1811 | if (offset < 8) { |
1812 | /* SIx_{0,1} */ |
1813 | return GPIO_LINE_DIRECTION_IN; |
1814 | } |
1815 | if (offset < 16) { |
1816 | /* SOx_{0,1} */ |
1817 | return GPIO_LINE_DIRECTION_OUT; |
1818 | } |
1819 | |
1820 | ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, xr_reg: &xr_reg, mask: &mask); |
1821 | if (ret) { |
1822 | dev_err(&peb2466->spi->dev, "cannot get gpio %d direction (%d)\n" , |
1823 | offset, ret); |
1824 | return ret; |
1825 | } |
1826 | |
1827 | ret = regmap_read(map: peb2466->regmap, reg: xr_reg, val: &val); |
1828 | if (ret) { |
1829 | dev_err(&peb2466->spi->dev, "get dir gpio %d (0x%x, 0x%x) failed (%d)\n" , |
1830 | offset, xr_reg, mask, ret); |
1831 | return ret; |
1832 | } |
1833 | |
1834 | return val & mask ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; |
1835 | } |
1836 | |
1837 | static int peb2466_chip_direction_input(struct gpio_chip *c, unsigned int offset) |
1838 | { |
1839 | struct peb2466 *peb2466 = gpiochip_get_data(gc: c); |
1840 | unsigned int xr_reg; |
1841 | unsigned int mask; |
1842 | int ret; |
1843 | |
1844 | if (offset < 8) { |
1845 | /* SIx_{0,1} */ |
1846 | return 0; |
1847 | } |
1848 | if (offset < 16) { |
1849 | /* SOx_{0,1} */ |
1850 | return -EINVAL; |
1851 | } |
1852 | |
1853 | ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, xr_reg: &xr_reg, mask: &mask); |
1854 | if (ret) { |
1855 | dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n" , |
1856 | offset, ret); |
1857 | return ret; |
1858 | } |
1859 | |
1860 | ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val: 0); |
1861 | if (ret) { |
1862 | dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n" , |
1863 | offset, xr_reg, mask, ret); |
1864 | return ret; |
1865 | } |
1866 | |
1867 | return 0; |
1868 | } |
1869 | |
1870 | static int peb2466_chip_direction_output(struct gpio_chip *c, unsigned int offset, int val) |
1871 | { |
1872 | struct peb2466 *peb2466 = gpiochip_get_data(gc: c); |
1873 | unsigned int xr_reg; |
1874 | unsigned int mask; |
1875 | int ret; |
1876 | |
1877 | if (offset < 8) { |
1878 | /* SIx_{0,1} */ |
1879 | return -EINVAL; |
1880 | } |
1881 | |
1882 | peb2466_chip_gpio_set(c, offset, val); |
1883 | |
1884 | if (offset < 16) { |
1885 | /* SOx_{0,1} */ |
1886 | return 0; |
1887 | } |
1888 | |
1889 | ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, xr_reg: &xr_reg, mask: &mask); |
1890 | if (ret) { |
1891 | dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n" , |
1892 | offset, ret); |
1893 | return ret; |
1894 | } |
1895 | |
1896 | ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val: mask); |
1897 | if (ret) { |
1898 | dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n" , |
1899 | offset, xr_reg, mask, ret); |
1900 | return ret; |
1901 | } |
1902 | |
1903 | return 0; |
1904 | } |
1905 | |
1906 | static int peb2466_reset_gpio(struct peb2466 *peb2466) |
1907 | { |
1908 | static const struct reg_sequence reg_reset[] = { |
1909 | /* Output pins at 0, input/output pins as input */ |
1910 | { .reg = PEB2466_XR0, .def = 0 }, |
1911 | { .reg = PEB2466_XR1, .def = 0 }, |
1912 | { .reg = PEB2466_XR2, .def = 0 }, |
1913 | { .reg = PEB2466_XR3, .def = 0 }, |
1914 | }; |
1915 | |
1916 | peb2466->gpio.cache.xr0 = 0; |
1917 | peb2466->gpio.cache.xr1 = 0; |
1918 | peb2466->gpio.cache.xr2 = 0; |
1919 | peb2466->gpio.cache.xr3 = 0; |
1920 | |
1921 | return regmap_multi_reg_write(map: peb2466->regmap, regs: reg_reset, ARRAY_SIZE(reg_reset)); |
1922 | } |
1923 | |
1924 | static int peb2466_gpio_init(struct peb2466 *peb2466) |
1925 | { |
1926 | int ret; |
1927 | |
1928 | mutex_init(&peb2466->gpio.lock); |
1929 | |
1930 | ret = peb2466_reset_gpio(peb2466); |
1931 | if (ret) |
1932 | return ret; |
1933 | |
1934 | peb2466->gpio.gpio_chip.owner = THIS_MODULE; |
1935 | peb2466->gpio.gpio_chip.label = dev_name(dev: &peb2466->spi->dev); |
1936 | peb2466->gpio.gpio_chip.parent = &peb2466->spi->dev; |
1937 | peb2466->gpio.gpio_chip.base = -1; |
1938 | peb2466->gpio.gpio_chip.ngpio = 28; |
1939 | peb2466->gpio.gpio_chip.get_direction = peb2466_chip_get_direction; |
1940 | peb2466->gpio.gpio_chip.direction_input = peb2466_chip_direction_input; |
1941 | peb2466->gpio.gpio_chip.direction_output = peb2466_chip_direction_output; |
1942 | peb2466->gpio.gpio_chip.get = peb2466_chip_gpio_get; |
1943 | peb2466->gpio.gpio_chip.set = peb2466_chip_gpio_set; |
1944 | peb2466->gpio.gpio_chip.can_sleep = true; |
1945 | |
1946 | return devm_gpiochip_add_data(&peb2466->spi->dev, &peb2466->gpio.gpio_chip, |
1947 | peb2466); |
1948 | } |
1949 | |
1950 | static int peb2466_spi_probe(struct spi_device *spi) |
1951 | { |
1952 | struct peb2466 *peb2466; |
1953 | unsigned long mclk_rate; |
1954 | int ret; |
1955 | u8 xr5; |
1956 | |
1957 | spi->bits_per_word = 8; |
1958 | ret = spi_setup(spi); |
1959 | if (ret < 0) |
1960 | return ret; |
1961 | |
1962 | peb2466 = devm_kzalloc(dev: &spi->dev, size: sizeof(*peb2466), GFP_KERNEL); |
1963 | if (!peb2466) |
1964 | return -ENOMEM; |
1965 | |
1966 | peb2466->spi = spi; |
1967 | |
1968 | peb2466->regmap = devm_regmap_init(&peb2466->spi->dev, NULL, peb2466, |
1969 | &peb2466_regmap_config); |
1970 | if (IS_ERR(ptr: peb2466->regmap)) |
1971 | return PTR_ERR(ptr: peb2466->regmap); |
1972 | |
1973 | peb2466->reset_gpio = devm_gpiod_get_optional(dev: &peb2466->spi->dev, |
1974 | con_id: "reset" , flags: GPIOD_OUT_LOW); |
1975 | if (IS_ERR(ptr: peb2466->reset_gpio)) |
1976 | return PTR_ERR(ptr: peb2466->reset_gpio); |
1977 | |
1978 | peb2466->mclk = devm_clk_get(dev: &peb2466->spi->dev, id: "mclk" ); |
1979 | if (IS_ERR(ptr: peb2466->mclk)) |
1980 | return PTR_ERR(ptr: peb2466->mclk); |
1981 | ret = clk_prepare_enable(clk: peb2466->mclk); |
1982 | if (ret) |
1983 | return ret; |
1984 | |
1985 | if (peb2466->reset_gpio) { |
1986 | gpiod_set_value_cansleep(desc: peb2466->reset_gpio, value: 1); |
1987 | udelay(4); |
1988 | gpiod_set_value_cansleep(desc: peb2466->reset_gpio, value: 0); |
1989 | udelay(4); |
1990 | } |
1991 | |
1992 | spi_set_drvdata(spi, data: peb2466); |
1993 | |
1994 | mclk_rate = clk_get_rate(clk: peb2466->mclk); |
1995 | switch (mclk_rate) { |
1996 | case 1536000: |
1997 | xr5 = PEB2466_XR5_MCLK_1536; |
1998 | break; |
1999 | case 2048000: |
2000 | xr5 = PEB2466_XR5_MCLK_2048; |
2001 | break; |
2002 | case 4096000: |
2003 | xr5 = PEB2466_XR5_MCLK_4096; |
2004 | break; |
2005 | case 8192000: |
2006 | xr5 = PEB2466_XR5_MCLK_8192; |
2007 | break; |
2008 | default: |
2009 | dev_err(&peb2466->spi->dev, "Unsupported clock rate %lu\n" , |
2010 | mclk_rate); |
2011 | ret = -EINVAL; |
2012 | goto failed; |
2013 | } |
2014 | ret = regmap_write(map: peb2466->regmap, PEB2466_XR5, val: xr5); |
2015 | if (ret) { |
2016 | dev_err(&peb2466->spi->dev, "Setting MCLK failed (%d)\n" , ret); |
2017 | goto failed; |
2018 | } |
2019 | |
2020 | ret = devm_snd_soc_register_component(dev: &spi->dev, component_driver: &peb2466_component_driver, |
2021 | dai_drv: &peb2466_dai_driver, num_dai: 1); |
2022 | if (ret) |
2023 | goto failed; |
2024 | |
2025 | if (IS_ENABLED(CONFIG_GPIOLIB)) { |
2026 | ret = peb2466_gpio_init(peb2466); |
2027 | if (ret) |
2028 | goto failed; |
2029 | } |
2030 | |
2031 | return 0; |
2032 | |
2033 | failed: |
2034 | clk_disable_unprepare(clk: peb2466->mclk); |
2035 | return ret; |
2036 | } |
2037 | |
2038 | static void peb2466_spi_remove(struct spi_device *spi) |
2039 | { |
2040 | struct peb2466 *peb2466 = spi_get_drvdata(spi); |
2041 | |
2042 | clk_disable_unprepare(clk: peb2466->mclk); |
2043 | } |
2044 | |
2045 | static const struct of_device_id peb2466_of_match[] = { |
2046 | { .compatible = "infineon,peb2466" , }, |
2047 | { } |
2048 | }; |
2049 | MODULE_DEVICE_TABLE(of, peb2466_of_match); |
2050 | |
2051 | static const struct spi_device_id peb2466_id_table[] = { |
2052 | { "peb2466" , 0 }, |
2053 | { } |
2054 | }; |
2055 | MODULE_DEVICE_TABLE(spi, peb2466_id_table); |
2056 | |
2057 | static struct spi_driver peb2466_spi_driver = { |
2058 | .driver = { |
2059 | .name = "peb2466" , |
2060 | .of_match_table = peb2466_of_match, |
2061 | }, |
2062 | .id_table = peb2466_id_table, |
2063 | .probe = peb2466_spi_probe, |
2064 | .remove = peb2466_spi_remove, |
2065 | }; |
2066 | |
2067 | module_spi_driver(peb2466_spi_driver); |
2068 | |
2069 | MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>" ); |
2070 | MODULE_DESCRIPTION("PEB2466 ALSA SoC driver" ); |
2071 | MODULE_LICENSE("GPL" ); |
2072 | |