1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // rt1308-sdw.c -- rt1308 ALSA SoC audio driver |
4 | // |
5 | // Copyright(c) 2019 Realtek Semiconductor Corp. |
6 | // |
7 | // |
8 | #include <linux/delay.h> |
9 | #include <linux/device.h> |
10 | #include <linux/pm_runtime.h> |
11 | #include <linux/mod_devicetable.h> |
12 | #include <linux/soundwire/sdw.h> |
13 | #include <linux/soundwire/sdw_type.h> |
14 | #include <linux/soundwire/sdw_registers.h> |
15 | #include <linux/module.h> |
16 | #include <linux/regmap.h> |
17 | #include <sound/core.h> |
18 | #include <sound/pcm.h> |
19 | #include <sound/pcm_params.h> |
20 | #include <sound/sdw.h> |
21 | #include <sound/soc.h> |
22 | #include <sound/soc-dapm.h> |
23 | #include <sound/initval.h> |
24 | |
25 | #include "rt1308.h" |
26 | #include "rt1308-sdw.h" |
27 | |
28 | static bool rt1308_readable_register(struct device *dev, unsigned int reg) |
29 | { |
30 | switch (reg) { |
31 | case 0x00e0: |
32 | case 0x00f0: |
33 | case 0x2f01 ... 0x2f07: |
34 | case 0x3000 ... 0x3001: |
35 | case 0x3004 ... 0x3005: |
36 | case 0x3008: |
37 | case 0x300a: |
38 | case 0xc000 ... 0xcff3: |
39 | return true; |
40 | default: |
41 | return false; |
42 | } |
43 | } |
44 | |
45 | static bool rt1308_volatile_register(struct device *dev, unsigned int reg) |
46 | { |
47 | switch (reg) { |
48 | case 0x2f01 ... 0x2f07: |
49 | case 0x3000 ... 0x3001: |
50 | case 0x3004 ... 0x3005: |
51 | case 0x3008: |
52 | case 0x300a: |
53 | case 0xc000: |
54 | case 0xc710: |
55 | case 0xcf01: |
56 | case 0xc860 ... 0xc863: |
57 | case 0xc870 ... 0xc873: |
58 | return true; |
59 | default: |
60 | return false; |
61 | } |
62 | } |
63 | |
64 | static const struct regmap_config rt1308_sdw_regmap = { |
65 | .reg_bits = 32, |
66 | .val_bits = 8, |
67 | .readable_reg = rt1308_readable_register, |
68 | .volatile_reg = rt1308_volatile_register, |
69 | .max_register = 0xcfff, |
70 | .reg_defaults = rt1308_reg_defaults, |
71 | .num_reg_defaults = ARRAY_SIZE(rt1308_reg_defaults), |
72 | .cache_type = REGCACHE_MAPLE, |
73 | .use_single_read = true, |
74 | .use_single_write = true, |
75 | }; |
76 | |
77 | /* Bus clock frequency */ |
78 | #define RT1308_CLK_FREQ_9600000HZ 9600000 |
79 | #define RT1308_CLK_FREQ_12000000HZ 12000000 |
80 | #define RT1308_CLK_FREQ_6000000HZ 6000000 |
81 | #define RT1308_CLK_FREQ_4800000HZ 4800000 |
82 | #define RT1308_CLK_FREQ_2400000HZ 2400000 |
83 | #define RT1308_CLK_FREQ_12288000HZ 12288000 |
84 | |
85 | static int rt1308_clock_config(struct device *dev) |
86 | { |
87 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); |
88 | unsigned int clk_freq, value; |
89 | |
90 | clk_freq = (rt1308->params.curr_dr_freq >> 1); |
91 | |
92 | switch (clk_freq) { |
93 | case RT1308_CLK_FREQ_12000000HZ: |
94 | value = 0x0; |
95 | break; |
96 | case RT1308_CLK_FREQ_6000000HZ: |
97 | value = 0x1; |
98 | break; |
99 | case RT1308_CLK_FREQ_9600000HZ: |
100 | value = 0x2; |
101 | break; |
102 | case RT1308_CLK_FREQ_4800000HZ: |
103 | value = 0x3; |
104 | break; |
105 | case RT1308_CLK_FREQ_2400000HZ: |
106 | value = 0x4; |
107 | break; |
108 | case RT1308_CLK_FREQ_12288000HZ: |
109 | value = 0x5; |
110 | break; |
111 | default: |
112 | return -EINVAL; |
113 | } |
114 | |
115 | regmap_write(map: rt1308->regmap, reg: 0xe0, val: value); |
116 | regmap_write(map: rt1308->regmap, reg: 0xf0, val: value); |
117 | |
118 | dev_dbg(dev, "%s complete, clk_freq=%d\n" , __func__, clk_freq); |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | static int rt1308_read_prop(struct sdw_slave *slave) |
124 | { |
125 | struct sdw_slave_prop *prop = &slave->prop; |
126 | int nval, i; |
127 | u32 bit; |
128 | unsigned long addr; |
129 | struct sdw_dpn_prop *dpn; |
130 | |
131 | prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; |
132 | prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; |
133 | |
134 | prop->paging_support = true; |
135 | |
136 | /* first we need to allocate memory for set bits in port lists */ |
137 | prop->source_ports = 0x00; /* BITMAP: 00010100 (not enable yet) */ |
138 | prop->sink_ports = 0x2; /* BITMAP: 00000010 */ |
139 | |
140 | /* for sink */ |
141 | nval = hweight32(prop->sink_ports); |
142 | prop->sink_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
143 | size: sizeof(*prop->sink_dpn_prop), |
144 | GFP_KERNEL); |
145 | if (!prop->sink_dpn_prop) |
146 | return -ENOMEM; |
147 | |
148 | i = 0; |
149 | dpn = prop->sink_dpn_prop; |
150 | addr = prop->sink_ports; |
151 | for_each_set_bit(bit, &addr, 32) { |
152 | dpn[i].num = bit; |
153 | dpn[i].type = SDW_DPN_FULL; |
154 | dpn[i].simple_ch_prep_sm = true; |
155 | dpn[i].ch_prep_timeout = 10; |
156 | i++; |
157 | } |
158 | |
159 | /* set the timeout values */ |
160 | prop->clk_stop_timeout = 20; |
161 | |
162 | dev_dbg(&slave->dev, "%s\n" , __func__); |
163 | |
164 | return 0; |
165 | } |
166 | |
167 | static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308) |
168 | { |
169 | unsigned int efuse_m_btl_l, efuse_m_btl_r, tmp; |
170 | unsigned int efuse_c_btl_l, efuse_c_btl_r; |
171 | |
172 | /* read efuse to apply calibration parameters */ |
173 | regmap_write(map: rt1308->regmap, reg: 0xc7f0, val: 0x04); |
174 | regmap_write(map: rt1308->regmap, reg: 0xc7f1, val: 0xfe); |
175 | msleep(msecs: 100); |
176 | regmap_write(map: rt1308->regmap, reg: 0xc7f0, val: 0x44); |
177 | msleep(msecs: 20); |
178 | regmap_write(map: rt1308->regmap, reg: 0xc240, val: 0x10); |
179 | |
180 | regmap_read(map: rt1308->regmap, reg: 0xc861, val: &tmp); |
181 | efuse_m_btl_l = tmp; |
182 | regmap_read(map: rt1308->regmap, reg: 0xc860, val: &tmp); |
183 | efuse_m_btl_l = efuse_m_btl_l | (tmp << 8); |
184 | regmap_read(map: rt1308->regmap, reg: 0xc863, val: &tmp); |
185 | efuse_c_btl_l = tmp; |
186 | regmap_read(map: rt1308->regmap, reg: 0xc862, val: &tmp); |
187 | efuse_c_btl_l = efuse_c_btl_l | (tmp << 8); |
188 | regmap_read(map: rt1308->regmap, reg: 0xc871, val: &tmp); |
189 | efuse_m_btl_r = tmp; |
190 | regmap_read(map: rt1308->regmap, reg: 0xc870, val: &tmp); |
191 | efuse_m_btl_r = efuse_m_btl_r | (tmp << 8); |
192 | regmap_read(map: rt1308->regmap, reg: 0xc873, val: &tmp); |
193 | efuse_c_btl_r = tmp; |
194 | regmap_read(map: rt1308->regmap, reg: 0xc872, val: &tmp); |
195 | efuse_c_btl_r = efuse_c_btl_r | (tmp << 8); |
196 | dev_dbg(&rt1308->sdw_slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n" , __func__, |
197 | efuse_m_btl_l, efuse_m_btl_r); |
198 | dev_dbg(&rt1308->sdw_slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n" , __func__, |
199 | efuse_c_btl_l, efuse_c_btl_r); |
200 | } |
201 | |
202 | static void rt1308_apply_bq_params(struct rt1308_sdw_priv *rt1308) |
203 | { |
204 | unsigned int i, reg, data; |
205 | |
206 | for (i = 0; i < rt1308->bq_params_cnt; i += 3) { |
207 | reg = rt1308->bq_params[i] | (rt1308->bq_params[i + 1] << 8); |
208 | data = rt1308->bq_params[i + 2]; |
209 | regmap_write(map: rt1308->regmap, reg, val: data); |
210 | } |
211 | } |
212 | |
213 | static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) |
214 | { |
215 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); |
216 | int ret = 0; |
217 | unsigned int tmp, hibernation_flag; |
218 | |
219 | if (rt1308->hw_init) |
220 | return 0; |
221 | |
222 | regcache_cache_only(map: rt1308->regmap, enable: false); |
223 | if (rt1308->first_hw_init) |
224 | regcache_cache_bypass(map: rt1308->regmap, enable: true); |
225 | |
226 | /* |
227 | * PM runtime status is marked as 'active' only when a Slave reports as Attached |
228 | */ |
229 | if (!rt1308->first_hw_init) |
230 | /* update count of parent 'active' children */ |
231 | pm_runtime_set_active(dev: &slave->dev); |
232 | |
233 | pm_runtime_get_noresume(dev: &slave->dev); |
234 | |
235 | regmap_read(map: rt1308->regmap, reg: 0xcf01, val: &hibernation_flag); |
236 | if ((hibernation_flag != 0x00) && rt1308->first_hw_init) |
237 | goto _preset_ready_; |
238 | |
239 | /* sw reset */ |
240 | regmap_write(map: rt1308->regmap, RT1308_SDW_RESET, val: 0); |
241 | |
242 | regmap_read(map: rt1308->regmap, reg: 0xc710, val: &tmp); |
243 | rt1308->hw_ver = tmp; |
244 | dev_dbg(dev, "%s, hw_ver=0x%x\n" , __func__, rt1308->hw_ver); |
245 | |
246 | /* initial settings */ |
247 | regmap_write(map: rt1308->regmap, reg: 0xc103, val: 0xc0); |
248 | regmap_write(map: rt1308->regmap, reg: 0xc030, val: 0x17); |
249 | regmap_write(map: rt1308->regmap, reg: 0xc031, val: 0x81); |
250 | regmap_write(map: rt1308->regmap, reg: 0xc032, val: 0x26); |
251 | regmap_write(map: rt1308->regmap, reg: 0xc040, val: 0x80); |
252 | regmap_write(map: rt1308->regmap, reg: 0xc041, val: 0x80); |
253 | regmap_write(map: rt1308->regmap, reg: 0xc042, val: 0x06); |
254 | regmap_write(map: rt1308->regmap, reg: 0xc052, val: 0x0a); |
255 | regmap_write(map: rt1308->regmap, reg: 0xc080, val: 0x0a); |
256 | regmap_write(map: rt1308->regmap, reg: 0xc060, val: 0x02); |
257 | regmap_write(map: rt1308->regmap, reg: 0xc061, val: 0x75); |
258 | regmap_write(map: rt1308->regmap, reg: 0xc062, val: 0x05); |
259 | regmap_write(map: rt1308->regmap, reg: 0xc171, val: 0x07); |
260 | regmap_write(map: rt1308->regmap, reg: 0xc173, val: 0x0d); |
261 | if (rt1308->hw_ver == RT1308_VER_C) { |
262 | regmap_write(map: rt1308->regmap, reg: 0xc311, val: 0x7f); |
263 | regmap_write(map: rt1308->regmap, reg: 0xc300, val: 0x09); |
264 | } else { |
265 | regmap_write(map: rt1308->regmap, reg: 0xc311, val: 0x4f); |
266 | regmap_write(map: rt1308->regmap, reg: 0xc300, val: 0x0b); |
267 | } |
268 | regmap_write(map: rt1308->regmap, reg: 0xc900, val: 0x5a); |
269 | regmap_write(map: rt1308->regmap, reg: 0xc1a0, val: 0x84); |
270 | regmap_write(map: rt1308->regmap, reg: 0xc1a1, val: 0x01); |
271 | regmap_write(map: rt1308->regmap, reg: 0xc360, val: 0x78); |
272 | regmap_write(map: rt1308->regmap, reg: 0xc361, val: 0x87); |
273 | regmap_write(map: rt1308->regmap, reg: 0xc0a1, val: 0x71); |
274 | regmap_write(map: rt1308->regmap, reg: 0xc210, val: 0x00); |
275 | regmap_write(map: rt1308->regmap, reg: 0xc070, val: 0x00); |
276 | regmap_write(map: rt1308->regmap, reg: 0xc100, val: 0xd7); |
277 | regmap_write(map: rt1308->regmap, reg: 0xc101, val: 0xd7); |
278 | |
279 | /* apply BQ params */ |
280 | rt1308_apply_bq_params(rt1308); |
281 | |
282 | regmap_write(map: rt1308->regmap, reg: 0xcf01, val: 0x01); |
283 | |
284 | _preset_ready_: |
285 | if (rt1308->first_hw_init) { |
286 | regcache_cache_bypass(map: rt1308->regmap, enable: false); |
287 | regcache_mark_dirty(map: rt1308->regmap); |
288 | } else |
289 | rt1308->first_hw_init = true; |
290 | |
291 | /* Mark Slave initialization complete */ |
292 | rt1308->hw_init = true; |
293 | |
294 | pm_runtime_mark_last_busy(dev: &slave->dev); |
295 | pm_runtime_put_autosuspend(dev: &slave->dev); |
296 | |
297 | dev_dbg(&slave->dev, "%s hw_init complete\n" , __func__); |
298 | |
299 | return ret; |
300 | } |
301 | |
302 | static int rt1308_update_status(struct sdw_slave *slave, |
303 | enum sdw_slave_status status) |
304 | { |
305 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev: &slave->dev); |
306 | |
307 | if (status == SDW_SLAVE_UNATTACHED) |
308 | rt1308->hw_init = false; |
309 | |
310 | /* |
311 | * Perform initialization only if slave status is present and |
312 | * hw_init flag is false |
313 | */ |
314 | if (rt1308->hw_init || status != SDW_SLAVE_ATTACHED) |
315 | return 0; |
316 | |
317 | /* perform I/O transfers required for Slave initialization */ |
318 | return rt1308_io_init(dev: &slave->dev, slave); |
319 | } |
320 | |
321 | static int rt1308_bus_config(struct sdw_slave *slave, |
322 | struct sdw_bus_params *params) |
323 | { |
324 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev: &slave->dev); |
325 | int ret; |
326 | |
327 | memcpy(&rt1308->params, params, sizeof(*params)); |
328 | |
329 | ret = rt1308_clock_config(dev: &slave->dev); |
330 | if (ret < 0) |
331 | dev_err(&slave->dev, "Invalid clk config" ); |
332 | |
333 | return ret; |
334 | } |
335 | |
336 | static int rt1308_interrupt_callback(struct sdw_slave *slave, |
337 | struct sdw_slave_intr_status *status) |
338 | { |
339 | dev_dbg(&slave->dev, |
340 | "%s control_port_stat=%x" , __func__, status->control_port); |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | static int rt1308_classd_event(struct snd_soc_dapm_widget *w, |
346 | struct snd_kcontrol *kcontrol, int event) |
347 | { |
348 | struct snd_soc_component *component = |
349 | snd_soc_dapm_to_component(dapm: w->dapm); |
350 | struct rt1308_sdw_priv *rt1308 = |
351 | snd_soc_component_get_drvdata(c: component); |
352 | |
353 | switch (event) { |
354 | case SND_SOC_DAPM_POST_PMU: |
355 | msleep(msecs: 30); |
356 | snd_soc_component_update_bits(component, |
357 | RT1308_SDW_OFFSET | (RT1308_POWER_STATUS << 4), |
358 | mask: 0x3, val: 0x3); |
359 | msleep(msecs: 40); |
360 | rt1308_apply_calib_params(rt1308); |
361 | break; |
362 | case SND_SOC_DAPM_PRE_PMD: |
363 | snd_soc_component_update_bits(component, |
364 | RT1308_SDW_OFFSET | (RT1308_POWER_STATUS << 4), |
365 | mask: 0x3, val: 0); |
366 | usleep_range(min: 150000, max: 200000); |
367 | break; |
368 | |
369 | default: |
370 | break; |
371 | } |
372 | |
373 | return 0; |
374 | } |
375 | |
376 | static const char * const rt1308_rx_data_ch_select[] = { |
377 | "LR" , |
378 | "LL" , |
379 | "RL" , |
380 | "RR" , |
381 | }; |
382 | |
383 | static SOC_ENUM_SINGLE_DECL(rt1308_rx_data_ch_enum, |
384 | RT1308_SDW_OFFSET | (RT1308_DATA_PATH << 4), 0, |
385 | rt1308_rx_data_ch_select); |
386 | |
387 | static const struct snd_kcontrol_new rt1308_snd_controls[] = { |
388 | |
389 | /* I2S Data Channel Selection */ |
390 | SOC_ENUM("RX Channel Select" , rt1308_rx_data_ch_enum), |
391 | }; |
392 | |
393 | static const struct snd_kcontrol_new rt1308_sto_dac_l = |
394 | SOC_DAPM_SINGLE_AUTODISABLE("Switch" , |
395 | RT1308_SDW_OFFSET_BYTE3 | (RT1308_DAC_SET << 4), |
396 | RT1308_DVOL_MUTE_L_EN_SFT, 1, 1); |
397 | |
398 | static const struct snd_kcontrol_new rt1308_sto_dac_r = |
399 | SOC_DAPM_SINGLE_AUTODISABLE("Switch" , |
400 | RT1308_SDW_OFFSET_BYTE3 | (RT1308_DAC_SET << 4), |
401 | RT1308_DVOL_MUTE_R_EN_SFT, 1, 1); |
402 | |
403 | static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = { |
404 | /* Audio Interface */ |
405 | SND_SOC_DAPM_AIF_IN("AIF1RX" , "DP1 Playback" , 0, SND_SOC_NOPM, 0, 0), |
406 | |
407 | /* Supply Widgets */ |
408 | SND_SOC_DAPM_SUPPLY("MBIAS20U" , |
409 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 7, 0, NULL, 0), |
410 | SND_SOC_DAPM_SUPPLY("ALDO" , |
411 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 6, 0, NULL, 0), |
412 | SND_SOC_DAPM_SUPPLY("DBG" , |
413 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 5, 0, NULL, 0), |
414 | SND_SOC_DAPM_SUPPLY("DACL" , |
415 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 4, 0, NULL, 0), |
416 | SND_SOC_DAPM_SUPPLY("CLK25M" , |
417 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 2, 0, NULL, 0), |
418 | SND_SOC_DAPM_SUPPLY("ADC_R" , |
419 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 1, 0, NULL, 0), |
420 | SND_SOC_DAPM_SUPPLY("ADC_L" , |
421 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 0, 0, NULL, 0), |
422 | SND_SOC_DAPM_SUPPLY("DAC Power" , |
423 | RT1308_SDW_OFFSET | (RT1308_POWER << 4), 3, 0, NULL, 0), |
424 | |
425 | SND_SOC_DAPM_SUPPLY("DLDO" , |
426 | RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 5, 0, NULL, 0), |
427 | SND_SOC_DAPM_SUPPLY("VREF" , |
428 | RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 4, 0, NULL, 0), |
429 | SND_SOC_DAPM_SUPPLY("MIXER_R" , |
430 | RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 2, 0, NULL, 0), |
431 | SND_SOC_DAPM_SUPPLY("MIXER_L" , |
432 | RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 1, 0, NULL, 0), |
433 | SND_SOC_DAPM_SUPPLY("MBIAS4U" , |
434 | RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 0, 0, NULL, 0), |
435 | |
436 | SND_SOC_DAPM_SUPPLY("PLL2_LDO" , |
437 | RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 4, 0, NULL, 0), |
438 | SND_SOC_DAPM_SUPPLY("PLL2B" , |
439 | RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 3, 0, NULL, 0), |
440 | SND_SOC_DAPM_SUPPLY("PLL2F" , |
441 | RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 2, 0, NULL, 0), |
442 | SND_SOC_DAPM_SUPPLY("PLL2F2" , |
443 | RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 1, 0, NULL, 0), |
444 | SND_SOC_DAPM_SUPPLY("PLL2B2" , |
445 | RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 0, 0, NULL, 0), |
446 | |
447 | /* Digital Interface */ |
448 | SND_SOC_DAPM_DAC("DAC" , NULL, SND_SOC_NOPM, 0, 0), |
449 | SND_SOC_DAPM_SWITCH("DAC L" , SND_SOC_NOPM, 0, 0, &rt1308_sto_dac_l), |
450 | SND_SOC_DAPM_SWITCH("DAC R" , SND_SOC_NOPM, 0, 0, &rt1308_sto_dac_r), |
451 | |
452 | /* Output Lines */ |
453 | SND_SOC_DAPM_PGA_E("CLASS D" , SND_SOC_NOPM, 0, 0, NULL, 0, |
454 | rt1308_classd_event, |
455 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), |
456 | SND_SOC_DAPM_OUTPUT("SPOL" ), |
457 | SND_SOC_DAPM_OUTPUT("SPOR" ), |
458 | }; |
459 | |
460 | static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { |
461 | |
462 | { "DAC" , NULL, "AIF1RX" }, |
463 | |
464 | { "DAC" , NULL, "MBIAS20U" }, |
465 | { "DAC" , NULL, "ALDO" }, |
466 | { "DAC" , NULL, "DBG" }, |
467 | { "DAC" , NULL, "DACL" }, |
468 | { "DAC" , NULL, "CLK25M" }, |
469 | { "DAC" , NULL, "ADC_R" }, |
470 | { "DAC" , NULL, "ADC_L" }, |
471 | { "DAC" , NULL, "DLDO" }, |
472 | { "DAC" , NULL, "VREF" }, |
473 | { "DAC" , NULL, "MIXER_R" }, |
474 | { "DAC" , NULL, "MIXER_L" }, |
475 | { "DAC" , NULL, "MBIAS4U" }, |
476 | { "DAC" , NULL, "PLL2_LDO" }, |
477 | { "DAC" , NULL, "PLL2B" }, |
478 | { "DAC" , NULL, "PLL2F" }, |
479 | { "DAC" , NULL, "PLL2F2" }, |
480 | { "DAC" , NULL, "PLL2B2" }, |
481 | |
482 | { "DAC L" , "Switch" , "DAC" }, |
483 | { "DAC R" , "Switch" , "DAC" }, |
484 | { "DAC L" , NULL, "DAC Power" }, |
485 | { "DAC R" , NULL, "DAC Power" }, |
486 | |
487 | { "CLASS D" , NULL, "DAC L" }, |
488 | { "CLASS D" , NULL, "DAC R" }, |
489 | { "SPOL" , NULL, "CLASS D" }, |
490 | { "SPOR" , NULL, "CLASS D" }, |
491 | }; |
492 | |
493 | static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, |
494 | int direction) |
495 | { |
496 | snd_soc_dai_dma_data_set(dai, stream: direction, data: sdw_stream); |
497 | |
498 | return 0; |
499 | } |
500 | |
501 | static void rt1308_sdw_shutdown(struct snd_pcm_substream *substream, |
502 | struct snd_soc_dai *dai) |
503 | { |
504 | snd_soc_dai_set_dma_data(dai, substream, NULL); |
505 | } |
506 | |
507 | static int rt1308_sdw_set_tdm_slot(struct snd_soc_dai *dai, |
508 | unsigned int tx_mask, |
509 | unsigned int rx_mask, |
510 | int slots, int slot_width) |
511 | { |
512 | struct snd_soc_component *component = dai->component; |
513 | struct rt1308_sdw_priv *rt1308 = |
514 | snd_soc_component_get_drvdata(c: component); |
515 | |
516 | if (tx_mask) |
517 | return -EINVAL; |
518 | |
519 | if (slots > 2) |
520 | return -EINVAL; |
521 | |
522 | rt1308->rx_mask = rx_mask; |
523 | rt1308->slots = slots; |
524 | /* slot_width is not used since it's irrelevant for SoundWire */ |
525 | |
526 | return 0; |
527 | } |
528 | |
529 | static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream, |
530 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
531 | { |
532 | struct snd_soc_component *component = dai->component; |
533 | struct rt1308_sdw_priv *rt1308 = |
534 | snd_soc_component_get_drvdata(c: component); |
535 | struct sdw_stream_config stream_config = {0}; |
536 | struct sdw_port_config port_config = {0}; |
537 | struct sdw_stream_runtime *sdw_stream; |
538 | int retval; |
539 | |
540 | dev_dbg(dai->dev, "%s %s" , __func__, dai->name); |
541 | sdw_stream = snd_soc_dai_get_dma_data(dai, substream); |
542 | |
543 | if (!sdw_stream) |
544 | return -EINVAL; |
545 | |
546 | if (!rt1308->sdw_slave) |
547 | return -EINVAL; |
548 | |
549 | /* SoundWire specific configuration */ |
550 | snd_sdw_params_to_config(substream, params, stream_config: &stream_config, port_config: &port_config); |
551 | |
552 | /* port 1 for playback */ |
553 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
554 | port_config.num = 1; |
555 | else |
556 | return -EINVAL; |
557 | |
558 | if (rt1308->slots) { |
559 | stream_config.ch_count = rt1308->slots; |
560 | port_config.ch_mask = rt1308->rx_mask; |
561 | } |
562 | |
563 | retval = sdw_stream_add_slave(slave: rt1308->sdw_slave, stream_config: &stream_config, |
564 | port_config: &port_config, num_ports: 1, stream: sdw_stream); |
565 | if (retval) { |
566 | dev_err(dai->dev, "Unable to configure port\n" ); |
567 | return retval; |
568 | } |
569 | |
570 | return retval; |
571 | } |
572 | |
573 | static int rt1308_sdw_pcm_hw_free(struct snd_pcm_substream *substream, |
574 | struct snd_soc_dai *dai) |
575 | { |
576 | struct snd_soc_component *component = dai->component; |
577 | struct rt1308_sdw_priv *rt1308 = |
578 | snd_soc_component_get_drvdata(c: component); |
579 | struct sdw_stream_runtime *sdw_stream = |
580 | snd_soc_dai_get_dma_data(dai, substream); |
581 | |
582 | if (!rt1308->sdw_slave) |
583 | return -EINVAL; |
584 | |
585 | sdw_stream_remove_slave(slave: rt1308->sdw_slave, stream: sdw_stream); |
586 | return 0; |
587 | } |
588 | |
589 | /* |
590 | * slave_ops: callbacks for get_clock_stop_mode, clock_stop and |
591 | * port_prep are not defined for now |
592 | */ |
593 | static const struct sdw_slave_ops rt1308_slave_ops = { |
594 | .read_prop = rt1308_read_prop, |
595 | .interrupt_callback = rt1308_interrupt_callback, |
596 | .update_status = rt1308_update_status, |
597 | .bus_config = rt1308_bus_config, |
598 | }; |
599 | |
600 | static int rt1308_sdw_parse_dt(struct rt1308_sdw_priv *rt1308, struct device *dev) |
601 | { |
602 | int ret = 0; |
603 | |
604 | device_property_read_u32(dev, propname: "realtek,bq-params-cnt" , val: &rt1308->bq_params_cnt); |
605 | if (rt1308->bq_params_cnt) { |
606 | rt1308->bq_params = devm_kzalloc(dev, size: rt1308->bq_params_cnt, GFP_KERNEL); |
607 | if (!rt1308->bq_params) { |
608 | dev_err(dev, "Could not allocate bq_params memory\n" ); |
609 | ret = -ENOMEM; |
610 | } else { |
611 | ret = device_property_read_u8_array(dev, propname: "realtek,bq-params" , val: rt1308->bq_params, nval: rt1308->bq_params_cnt); |
612 | if (ret < 0) |
613 | dev_err(dev, "Could not read list of realtek,bq-params\n" ); |
614 | } |
615 | } |
616 | |
617 | dev_dbg(dev, "bq_params_cnt=%d\n" , rt1308->bq_params_cnt); |
618 | return ret; |
619 | } |
620 | |
621 | static int rt1308_sdw_component_probe(struct snd_soc_component *component) |
622 | { |
623 | struct rt1308_sdw_priv *rt1308 = snd_soc_component_get_drvdata(c: component); |
624 | int ret; |
625 | |
626 | rt1308->component = component; |
627 | rt1308_sdw_parse_dt(rt1308, dev: &rt1308->sdw_slave->dev); |
628 | |
629 | if (!rt1308->first_hw_init) |
630 | return 0; |
631 | |
632 | ret = pm_runtime_resume(dev: component->dev); |
633 | if (ret < 0 && ret != -EACCES) |
634 | return ret; |
635 | |
636 | /* apply BQ params */ |
637 | rt1308_apply_bq_params(rt1308); |
638 | |
639 | return 0; |
640 | } |
641 | |
642 | static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { |
643 | .probe = rt1308_sdw_component_probe, |
644 | .controls = rt1308_snd_controls, |
645 | .num_controls = ARRAY_SIZE(rt1308_snd_controls), |
646 | .dapm_widgets = rt1308_dapm_widgets, |
647 | .num_dapm_widgets = ARRAY_SIZE(rt1308_dapm_widgets), |
648 | .dapm_routes = rt1308_dapm_routes, |
649 | .num_dapm_routes = ARRAY_SIZE(rt1308_dapm_routes), |
650 | .endianness = 1, |
651 | }; |
652 | |
653 | static const struct snd_soc_dai_ops rt1308_aif_dai_ops = { |
654 | .hw_params = rt1308_sdw_hw_params, |
655 | .hw_free = rt1308_sdw_pcm_hw_free, |
656 | .set_stream = rt1308_set_sdw_stream, |
657 | .shutdown = rt1308_sdw_shutdown, |
658 | .set_tdm_slot = rt1308_sdw_set_tdm_slot, |
659 | }; |
660 | |
661 | #define RT1308_STEREO_RATES SNDRV_PCM_RATE_48000 |
662 | #define RT1308_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ |
663 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ |
664 | SNDRV_PCM_FMTBIT_S24_LE) |
665 | |
666 | static struct snd_soc_dai_driver rt1308_sdw_dai[] = { |
667 | { |
668 | .name = "rt1308-aif" , |
669 | .playback = { |
670 | .stream_name = "DP1 Playback" , |
671 | .channels_min = 1, |
672 | .channels_max = 2, |
673 | .rates = RT1308_STEREO_RATES, |
674 | .formats = RT1308_FORMATS, |
675 | }, |
676 | .ops = &rt1308_aif_dai_ops, |
677 | }, |
678 | }; |
679 | |
680 | static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, |
681 | struct sdw_slave *slave) |
682 | { |
683 | struct rt1308_sdw_priv *rt1308; |
684 | int ret; |
685 | |
686 | rt1308 = devm_kzalloc(dev, size: sizeof(*rt1308), GFP_KERNEL); |
687 | if (!rt1308) |
688 | return -ENOMEM; |
689 | |
690 | dev_set_drvdata(dev, data: rt1308); |
691 | rt1308->sdw_slave = slave; |
692 | rt1308->regmap = regmap; |
693 | |
694 | regcache_cache_only(map: rt1308->regmap, enable: true); |
695 | |
696 | /* |
697 | * Mark hw_init to false |
698 | * HW init will be performed when device reports present |
699 | */ |
700 | rt1308->hw_init = false; |
701 | rt1308->first_hw_init = false; |
702 | |
703 | ret = devm_snd_soc_register_component(dev, |
704 | component_driver: &soc_component_sdw_rt1308, |
705 | dai_drv: rt1308_sdw_dai, |
706 | ARRAY_SIZE(rt1308_sdw_dai)); |
707 | if (ret < 0) |
708 | return ret; |
709 | |
710 | /* set autosuspend parameters */ |
711 | pm_runtime_set_autosuspend_delay(dev, delay: 3000); |
712 | pm_runtime_use_autosuspend(dev); |
713 | |
714 | /* make sure the device does not suspend immediately */ |
715 | pm_runtime_mark_last_busy(dev); |
716 | |
717 | pm_runtime_enable(dev); |
718 | |
719 | /* important note: the device is NOT tagged as 'active' and will remain |
720 | * 'suspended' until the hardware is enumerated/initialized. This is required |
721 | * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently |
722 | * fail with -EACCESS because of race conditions between card creation and enumeration |
723 | */ |
724 | |
725 | dev_dbg(dev, "%s\n" , __func__); |
726 | |
727 | return 0; |
728 | } |
729 | |
730 | static int rt1308_sdw_probe(struct sdw_slave *slave, |
731 | const struct sdw_device_id *id) |
732 | { |
733 | struct regmap *regmap; |
734 | |
735 | /* Regmap Initialization */ |
736 | regmap = devm_regmap_init_sdw(slave, &rt1308_sdw_regmap); |
737 | if (IS_ERR(ptr: regmap)) |
738 | return PTR_ERR(ptr: regmap); |
739 | |
740 | return rt1308_sdw_init(dev: &slave->dev, regmap, slave); |
741 | } |
742 | |
743 | static int rt1308_sdw_remove(struct sdw_slave *slave) |
744 | { |
745 | pm_runtime_disable(dev: &slave->dev); |
746 | |
747 | return 0; |
748 | } |
749 | |
750 | static const struct sdw_device_id rt1308_id[] = { |
751 | SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0), |
752 | {}, |
753 | }; |
754 | MODULE_DEVICE_TABLE(sdw, rt1308_id); |
755 | |
756 | static int __maybe_unused rt1308_dev_suspend(struct device *dev) |
757 | { |
758 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); |
759 | |
760 | if (!rt1308->hw_init) |
761 | return 0; |
762 | |
763 | regcache_cache_only(map: rt1308->regmap, enable: true); |
764 | |
765 | return 0; |
766 | } |
767 | |
768 | #define RT1308_PROBE_TIMEOUT 5000 |
769 | |
770 | static int __maybe_unused rt1308_dev_resume(struct device *dev) |
771 | { |
772 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
773 | struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); |
774 | unsigned long time; |
775 | |
776 | if (!rt1308->first_hw_init) |
777 | return 0; |
778 | |
779 | if (!slave->unattach_request) |
780 | goto regmap_sync; |
781 | |
782 | time = wait_for_completion_timeout(x: &slave->initialization_complete, |
783 | timeout: msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); |
784 | if (!time) { |
785 | dev_err(&slave->dev, "Initialization not complete, timed out\n" ); |
786 | sdw_show_ping_status(bus: slave->bus, sync_delay: true); |
787 | |
788 | return -ETIMEDOUT; |
789 | } |
790 | |
791 | regmap_sync: |
792 | slave->unattach_request = 0; |
793 | regcache_cache_only(map: rt1308->regmap, enable: false); |
794 | regcache_sync_region(map: rt1308->regmap, min: 0xc000, max: 0xcfff); |
795 | |
796 | return 0; |
797 | } |
798 | |
799 | static const struct dev_pm_ops rt1308_pm = { |
800 | SET_SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume) |
801 | SET_RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL) |
802 | }; |
803 | |
804 | static struct sdw_driver rt1308_sdw_driver = { |
805 | .driver = { |
806 | .name = "rt1308" , |
807 | .owner = THIS_MODULE, |
808 | .pm = &rt1308_pm, |
809 | }, |
810 | .probe = rt1308_sdw_probe, |
811 | .remove = rt1308_sdw_remove, |
812 | .ops = &rt1308_slave_ops, |
813 | .id_table = rt1308_id, |
814 | }; |
815 | module_sdw_driver(rt1308_sdw_driver); |
816 | |
817 | MODULE_DESCRIPTION("ASoC RT1308 driver SDW" ); |
818 | MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>" ); |
819 | MODULE_LICENSE("GPL v2" ); |
820 | |