1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // IDT821034 ALSA SoC driver |
4 | // |
5 | // Copyright 2022 CS GROUP France |
6 | // |
7 | // Author: Herve Codina <herve.codina@bootlin.com> |
8 | |
9 | #include <linux/bitrev.h> |
10 | #include <linux/gpio/driver.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/spi/spi.h> |
14 | #include <sound/pcm_params.h> |
15 | #include <sound/soc.h> |
16 | #include <sound/tlv.h> |
17 | |
18 | #define IDT821034_NB_CHANNEL 4 |
19 | |
20 | struct idt821034_amp { |
21 | u16 gain; |
22 | bool is_muted; |
23 | }; |
24 | |
25 | struct idt821034 { |
26 | struct spi_device *spi; |
27 | struct mutex mutex; |
28 | u8 spi_tx_buf; /* Cannot use stack area for SPI (dma-safe memory) */ |
29 | u8 spi_rx_buf; /* Cannot use stack area for SPI (dma-safe memory) */ |
30 | struct { |
31 | u8 codec_conf; |
32 | struct { |
33 | u8 power; |
34 | u8 tx_slot; |
35 | u8 rx_slot; |
36 | u8 slic_conf; |
37 | u8 slic_control; |
38 | } ch[IDT821034_NB_CHANNEL]; |
39 | } cache; |
40 | struct { |
41 | struct { |
42 | struct idt821034_amp amp_out; |
43 | struct idt821034_amp amp_in; |
44 | } ch[IDT821034_NB_CHANNEL]; |
45 | } amps; |
46 | int max_ch_playback; |
47 | int max_ch_capture; |
48 | struct gpio_chip gpio_chip; |
49 | }; |
50 | |
51 | static int idt821034_8bit_write(struct idt821034 *idt821034, u8 val) |
52 | { |
53 | struct spi_transfer xfer[] = { |
54 | { |
55 | .tx_buf = &idt821034->spi_tx_buf, |
56 | .len = 1, |
57 | }, { |
58 | .cs_off = 1, |
59 | .tx_buf = &idt821034->spi_tx_buf, |
60 | .len = 1, |
61 | } |
62 | }; |
63 | |
64 | idt821034->spi_tx_buf = val; |
65 | |
66 | dev_vdbg(&idt821034->spi->dev, "spi xfer wr 0x%x\n" , val); |
67 | |
68 | return spi_sync_transfer(spi: idt821034->spi, xfers: xfer, num_xfers: 2); |
69 | } |
70 | |
71 | static int idt821034_2x8bit_write(struct idt821034 *idt821034, u8 val1, u8 val2) |
72 | { |
73 | int ret; |
74 | |
75 | ret = idt821034_8bit_write(idt821034, val: val1); |
76 | if (ret) |
77 | return ret; |
78 | return idt821034_8bit_write(idt821034, val: val2); |
79 | } |
80 | |
81 | static int idt821034_8bit_read(struct idt821034 *idt821034, u8 valw, u8 *valr) |
82 | { |
83 | struct spi_transfer xfer[] = { |
84 | { |
85 | .tx_buf = &idt821034->spi_tx_buf, |
86 | .rx_buf = &idt821034->spi_rx_buf, |
87 | .len = 1, |
88 | }, { |
89 | .cs_off = 1, |
90 | .tx_buf = &idt821034->spi_tx_buf, |
91 | .len = 1, |
92 | } |
93 | }; |
94 | int ret; |
95 | |
96 | idt821034->spi_tx_buf = valw; |
97 | |
98 | ret = spi_sync_transfer(spi: idt821034->spi, xfers: xfer, num_xfers: 2); |
99 | if (ret) |
100 | return ret; |
101 | |
102 | *valr = idt821034->spi_rx_buf; |
103 | |
104 | dev_vdbg(&idt821034->spi->dev, "spi xfer wr 0x%x, rd 0x%x\n" , |
105 | valw, *valr); |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | /* Available mode for the programming sequence */ |
111 | #define IDT821034_MODE_CODEC(_ch) (0x80 | ((_ch) << 2)) |
112 | #define IDT821034_MODE_SLIC(_ch) (0xD0 | ((_ch) << 2)) |
113 | #define IDT821034_MODE_GAIN(_ch) (0xC0 | ((_ch) << 2)) |
114 | |
115 | /* Power values that can be used in 'power' (can be ORed) */ |
116 | #define IDT821034_CONF_PWRUP_TX BIT(1) /* from analog input to PCM */ |
117 | #define IDT821034_CONF_PWRUP_RX BIT(0) /* from PCM to analog output */ |
118 | |
119 | static int idt821034_set_channel_power(struct idt821034 *idt821034, u8 ch, u8 power) |
120 | { |
121 | u8 conf; |
122 | int ret; |
123 | |
124 | dev_dbg(&idt821034->spi->dev, "set_channel_power(%u, 0x%x)\n" , ch, power); |
125 | |
126 | conf = IDT821034_MODE_CODEC(ch) | idt821034->cache.codec_conf; |
127 | |
128 | if (power & IDT821034_CONF_PWRUP_RX) { |
129 | ret = idt821034_2x8bit_write(idt821034, |
130 | val1: conf | IDT821034_CONF_PWRUP_RX, |
131 | val2: idt821034->cache.ch[ch].rx_slot); |
132 | if (ret) |
133 | return ret; |
134 | } |
135 | if (power & IDT821034_CONF_PWRUP_TX) { |
136 | ret = idt821034_2x8bit_write(idt821034, |
137 | val1: conf | IDT821034_CONF_PWRUP_TX, |
138 | val2: idt821034->cache.ch[ch].tx_slot); |
139 | if (ret) |
140 | return ret; |
141 | } |
142 | if (!(power & (IDT821034_CONF_PWRUP_TX | IDT821034_CONF_PWRUP_RX))) { |
143 | ret = idt821034_2x8bit_write(idt821034, val1: conf, val2: 0); |
144 | if (ret) |
145 | return ret; |
146 | } |
147 | |
148 | idt821034->cache.ch[ch].power = power; |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | static u8 idt821034_get_channel_power(struct idt821034 *idt821034, u8 ch) |
154 | { |
155 | return idt821034->cache.ch[ch].power; |
156 | } |
157 | |
158 | /* Codec configuration values that can be used in 'codec_conf' (can be ORed) */ |
159 | #define IDT821034_CONF_ALAW_MODE BIT(5) |
160 | #define IDT821034_CONF_DELAY_MODE BIT(4) |
161 | |
162 | static int idt821034_set_codec_conf(struct idt821034 *idt821034, u8 codec_conf) |
163 | { |
164 | u8 conf; |
165 | u8 ts; |
166 | int ret; |
167 | |
168 | dev_dbg(&idt821034->spi->dev, "set_codec_conf(0x%x)\n" , codec_conf); |
169 | |
170 | /* codec conf fields are common to all channel. |
171 | * Arbitrary use of channel 0 for this configuration. |
172 | */ |
173 | |
174 | /* Set Configuration Register */ |
175 | conf = IDT821034_MODE_CODEC(0) | codec_conf; |
176 | |
177 | /* Update conf value and timeslot register value according |
178 | * to cache values |
179 | */ |
180 | if (idt821034->cache.ch[0].power & IDT821034_CONF_PWRUP_RX) { |
181 | conf |= IDT821034_CONF_PWRUP_RX; |
182 | ts = idt821034->cache.ch[0].rx_slot; |
183 | } else if (idt821034->cache.ch[0].power & IDT821034_CONF_PWRUP_TX) { |
184 | conf |= IDT821034_CONF_PWRUP_TX; |
185 | ts = idt821034->cache.ch[0].tx_slot; |
186 | } else { |
187 | ts = 0x00; |
188 | } |
189 | |
190 | /* Write configuration register and time-slot register */ |
191 | ret = idt821034_2x8bit_write(idt821034, val1: conf, val2: ts); |
192 | if (ret) |
193 | return ret; |
194 | |
195 | idt821034->cache.codec_conf = codec_conf; |
196 | return 0; |
197 | } |
198 | |
199 | static u8 idt821034_get_codec_conf(struct idt821034 *idt821034) |
200 | { |
201 | return idt821034->cache.codec_conf; |
202 | } |
203 | |
204 | /* Channel direction values that can be used in 'ch_dir' (can be ORed) */ |
205 | #define IDT821034_CH_RX BIT(0) /* from PCM to analog output */ |
206 | #define IDT821034_CH_TX BIT(1) /* from analog input to PCM */ |
207 | |
208 | static int idt821034_set_channel_ts(struct idt821034 *idt821034, u8 ch, u8 ch_dir, u8 ts_num) |
209 | { |
210 | u8 conf; |
211 | int ret; |
212 | |
213 | dev_dbg(&idt821034->spi->dev, "set_channel_ts(%u, 0x%x, %d)\n" , ch, ch_dir, ts_num); |
214 | |
215 | conf = IDT821034_MODE_CODEC(ch) | idt821034->cache.codec_conf; |
216 | |
217 | if (ch_dir & IDT821034_CH_RX) { |
218 | if (idt821034->cache.ch[ch].power & IDT821034_CONF_PWRUP_RX) { |
219 | ret = idt821034_2x8bit_write(idt821034, |
220 | val1: conf | IDT821034_CONF_PWRUP_RX, |
221 | val2: ts_num); |
222 | if (ret) |
223 | return ret; |
224 | } |
225 | idt821034->cache.ch[ch].rx_slot = ts_num; |
226 | } |
227 | if (ch_dir & IDT821034_CH_TX) { |
228 | if (idt821034->cache.ch[ch].power & IDT821034_CONF_PWRUP_TX) { |
229 | ret = idt821034_2x8bit_write(idt821034, |
230 | val1: conf | IDT821034_CONF_PWRUP_TX, |
231 | val2: ts_num); |
232 | if (ret) |
233 | return ret; |
234 | } |
235 | idt821034->cache.ch[ch].tx_slot = ts_num; |
236 | } |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | /* SLIC direction values that can be used in 'slic_dir' (can be ORed) */ |
242 | #define IDT821034_SLIC_IO1_IN BIT(1) |
243 | #define IDT821034_SLIC_IO0_IN BIT(0) |
244 | |
245 | static int idt821034_set_slic_conf(struct idt821034 *idt821034, u8 ch, u8 slic_dir) |
246 | { |
247 | u8 conf; |
248 | int ret; |
249 | |
250 | dev_dbg(&idt821034->spi->dev, "set_slic_conf(%u, 0x%x)\n" , ch, slic_dir); |
251 | |
252 | conf = IDT821034_MODE_SLIC(ch) | slic_dir; |
253 | ret = idt821034_2x8bit_write(idt821034, val1: conf, val2: idt821034->cache.ch[ch].slic_control); |
254 | if (ret) |
255 | return ret; |
256 | |
257 | idt821034->cache.ch[ch].slic_conf = slic_dir; |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static u8 idt821034_get_slic_conf(struct idt821034 *idt821034, u8 ch) |
263 | { |
264 | return idt821034->cache.ch[ch].slic_conf; |
265 | } |
266 | |
267 | static int idt821034_write_slic_raw(struct idt821034 *idt821034, u8 ch, u8 slic_raw) |
268 | { |
269 | u8 conf; |
270 | int ret; |
271 | |
272 | dev_dbg(&idt821034->spi->dev, "write_slic_raw(%u, 0x%x)\n" , ch, slic_raw); |
273 | |
274 | /* |
275 | * On write, slic_raw is mapped as follow : |
276 | * b4: O_4 |
277 | * b3: O_3 |
278 | * b2: O_2 |
279 | * b1: I/O_1 |
280 | * b0: I/O_0 |
281 | */ |
282 | |
283 | conf = IDT821034_MODE_SLIC(ch) | idt821034->cache.ch[ch].slic_conf; |
284 | ret = idt821034_2x8bit_write(idt821034, val1: conf, val2: slic_raw); |
285 | if (ret) |
286 | return ret; |
287 | |
288 | idt821034->cache.ch[ch].slic_control = slic_raw; |
289 | return 0; |
290 | } |
291 | |
292 | static u8 idt821034_get_written_slic_raw(struct idt821034 *idt821034, u8 ch) |
293 | { |
294 | return idt821034->cache.ch[ch].slic_control; |
295 | } |
296 | |
297 | static int idt821034_read_slic_raw(struct idt821034 *idt821034, u8 ch, u8 *slic_raw) |
298 | { |
299 | u8 val; |
300 | int ret; |
301 | |
302 | /* |
303 | * On read, slic_raw is mapped as follow : |
304 | * b7: I/O_0 |
305 | * b6: I/O_1 |
306 | * b5: O_2 |
307 | * b4: O_3 |
308 | * b3: O_4 |
309 | * b2: I/O1_0, I/O_0 from channel 1 (no matter ch value) |
310 | * b1: I/O2_0, I/O_0 from channel 2 (no matter ch value) |
311 | * b2: I/O3_0, I/O_0 from channel 3 (no matter ch value) |
312 | */ |
313 | |
314 | val = IDT821034_MODE_SLIC(ch) | idt821034->cache.ch[ch].slic_conf; |
315 | ret = idt821034_8bit_write(idt821034, val); |
316 | if (ret) |
317 | return ret; |
318 | |
319 | ret = idt821034_8bit_read(idt821034, valw: idt821034->cache.ch[ch].slic_control, valr: slic_raw); |
320 | if (ret) |
321 | return ret; |
322 | |
323 | dev_dbg(&idt821034->spi->dev, "read_slic_raw(%i) 0x%x\n" , ch, *slic_raw); |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | /* Gain type values that can be used in 'gain_type' (cannot be ORed) */ |
329 | #define IDT821034_GAIN_RX (0 << 1) /* from PCM to analog output */ |
330 | #define IDT821034_GAIN_TX (1 << 1) /* from analog input to PCM */ |
331 | |
332 | static int idt821034_set_gain_channel(struct idt821034 *idt821034, u8 ch, |
333 | u8 gain_type, u16 gain_val) |
334 | { |
335 | u8 conf; |
336 | int ret; |
337 | |
338 | dev_dbg(&idt821034->spi->dev, "set_gain_channel(%u, 0x%x, 0x%x-%d)\n" , |
339 | ch, gain_type, gain_val, gain_val); |
340 | |
341 | /* |
342 | * The gain programming coefficients should be calculated as: |
343 | * Transmit : Coeff_X = round [ gain_X0dB × gain_X ] |
344 | * Receive: Coeff_R = round [ gain_R0dB × gain_R ] |
345 | * where: |
346 | * gain_X0dB = 1820; |
347 | * gain_X is the target gain; |
348 | * Coeff_X should be in the range of 0 to 8192. |
349 | * gain_R0dB = 2506; |
350 | * gain_R is the target gain; |
351 | * Coeff_R should be in the range of 0 to 8192. |
352 | * |
353 | * A gain programming coefficient is 14-bit wide and in binary format. |
354 | * The 7 Most Significant Bits of the coefficient is called |
355 | * GA_MSB_Transmit for transmit path, or is called GA_MSB_Receive for |
356 | * receive path; The 7 Least Significant Bits of the coefficient is |
357 | * called GA_LSB_ Transmit for transmit path, or is called |
358 | * GA_LSB_Receive for receive path. |
359 | * |
360 | * An example is given below to clarify the calculation of the |
361 | * coefficient. To program a +3 dB gain in transmit path and a -3.5 dB |
362 | * gain in receive path: |
363 | * |
364 | * Linear Code of +3dB = 10^(3/20)= 1.412537545 |
365 | * Coeff_X = round (1820 × 1.412537545) = 2571 |
366 | * = 0b001010_00001011 |
367 | * GA_MSB_Transmit = 0b0010100 |
368 | * GA_LSB_Transmit = 0b0001011 |
369 | * |
370 | * Linear Code of -3.5dB = 10^(-3.5/20) = 0.668343917 |
371 | * Coeff_R= round (2506 × 0.668343917) = 1675 |
372 | * = 0b0001101_0001011 |
373 | * GA_MSB_Receive = 0b0001101 |
374 | * GA_LSB_Receive = 0b0001011 |
375 | */ |
376 | |
377 | conf = IDT821034_MODE_GAIN(ch) | gain_type; |
378 | |
379 | ret = idt821034_2x8bit_write(idt821034, val1: conf | 0x00, val2: gain_val & 0x007F); |
380 | if (ret) |
381 | return ret; |
382 | |
383 | ret = idt821034_2x8bit_write(idt821034, val1: conf | 0x01, val2: (gain_val >> 7) & 0x7F); |
384 | if (ret) |
385 | return ret; |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | /* Id helpers used in controls and dapm */ |
391 | #define IDT821034_DIR_OUT (1 << 3) |
392 | #define IDT821034_DIR_IN (0 << 3) |
393 | #define IDT821034_ID(_ch, _dir) (((_ch) & 0x03) | (_dir)) |
394 | #define IDT821034_ID_OUT(_ch) IDT821034_ID(_ch, IDT821034_DIR_OUT) |
395 | #define IDT821034_ID_IN(_ch) IDT821034_ID(_ch, IDT821034_DIR_IN) |
396 | |
397 | #define IDT821034_ID_GET_CHAN(_id) ((_id) & 0x03) |
398 | #define IDT821034_ID_GET_DIR(_id) ((_id) & (1 << 3)) |
399 | #define IDT821034_ID_IS_OUT(_id) (IDT821034_ID_GET_DIR(_id) == IDT821034_DIR_OUT) |
400 | |
401 | static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol, |
402 | struct snd_ctl_elem_value *ucontrol) |
403 | { |
404 | struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; |
405 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
406 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
407 | int min = mc->min; |
408 | int max = mc->max; |
409 | unsigned int mask = (1 << fls(x: max)) - 1; |
410 | unsigned int invert = mc->invert; |
411 | int val; |
412 | u8 ch; |
413 | |
414 | ch = IDT821034_ID_GET_CHAN(mc->reg); |
415 | |
416 | mutex_lock(&idt821034->mutex); |
417 | if (IDT821034_ID_IS_OUT(mc->reg)) |
418 | val = idt821034->amps.ch[ch].amp_out.gain; |
419 | else |
420 | val = idt821034->amps.ch[ch].amp_in.gain; |
421 | mutex_unlock(lock: &idt821034->mutex); |
422 | |
423 | ucontrol->value.integer.value[0] = val & mask; |
424 | if (invert) |
425 | ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; |
426 | else |
427 | ucontrol->value.integer.value[0] = ucontrol->value.integer.value[0] - min; |
428 | |
429 | return 0; |
430 | } |
431 | |
432 | static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, |
433 | struct snd_ctl_elem_value *ucontrol) |
434 | { |
435 | struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; |
436 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
437 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
438 | struct idt821034_amp *amp; |
439 | int min = mc->min; |
440 | int max = mc->max; |
441 | unsigned int mask = (1 << fls(x: max)) - 1; |
442 | unsigned int invert = mc->invert; |
443 | unsigned int val; |
444 | int ret; |
445 | u8 gain_type; |
446 | u8 ch; |
447 | |
448 | val = ucontrol->value.integer.value[0]; |
449 | if (val > max - min) |
450 | return -EINVAL; |
451 | |
452 | if (invert) |
453 | val = (max - val) & mask; |
454 | else |
455 | val = (val + min) & mask; |
456 | |
457 | ch = IDT821034_ID_GET_CHAN(mc->reg); |
458 | |
459 | mutex_lock(&idt821034->mutex); |
460 | |
461 | if (IDT821034_ID_IS_OUT(mc->reg)) { |
462 | amp = &idt821034->amps.ch[ch].amp_out; |
463 | gain_type = IDT821034_GAIN_RX; |
464 | } else { |
465 | amp = &idt821034->amps.ch[ch].amp_in; |
466 | gain_type = IDT821034_GAIN_TX; |
467 | } |
468 | |
469 | if (amp->gain == val) { |
470 | ret = 0; |
471 | goto end; |
472 | } |
473 | |
474 | if (!amp->is_muted) { |
475 | ret = idt821034_set_gain_channel(idt821034, ch, gain_type, gain_val: val); |
476 | if (ret) |
477 | goto end; |
478 | } |
479 | |
480 | amp->gain = val; |
481 | ret = 1; /* The value changed */ |
482 | end: |
483 | mutex_unlock(lock: &idt821034->mutex); |
484 | return ret; |
485 | } |
486 | |
487 | static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, |
488 | struct snd_ctl_elem_value *ucontrol) |
489 | { |
490 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
491 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
492 | int id = kcontrol->private_value; |
493 | bool is_muted; |
494 | u8 ch; |
495 | |
496 | ch = IDT821034_ID_GET_CHAN(id); |
497 | |
498 | mutex_lock(&idt821034->mutex); |
499 | is_muted = IDT821034_ID_IS_OUT(id) ? |
500 | idt821034->amps.ch[ch].amp_out.is_muted : |
501 | idt821034->amps.ch[ch].amp_in.is_muted; |
502 | mutex_unlock(lock: &idt821034->mutex); |
503 | |
504 | ucontrol->value.integer.value[0] = !is_muted; |
505 | |
506 | return 0; |
507 | } |
508 | |
509 | static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, |
510 | struct snd_ctl_elem_value *ucontrol) |
511 | { |
512 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
513 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
514 | int id = kcontrol->private_value; |
515 | struct idt821034_amp *amp; |
516 | bool is_mute; |
517 | u8 gain_type; |
518 | int ret; |
519 | u8 ch; |
520 | |
521 | ch = IDT821034_ID_GET_CHAN(id); |
522 | is_mute = !ucontrol->value.integer.value[0]; |
523 | |
524 | mutex_lock(&idt821034->mutex); |
525 | |
526 | if (IDT821034_ID_IS_OUT(id)) { |
527 | amp = &idt821034->amps.ch[ch].amp_out; |
528 | gain_type = IDT821034_GAIN_RX; |
529 | } else { |
530 | amp = &idt821034->amps.ch[ch].amp_in; |
531 | gain_type = IDT821034_GAIN_TX; |
532 | } |
533 | |
534 | if (amp->is_muted == is_mute) { |
535 | ret = 0; |
536 | goto end; |
537 | } |
538 | |
539 | ret = idt821034_set_gain_channel(idt821034, ch, gain_type, |
540 | gain_val: is_mute ? 0 : amp->gain); |
541 | if (ret) |
542 | goto end; |
543 | |
544 | amp->is_muted = is_mute; |
545 | ret = 1; /* The value changed */ |
546 | end: |
547 | mutex_unlock(lock: &idt821034->mutex); |
548 | return ret; |
549 | } |
550 | |
551 | static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -6520, 1306); |
552 | #define IDT821034_GAIN_IN_MIN_RAW 1 /* -65.20 dB -> 10^(-65.2/20.0) * 1820 = 1 */ |
553 | #define IDT821034_GAIN_IN_MAX_RAW 8191 /* 13.06 dB -> 10^(13.06/20.0) * 1820 = 8191 */ |
554 | #define IDT821034_GAIN_IN_INIT_RAW 1820 /* 0dB -> 10^(0/20) * 1820 = 1820 */ |
555 | |
556 | static const DECLARE_TLV_DB_LINEAR(idt821034_gain_out, -6798, 1029); |
557 | #define IDT821034_GAIN_OUT_MIN_RAW 1 /* -67.98 dB -> 10^(-67.98/20.0) * 2506 = 1*/ |
558 | #define IDT821034_GAIN_OUT_MAX_RAW 8191 /* 10.29 dB -> 10^(10.29/20.0) * 2506 = 8191 */ |
559 | #define IDT821034_GAIN_OUT_INIT_RAW 2506 /* 0dB -> 10^(0/20) * 2506 = 2506 */ |
560 | |
561 | static const struct snd_kcontrol_new idt821034_controls[] = { |
562 | /* DAC volume control */ |
563 | SOC_SINGLE_RANGE_EXT_TLV("DAC0 Playback Volume" , IDT821034_ID_OUT(0), 0, |
564 | IDT821034_GAIN_OUT_MIN_RAW, IDT821034_GAIN_OUT_MAX_RAW, |
565 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
566 | idt821034_gain_out), |
567 | SOC_SINGLE_RANGE_EXT_TLV("DAC1 Playback Volume" , IDT821034_ID_OUT(1), 0, |
568 | IDT821034_GAIN_OUT_MIN_RAW, IDT821034_GAIN_OUT_MAX_RAW, |
569 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
570 | idt821034_gain_out), |
571 | SOC_SINGLE_RANGE_EXT_TLV("DAC2 Playback Volume" , IDT821034_ID_OUT(2), 0, |
572 | IDT821034_GAIN_OUT_MIN_RAW, IDT821034_GAIN_OUT_MAX_RAW, |
573 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
574 | idt821034_gain_out), |
575 | SOC_SINGLE_RANGE_EXT_TLV("DAC3 Playback Volume" , IDT821034_ID_OUT(3), 0, |
576 | IDT821034_GAIN_OUT_MIN_RAW, IDT821034_GAIN_OUT_MAX_RAW, |
577 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
578 | idt821034_gain_out), |
579 | |
580 | /* DAC mute control */ |
581 | SOC_SINGLE_BOOL_EXT("DAC0 Playback Switch" , IDT821034_ID_OUT(0), |
582 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
583 | SOC_SINGLE_BOOL_EXT("DAC1 Playback Switch" , IDT821034_ID_OUT(1), |
584 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
585 | SOC_SINGLE_BOOL_EXT("DAC2 Playback Switch" , IDT821034_ID_OUT(2), |
586 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
587 | SOC_SINGLE_BOOL_EXT("DAC3 Playback Switch" , IDT821034_ID_OUT(3), |
588 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
589 | |
590 | /* ADC volume control */ |
591 | SOC_SINGLE_RANGE_EXT_TLV("ADC0 Capture Volume" , IDT821034_ID_IN(0), 0, |
592 | IDT821034_GAIN_IN_MIN_RAW, IDT821034_GAIN_IN_MAX_RAW, |
593 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
594 | idt821034_gain_in), |
595 | SOC_SINGLE_RANGE_EXT_TLV("ADC1 Capture Volume" , IDT821034_ID_IN(1), 0, |
596 | IDT821034_GAIN_IN_MIN_RAW, IDT821034_GAIN_IN_MAX_RAW, |
597 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
598 | idt821034_gain_in), |
599 | SOC_SINGLE_RANGE_EXT_TLV("ADC2 Capture Volume" , IDT821034_ID_IN(2), 0, |
600 | IDT821034_GAIN_IN_MIN_RAW, IDT821034_GAIN_IN_MAX_RAW, |
601 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
602 | idt821034_gain_in), |
603 | SOC_SINGLE_RANGE_EXT_TLV("ADC3 Capture Volume" , IDT821034_ID_IN(3), 0, |
604 | IDT821034_GAIN_IN_MIN_RAW, IDT821034_GAIN_IN_MAX_RAW, |
605 | 0, idt821034_kctrl_gain_get, idt821034_kctrl_gain_put, |
606 | idt821034_gain_in), |
607 | |
608 | /* ADC mute control */ |
609 | SOC_SINGLE_BOOL_EXT("ADC0 Capture Switch" , IDT821034_ID_IN(0), |
610 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
611 | SOC_SINGLE_BOOL_EXT("ADC1 Capture Switch" , IDT821034_ID_IN(1), |
612 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
613 | SOC_SINGLE_BOOL_EXT("ADC2 Capture Switch" , IDT821034_ID_IN(2), |
614 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
615 | SOC_SINGLE_BOOL_EXT("ADC3 Capture Switch" , IDT821034_ID_IN(3), |
616 | idt821034_kctrl_mute_get, idt821034_kctrl_mute_put), |
617 | }; |
618 | |
619 | static int idt821034_power_event(struct snd_soc_dapm_widget *w, |
620 | struct snd_kcontrol *kcontrol, int event) |
621 | { |
622 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
623 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
624 | unsigned int id = w->shift; |
625 | u8 power, mask; |
626 | int ret; |
627 | u8 ch; |
628 | |
629 | ch = IDT821034_ID_GET_CHAN(id); |
630 | mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX; |
631 | |
632 | mutex_lock(&idt821034->mutex); |
633 | |
634 | power = idt821034_get_channel_power(idt821034, ch); |
635 | if (SND_SOC_DAPM_EVENT_ON(event)) |
636 | power |= mask; |
637 | else |
638 | power &= ~mask; |
639 | ret = idt821034_set_channel_power(idt821034, ch, power); |
640 | |
641 | mutex_unlock(lock: &idt821034->mutex); |
642 | |
643 | return ret; |
644 | } |
645 | |
646 | static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = { |
647 | SND_SOC_DAPM_DAC_E("DAC0" , "Playback" , SND_SOC_NOPM, IDT821034_ID_OUT(0), 0, |
648 | idt821034_power_event, |
649 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
650 | SND_SOC_DAPM_DAC_E("DAC1" , "Playback" , SND_SOC_NOPM, IDT821034_ID_OUT(1), 0, |
651 | idt821034_power_event, |
652 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
653 | SND_SOC_DAPM_DAC_E("DAC2" , "Playback" , SND_SOC_NOPM, IDT821034_ID_OUT(2), 0, |
654 | idt821034_power_event, |
655 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
656 | SND_SOC_DAPM_DAC_E("DAC3" , "Playback" , SND_SOC_NOPM, IDT821034_ID_OUT(3), 0, |
657 | idt821034_power_event, |
658 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
659 | |
660 | SND_SOC_DAPM_OUTPUT("OUT0" ), |
661 | SND_SOC_DAPM_OUTPUT("OUT1" ), |
662 | SND_SOC_DAPM_OUTPUT("OUT2" ), |
663 | SND_SOC_DAPM_OUTPUT("OUT3" ), |
664 | |
665 | SND_SOC_DAPM_DAC_E("ADC0" , "Capture" , SND_SOC_NOPM, IDT821034_ID_IN(0), 0, |
666 | idt821034_power_event, |
667 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
668 | SND_SOC_DAPM_DAC_E("ADC1" , "Capture" , SND_SOC_NOPM, IDT821034_ID_IN(1), 0, |
669 | idt821034_power_event, |
670 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
671 | SND_SOC_DAPM_DAC_E("ADC2" , "Capture" , SND_SOC_NOPM, IDT821034_ID_IN(2), 0, |
672 | idt821034_power_event, |
673 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
674 | SND_SOC_DAPM_DAC_E("ADC3" , "Capture" , SND_SOC_NOPM, IDT821034_ID_IN(3), 0, |
675 | idt821034_power_event, |
676 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
677 | |
678 | SND_SOC_DAPM_INPUT("IN0" ), |
679 | SND_SOC_DAPM_INPUT("IN1" ), |
680 | SND_SOC_DAPM_INPUT("IN2" ), |
681 | SND_SOC_DAPM_INPUT("IN3" ), |
682 | }; |
683 | |
684 | static const struct snd_soc_dapm_route idt821034_dapm_routes[] = { |
685 | { "OUT0" , NULL, "DAC0" }, |
686 | { "OUT1" , NULL, "DAC1" }, |
687 | { "OUT2" , NULL, "DAC2" }, |
688 | { "OUT3" , NULL, "DAC3" }, |
689 | |
690 | { "ADC0" , NULL, "IN0" }, |
691 | { "ADC1" , NULL, "IN1" }, |
692 | { "ADC2" , NULL, "IN2" }, |
693 | { "ADC3" , NULL, "IN3" }, |
694 | }; |
695 | |
696 | static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, |
697 | unsigned int tx_mask, unsigned int rx_mask, |
698 | int slots, int width) |
699 | { |
700 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: dai->component); |
701 | unsigned int mask; |
702 | u8 slot; |
703 | int ret; |
704 | u8 ch; |
705 | |
706 | switch (width) { |
707 | case 0: /* Not set -> default 8 */ |
708 | case 8: |
709 | break; |
710 | default: |
711 | dev_err(dai->dev, "tdm slot width %d not supported\n" , width); |
712 | return -EINVAL; |
713 | } |
714 | |
715 | mask = tx_mask; |
716 | slot = 0; |
717 | ch = 0; |
718 | while (mask && ch < IDT821034_NB_CHANNEL) { |
719 | if (mask & 0x1) { |
720 | mutex_lock(&idt821034->mutex); |
721 | ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, ts_num: slot); |
722 | mutex_unlock(lock: &idt821034->mutex); |
723 | if (ret) { |
724 | dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n" , |
725 | ch, ret); |
726 | return ret; |
727 | } |
728 | ch++; |
729 | } |
730 | mask >>= 1; |
731 | slot++; |
732 | } |
733 | if (mask) { |
734 | dev_err(dai->dev, "too much tx slots defined (mask = 0x%x) support max %d\n" , |
735 | tx_mask, IDT821034_NB_CHANNEL); |
736 | return -EINVAL; |
737 | } |
738 | idt821034->max_ch_playback = ch; |
739 | |
740 | mask = rx_mask; |
741 | slot = 0; |
742 | ch = 0; |
743 | while (mask && ch < IDT821034_NB_CHANNEL) { |
744 | if (mask & 0x1) { |
745 | mutex_lock(&idt821034->mutex); |
746 | ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, ts_num: slot); |
747 | mutex_unlock(lock: &idt821034->mutex); |
748 | if (ret) { |
749 | dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n" , |
750 | ch, ret); |
751 | return ret; |
752 | } |
753 | ch++; |
754 | } |
755 | mask >>= 1; |
756 | slot++; |
757 | } |
758 | if (mask) { |
759 | dev_err(dai->dev, "too much rx slots defined (mask = 0x%x) support max %d\n" , |
760 | rx_mask, IDT821034_NB_CHANNEL); |
761 | return -EINVAL; |
762 | } |
763 | idt821034->max_ch_capture = ch; |
764 | |
765 | return 0; |
766 | } |
767 | |
768 | static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
769 | { |
770 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: dai->component); |
771 | u8 conf; |
772 | int ret; |
773 | |
774 | mutex_lock(&idt821034->mutex); |
775 | |
776 | conf = idt821034_get_codec_conf(idt821034); |
777 | |
778 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
779 | case SND_SOC_DAIFMT_DSP_A: |
780 | conf |= IDT821034_CONF_DELAY_MODE; |
781 | break; |
782 | case SND_SOC_DAIFMT_DSP_B: |
783 | conf &= ~IDT821034_CONF_DELAY_MODE; |
784 | break; |
785 | default: |
786 | dev_err(dai->dev, "Unsupported DAI format 0x%x\n" , |
787 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
788 | ret = -EINVAL; |
789 | goto end; |
790 | } |
791 | ret = idt821034_set_codec_conf(idt821034, codec_conf: conf); |
792 | end: |
793 | mutex_unlock(lock: &idt821034->mutex); |
794 | return ret; |
795 | } |
796 | |
797 | static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, |
798 | struct snd_pcm_hw_params *params, |
799 | struct snd_soc_dai *dai) |
800 | { |
801 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: dai->component); |
802 | u8 conf; |
803 | int ret; |
804 | |
805 | mutex_lock(&idt821034->mutex); |
806 | |
807 | conf = idt821034_get_codec_conf(idt821034); |
808 | |
809 | switch (params_format(p: params)) { |
810 | case SNDRV_PCM_FORMAT_A_LAW: |
811 | conf |= IDT821034_CONF_ALAW_MODE; |
812 | break; |
813 | case SNDRV_PCM_FORMAT_MU_LAW: |
814 | conf &= ~IDT821034_CONF_ALAW_MODE; |
815 | break; |
816 | default: |
817 | dev_err(dai->dev, "Unsupported PCM format 0x%x\n" , |
818 | params_format(params)); |
819 | ret = -EINVAL; |
820 | goto end; |
821 | } |
822 | ret = idt821034_set_codec_conf(idt821034, codec_conf: conf); |
823 | end: |
824 | mutex_unlock(lock: &idt821034->mutex); |
825 | return ret; |
826 | } |
827 | |
828 | static const unsigned int idt821034_sample_bits[] = {8}; |
829 | |
830 | static struct snd_pcm_hw_constraint_list idt821034_sample_bits_constr = { |
831 | .list = idt821034_sample_bits, |
832 | .count = ARRAY_SIZE(idt821034_sample_bits), |
833 | }; |
834 | |
835 | static int idt821034_dai_startup(struct snd_pcm_substream *substream, |
836 | struct snd_soc_dai *dai) |
837 | { |
838 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: dai->component); |
839 | unsigned int max_ch = 0; |
840 | int ret; |
841 | |
842 | max_ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
843 | idt821034->max_ch_playback : idt821034->max_ch_capture; |
844 | |
845 | /* |
846 | * Disable stream support (min = 0, max = 0) if no timeslots were |
847 | * configured otherwise, limit the number of channels to those |
848 | * configured. |
849 | */ |
850 | ret = snd_pcm_hw_constraint_minmax(runtime: substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, |
851 | min: max_ch ? 1 : 0, max: max_ch); |
852 | if (ret < 0) |
853 | return ret; |
854 | |
855 | ret = snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, |
856 | l: &idt821034_sample_bits_constr); |
857 | if (ret) |
858 | return ret; |
859 | |
860 | return 0; |
861 | } |
862 | |
863 | static u64 idt821034_dai_formats[] = { |
864 | SND_SOC_POSSIBLE_DAIFMT_DSP_A | |
865 | SND_SOC_POSSIBLE_DAIFMT_DSP_B, |
866 | }; |
867 | |
868 | static const struct snd_soc_dai_ops idt821034_dai_ops = { |
869 | .startup = idt821034_dai_startup, |
870 | .hw_params = idt821034_dai_hw_params, |
871 | .set_tdm_slot = idt821034_dai_set_tdm_slot, |
872 | .set_fmt = idt821034_dai_set_fmt, |
873 | .auto_selectable_formats = idt821034_dai_formats, |
874 | .num_auto_selectable_formats = ARRAY_SIZE(idt821034_dai_formats), |
875 | }; |
876 | |
877 | static struct snd_soc_dai_driver idt821034_dai_driver = { |
878 | .name = "idt821034" , |
879 | .playback = { |
880 | .stream_name = "Playback" , |
881 | .channels_min = 1, |
882 | .channels_max = IDT821034_NB_CHANNEL, |
883 | .rates = SNDRV_PCM_RATE_8000, |
884 | .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, |
885 | }, |
886 | .capture = { |
887 | .stream_name = "Capture" , |
888 | .channels_min = 1, |
889 | .channels_max = IDT821034_NB_CHANNEL, |
890 | .rates = SNDRV_PCM_RATE_8000, |
891 | .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, |
892 | }, |
893 | .ops = &idt821034_dai_ops, |
894 | }; |
895 | |
896 | static int idt821034_reset_audio(struct idt821034 *idt821034) |
897 | { |
898 | int ret; |
899 | u8 i; |
900 | |
901 | mutex_lock(&idt821034->mutex); |
902 | |
903 | ret = idt821034_set_codec_conf(idt821034, codec_conf: 0); |
904 | if (ret) |
905 | goto end; |
906 | |
907 | for (i = 0; i < IDT821034_NB_CHANNEL; i++) { |
908 | idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW; |
909 | idt821034->amps.ch[i].amp_out.is_muted = false; |
910 | ret = idt821034_set_gain_channel(idt821034, ch: i, IDT821034_GAIN_RX, |
911 | gain_val: idt821034->amps.ch[i].amp_out.gain); |
912 | if (ret) |
913 | goto end; |
914 | |
915 | idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW; |
916 | idt821034->amps.ch[i].amp_in.is_muted = false; |
917 | ret = idt821034_set_gain_channel(idt821034, ch: i, IDT821034_GAIN_TX, |
918 | gain_val: idt821034->amps.ch[i].amp_in.gain); |
919 | if (ret) |
920 | goto end; |
921 | |
922 | ret = idt821034_set_channel_power(idt821034, ch: i, power: 0); |
923 | if (ret) |
924 | goto end; |
925 | } |
926 | |
927 | ret = 0; |
928 | end: |
929 | mutex_unlock(lock: &idt821034->mutex); |
930 | return ret; |
931 | } |
932 | |
933 | static int idt821034_component_probe(struct snd_soc_component *component) |
934 | { |
935 | struct idt821034 *idt821034 = snd_soc_component_get_drvdata(c: component); |
936 | int ret; |
937 | |
938 | /* reset idt821034 audio part*/ |
939 | ret = idt821034_reset_audio(idt821034); |
940 | if (ret) |
941 | return ret; |
942 | |
943 | return 0; |
944 | } |
945 | |
946 | static const struct snd_soc_component_driver idt821034_component_driver = { |
947 | .probe = idt821034_component_probe, |
948 | .controls = idt821034_controls, |
949 | .num_controls = ARRAY_SIZE(idt821034_controls), |
950 | .dapm_widgets = idt821034_dapm_widgets, |
951 | .num_dapm_widgets = ARRAY_SIZE(idt821034_dapm_widgets), |
952 | .dapm_routes = idt821034_dapm_routes, |
953 | .num_dapm_routes = ARRAY_SIZE(idt821034_dapm_routes), |
954 | .endianness = 1, |
955 | }; |
956 | |
957 | #define IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(_offset) (((_offset) / 5) % 4) |
958 | #define IDT821034_GPIO_OFFSET_TO_SLIC_MASK(_offset) BIT((_offset) % 5) |
959 | |
960 | static void idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) |
961 | { |
962 | u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset); |
963 | u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset); |
964 | struct idt821034 *idt821034 = gpiochip_get_data(gc: c); |
965 | u8 slic_raw; |
966 | int ret; |
967 | |
968 | mutex_lock(&idt821034->mutex); |
969 | |
970 | slic_raw = idt821034_get_written_slic_raw(idt821034, ch); |
971 | if (val) |
972 | slic_raw |= mask; |
973 | else |
974 | slic_raw &= ~mask; |
975 | ret = idt821034_write_slic_raw(idt821034, ch, slic_raw); |
976 | if (ret) { |
977 | dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n" , |
978 | offset, ch, mask, ret); |
979 | } |
980 | |
981 | mutex_unlock(lock: &idt821034->mutex); |
982 | } |
983 | |
984 | static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset) |
985 | { |
986 | u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset); |
987 | u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset); |
988 | struct idt821034 *idt821034 = gpiochip_get_data(gc: c); |
989 | u8 slic_raw; |
990 | int ret; |
991 | |
992 | mutex_lock(&idt821034->mutex); |
993 | ret = idt821034_read_slic_raw(idt821034, ch, slic_raw: &slic_raw); |
994 | mutex_unlock(lock: &idt821034->mutex); |
995 | if (ret) { |
996 | dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n" , |
997 | offset, ch, mask, ret); |
998 | return ret; |
999 | } |
1000 | |
1001 | /* |
1002 | * SLIC IOs are read in reverse order compared to write. |
1003 | * Reverse the read value here in order to have IO0 at lsb (ie same |
1004 | * order as write) |
1005 | */ |
1006 | return !!(bitrev8(slic_raw) & mask); |
1007 | } |
1008 | |
1009 | static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset) |
1010 | { |
1011 | u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset); |
1012 | u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset); |
1013 | struct idt821034 *idt821034 = gpiochip_get_data(gc: c); |
1014 | u8 slic_dir; |
1015 | |
1016 | mutex_lock(&idt821034->mutex); |
1017 | slic_dir = idt821034_get_slic_conf(idt821034, ch); |
1018 | mutex_unlock(lock: &idt821034->mutex); |
1019 | |
1020 | return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; |
1021 | } |
1022 | |
1023 | static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offset) |
1024 | { |
1025 | u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset); |
1026 | u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset); |
1027 | struct idt821034 *idt821034 = gpiochip_get_data(gc: c); |
1028 | u8 slic_conf; |
1029 | int ret; |
1030 | |
1031 | /* Only IO0 and IO1 can be set as input */ |
1032 | if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN)) |
1033 | return -EPERM; |
1034 | |
1035 | mutex_lock(&idt821034->mutex); |
1036 | |
1037 | slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask; |
1038 | |
1039 | ret = idt821034_set_slic_conf(idt821034, ch, slic_dir: slic_conf); |
1040 | if (ret) { |
1041 | dev_err(&idt821034->spi->dev, "dir in gpio %d (%u, 0x%x) failed (%d)\n" , |
1042 | offset, ch, mask, ret); |
1043 | } |
1044 | |
1045 | mutex_unlock(lock: &idt821034->mutex); |
1046 | return ret; |
1047 | } |
1048 | |
1049 | static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int offset, int val) |
1050 | { |
1051 | u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset); |
1052 | u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset); |
1053 | struct idt821034 *idt821034 = gpiochip_get_data(gc: c); |
1054 | u8 slic_conf; |
1055 | int ret; |
1056 | |
1057 | idt821034_chip_gpio_set(c, offset, val); |
1058 | |
1059 | mutex_lock(&idt821034->mutex); |
1060 | |
1061 | slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask; |
1062 | |
1063 | ret = idt821034_set_slic_conf(idt821034, ch, slic_dir: slic_conf); |
1064 | if (ret) { |
1065 | dev_err(&idt821034->spi->dev, "dir in gpio %d (%u, 0x%x) failed (%d)\n" , |
1066 | offset, ch, mask, ret); |
1067 | } |
1068 | |
1069 | mutex_unlock(lock: &idt821034->mutex); |
1070 | return ret; |
1071 | } |
1072 | |
1073 | static int idt821034_reset_gpio(struct idt821034 *idt821034) |
1074 | { |
1075 | int ret; |
1076 | u8 i; |
1077 | |
1078 | mutex_lock(&idt821034->mutex); |
1079 | |
1080 | /* IO0 and IO1 as input for all channels and output IO set to 0 */ |
1081 | for (i = 0; i < IDT821034_NB_CHANNEL; i++) { |
1082 | ret = idt821034_set_slic_conf(idt821034, ch: i, |
1083 | IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN); |
1084 | if (ret) |
1085 | goto end; |
1086 | |
1087 | ret = idt821034_write_slic_raw(idt821034, ch: i, slic_raw: 0); |
1088 | if (ret) |
1089 | goto end; |
1090 | |
1091 | } |
1092 | ret = 0; |
1093 | end: |
1094 | mutex_unlock(lock: &idt821034->mutex); |
1095 | return ret; |
1096 | } |
1097 | |
1098 | static int idt821034_gpio_init(struct idt821034 *idt821034) |
1099 | { |
1100 | int ret; |
1101 | |
1102 | ret = idt821034_reset_gpio(idt821034); |
1103 | if (ret) |
1104 | return ret; |
1105 | |
1106 | idt821034->gpio_chip.owner = THIS_MODULE; |
1107 | idt821034->gpio_chip.label = dev_name(dev: &idt821034->spi->dev); |
1108 | idt821034->gpio_chip.parent = &idt821034->spi->dev; |
1109 | idt821034->gpio_chip.base = -1; |
1110 | idt821034->gpio_chip.ngpio = 5 * 4; /* 5 GPIOs on 4 channels */ |
1111 | idt821034->gpio_chip.get_direction = idt821034_chip_get_direction; |
1112 | idt821034->gpio_chip.direction_input = idt821034_chip_direction_input; |
1113 | idt821034->gpio_chip.direction_output = idt821034_chip_direction_output; |
1114 | idt821034->gpio_chip.get = idt821034_chip_gpio_get; |
1115 | idt821034->gpio_chip.set = idt821034_chip_gpio_set; |
1116 | idt821034->gpio_chip.can_sleep = true; |
1117 | |
1118 | return devm_gpiochip_add_data(&idt821034->spi->dev, &idt821034->gpio_chip, |
1119 | idt821034); |
1120 | } |
1121 | |
1122 | static int idt821034_spi_probe(struct spi_device *spi) |
1123 | { |
1124 | struct idt821034 *idt821034; |
1125 | int ret; |
1126 | |
1127 | spi->bits_per_word = 8; |
1128 | ret = spi_setup(spi); |
1129 | if (ret < 0) |
1130 | return ret; |
1131 | |
1132 | idt821034 = devm_kzalloc(dev: &spi->dev, size: sizeof(*idt821034), GFP_KERNEL); |
1133 | if (!idt821034) |
1134 | return -ENOMEM; |
1135 | |
1136 | idt821034->spi = spi; |
1137 | |
1138 | mutex_init(&idt821034->mutex); |
1139 | |
1140 | spi_set_drvdata(spi, data: idt821034); |
1141 | |
1142 | ret = devm_snd_soc_register_component(dev: &spi->dev, component_driver: &idt821034_component_driver, |
1143 | dai_drv: &idt821034_dai_driver, num_dai: 1); |
1144 | if (ret) |
1145 | return ret; |
1146 | |
1147 | if (IS_ENABLED(CONFIG_GPIOLIB)) |
1148 | return idt821034_gpio_init(idt821034); |
1149 | |
1150 | return 0; |
1151 | } |
1152 | |
1153 | static const struct of_device_id idt821034_of_match[] = { |
1154 | { .compatible = "renesas,idt821034" , }, |
1155 | { } |
1156 | }; |
1157 | MODULE_DEVICE_TABLE(of, idt821034_of_match); |
1158 | |
1159 | static const struct spi_device_id idt821034_id_table[] = { |
1160 | { "idt821034" , 0 }, |
1161 | { } |
1162 | }; |
1163 | MODULE_DEVICE_TABLE(spi, idt821034_id_table); |
1164 | |
1165 | static struct spi_driver idt821034_spi_driver = { |
1166 | .driver = { |
1167 | .name = "idt821034" , |
1168 | .of_match_table = idt821034_of_match, |
1169 | }, |
1170 | .id_table = idt821034_id_table, |
1171 | .probe = idt821034_spi_probe, |
1172 | }; |
1173 | |
1174 | module_spi_driver(idt821034_spi_driver); |
1175 | |
1176 | MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>" ); |
1177 | MODULE_DESCRIPTION("IDT821034 ALSA SoC driver" ); |
1178 | MODULE_LICENSE("GPL" ); |
1179 | |