1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // rt711-sdw-sdca.c -- rt711 SDCA ALSA SoC audio driver |
4 | // |
5 | // Copyright(c) 2021 Realtek Semiconductor Corp. |
6 | // |
7 | // |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/mod_devicetable.h> |
12 | #include <linux/soundwire/sdw_registers.h> |
13 | #include <linux/module.h> |
14 | #include <linux/pm_runtime.h> |
15 | |
16 | #include "rt711-sdca.h" |
17 | #include "rt711-sdca-sdw.h" |
18 | |
19 | static bool rt711_sdca_readable_register(struct device *dev, unsigned int reg) |
20 | { |
21 | switch (reg) { |
22 | case 0x201a ... 0x2027: |
23 | case 0x2029 ... 0x202a: |
24 | case 0x202d ... 0x2034: |
25 | case 0x2200 ... 0x2204: |
26 | case 0x2206 ... 0x2212: |
27 | case 0x2220 ... 0x2223: |
28 | case 0x2230 ... 0x2239: |
29 | case 0x2f01 ... 0x2f0f: |
30 | case 0x2f30 ... 0x2f36: |
31 | case 0x2f50 ... 0x2f5a: |
32 | case 0x2f60: |
33 | case 0x3200 ... 0x3212: |
34 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_SELECTED_MODE, 0): |
35 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0): |
36 | case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... |
37 | SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): |
38 | case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2: |
39 | return true; |
40 | default: |
41 | return false; |
42 | } |
43 | } |
44 | |
45 | static bool rt711_sdca_volatile_register(struct device *dev, unsigned int reg) |
46 | { |
47 | switch (reg) { |
48 | case 0x201b: |
49 | case 0x201c: |
50 | case 0x201d: |
51 | case 0x201f: |
52 | case 0x2021: |
53 | case 0x2023: |
54 | case 0x2230: |
55 | case 0x202d ... 0x202f: /* BRA */ |
56 | case 0x2200 ... 0x2212: /* i2c debug */ |
57 | case RT711_RC_CAL_STATUS: |
58 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0): |
59 | case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... |
60 | SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): |
61 | case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2: |
62 | return true; |
63 | default: |
64 | return false; |
65 | } |
66 | } |
67 | |
68 | static bool rt711_sdca_mbq_readable_register(struct device *dev, unsigned int reg) |
69 | { |
70 | switch (reg) { |
71 | case 0x2000000 ... 0x20000ff: |
72 | case 0x5600000 ... 0x56000ff: |
73 | case 0x5700000 ... 0x57000ff: |
74 | case 0x5800000 ... 0x58000ff: |
75 | case 0x5900000 ... 0x59000ff: |
76 | case 0x5b00000 ... 0x5b000ff: |
77 | case 0x5f00000 ... 0x5f000ff: |
78 | case 0x6100000 ... 0x61000ff: |
79 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L): |
80 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R): |
81 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L): |
82 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R): |
83 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L): |
84 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R): |
85 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L): |
86 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R): |
87 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L): |
88 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R): |
89 | return true; |
90 | default: |
91 | return false; |
92 | } |
93 | } |
94 | |
95 | static bool rt711_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) |
96 | { |
97 | switch (reg) { |
98 | case 0x2000000: |
99 | case 0x200001a: |
100 | case 0x2000046: |
101 | case 0x2000080: |
102 | case 0x2000081: |
103 | case 0x2000083: |
104 | case 0x5800000: |
105 | case 0x5800001: |
106 | case 0x5f00001: |
107 | case 0x6100008: |
108 | return true; |
109 | default: |
110 | return false; |
111 | } |
112 | } |
113 | |
114 | static const struct regmap_config rt711_sdca_regmap = { |
115 | .reg_bits = 32, |
116 | .val_bits = 8, |
117 | .readable_reg = rt711_sdca_readable_register, |
118 | .volatile_reg = rt711_sdca_volatile_register, |
119 | .max_register = 0x44ffffff, |
120 | .reg_defaults = rt711_sdca_reg_defaults, |
121 | .num_reg_defaults = ARRAY_SIZE(rt711_sdca_reg_defaults), |
122 | .cache_type = REGCACHE_MAPLE, |
123 | .use_single_read = true, |
124 | .use_single_write = true, |
125 | }; |
126 | |
127 | static const struct regmap_config rt711_sdca_mbq_regmap = { |
128 | .name = "sdw-mbq" , |
129 | .reg_bits = 32, |
130 | .val_bits = 16, |
131 | .readable_reg = rt711_sdca_mbq_readable_register, |
132 | .volatile_reg = rt711_sdca_mbq_volatile_register, |
133 | .max_register = 0x40800f12, |
134 | .reg_defaults = rt711_sdca_mbq_defaults, |
135 | .num_reg_defaults = ARRAY_SIZE(rt711_sdca_mbq_defaults), |
136 | .cache_type = REGCACHE_MAPLE, |
137 | .use_single_read = true, |
138 | .use_single_write = true, |
139 | }; |
140 | |
141 | static int rt711_sdca_update_status(struct sdw_slave *slave, |
142 | enum sdw_slave_status status) |
143 | { |
144 | struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev: &slave->dev); |
145 | |
146 | if (status == SDW_SLAVE_UNATTACHED) |
147 | rt711->hw_init = false; |
148 | |
149 | if (status == SDW_SLAVE_ATTACHED) { |
150 | if (rt711->hs_jack) { |
151 | /* |
152 | * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then |
153 | * if the device attached again, we will need to set the setting back. |
154 | * It could avoid losing the jack detection interrupt. |
155 | * This also could sync with the cache value as the rt711_sdca_jack_init set. |
156 | */ |
157 | sdw_write_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INTMASK1, |
158 | SDW_SCP_SDCA_INTMASK_SDCA_0); |
159 | sdw_write_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INTMASK2, |
160 | SDW_SCP_SDCA_INTMASK_SDCA_8); |
161 | } |
162 | } |
163 | |
164 | /* |
165 | * Perform initialization only if slave status is present and |
166 | * hw_init flag is false |
167 | */ |
168 | if (rt711->hw_init || status != SDW_SLAVE_ATTACHED) |
169 | return 0; |
170 | |
171 | /* perform I/O transfers required for Slave initialization */ |
172 | return rt711_sdca_io_init(dev: &slave->dev, slave); |
173 | } |
174 | |
175 | static int rt711_sdca_read_prop(struct sdw_slave *slave) |
176 | { |
177 | struct sdw_slave_prop *prop = &slave->prop; |
178 | int nval; |
179 | int i, j; |
180 | u32 bit; |
181 | unsigned long addr; |
182 | struct sdw_dpn_prop *dpn; |
183 | |
184 | prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; |
185 | prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; |
186 | |
187 | prop->paging_support = true; |
188 | |
189 | /* first we need to allocate memory for set bits in port lists */ |
190 | prop->source_ports = 0x14; /* BITMAP: 00010100 */ |
191 | prop->sink_ports = 0x8; /* BITMAP: 00001000 */ |
192 | |
193 | nval = hweight32(prop->source_ports); |
194 | prop->src_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
195 | size: sizeof(*prop->src_dpn_prop), GFP_KERNEL); |
196 | if (!prop->src_dpn_prop) |
197 | return -ENOMEM; |
198 | |
199 | i = 0; |
200 | dpn = prop->src_dpn_prop; |
201 | addr = prop->source_ports; |
202 | for_each_set_bit(bit, &addr, 32) { |
203 | dpn[i].num = bit; |
204 | dpn[i].type = SDW_DPN_FULL; |
205 | dpn[i].simple_ch_prep_sm = true; |
206 | dpn[i].ch_prep_timeout = 10; |
207 | i++; |
208 | } |
209 | |
210 | /* do this again for sink now */ |
211 | nval = hweight32(prop->sink_ports); |
212 | prop->sink_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
213 | size: sizeof(*prop->sink_dpn_prop), GFP_KERNEL); |
214 | if (!prop->sink_dpn_prop) |
215 | return -ENOMEM; |
216 | |
217 | j = 0; |
218 | dpn = prop->sink_dpn_prop; |
219 | addr = prop->sink_ports; |
220 | for_each_set_bit(bit, &addr, 32) { |
221 | dpn[j].num = bit; |
222 | dpn[j].type = SDW_DPN_FULL; |
223 | dpn[j].simple_ch_prep_sm = true; |
224 | dpn[j].ch_prep_timeout = 10; |
225 | j++; |
226 | } |
227 | |
228 | /* set the timeout values */ |
229 | prop->clk_stop_timeout = 700; |
230 | |
231 | /* wake-up event */ |
232 | prop->wake_capable = 1; |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | static int rt711_sdca_interrupt_callback(struct sdw_slave *slave, |
238 | struct sdw_slave_intr_status *status) |
239 | { |
240 | struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev: &slave->dev); |
241 | int ret, stat; |
242 | int count = 0, retry = 3; |
243 | unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; |
244 | |
245 | dev_dbg(&slave->dev, |
246 | "%s control_port_stat=%x, sdca_cascade=%x" , __func__, |
247 | status->control_port, status->sdca_cascade); |
248 | |
249 | if (cancel_delayed_work_sync(dwork: &rt711->jack_detect_work)) { |
250 | dev_warn(&slave->dev, "%s the pending delayed_work was cancelled" , __func__); |
251 | /* avoid the HID owner doesn't change to device */ |
252 | if (rt711->scp_sdca_stat2) |
253 | scp_sdca_stat2 = rt711->scp_sdca_stat2; |
254 | } |
255 | |
256 | /* |
257 | * The critical section below intentionally protects a rather large piece of code. |
258 | * We don't want to allow the system suspend to disable an interrupt while we are |
259 | * processing it, which could be problematic given the quirky SoundWire interrupt |
260 | * scheme. We do want however to prevent new workqueues from being scheduled if |
261 | * the disable_irq flag was set during system suspend. |
262 | */ |
263 | mutex_lock(&rt711->disable_irq_lock); |
264 | |
265 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT1); |
266 | if (ret < 0) |
267 | goto io_error; |
268 | rt711->scp_sdca_stat1 = ret; |
269 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT2); |
270 | if (ret < 0) |
271 | goto io_error; |
272 | rt711->scp_sdca_stat2 = ret; |
273 | if (scp_sdca_stat2) |
274 | rt711->scp_sdca_stat2 |= scp_sdca_stat2; |
275 | |
276 | do { |
277 | /* clear flag */ |
278 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT1); |
279 | if (ret < 0) |
280 | goto io_error; |
281 | if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { |
282 | ret = sdw_write_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT1, |
283 | SDW_SCP_SDCA_INTMASK_SDCA_0); |
284 | if (ret < 0) |
285 | goto io_error; |
286 | } |
287 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT2); |
288 | if (ret < 0) |
289 | goto io_error; |
290 | if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { |
291 | ret = sdw_write_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT2, |
292 | SDW_SCP_SDCA_INTMASK_SDCA_8); |
293 | if (ret < 0) |
294 | goto io_error; |
295 | } |
296 | |
297 | /* check if flag clear or not */ |
298 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_DP0_INT); |
299 | if (ret < 0) |
300 | goto io_error; |
301 | sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; |
302 | |
303 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT1); |
304 | if (ret < 0) |
305 | goto io_error; |
306 | scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; |
307 | |
308 | ret = sdw_read_no_pm(slave: rt711->slave, SDW_SCP_SDCA_INT2); |
309 | if (ret < 0) |
310 | goto io_error; |
311 | scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; |
312 | |
313 | stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; |
314 | |
315 | count++; |
316 | } while (stat != 0 && count < retry); |
317 | |
318 | if (stat) |
319 | dev_warn(&slave->dev, |
320 | "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n" , __func__, |
321 | rt711->scp_sdca_stat1, rt711->scp_sdca_stat2); |
322 | |
323 | if (status->sdca_cascade && !rt711->disable_irq) |
324 | mod_delayed_work(wq: system_power_efficient_wq, |
325 | dwork: &rt711->jack_detect_work, delay: msecs_to_jiffies(m: 30)); |
326 | |
327 | mutex_unlock(lock: &rt711->disable_irq_lock); |
328 | |
329 | return 0; |
330 | |
331 | io_error: |
332 | mutex_unlock(lock: &rt711->disable_irq_lock); |
333 | pr_err_ratelimited("IO error in %s, ret %d\n" , __func__, ret); |
334 | return ret; |
335 | } |
336 | |
337 | static const struct sdw_slave_ops rt711_sdca_slave_ops = { |
338 | .read_prop = rt711_sdca_read_prop, |
339 | .interrupt_callback = rt711_sdca_interrupt_callback, |
340 | .update_status = rt711_sdca_update_status, |
341 | }; |
342 | |
343 | static int rt711_sdca_sdw_probe(struct sdw_slave *slave, |
344 | const struct sdw_device_id *id) |
345 | { |
346 | struct regmap *regmap, *mbq_regmap; |
347 | |
348 | /* Regmap Initialization */ |
349 | mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt711_sdca_mbq_regmap); |
350 | if (IS_ERR(ptr: mbq_regmap)) |
351 | return PTR_ERR(ptr: mbq_regmap); |
352 | |
353 | regmap = devm_regmap_init_sdw(slave, &rt711_sdca_regmap); |
354 | if (IS_ERR(ptr: regmap)) |
355 | return PTR_ERR(ptr: regmap); |
356 | |
357 | return rt711_sdca_init(dev: &slave->dev, regmap, mbq_regmap, slave); |
358 | } |
359 | |
360 | static int rt711_sdca_sdw_remove(struct sdw_slave *slave) |
361 | { |
362 | struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev: &slave->dev); |
363 | |
364 | if (rt711->hw_init) { |
365 | cancel_delayed_work_sync(dwork: &rt711->jack_detect_work); |
366 | cancel_delayed_work_sync(dwork: &rt711->jack_btn_check_work); |
367 | } |
368 | |
369 | pm_runtime_disable(dev: &slave->dev); |
370 | |
371 | mutex_destroy(lock: &rt711->calibrate_mutex); |
372 | mutex_destroy(lock: &rt711->disable_irq_lock); |
373 | |
374 | return 0; |
375 | } |
376 | |
377 | static const struct sdw_device_id rt711_sdca_id[] = { |
378 | SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x3, 0x1, 0), |
379 | {}, |
380 | }; |
381 | MODULE_DEVICE_TABLE(sdw, rt711_sdca_id); |
382 | |
383 | static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev) |
384 | { |
385 | struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); |
386 | |
387 | if (!rt711->hw_init) |
388 | return 0; |
389 | |
390 | cancel_delayed_work_sync(dwork: &rt711->jack_detect_work); |
391 | cancel_delayed_work_sync(dwork: &rt711->jack_btn_check_work); |
392 | |
393 | regcache_cache_only(map: rt711->regmap, enable: true); |
394 | regcache_cache_only(map: rt711->mbq_regmap, enable: true); |
395 | |
396 | return 0; |
397 | } |
398 | |
399 | static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev) |
400 | { |
401 | struct rt711_sdca_priv *rt711_sdca = dev_get_drvdata(dev); |
402 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
403 | int ret1, ret2; |
404 | |
405 | if (!rt711_sdca->hw_init) |
406 | return 0; |
407 | |
408 | /* |
409 | * prevent new interrupts from being handled after the |
410 | * deferred work completes and before the parent disables |
411 | * interrupts on the link |
412 | */ |
413 | mutex_lock(&rt711_sdca->disable_irq_lock); |
414 | rt711_sdca->disable_irq = true; |
415 | ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, |
416 | SDW_SCP_SDCA_INTMASK_SDCA_0, val: 0); |
417 | ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, |
418 | SDW_SCP_SDCA_INTMASK_SDCA_8, val: 0); |
419 | mutex_unlock(lock: &rt711_sdca->disable_irq_lock); |
420 | |
421 | if (ret1 < 0 || ret2 < 0) { |
422 | /* log but don't prevent suspend from happening */ |
423 | dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:" , __func__); |
424 | } |
425 | |
426 | return rt711_sdca_dev_suspend(dev); |
427 | } |
428 | |
429 | #define RT711_PROBE_TIMEOUT 5000 |
430 | |
431 | static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) |
432 | { |
433 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
434 | struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); |
435 | unsigned long time; |
436 | |
437 | if (!rt711->first_hw_init) |
438 | return 0; |
439 | |
440 | if (!slave->unattach_request) { |
441 | mutex_lock(&rt711->disable_irq_lock); |
442 | if (rt711->disable_irq == true) { |
443 | sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); |
444 | sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); |
445 | rt711->disable_irq = false; |
446 | } |
447 | mutex_unlock(lock: &rt711->disable_irq_lock); |
448 | goto regmap_sync; |
449 | } |
450 | |
451 | time = wait_for_completion_timeout(x: &slave->initialization_complete, |
452 | timeout: msecs_to_jiffies(RT711_PROBE_TIMEOUT)); |
453 | if (!time) { |
454 | dev_err(&slave->dev, "%s: Initialization not complete, timed out\n" , __func__); |
455 | sdw_show_ping_status(bus: slave->bus, sync_delay: true); |
456 | |
457 | return -ETIMEDOUT; |
458 | } |
459 | |
460 | regmap_sync: |
461 | slave->unattach_request = 0; |
462 | regcache_cache_only(map: rt711->regmap, enable: false); |
463 | regcache_sync(map: rt711->regmap); |
464 | regcache_cache_only(map: rt711->mbq_regmap, enable: false); |
465 | regcache_sync(map: rt711->mbq_regmap); |
466 | return 0; |
467 | } |
468 | |
469 | static const struct dev_pm_ops rt711_sdca_pm = { |
470 | SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume) |
471 | SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL) |
472 | }; |
473 | |
474 | static struct sdw_driver rt711_sdca_sdw_driver = { |
475 | .driver = { |
476 | .name = "rt711-sdca" , |
477 | .owner = THIS_MODULE, |
478 | .pm = &rt711_sdca_pm, |
479 | }, |
480 | .probe = rt711_sdca_sdw_probe, |
481 | .remove = rt711_sdca_sdw_remove, |
482 | .ops = &rt711_sdca_slave_ops, |
483 | .id_table = rt711_sdca_id, |
484 | }; |
485 | module_sdw_driver(rt711_sdca_sdw_driver); |
486 | |
487 | MODULE_DESCRIPTION("ASoC RT711 SDCA SDW driver" ); |
488 | MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>" ); |
489 | MODULE_LICENSE("GPL" ); |
490 | |