1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Copyright (c) 2023 Richtek Technology Corp. |
4 | // |
5 | // Author: ChiYuan Huang <cy_huang@richtek.com> |
6 | // |
7 | |
8 | #include <linux/bitfield.h> |
9 | #include <linux/bits.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/mod_devicetable.h> |
15 | #include <linux/module.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/property.h> |
18 | #include <linux/regmap.h> |
19 | #include <sound/pcm_params.h> |
20 | #include <sound/soc.h> |
21 | #include <sound/tlv.h> |
22 | |
23 | #define RTQ9128_REG_SDI_SEL 0x00 |
24 | #define RTQ9128_REG_SDO_SEL 0x01 |
25 | #define RTQ9128_REG_I2S_OPT 0x02 |
26 | #define RTQ9128_REG_MISC 0x03 |
27 | #define RTQ9128_REG_STATE_CTRL 0x04 |
28 | #define RTQ9128_REG_PLLTRI_GEN1 0x05 |
29 | #define RTQ9128_REG_PLLTRI_GEN2 0x06 |
30 | #define RTQ9128_REG_PWM_SS_OPT 0x07 |
31 | #define RTQ9128_REG_DSP_EN 0x08 |
32 | #define RTQ9128_REG_TDM_TX_CH1 0x21 |
33 | #define RTQ9128_REG_TDM_RX_CH1 0x25 |
34 | #define RTQ9128_REG_MS_VOL 0x30 |
35 | #define RTQ9128_REG_CH1_VOL 0x31 |
36 | #define RTQ9128_REG_CH2_VOL 0x32 |
37 | #define RTQ9128_REG_CH3_VOL 0x33 |
38 | #define RTQ9128_REG_CH4_VOL 0x34 |
39 | #define RTQ9128_REG_PROT_OPT 0x71 |
40 | #define RTQ9128_REG_EFUSE_DATA 0xE0 |
41 | #define RTQ9128_REG_VENDOR_ID 0xF9 |
42 | |
43 | #define RTQ9128_CHSTAT_VAL_MASK GENMASK(1, 0) |
44 | #define RTQ9128_DOLEN_MASK GENMASK(7, 6) |
45 | #define RTQ9128_TDMSRCIN_MASK GENMASK(5, 4) |
46 | #define RTQ9128_AUDBIT_MASK GENMASK(5, 4) |
47 | #define RTQ9128_AUDFMT_MASK GENMASK(3, 0) |
48 | #define RTQ9128_MSMUTE_MASK BIT(0) |
49 | #define RTQ9128_DIE_CHECK_MASK GENMASK(4, 0) |
50 | #define RTQ9128_VENDOR_ID_MASK GENMASK(19, 8) |
51 | |
52 | #define RTQ9128_SOFT_RESET_VAL 0x80 |
53 | #define RTQ9128_VENDOR_ID_VAL 0x470 |
54 | #define RTQ9128_ALLCH_HIZ_VAL 0x55 |
55 | #define RTQ9128_ALLCH_ULQM_VAL 0xFF |
56 | #define RTQ9128_TKA470B_VAL 0 |
57 | #define RTQ9128_RTQ9128DH_VAL 0x0F |
58 | #define RTQ9128_RTQ9128DL_VAL 0x10 |
59 | |
60 | struct rtq9128_data { |
61 | struct gpio_desc *enable; |
62 | unsigned int daifmt; |
63 | int tdm_slots; |
64 | int tdm_slot_width; |
65 | bool tdm_input_data2_select; |
66 | }; |
67 | |
68 | struct rtq9128_init_reg { |
69 | unsigned int reg; |
70 | unsigned int val; |
71 | }; |
72 | |
73 | static int rtq9128_get_reg_size(unsigned int reg) |
74 | { |
75 | switch (reg) { |
76 | case 0x5C ... 0x6F: |
77 | case 0x98 ... 0x9F: |
78 | case 0xC0 ... 0xC3: |
79 | case 0xC8 ... 0xCF: |
80 | case 0xDF ... 0xE5: |
81 | case 0xF9: |
82 | return 4; |
83 | case 0x40 ... 0x4F: |
84 | return 3; |
85 | case 0x30 ... 0x35: |
86 | case 0x8C ... 0x97: |
87 | case 0xC4 ... 0xC7: |
88 | case 0xD7 ... 0xDA: |
89 | return 2; |
90 | default: |
91 | return 1; |
92 | } |
93 | } |
94 | |
95 | static int rtq9128_i2c_write(void *context, const void *data, size_t count) |
96 | { |
97 | struct device *dev = context; |
98 | struct i2c_client *i2c = to_i2c_client(dev); |
99 | u8 reg = *(u8 *)data; |
100 | int rg_size; |
101 | |
102 | if (count != 5) { |
103 | dev_err(dev, "Invalid write for data length (%d)\n" , (int)count); |
104 | return -EINVAL; |
105 | } |
106 | |
107 | rg_size = rtq9128_get_reg_size(reg); |
108 | return i2c_smbus_write_i2c_block_data(client: i2c, command: reg, length: rg_size, values: data + count - rg_size); |
109 | } |
110 | |
111 | static int rtq9128_i2c_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, |
112 | size_t val_size) |
113 | { |
114 | struct device *dev = context; |
115 | struct i2c_client *i2c = to_i2c_client(dev); |
116 | u8 reg = *(u8 *)reg_buf; |
117 | u8 data_tmp[4] = {}; |
118 | int rg_size, ret; |
119 | |
120 | if (reg_size != 1 || val_size != 4) { |
121 | dev_err(dev, "Invalid read for reg_size (%d) or val_size (%d)\n" , (int)reg_size, |
122 | (int)val_size); |
123 | return -EINVAL; |
124 | } |
125 | |
126 | rg_size = rtq9128_get_reg_size(reg); |
127 | ret = i2c_smbus_read_i2c_block_data(client: i2c, command: reg, length: rg_size, values: data_tmp); |
128 | if (ret < 0) |
129 | return ret; |
130 | else if (ret != rg_size) |
131 | return -EIO; |
132 | |
133 | memset(val_buf, 0, val_size - rg_size); |
134 | memcpy(val_buf + val_size - rg_size, data_tmp, rg_size); |
135 | |
136 | return 0; |
137 | } |
138 | |
139 | static const struct regmap_bus rtq9128_regmap_bus = { |
140 | .write = rtq9128_i2c_write, |
141 | .read = rtq9128_i2c_read, |
142 | .max_raw_read = 4, |
143 | .max_raw_write = 4, |
144 | }; |
145 | |
146 | static bool rtq9128_is_readable_reg(struct device *dev, unsigned int reg) |
147 | { |
148 | switch (reg) { |
149 | case 0x00 ... 0x2B: |
150 | case 0x30 ... 0x35: |
151 | case 0x40 ... 0x56: |
152 | case 0x5C ... 0x76: |
153 | case 0x80 ... 0xAD: |
154 | case 0xB0 ... 0xBA: |
155 | case 0xC0 ... 0xE5: |
156 | case 0xF0 ... 0xFB: |
157 | return true; |
158 | default: |
159 | return false; |
160 | } |
161 | } |
162 | |
163 | static bool rtq9128_is_writeable_reg(struct device *dev, unsigned int reg) |
164 | { |
165 | switch (reg) { |
166 | case 0x00 ... 0x1F: |
167 | case 0x21 ... 0x2B: |
168 | case 0x30 ... 0x35: |
169 | case 0x40 ... 0x56: |
170 | case 0x5C ... 0x76: |
171 | case 0x80 ... 0x8B: |
172 | case 0xA0 ... 0xAD: |
173 | case 0xB0 ... 0xBA: |
174 | case 0xC0: |
175 | case 0xD0 ... 0xDE: |
176 | case 0xE0 ... 0xE5: |
177 | case 0xF0 ... 0xF3: |
178 | case 0xF6 ... 0xF8: |
179 | case 0xFA ... 0xFB: |
180 | return true; |
181 | default: |
182 | return false; |
183 | } |
184 | } |
185 | |
186 | static bool rtq9128_is_volatile_reg(struct device *dev, unsigned int reg) |
187 | { |
188 | switch (reg) { |
189 | case 0x0F ... 0x17: |
190 | case 0x20: |
191 | case 0x53: |
192 | case 0x55: |
193 | case 0x5C ... 0x6F: |
194 | case 0x8C ... 0x9F: |
195 | case 0xC0 ... 0xCF: |
196 | case 0xDF: |
197 | case 0xF0 ... 0xF1: |
198 | case 0xF4 ... 0xF5: |
199 | return true; |
200 | default: |
201 | return false; |
202 | } |
203 | } |
204 | |
205 | static const struct regmap_config rtq9128_regmap_config = { |
206 | .name = "rtq9128" , |
207 | .reg_bits = 8, |
208 | .val_bits = 32, |
209 | .val_format_endian = REGMAP_ENDIAN_BIG, |
210 | .cache_type = REGCACHE_MAPLE, |
211 | |
212 | .readable_reg = rtq9128_is_readable_reg, |
213 | .writeable_reg = rtq9128_is_writeable_reg, |
214 | .volatile_reg = rtq9128_is_volatile_reg, |
215 | .num_reg_defaults_raw = RTQ9128_REG_VENDOR_ID + 1, |
216 | }; |
217 | |
218 | static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0); |
219 | |
220 | static const DECLARE_TLV_DB_RANGE(spkgain_tlv, |
221 | 0, 3, TLV_DB_SCALE_ITEM(-600, 600, 0), |
222 | 4, 5, TLV_DB_SCALE_ITEM(1500, 300, 0), |
223 | ); |
224 | |
225 | static const char * const source_select_text[] = { "CH1" , "CH2" , "CH3" , "CH4" }; |
226 | static const char * const pwmfreq_select_text[] = { "8fs" , "10fs" , "40fs" , "44fs" , "48fs" }; |
227 | static const char * const phase_select_text[] = { |
228 | "0 degree" , "45 degree" , "90 degree" , "135 degree" , |
229 | "180 degree" , "225 degree" , "270 degree" , "315 degree" , |
230 | }; |
231 | static const char * const dvdduv_select_text[] = { "1P4V" , "1P5V" , "2P1V" , "2P3V" }; |
232 | |
233 | static const struct soc_enum rtq9128_ch1_si_enum = |
234 | SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 6, ARRAY_SIZE(source_select_text), source_select_text); |
235 | static const struct soc_enum rtq9128_ch2_si_enum = |
236 | SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 4, ARRAY_SIZE(source_select_text), source_select_text); |
237 | static const struct soc_enum rtq9128_ch3_si_enum = |
238 | SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 2, ARRAY_SIZE(source_select_text), source_select_text); |
239 | static const struct soc_enum rtq9128_ch4_si_enum = |
240 | SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 0, ARRAY_SIZE(source_select_text), source_select_text); |
241 | static const struct soc_enum rtq9128_pwm_freq_enum = |
242 | SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN1, 4, ARRAY_SIZE(pwmfreq_select_text), |
243 | pwmfreq_select_text); |
244 | static const struct soc_enum rtq9128_out2_phase_enum = |
245 | SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN1, 0, ARRAY_SIZE(phase_select_text), |
246 | phase_select_text); |
247 | static const struct soc_enum rtq9128_out3_phase_enum = |
248 | SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN2, 4, ARRAY_SIZE(phase_select_text), |
249 | phase_select_text); |
250 | static const struct soc_enum rtq9128_out4_phase_enum = |
251 | SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN2, 0, ARRAY_SIZE(phase_select_text), |
252 | phase_select_text); |
253 | |
254 | /* |
255 | * In general usage, DVDD could be 1P8V, 3P0V or 3P3V. |
256 | * This DVDD undervoltage protection is to prevent from the abnormal power |
257 | * lose case while the amplifier is operating. Due to the different DVDD |
258 | * application, treat this threshold as a user choosable option. |
259 | */ |
260 | static const struct soc_enum rtq9128_dvdduv_select_enum = |
261 | SOC_ENUM_SINGLE(RTQ9128_REG_PROT_OPT, 6, ARRAY_SIZE(dvdduv_select_text), |
262 | dvdduv_select_text); |
263 | |
264 | static const struct snd_kcontrol_new rtq9128_snd_ctrls[] = { |
265 | SOC_SINGLE_TLV("MS Volume" , RTQ9128_REG_MS_VOL, 2, 511, 1, dig_tlv), |
266 | SOC_SINGLE_TLV("CH1 Volume" , RTQ9128_REG_CH1_VOL, 2, 511, 1, dig_tlv), |
267 | SOC_SINGLE_TLV("CH2 Volume" , RTQ9128_REG_CH2_VOL, 2, 511, 1, dig_tlv), |
268 | SOC_SINGLE_TLV("CH3 Volume" , RTQ9128_REG_CH3_VOL, 2, 511, 1, dig_tlv), |
269 | SOC_SINGLE_TLV("CH4 Volume" , RTQ9128_REG_CH4_VOL, 2, 511, 1, dig_tlv), |
270 | SOC_SINGLE_TLV("SPK Gain Volume" , RTQ9128_REG_MISC, 0, 5, 0, spkgain_tlv), |
271 | SOC_SINGLE("PBTL12 Switch" , RTQ9128_REG_MISC, 5, 1, 0), |
272 | SOC_SINGLE("PBTL34 Switch" , RTQ9128_REG_MISC, 4, 1, 0), |
273 | SOC_SINGLE("Spread Spectrum Switch" , RTQ9128_REG_PWM_SS_OPT, 7, 1, 0), |
274 | SOC_SINGLE("SDO Select" , RTQ9128_REG_SDO_SEL, 0, 15, 0), |
275 | SOC_ENUM("CH1 SI Select" , rtq9128_ch1_si_enum), |
276 | SOC_ENUM("CH2 SI Select" , rtq9128_ch2_si_enum), |
277 | SOC_ENUM("CH3 SI Select" , rtq9128_ch3_si_enum), |
278 | SOC_ENUM("CH4 SI Select" , rtq9128_ch4_si_enum), |
279 | SOC_ENUM("PWM FREQ Select" , rtq9128_pwm_freq_enum), |
280 | SOC_ENUM("OUT2 Phase Select" , rtq9128_out2_phase_enum), |
281 | SOC_ENUM("OUT3 Phase Select" , rtq9128_out3_phase_enum), |
282 | SOC_ENUM("OUT4 Phase Select" , rtq9128_out4_phase_enum), |
283 | SOC_ENUM("DVDD UV Threshold Select" , rtq9128_dvdduv_select_enum), |
284 | }; |
285 | |
286 | static int rtq9128_dac_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, |
287 | int event) |
288 | { |
289 | struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm: w->dapm); |
290 | unsigned int shift, mask; |
291 | int ret; |
292 | |
293 | dev_dbg(comp->dev, "%s: %s event %d\n" , __func__, w->name, event); |
294 | |
295 | if (snd_soc_dapm_widget_name_cmp(widget: w, s: "DAC1" ) == 0) |
296 | shift = 6; |
297 | else if (snd_soc_dapm_widget_name_cmp(widget: w, s: "DAC2" ) == 0) |
298 | shift = 4; |
299 | else if (snd_soc_dapm_widget_name_cmp(widget: w, s: "DAC3" ) == 0) |
300 | shift = 2; |
301 | else |
302 | shift = 0; |
303 | |
304 | mask = RTQ9128_CHSTAT_VAL_MASK << shift; |
305 | |
306 | /* Turn channel state to Normal or HiZ */ |
307 | ret = snd_soc_component_write_field(component: comp, RTQ9128_REG_STATE_CTRL, mask, |
308 | val: event != SND_SOC_DAPM_POST_PMU); |
309 | if (ret < 0) |
310 | return ret; |
311 | |
312 | /* |
313 | * For each channel turns on, HW will trigger DC load detect and DC |
314 | * offset calibration, the time is needed for all the actions done. |
315 | */ |
316 | if (event == SND_SOC_DAPM_POST_PMU) |
317 | msleep(msecs: 25); |
318 | |
319 | return 0; |
320 | } |
321 | |
322 | static const struct snd_soc_dapm_widget rtq9128_dapm_widgets[] = { |
323 | SND_SOC_DAPM_DAC_E("DAC1" , NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, |
324 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
325 | SND_SOC_DAPM_DAC_E("DAC2" , NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, |
326 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
327 | SND_SOC_DAPM_DAC_E("DAC3" , NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, |
328 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
329 | SND_SOC_DAPM_DAC_E("DAC4" , NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event, |
330 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
331 | SND_SOC_DAPM_OUTPUT("OUT1" ), |
332 | SND_SOC_DAPM_OUTPUT("OUT2" ), |
333 | SND_SOC_DAPM_OUTPUT("OUT3" ), |
334 | SND_SOC_DAPM_OUTPUT("OUT4" ), |
335 | }; |
336 | |
337 | static const struct snd_soc_dapm_route rtq9128_dapm_routes[] = { |
338 | { "DAC1" , NULL, "Playback" }, |
339 | { "DAC2" , NULL, "Playback" }, |
340 | { "DAC3" , NULL, "Playback" }, |
341 | { "DAC4" , NULL, "Playback" }, |
342 | { "OUT1" , NULL, "DAC1" }, |
343 | { "OUT2" , NULL, "DAC2" }, |
344 | { "OUT3" , NULL, "DAC3" }, |
345 | { "OUT4" , NULL, "DAC4" }, |
346 | { "Capture" , NULL, "DAC1" }, |
347 | { "Capture" , NULL, "DAC2" }, |
348 | { "Capture" , NULL, "DAC3" }, |
349 | { "Capture" , NULL, "DAC4" }, |
350 | }; |
351 | |
352 | static const struct rtq9128_init_reg rtq9128_tka470b_tables[] = { |
353 | { 0xA0, 0xEF }, |
354 | { 0x0D, 0x00 }, |
355 | { 0x03, 0x05 }, |
356 | { 0x05, 0x31 }, |
357 | { 0x06, 0x23 }, |
358 | { 0x70, 0x11 }, |
359 | { 0x75, 0x1F }, |
360 | { 0xB6, 0x03 }, |
361 | { 0xB9, 0x03 }, |
362 | { 0xB8, 0x03 }, |
363 | { 0xC1, 0xFF }, |
364 | { 0xF8, 0x72 }, |
365 | { 0x30, 0x180 }, |
366 | }; |
367 | |
368 | static const struct rtq9128_init_reg rtq9128_dh_tables[] = { |
369 | { 0x0F, 0x00 }, |
370 | { 0x03, 0x0D }, |
371 | { 0xB2, 0xFF }, |
372 | { 0xB3, 0xFF }, |
373 | { 0x30, 0x180 }, |
374 | { 0x8A, 0x55 }, |
375 | { 0x72, 0x00 }, |
376 | { 0xB1, 0xE3 }, |
377 | }; |
378 | |
379 | static const struct rtq9128_init_reg rtq9128_dl_tables[] = { |
380 | { 0x0F, 0x00 }, |
381 | { 0x03, 0x0D }, |
382 | { 0x30, 0x180 }, |
383 | { 0x8A, 0x55 }, |
384 | { 0x72, 0x00 }, |
385 | { 0xB1, 0xE3 }, |
386 | }; |
387 | |
388 | static int rtq9128_component_probe(struct snd_soc_component *comp) |
389 | { |
390 | const struct rtq9128_init_reg *table, *curr; |
391 | size_t table_size; |
392 | unsigned int val; |
393 | int i, ret; |
394 | |
395 | ret = pm_runtime_resume_and_get(dev: comp->dev); |
396 | if (ret < 0) { |
397 | dev_err(comp->dev, "Failed to resume device (%d)\n" , ret); |
398 | return ret; |
399 | } |
400 | |
401 | val = snd_soc_component_read(component: comp, RTQ9128_REG_EFUSE_DATA); |
402 | |
403 | switch (FIELD_GET(RTQ9128_DIE_CHECK_MASK, val)) { |
404 | case RTQ9128_TKA470B_VAL: |
405 | table = rtq9128_tka470b_tables; |
406 | table_size = ARRAY_SIZE(rtq9128_tka470b_tables); |
407 | break; |
408 | case RTQ9128_RTQ9128DH_VAL: |
409 | table = rtq9128_dh_tables; |
410 | table_size = ARRAY_SIZE(rtq9128_dh_tables); |
411 | break; |
412 | default: |
413 | table = rtq9128_dl_tables; |
414 | table_size = ARRAY_SIZE(rtq9128_dl_tables); |
415 | break; |
416 | } |
417 | |
418 | for (i = 0, curr = table; i < table_size; i++, curr++) { |
419 | ret = snd_soc_component_write(component: comp, reg: curr->reg, val: curr->val); |
420 | if (ret < 0) |
421 | return ret; |
422 | } |
423 | |
424 | pm_runtime_mark_last_busy(dev: comp->dev); |
425 | pm_runtime_put(dev: comp->dev); |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static const struct snd_soc_component_driver rtq9128_comp_driver = { |
431 | .probe = rtq9128_component_probe, |
432 | .controls = rtq9128_snd_ctrls, |
433 | .num_controls = ARRAY_SIZE(rtq9128_snd_ctrls), |
434 | .dapm_widgets = rtq9128_dapm_widgets, |
435 | .num_dapm_widgets = ARRAY_SIZE(rtq9128_dapm_widgets), |
436 | .dapm_routes = rtq9128_dapm_routes, |
437 | .num_dapm_routes = ARRAY_SIZE(rtq9128_dapm_routes), |
438 | .use_pmdown_time = 1, |
439 | .endianness = 1, |
440 | }; |
441 | |
442 | static int rtq9128_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
443 | { |
444 | struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); |
445 | struct device *dev = dai->dev; |
446 | |
447 | dev_dbg(dev, "%s: fmt 0x%8x\n" , __func__, fmt); |
448 | |
449 | /* Only support bitclock & framesync as consumer */ |
450 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) { |
451 | dev_err(dev, "Only support BCK and LRCK as consumer\n" ); |
452 | return -EINVAL; |
453 | } |
454 | |
455 | /* Store here and will be used in runtime hw_params for DAI format setting */ |
456 | data->daifmt = fmt; |
457 | |
458 | return 0; |
459 | } |
460 | |
461 | static int rtq9128_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
462 | unsigned int rx_mask, int slots, int slot_width) |
463 | { |
464 | struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); |
465 | struct snd_soc_component *comp = dai->component; |
466 | struct device *dev = dai->dev; |
467 | unsigned int mask, start_loc, srcin_select; |
468 | int i, frame_length, ret; |
469 | |
470 | dev_dbg(dev, "%s: slot %d slot_width %d, tx/rx mask 0x%x 0x%x\n" , __func__, slots, |
471 | slot_width, tx_mask, rx_mask); |
472 | |
473 | if (slots <= 0 || slot_width <= 0 || slot_width % 8) { |
474 | dev_err(dev, "Invalid slot numbers (%d) or width (%d)\n" , slots, slot_width); |
475 | return -EINVAL; |
476 | } |
477 | |
478 | /* HW supported maximum frame length 512 */ |
479 | frame_length = slots * slot_width; |
480 | if (frame_length > 512) { |
481 | dev_err(dev, "frame length exceed the maximum (%d)\n" , frame_length); |
482 | return -EINVAL; |
483 | } |
484 | |
485 | if (!rx_mask || hweight_long(w: tx_mask) > slots || hweight_long(w: rx_mask) > slots || |
486 | fls(x: tx_mask) > slots || fls(x: rx_mask) > slots) { |
487 | dev_err(dev, "Invalid tx/rx mask (0x%x/0x%x)\n" , tx_mask, rx_mask); |
488 | return -EINVAL; |
489 | } |
490 | |
491 | for (mask = tx_mask, i = 0; i < 4 && mask; i++) { |
492 | start_loc = (ffs(mask) - 1) * slot_width / 8; |
493 | mask &= ~BIT(ffs(mask) - 1); |
494 | |
495 | ret = snd_soc_component_write(component: comp, RTQ9128_REG_TDM_TX_CH1 + i, val: start_loc); |
496 | if (ret < 0) { |
497 | dev_err(dev, "Failed to assign tx_loc %d (%d)\n" , i, ret); |
498 | return ret; |
499 | } |
500 | } |
501 | |
502 | for (mask = rx_mask, i = 0; i < 4 && mask; i++) { |
503 | start_loc = (ffs(mask) - 1) * slot_width / 8; |
504 | mask &= ~BIT(ffs(mask) - 1); |
505 | |
506 | ret = snd_soc_component_write(component: comp, RTQ9128_REG_TDM_RX_CH1 + i, val: start_loc); |
507 | if (ret < 0) { |
508 | dev_err(dev, "Failed to assign rx_loc %d (%d)\n" , i, ret); |
509 | return ret; |
510 | } |
511 | } |
512 | |
513 | srcin_select = data->tdm_input_data2_select ? RTQ9128_TDMSRCIN_MASK : 0; |
514 | ret = snd_soc_component_update_bits(component: comp, RTQ9128_REG_SDO_SEL, RTQ9128_TDMSRCIN_MASK, |
515 | val: srcin_select); |
516 | if (ret < 0) { |
517 | dev_err(dev, "Failed to configure TDM source input select\n" ); |
518 | return ret; |
519 | } |
520 | |
521 | data->tdm_slots = slots; |
522 | data->tdm_slot_width = slot_width; |
523 | |
524 | return 0; |
525 | } |
526 | |
527 | static int rtq9128_dai_hw_params(struct snd_pcm_substream *stream, struct snd_pcm_hw_params *param, |
528 | struct snd_soc_dai *dai) |
529 | { |
530 | struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); |
531 | unsigned int width, slot_width, bitrate, audbit, dolen; |
532 | struct snd_soc_component *comp = dai->component; |
533 | struct device *dev = dai->dev; |
534 | unsigned int fmtval, audfmt; |
535 | int ret; |
536 | |
537 | dev_dbg(dev, "%s: width %d\n" , __func__, params_width(param)); |
538 | |
539 | fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, data->daifmt); |
540 | if (data->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) { |
541 | dev_err(dev, "TDM is used, format only support DSP_A or DSP_B\n" ); |
542 | return -EINVAL; |
543 | } |
544 | |
545 | switch (fmtval) { |
546 | case SND_SOC_DAIFMT_I2S: |
547 | audfmt = 8; |
548 | break; |
549 | case SND_SOC_DAIFMT_LEFT_J: |
550 | audfmt = 9; |
551 | break; |
552 | case SND_SOC_DAIFMT_RIGHT_J: |
553 | audfmt = 10; |
554 | break; |
555 | case SND_SOC_DAIFMT_DSP_A: |
556 | audfmt = data->tdm_slots ? 12 : 11; |
557 | break; |
558 | case SND_SOC_DAIFMT_DSP_B: |
559 | audfmt = data->tdm_slots ? 4 : 3; |
560 | break; |
561 | default: |
562 | dev_err(dev, "Unsupported format 0x%8x\n" , fmtval); |
563 | return -EINVAL; |
564 | } |
565 | |
566 | switch (width = params_width(p: param)) { |
567 | case 16: |
568 | audbit = 0; |
569 | break; |
570 | case 18: |
571 | audbit = 1; |
572 | break; |
573 | case 20: |
574 | audbit = 2; |
575 | break; |
576 | case 24: |
577 | case 32: |
578 | audbit = 3; |
579 | break; |
580 | default: |
581 | dev_err(dev, "Unsupported width (%d)\n" , width); |
582 | return -EINVAL; |
583 | } |
584 | |
585 | slot_width = params_physical_width(p: param); |
586 | |
587 | if (data->tdm_slots) { |
588 | if (slot_width > data->tdm_slot_width) { |
589 | dev_err(dev, "slot width is larger than TDM slot width\n" ); |
590 | return -EINVAL; |
591 | } |
592 | |
593 | /* Check BCK not exceed the maximum supported rate 24.576MHz */ |
594 | bitrate = data->tdm_slots * data->tdm_slot_width * params_rate(p: param); |
595 | if (bitrate > 24576000) { |
596 | dev_err(dev, "bitrate exceed the maximum (%d)\n" , bitrate); |
597 | return -EINVAL; |
598 | } |
599 | |
600 | /* If TDM is used, configure slot width as TDM slot witdh */ |
601 | slot_width = data->tdm_slot_width; |
602 | } |
603 | |
604 | switch (slot_width) { |
605 | case 16: |
606 | dolen = 0; |
607 | break; |
608 | case 24: |
609 | dolen = 1; |
610 | break; |
611 | case 32: |
612 | dolen = 2; |
613 | break; |
614 | default: |
615 | dev_err(dev, "Unsupported slot width (%d)\n" , slot_width); |
616 | return -EINVAL; |
617 | } |
618 | |
619 | ret = snd_soc_component_write_field(component: comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDFMT_MASK, val: audfmt); |
620 | if (ret < 0) |
621 | return ret; |
622 | |
623 | ret = snd_soc_component_write_field(component: comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDBIT_MASK, val: audbit); |
624 | if (ret < 0) |
625 | return ret; |
626 | |
627 | ret = snd_soc_component_write_field(component: comp, RTQ9128_REG_SDO_SEL, RTQ9128_DOLEN_MASK, val: dolen); |
628 | return ret < 0 ? ret : 0; |
629 | } |
630 | |
631 | static int rtq9128_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream) |
632 | { |
633 | struct snd_soc_component *comp = dai->component; |
634 | struct device *dev = dai->dev; |
635 | int ret; |
636 | |
637 | dev_dbg(dev, "%s: mute (%d), stream (%d)\n" , __func__, mute, stream); |
638 | |
639 | ret = snd_soc_component_write_field(component: comp, RTQ9128_REG_DSP_EN, RTQ9128_MSMUTE_MASK, |
640 | val: mute ? 1 : 0); |
641 | return ret < 0 ? ret : 0; |
642 | } |
643 | |
644 | static const struct snd_soc_dai_ops rtq9128_dai_ops = { |
645 | .set_fmt = rtq9128_dai_set_fmt, |
646 | .set_tdm_slot = rtq9128_dai_set_tdm_slot, |
647 | .hw_params = rtq9128_dai_hw_params, |
648 | .mute_stream = rtq9128_dai_mute_stream, |
649 | .no_capture_mute = 1, |
650 | }; |
651 | |
652 | #define RTQ9128_FMTS_MASK (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ |
653 | SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |\ |
654 | SNDRV_PCM_FMTBIT_S32_LE) |
655 | |
656 | static struct snd_soc_dai_driver rtq9128_dai = { |
657 | .name = "rtq9128-aif" , |
658 | .playback = { |
659 | .stream_name = "Playback" , |
660 | .rates = SNDRV_PCM_RATE_8000_192000, |
661 | .formats = RTQ9128_FMTS_MASK, |
662 | .channels_min = 1, |
663 | .channels_max = 4, |
664 | }, |
665 | .capture = { |
666 | .stream_name = "Capture" , |
667 | .rates = SNDRV_PCM_RATE_8000_192000, |
668 | .formats = RTQ9128_FMTS_MASK, |
669 | .channels_min = 1, |
670 | .channels_max = 4, |
671 | }, |
672 | .ops = &rtq9128_dai_ops, |
673 | .symmetric_rate = 1, |
674 | .symmetric_sample_bits = 1, |
675 | }; |
676 | |
677 | static int rtq9128_probe(struct i2c_client *i2c) |
678 | { |
679 | struct device *dev = &i2c->dev; |
680 | struct rtq9128_data *data; |
681 | struct regmap *regmap; |
682 | unsigned int venid; |
683 | int ret; |
684 | |
685 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
686 | if (!data) |
687 | return -ENOMEM; |
688 | |
689 | data->enable = devm_gpiod_get_optional(dev, con_id: "enable" , flags: GPIOD_OUT_HIGH); |
690 | if (IS_ERR(ptr: data->enable)) |
691 | return dev_err_probe(dev, err: PTR_ERR(ptr: data->enable), fmt: "Failed to get 'enable' gpio\n" ); |
692 | else if (data->enable) |
693 | usleep_range(min: 10000, max: 11000); |
694 | |
695 | data->tdm_input_data2_select = device_property_read_bool(dev, |
696 | propname: "richtek,tdm-input-data2-select" ); |
697 | |
698 | i2c_set_clientdata(client: i2c, data); |
699 | |
700 | /* |
701 | * Due to the bad design to combine SOFT_RESET bit with other function, |
702 | * directly use generic i2c API to trigger SOFT_RESET. |
703 | */ |
704 | ret = i2c_smbus_write_byte_data(client: i2c, RTQ9128_REG_MISC, RTQ9128_SOFT_RESET_VAL); |
705 | if (ret) |
706 | return dev_err_probe(dev, err: ret, fmt: "Failed to trigger software reset\n" ); |
707 | |
708 | /* After trigger soft reset, have to wait 10ms for digital reset done */ |
709 | usleep_range(min: 10000, max: 11000); |
710 | |
711 | regmap = devm_regmap_init(dev, &rtq9128_regmap_bus, dev, &rtq9128_regmap_config); |
712 | if (IS_ERR(ptr: regmap)) |
713 | return dev_err_probe(dev, err: PTR_ERR(ptr: regmap), fmt: "Failed to init regmap\n" ); |
714 | |
715 | ret = regmap_read(map: regmap, RTQ9128_REG_VENDOR_ID, val: &venid); |
716 | if (ret) |
717 | return dev_err_probe(dev, err: ret, fmt: "Failed to get vendor id\n" ); |
718 | |
719 | venid = FIELD_GET(RTQ9128_VENDOR_ID_MASK, venid); |
720 | if (venid != RTQ9128_VENDOR_ID_VAL) |
721 | return dev_err_probe(dev, err: -ENODEV, fmt: "Vendor ID not match (0x%x)\n" , venid); |
722 | |
723 | pm_runtime_set_active(dev); |
724 | pm_runtime_mark_last_busy(dev); |
725 | ret = devm_pm_runtime_enable(dev); |
726 | if (ret) |
727 | return dev_err_probe(dev, err: ret, fmt: "Failed to enable pm runtime\n" ); |
728 | |
729 | return devm_snd_soc_register_component(dev, component_driver: &rtq9128_comp_driver, dai_drv: &rtq9128_dai, num_dai: 1); |
730 | } |
731 | |
732 | static int __maybe_unused rtq9128_pm_runtime_suspend(struct device *dev) |
733 | { |
734 | struct rtq9128_data *data = dev_get_drvdata(dev); |
735 | struct regmap *regmap = dev_get_regmap(dev, NULL); |
736 | |
737 | /* If 'enable' gpio not specified, change all channels to ultra low quiescent */ |
738 | if (!data->enable) |
739 | return regmap_write(map: regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_ULQM_VAL); |
740 | |
741 | gpiod_set_value_cansleep(desc: data->enable, value: 0); |
742 | |
743 | regcache_cache_only(map: regmap, enable: true); |
744 | regcache_mark_dirty(map: regmap); |
745 | |
746 | return 0; |
747 | } |
748 | |
749 | static int __maybe_unused rtq9128_pm_runtime_resume(struct device *dev) |
750 | { |
751 | struct rtq9128_data *data = dev_get_drvdata(dev); |
752 | struct regmap *regmap = dev_get_regmap(dev, NULL); |
753 | |
754 | /* If 'enable' gpio not specified, change all channels to default Hi-Z */ |
755 | if (!data->enable) |
756 | return regmap_write(map: regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_HIZ_VAL); |
757 | |
758 | gpiod_set_value_cansleep(desc: data->enable, value: 1); |
759 | |
760 | /* Wait digital block to be ready */ |
761 | usleep_range(min: 10000, max: 11000); |
762 | |
763 | regcache_cache_only(map: regmap, enable: false); |
764 | return regcache_sync(map: regmap); |
765 | } |
766 | |
767 | static const struct dev_pm_ops __maybe_unused rtq9128_pm_ops = { |
768 | SET_RUNTIME_PM_OPS(rtq9128_pm_runtime_suspend, rtq9128_pm_runtime_resume, NULL) |
769 | }; |
770 | |
771 | static const struct of_device_id rtq9128_device_table[] = { |
772 | { .compatible = "richtek,rtq9128" }, |
773 | {} |
774 | }; |
775 | MODULE_DEVICE_TABLE(of, rtq9128_device_table); |
776 | |
777 | static struct i2c_driver rtq9128_driver = { |
778 | .driver = { |
779 | .name = "rtq9128" , |
780 | .of_match_table = rtq9128_device_table, |
781 | .pm = pm_ptr(&rtq9128_pm_ops), |
782 | }, |
783 | .probe = rtq9128_probe, |
784 | }; |
785 | module_i2c_driver(rtq9128_driver); |
786 | |
787 | MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>" ); |
788 | MODULE_DESCRIPTION("RTQ9128 4CH Audio Amplifier Driver" ); |
789 | MODULE_LICENSE("GPL" ); |
790 | |