1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // rt1019.c -- RT1019 ALSA SoC audio amplifier driver |
4 | // Author: Jack Yu <jack.yu@realtek.com> |
5 | // |
6 | // Copyright(c) 2021 Realtek Semiconductor Corp. |
7 | // |
8 | // |
9 | |
10 | #include <linux/acpi.h> |
11 | #include <linux/fs.h> |
12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> |
14 | #include <linux/init.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/i2c.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/firmware.h> |
21 | #include <sound/core.h> |
22 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> |
24 | #include <sound/soc.h> |
25 | #include <sound/soc-dapm.h> |
26 | #include <sound/initval.h> |
27 | #include <sound/tlv.h> |
28 | |
29 | #include "rl6231.h" |
30 | #include "rt1019.h" |
31 | |
32 | static const struct reg_default rt1019_reg[] = { |
33 | { 0x0000, 0x00 }, |
34 | { 0x0011, 0x04 }, |
35 | { 0x0013, 0x00 }, |
36 | { 0x0019, 0x30 }, |
37 | { 0x001b, 0x01 }, |
38 | { 0x005c, 0x00 }, |
39 | { 0x005e, 0x10 }, |
40 | { 0x005f, 0xec }, |
41 | { 0x0061, 0x10 }, |
42 | { 0x0062, 0x19 }, |
43 | { 0x0066, 0x08 }, |
44 | { 0x0100, 0x80 }, |
45 | { 0x0100, 0x51 }, |
46 | { 0x0102, 0x23 }, |
47 | { 0x0311, 0x00 }, |
48 | { 0x0312, 0x3e }, |
49 | { 0x0313, 0x86 }, |
50 | { 0x0400, 0x03 }, |
51 | { 0x0401, 0x02 }, |
52 | { 0x0402, 0x01 }, |
53 | { 0x0504, 0xff }, |
54 | { 0x0505, 0x24 }, |
55 | { 0x0b00, 0x50 }, |
56 | { 0x0b01, 0xc3 }, |
57 | }; |
58 | |
59 | static bool rt1019_volatile_register(struct device *dev, unsigned int reg) |
60 | { |
61 | switch (reg) { |
62 | case RT1019_PWR_STRP_2: |
63 | case RT1019_VER_ID: |
64 | case RT1019_VEND_ID_1: |
65 | case RT1019_VEND_ID_2: |
66 | case RT1019_DEV_ID_1: |
67 | case RT1019_DEV_ID_2: |
68 | return true; |
69 | |
70 | default: |
71 | return false; |
72 | } |
73 | } |
74 | |
75 | static bool rt1019_readable_register(struct device *dev, unsigned int reg) |
76 | { |
77 | switch (reg) { |
78 | case RT1019_RESET: |
79 | case RT1019_IDS_CTRL: |
80 | case RT1019_ASEL_CTRL: |
81 | case RT1019_PWR_STRP_2: |
82 | case RT1019_BEEP_TONE: |
83 | case RT1019_VER_ID: |
84 | case RT1019_VEND_ID_1: |
85 | case RT1019_VEND_ID_2: |
86 | case RT1019_DEV_ID_1: |
87 | case RT1019_DEV_ID_2: |
88 | case RT1019_SDB_CTRL: |
89 | case RT1019_CLK_TREE_1: |
90 | case RT1019_CLK_TREE_2: |
91 | case RT1019_CLK_TREE_3: |
92 | case RT1019_PLL_1: |
93 | case RT1019_PLL_2: |
94 | case RT1019_PLL_3: |
95 | case RT1019_TDM_1: |
96 | case RT1019_TDM_2: |
97 | case RT1019_TDM_3: |
98 | case RT1019_DMIX_MONO_1: |
99 | case RT1019_DMIX_MONO_2: |
100 | case RT1019_BEEP_1: |
101 | case RT1019_BEEP_2: |
102 | return true; |
103 | default: |
104 | return false; |
105 | } |
106 | } |
107 | |
108 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9525, 75, 0); |
109 | |
110 | static const char * const rt1019_din_source_select[] = { |
111 | "Left" , |
112 | "Right" , |
113 | "Left + Right average" , |
114 | }; |
115 | |
116 | static SOC_ENUM_SINGLE_DECL(rt1019_mono_lr_sel, RT1019_IDS_CTRL, 0, |
117 | rt1019_din_source_select); |
118 | |
119 | static const struct snd_kcontrol_new rt1019_snd_controls[] = { |
120 | SOC_SINGLE_TLV("DAC Playback Volume" , RT1019_DMIX_MONO_1, 0, |
121 | 127, 0, dac_vol_tlv), |
122 | SOC_ENUM("Mono LR Select" , rt1019_mono_lr_sel), |
123 | }; |
124 | |
125 | static int r1019_dac_event(struct snd_soc_dapm_widget *w, |
126 | struct snd_kcontrol *kcontrol, int event) |
127 | { |
128 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
129 | |
130 | switch (event) { |
131 | case SND_SOC_DAPM_PRE_PMU: |
132 | snd_soc_component_write(component, RT1019_SDB_CTRL, val: 0xb); |
133 | break; |
134 | case SND_SOC_DAPM_POST_PMD: |
135 | snd_soc_component_write(component, RT1019_SDB_CTRL, val: 0xa); |
136 | break; |
137 | default: |
138 | break; |
139 | } |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | static const struct snd_soc_dapm_widget rt1019_dapm_widgets[] = { |
145 | SND_SOC_DAPM_AIF_IN("AIFRX" , "AIF Playback" , 0, SND_SOC_NOPM, 0, 0), |
146 | SND_SOC_DAPM_DAC_E("DAC" , NULL, SND_SOC_NOPM, 0, 0, |
147 | r1019_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
148 | SND_SOC_DAPM_OUTPUT("SPO" ), |
149 | }; |
150 | |
151 | static const struct snd_soc_dapm_route rt1019_dapm_routes[] = { |
152 | { "DAC" , NULL, "AIFRX" }, |
153 | { "SPO" , NULL, "DAC" }, |
154 | }; |
155 | |
156 | static int rt1019_hw_params(struct snd_pcm_substream *substream, |
157 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
158 | { |
159 | struct snd_soc_component *component = dai->component; |
160 | struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(c: component); |
161 | int pre_div, bclk_ms, frame_size; |
162 | unsigned int val_len = 0, sys_div_da_filter = 0; |
163 | unsigned int sys_dac_osr = 0, sys_fifo_clk = 0; |
164 | unsigned int sys_clk_cal = 0, sys_asrc_in = 0; |
165 | |
166 | rt1019->lrck = params_rate(p: params); |
167 | pre_div = rl6231_get_clk_info(sclk: rt1019->sysclk, rate: rt1019->lrck); |
168 | if (pre_div < 0) { |
169 | dev_err(component->dev, "Unsupported clock setting\n" ); |
170 | return -EINVAL; |
171 | } |
172 | |
173 | frame_size = snd_soc_params_to_frame_size(params); |
174 | if (frame_size < 0) { |
175 | dev_err(component->dev, "Unsupported frame size: %d\n" , frame_size); |
176 | return -EINVAL; |
177 | } |
178 | |
179 | bclk_ms = frame_size > 32; |
180 | rt1019->bclk = rt1019->lrck * (32 << bclk_ms); |
181 | |
182 | dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n" , |
183 | rt1019->bclk, rt1019->lrck); |
184 | dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n" , |
185 | bclk_ms, pre_div, dai->id); |
186 | |
187 | switch (pre_div) { |
188 | case 0: |
189 | sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV1; |
190 | sys_dac_osr = RT1019_SYS_DA_OSR_DIV1; |
191 | sys_asrc_in = RT1019_ASRC_256FS_DIV1; |
192 | sys_fifo_clk = RT1019_SEL_FIFO_DIV1; |
193 | sys_clk_cal = RT1019_SEL_CLK_CAL_DIV1; |
194 | break; |
195 | case 1: |
196 | sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV2; |
197 | sys_dac_osr = RT1019_SYS_DA_OSR_DIV2; |
198 | sys_asrc_in = RT1019_ASRC_256FS_DIV2; |
199 | sys_fifo_clk = RT1019_SEL_FIFO_DIV2; |
200 | sys_clk_cal = RT1019_SEL_CLK_CAL_DIV2; |
201 | break; |
202 | case 3: |
203 | sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV4; |
204 | sys_dac_osr = RT1019_SYS_DA_OSR_DIV4; |
205 | sys_asrc_in = RT1019_ASRC_256FS_DIV4; |
206 | sys_fifo_clk = RT1019_SEL_FIFO_DIV4; |
207 | sys_clk_cal = RT1019_SEL_CLK_CAL_DIV4; |
208 | break; |
209 | default: |
210 | return -EINVAL; |
211 | } |
212 | |
213 | switch (params_width(p: params)) { |
214 | case 16: |
215 | break; |
216 | case 20: |
217 | val_len = RT1019_I2S_DL_20; |
218 | break; |
219 | case 24: |
220 | val_len = RT1019_I2S_DL_24; |
221 | break; |
222 | case 32: |
223 | val_len = RT1019_I2S_DL_32; |
224 | break; |
225 | case 8: |
226 | val_len = RT1019_I2S_DL_8; |
227 | break; |
228 | default: |
229 | return -EINVAL; |
230 | } |
231 | |
232 | snd_soc_component_update_bits(component, RT1019_TDM_2, RT1019_I2S_DL_MASK, |
233 | val: val_len); |
234 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, |
235 | RT1019_SEL_FIFO_MASK, val: sys_fifo_clk); |
236 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_2, |
237 | RT1019_SYS_DIV_DA_FIL_MASK | RT1019_SYS_DA_OSR_MASK | |
238 | RT1019_ASRC_256FS_MASK, val: sys_div_da_filter | sys_dac_osr | |
239 | sys_asrc_in); |
240 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_3, |
241 | RT1019_SEL_CLK_CAL_MASK, val: sys_clk_cal); |
242 | |
243 | return 0; |
244 | } |
245 | |
246 | static int rt1019_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
247 | { |
248 | struct snd_soc_component *component = dai->component; |
249 | unsigned int reg_val = 0, reg_val2 = 0; |
250 | |
251 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
252 | case SND_SOC_DAIFMT_NB_NF: |
253 | break; |
254 | case SND_SOC_DAIFMT_IB_NF: |
255 | reg_val2 |= RT1019_TDM_BCLK_INV; |
256 | break; |
257 | default: |
258 | return -EINVAL; |
259 | } |
260 | |
261 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
262 | case SND_SOC_DAIFMT_I2S: |
263 | break; |
264 | |
265 | case SND_SOC_DAIFMT_LEFT_J: |
266 | reg_val |= RT1019_I2S_DF_LEFT; |
267 | break; |
268 | |
269 | case SND_SOC_DAIFMT_DSP_A: |
270 | reg_val |= RT1019_I2S_DF_PCM_A_R; |
271 | break; |
272 | |
273 | case SND_SOC_DAIFMT_DSP_B: |
274 | reg_val |= RT1019_I2S_DF_PCM_B_R; |
275 | break; |
276 | |
277 | default: |
278 | return -EINVAL; |
279 | } |
280 | |
281 | snd_soc_component_update_bits(component, RT1019_TDM_2, |
282 | RT1019_I2S_DF_MASK, val: reg_val); |
283 | snd_soc_component_update_bits(component, RT1019_TDM_1, |
284 | RT1019_TDM_BCLK_MASK, val: reg_val2); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int rt1019_set_dai_sysclk(struct snd_soc_dai *dai, |
290 | int clk_id, unsigned int freq, int dir) |
291 | { |
292 | struct snd_soc_component *component = dai->component; |
293 | struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(c: component); |
294 | unsigned int reg_val = 0; |
295 | |
296 | if (freq == rt1019->sysclk && clk_id == rt1019->sysclk_src) |
297 | return 0; |
298 | |
299 | switch (clk_id) { |
300 | case RT1019_SCLK_S_BCLK: |
301 | reg_val |= RT1019_CLK_SYS_PRE_SEL_BCLK; |
302 | break; |
303 | |
304 | case RT1019_SCLK_S_PLL: |
305 | reg_val |= RT1019_CLK_SYS_PRE_SEL_PLL; |
306 | break; |
307 | |
308 | default: |
309 | dev_err(component->dev, "Invalid clock id (%d)\n" , clk_id); |
310 | return -EINVAL; |
311 | } |
312 | |
313 | rt1019->sysclk = freq; |
314 | rt1019->sysclk_src = clk_id; |
315 | |
316 | dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n" , freq, clk_id); |
317 | |
318 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, |
319 | RT1019_CLK_SYS_PRE_SEL_MASK, val: reg_val); |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | static int rt1019_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, |
325 | unsigned int freq_in, unsigned int freq_out) |
326 | { |
327 | struct snd_soc_component *component = dai->component; |
328 | struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(c: component); |
329 | struct rl6231_pll_code pll_code; |
330 | int ret; |
331 | |
332 | if (!freq_in || !freq_out) { |
333 | dev_dbg(component->dev, "PLL disabled\n" ); |
334 | rt1019->pll_in = 0; |
335 | rt1019->pll_out = 0; |
336 | return 0; |
337 | } |
338 | |
339 | if (source == rt1019->pll_src && freq_in == rt1019->pll_in && |
340 | freq_out == rt1019->pll_out) |
341 | return 0; |
342 | |
343 | switch (source) { |
344 | case RT1019_PLL_S_BCLK: |
345 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, |
346 | RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_BCLK); |
347 | break; |
348 | |
349 | case RT1019_PLL_S_RC25M: |
350 | snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, |
351 | RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_RC); |
352 | break; |
353 | |
354 | default: |
355 | dev_err(component->dev, "Unknown PLL source %d\n" , source); |
356 | return -EINVAL; |
357 | } |
358 | |
359 | ret = rl6231_pll_calc(freq_in, freq_out, pll_code: &pll_code); |
360 | if (ret < 0) { |
361 | dev_err(component->dev, "Unsupported input clock %d\n" , freq_in); |
362 | return ret; |
363 | } |
364 | |
365 | dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n" , |
366 | pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), |
367 | pll_code.n_code, pll_code.k_code); |
368 | |
369 | snd_soc_component_update_bits(component, RT1019_PWR_STRP_2, |
370 | RT1019_AUTO_BITS_SEL_MASK | RT1019_AUTO_CLK_SEL_MASK, |
371 | RT1019_AUTO_BITS_SEL_MANU | RT1019_AUTO_CLK_SEL_MANU); |
372 | snd_soc_component_update_bits(component, RT1019_PLL_1, |
373 | RT1019_PLL_M_MASK | RT1019_PLL_M_BP_MASK | RT1019_PLL_Q_8_8_MASK, |
374 | val: ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1019_PLL_M_SFT) | |
375 | (pll_code.m_bp << RT1019_PLL_M_BP_SFT) | |
376 | ((pll_code.n_code >> 8) & RT1019_PLL_Q_8_8_MASK)); |
377 | snd_soc_component_update_bits(component, RT1019_PLL_2, |
378 | RT1019_PLL_Q_7_0_MASK, val: pll_code.n_code & RT1019_PLL_Q_7_0_MASK); |
379 | snd_soc_component_update_bits(component, RT1019_PLL_3, |
380 | RT1019_PLL_K_MASK, val: pll_code.k_code); |
381 | |
382 | rt1019->pll_in = freq_in; |
383 | rt1019->pll_out = freq_out; |
384 | rt1019->pll_src = source; |
385 | |
386 | return 0; |
387 | } |
388 | |
389 | static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
390 | unsigned int rx_mask, int slots, int slot_width) |
391 | { |
392 | struct snd_soc_component *component = dai->component; |
393 | unsigned int cn = 0, cl = 0, rx_slotnum; |
394 | int ret = 0, first_bit; |
395 | |
396 | switch (slots) { |
397 | case 4: |
398 | cn = RT1019_I2S_TX_4CH; |
399 | break; |
400 | case 6: |
401 | cn = RT1019_I2S_TX_6CH; |
402 | break; |
403 | case 8: |
404 | cn = RT1019_I2S_TX_8CH; |
405 | break; |
406 | case 2: |
407 | break; |
408 | default: |
409 | return -EINVAL; |
410 | } |
411 | |
412 | switch (slot_width) { |
413 | case 20: |
414 | cl = RT1019_TDM_CL_20; |
415 | break; |
416 | case 24: |
417 | cl = RT1019_TDM_CL_24; |
418 | break; |
419 | case 32: |
420 | cl = RT1019_TDM_CL_32; |
421 | break; |
422 | case 8: |
423 | cl = RT1019_TDM_CL_8; |
424 | break; |
425 | case 16: |
426 | break; |
427 | default: |
428 | return -EINVAL; |
429 | } |
430 | |
431 | /* Rx slot configuration */ |
432 | rx_slotnum = hweight_long(w: rx_mask); |
433 | if (rx_slotnum != 1) { |
434 | ret = -EINVAL; |
435 | dev_err(component->dev, "too many rx slots or zero slot\n" ); |
436 | goto _set_tdm_err_; |
437 | } |
438 | /* This is an assumption that the system sends stereo audio to the |
439 | * amplifier typically. And the stereo audio is placed in slot 0/2/4/6 |
440 | * as the starting slot. The users could select the channel from |
441 | * L/R/L+R by "Mono LR Select" control. |
442 | */ |
443 | first_bit = __ffs(rx_mask); |
444 | switch (first_bit) { |
445 | case 0: |
446 | case 2: |
447 | case 4: |
448 | case 6: |
449 | snd_soc_component_update_bits(component, |
450 | RT1019_TDM_3, |
451 | RT1019_TDM_I2S_TX_L_DAC1_1_MASK | |
452 | RT1019_TDM_I2S_TX_R_DAC1_1_MASK, |
453 | val: (first_bit << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) | |
454 | ((first_bit + 1) << RT1019_TDM_I2S_TX_R_DAC1_1_SFT)); |
455 | break; |
456 | case 1: |
457 | case 3: |
458 | case 5: |
459 | case 7: |
460 | snd_soc_component_update_bits(component, |
461 | RT1019_TDM_3, |
462 | RT1019_TDM_I2S_TX_L_DAC1_1_MASK | |
463 | RT1019_TDM_I2S_TX_R_DAC1_1_MASK, |
464 | val: ((first_bit - 1) << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) | |
465 | (first_bit << RT1019_TDM_I2S_TX_R_DAC1_1_SFT)); |
466 | break; |
467 | default: |
468 | ret = -EINVAL; |
469 | goto _set_tdm_err_; |
470 | } |
471 | |
472 | snd_soc_component_update_bits(component, RT1019_TDM_1, |
473 | RT1019_TDM_CL_MASK, val: cl); |
474 | snd_soc_component_update_bits(component, RT1019_TDM_2, |
475 | RT1019_I2S_CH_TX_MASK, val: cn); |
476 | |
477 | _set_tdm_err_: |
478 | return ret; |
479 | } |
480 | |
481 | static int rt1019_probe(struct snd_soc_component *component) |
482 | { |
483 | struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(c: component); |
484 | |
485 | rt1019->component = component; |
486 | snd_soc_component_write(component, RT1019_SDB_CTRL, val: 0xa); |
487 | |
488 | return 0; |
489 | } |
490 | |
491 | #define RT1019_STEREO_RATES SNDRV_PCM_RATE_8000_192000 |
492 | #define RT1019_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
493 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) |
494 | |
495 | static const struct snd_soc_dai_ops rt1019_aif_dai_ops = { |
496 | .hw_params = rt1019_hw_params, |
497 | .set_fmt = rt1019_set_dai_fmt, |
498 | .set_sysclk = rt1019_set_dai_sysclk, |
499 | .set_pll = rt1019_set_dai_pll, |
500 | .set_tdm_slot = rt1019_set_tdm_slot, |
501 | }; |
502 | |
503 | static struct snd_soc_dai_driver rt1019_dai[] = { |
504 | { |
505 | .name = "rt1019-aif" , |
506 | .id = 0, |
507 | .playback = { |
508 | .stream_name = "AIF Playback" , |
509 | .channels_min = 1, |
510 | .channels_max = 2, |
511 | .rates = RT1019_STEREO_RATES, |
512 | .formats = RT1019_FORMATS, |
513 | }, |
514 | .ops = &rt1019_aif_dai_ops, |
515 | } |
516 | }; |
517 | |
518 | static const struct snd_soc_component_driver soc_component_dev_rt1019 = { |
519 | .probe = rt1019_probe, |
520 | .controls = rt1019_snd_controls, |
521 | .num_controls = ARRAY_SIZE(rt1019_snd_controls), |
522 | .dapm_widgets = rt1019_dapm_widgets, |
523 | .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets), |
524 | .dapm_routes = rt1019_dapm_routes, |
525 | .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes), |
526 | .endianness = 1, |
527 | }; |
528 | |
529 | static const struct regmap_config rt1019_regmap = { |
530 | .reg_bits = 16, |
531 | .val_bits = 8, |
532 | .use_single_read = true, |
533 | .use_single_write = true, |
534 | .max_register = RT1019_BEEP_2, |
535 | .volatile_reg = rt1019_volatile_register, |
536 | .readable_reg = rt1019_readable_register, |
537 | .cache_type = REGCACHE_MAPLE, |
538 | .reg_defaults = rt1019_reg, |
539 | .num_reg_defaults = ARRAY_SIZE(rt1019_reg), |
540 | }; |
541 | |
542 | static const struct i2c_device_id rt1019_i2c_id[] = { |
543 | { "rt1019" , 0 }, |
544 | { } |
545 | }; |
546 | MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id); |
547 | |
548 | static const struct of_device_id rt1019_of_match[] __maybe_unused = { |
549 | { .compatible = "realtek,rt1019" , }, |
550 | {}, |
551 | }; |
552 | MODULE_DEVICE_TABLE(of, rt1019_of_match); |
553 | |
554 | #ifdef CONFIG_ACPI |
555 | static const struct acpi_device_id rt1019_acpi_match[] = { |
556 | { "10EC1019" , 0}, |
557 | { }, |
558 | }; |
559 | MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match); |
560 | #endif |
561 | |
562 | static int rt1019_i2c_probe(struct i2c_client *i2c) |
563 | { |
564 | struct rt1019_priv *rt1019; |
565 | int ret; |
566 | unsigned int val, val2, dev_id; |
567 | |
568 | rt1019 = devm_kzalloc(dev: &i2c->dev, size: sizeof(struct rt1019_priv), |
569 | GFP_KERNEL); |
570 | if (!rt1019) |
571 | return -ENOMEM; |
572 | |
573 | i2c_set_clientdata(client: i2c, data: rt1019); |
574 | |
575 | rt1019->regmap = devm_regmap_init_i2c(i2c, &rt1019_regmap); |
576 | if (IS_ERR(ptr: rt1019->regmap)) { |
577 | ret = PTR_ERR(ptr: rt1019->regmap); |
578 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n" , |
579 | ret); |
580 | return ret; |
581 | } |
582 | |
583 | regmap_read(map: rt1019->regmap, RT1019_DEV_ID_1, val: &val); |
584 | regmap_read(map: rt1019->regmap, RT1019_DEV_ID_2, val: &val2); |
585 | dev_id = val << 8 | val2; |
586 | if (dev_id != RT1019_DEVICE_ID_VAL && dev_id != RT1019_DEVICE_ID_VAL2) { |
587 | dev_err(&i2c->dev, |
588 | "Device with ID register 0x%x is not rt1019\n" , dev_id); |
589 | return -ENODEV; |
590 | } |
591 | |
592 | return devm_snd_soc_register_component(dev: &i2c->dev, |
593 | component_driver: &soc_component_dev_rt1019, dai_drv: rt1019_dai, ARRAY_SIZE(rt1019_dai)); |
594 | } |
595 | |
596 | static struct i2c_driver rt1019_i2c_driver = { |
597 | .driver = { |
598 | .name = "rt1019" , |
599 | .of_match_table = of_match_ptr(rt1019_of_match), |
600 | .acpi_match_table = ACPI_PTR(rt1019_acpi_match), |
601 | }, |
602 | .probe = rt1019_i2c_probe, |
603 | .id_table = rt1019_i2c_id, |
604 | }; |
605 | module_i2c_driver(rt1019_i2c_driver); |
606 | |
607 | MODULE_DESCRIPTION("ASoC RT1019 driver" ); |
608 | MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>" ); |
609 | MODULE_LICENSE("GPL v2" ); |
610 | |