1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // rt722-sdca-sdw.c -- rt722 SDCA ALSA SoC audio driver |
4 | // |
5 | // Copyright(c) 2023 Realtek Semiconductor Corp. |
6 | // |
7 | // |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/module.h> |
12 | #include <linux/mod_devicetable.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/soundwire/sdw_registers.h> |
15 | |
16 | #include "rt722-sdca.h" |
17 | #include "rt722-sdca-sdw.h" |
18 | |
19 | static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) |
20 | { |
21 | switch (reg) { |
22 | case 0x2f01 ... 0x2f0a: |
23 | case 0x2f35 ... 0x2f36: |
24 | case 0x2f50: |
25 | case 0x2f54: |
26 | case 0x2f58 ... 0x2f5d: |
27 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_SELECTED_MODE, |
28 | 0): |
29 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, |
30 | 0): |
31 | case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, |
32 | 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, |
33 | RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): |
34 | case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: |
35 | return true; |
36 | default: |
37 | return false; |
38 | } |
39 | } |
40 | |
41 | static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg) |
42 | { |
43 | switch (reg) { |
44 | case 0x2f01: |
45 | case 0x2f54: |
46 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, |
47 | 0): |
48 | case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, |
49 | 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, |
50 | RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): |
51 | case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: |
52 | return true; |
53 | default: |
54 | return false; |
55 | } |
56 | } |
57 | |
58 | static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg) |
59 | { |
60 | switch (reg) { |
61 | case 0x2000000 ... 0x2000024: |
62 | case 0x2000029 ... 0x200004a: |
63 | case 0x2000051 ... 0x2000052: |
64 | case 0x200005a ... 0x200005b: |
65 | case 0x2000061 ... 0x2000069: |
66 | case 0x200006b: |
67 | case 0x2000070: |
68 | case 0x200007f: |
69 | case 0x2000082 ... 0x200008e: |
70 | case 0x2000090 ... 0x2000094: |
71 | case 0x5300000 ... 0x5300002: |
72 | case 0x5400002: |
73 | case 0x5600000 ... 0x5600007: |
74 | case 0x5700000 ... 0x5700004: |
75 | case 0x5800000 ... 0x5800004: |
76 | case 0x5b00003: |
77 | case 0x5c00011: |
78 | case 0x5d00006: |
79 | case 0x5f00000 ... 0x5f0000d: |
80 | case 0x5f00030: |
81 | case 0x6100000 ... 0x6100051: |
82 | case 0x6100055 ... 0x6100057: |
83 | case 0x6100062: |
84 | case 0x6100064 ... 0x6100065: |
85 | case 0x6100067: |
86 | case 0x6100070 ... 0x610007c: |
87 | case 0x6100080: |
88 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, |
89 | CH_01): |
90 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, |
91 | CH_02): |
92 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, |
93 | CH_03): |
94 | case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, |
95 | CH_04): |
96 | case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L): |
97 | case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R): |
98 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, |
99 | CH_L): |
100 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, |
101 | CH_R): |
102 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, |
103 | CH_L): |
104 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, |
105 | CH_R): |
106 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, |
107 | RT722_SDCA_CTL_FU_CH_GAIN, CH_L): |
108 | case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, |
109 | RT722_SDCA_CTL_FU_CH_GAIN, CH_R): |
110 | return true; |
111 | default: |
112 | return false; |
113 | } |
114 | } |
115 | |
116 | static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) |
117 | { |
118 | switch (reg) { |
119 | case 0x2000000: |
120 | case 0x200000d: |
121 | case 0x2000019: |
122 | case 0x2000020: |
123 | case 0x2000030: |
124 | case 0x2000046: |
125 | case 0x2000067: |
126 | case 0x2000084: |
127 | case 0x2000086: |
128 | return true; |
129 | default: |
130 | return false; |
131 | } |
132 | } |
133 | |
134 | static const struct regmap_config rt722_sdca_regmap = { |
135 | .reg_bits = 32, |
136 | .val_bits = 8, |
137 | .readable_reg = rt722_sdca_readable_register, |
138 | .volatile_reg = rt722_sdca_volatile_register, |
139 | .max_register = 0x44ffffff, |
140 | .reg_defaults = rt722_sdca_reg_defaults, |
141 | .num_reg_defaults = ARRAY_SIZE(rt722_sdca_reg_defaults), |
142 | .cache_type = REGCACHE_MAPLE, |
143 | .use_single_read = true, |
144 | .use_single_write = true, |
145 | }; |
146 | |
147 | static const struct regmap_config rt722_sdca_mbq_regmap = { |
148 | .name = "sdw-mbq" , |
149 | .reg_bits = 32, |
150 | .val_bits = 16, |
151 | .readable_reg = rt722_sdca_mbq_readable_register, |
152 | .volatile_reg = rt722_sdca_mbq_volatile_register, |
153 | .max_register = 0x41000312, |
154 | .reg_defaults = rt722_sdca_mbq_defaults, |
155 | .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults), |
156 | .cache_type = REGCACHE_MAPLE, |
157 | .use_single_read = true, |
158 | .use_single_write = true, |
159 | }; |
160 | |
161 | static int rt722_sdca_update_status(struct sdw_slave *slave, |
162 | enum sdw_slave_status status) |
163 | { |
164 | struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev: &slave->dev); |
165 | |
166 | if (status == SDW_SLAVE_UNATTACHED) |
167 | rt722->hw_init = false; |
168 | |
169 | if (status == SDW_SLAVE_ATTACHED) { |
170 | if (rt722->hs_jack) { |
171 | /* |
172 | * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then |
173 | * if the device attached again, we will need to set the setting back. |
174 | * It could avoid losing the jack detection interrupt. |
175 | * This also could sync with the cache value as the rt722_sdca_jack_init set. |
176 | */ |
177 | sdw_write_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INTMASK1, |
178 | SDW_SCP_SDCA_INTMASK_SDCA_6); |
179 | sdw_write_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INTMASK2, |
180 | SDW_SCP_SDCA_INTMASK_SDCA_8); |
181 | } |
182 | } |
183 | |
184 | /* |
185 | * Perform initialization only if slave status is present and |
186 | * hw_init flag is false |
187 | */ |
188 | if (rt722->hw_init || status != SDW_SLAVE_ATTACHED) |
189 | return 0; |
190 | |
191 | /* perform I/O transfers required for Slave initialization */ |
192 | return rt722_sdca_io_init(dev: &slave->dev, slave); |
193 | } |
194 | |
195 | static int rt722_sdca_read_prop(struct sdw_slave *slave) |
196 | { |
197 | struct sdw_slave_prop *prop = &slave->prop; |
198 | int nval; |
199 | int i, j; |
200 | u32 bit; |
201 | unsigned long addr; |
202 | struct sdw_dpn_prop *dpn; |
203 | |
204 | prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; |
205 | prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; |
206 | |
207 | prop->paging_support = true; |
208 | |
209 | /* |
210 | * port = 1 for headphone playback |
211 | * port = 2 for headset-mic capture |
212 | * port = 3 for speaker playback |
213 | * port = 6 for digital-mic capture |
214 | */ |
215 | prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */ |
216 | prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ |
217 | |
218 | nval = hweight32(prop->source_ports); |
219 | prop->src_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
220 | size: sizeof(*prop->src_dpn_prop), GFP_KERNEL); |
221 | if (!prop->src_dpn_prop) |
222 | return -ENOMEM; |
223 | |
224 | i = 0; |
225 | dpn = prop->src_dpn_prop; |
226 | addr = prop->source_ports; |
227 | for_each_set_bit(bit, &addr, 32) { |
228 | dpn[i].num = bit; |
229 | dpn[i].type = SDW_DPN_FULL; |
230 | dpn[i].simple_ch_prep_sm = true; |
231 | dpn[i].ch_prep_timeout = 10; |
232 | i++; |
233 | } |
234 | |
235 | /* do this again for sink now */ |
236 | nval = hweight32(prop->sink_ports); |
237 | prop->sink_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
238 | size: sizeof(*prop->sink_dpn_prop), GFP_KERNEL); |
239 | if (!prop->sink_dpn_prop) |
240 | return -ENOMEM; |
241 | |
242 | j = 0; |
243 | dpn = prop->sink_dpn_prop; |
244 | addr = prop->sink_ports; |
245 | for_each_set_bit(bit, &addr, 32) { |
246 | dpn[j].num = bit; |
247 | dpn[j].type = SDW_DPN_FULL; |
248 | dpn[j].simple_ch_prep_sm = true; |
249 | dpn[j].ch_prep_timeout = 10; |
250 | j++; |
251 | } |
252 | |
253 | /* set the timeout values */ |
254 | prop->clk_stop_timeout = 200; |
255 | |
256 | /* wake-up event */ |
257 | prop->wake_capable = 1; |
258 | |
259 | /* Three data lanes are supported by rt722-sdca codec */ |
260 | prop->lane_control_support = true; |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | static int rt722_sdca_interrupt_callback(struct sdw_slave *slave, |
266 | struct sdw_slave_intr_status *status) |
267 | { |
268 | struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev: &slave->dev); |
269 | int ret, stat; |
270 | int count = 0, retry = 3; |
271 | unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; |
272 | |
273 | if (cancel_delayed_work_sync(dwork: &rt722->jack_detect_work)) { |
274 | dev_warn(&slave->dev, "%s the pending delayed_work was cancelled" , __func__); |
275 | /* avoid the HID owner doesn't change to device */ |
276 | if (rt722->scp_sdca_stat2) |
277 | scp_sdca_stat2 = rt722->scp_sdca_stat2; |
278 | } |
279 | |
280 | /* |
281 | * The critical section below intentionally protects a rather large piece of code. |
282 | * We don't want to allow the system suspend to disable an interrupt while we are |
283 | * processing it, which could be problematic given the quirky SoundWire interrupt |
284 | * scheme. We do want however to prevent new workqueues from being scheduled if |
285 | * the disable_irq flag was set during system suspend. |
286 | */ |
287 | mutex_lock(&rt722->disable_irq_lock); |
288 | |
289 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT1); |
290 | if (ret < 0) |
291 | goto io_error; |
292 | rt722->scp_sdca_stat1 = ret; |
293 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT2); |
294 | if (ret < 0) |
295 | goto io_error; |
296 | rt722->scp_sdca_stat2 = ret; |
297 | if (scp_sdca_stat2) |
298 | rt722->scp_sdca_stat2 |= scp_sdca_stat2; |
299 | do { |
300 | /* clear flag */ |
301 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT1); |
302 | if (ret < 0) |
303 | goto io_error; |
304 | if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { |
305 | ret = sdw_update_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT1, |
306 | SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); |
307 | if (ret < 0) |
308 | goto io_error; |
309 | } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) { |
310 | ret = sdw_update_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT1, |
311 | SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6); |
312 | if (ret < 0) |
313 | goto io_error; |
314 | } |
315 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT2); |
316 | if (ret < 0) |
317 | goto io_error; |
318 | if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { |
319 | ret = sdw_write_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT2, |
320 | SDW_SCP_SDCA_INTMASK_SDCA_8); |
321 | if (ret < 0) |
322 | goto io_error; |
323 | } |
324 | |
325 | /* check if flag clear or not */ |
326 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_DP0_INT); |
327 | if (ret < 0) |
328 | goto io_error; |
329 | sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; |
330 | |
331 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT1); |
332 | if (ret < 0) |
333 | goto io_error; |
334 | scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; |
335 | |
336 | ret = sdw_read_no_pm(slave: rt722->slave, SDW_SCP_SDCA_INT2); |
337 | if (ret < 0) |
338 | goto io_error; |
339 | scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; |
340 | |
341 | stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; |
342 | |
343 | count++; |
344 | } while (stat != 0 && count < retry); |
345 | |
346 | if (stat) |
347 | dev_warn(&slave->dev, |
348 | "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n" , __func__, |
349 | rt722->scp_sdca_stat1, rt722->scp_sdca_stat2); |
350 | |
351 | if (status->sdca_cascade && !rt722->disable_irq) |
352 | mod_delayed_work(wq: system_power_efficient_wq, |
353 | dwork: &rt722->jack_detect_work, delay: msecs_to_jiffies(m: 30)); |
354 | |
355 | mutex_unlock(lock: &rt722->disable_irq_lock); |
356 | |
357 | return 0; |
358 | |
359 | io_error: |
360 | mutex_unlock(lock: &rt722->disable_irq_lock); |
361 | pr_err_ratelimited("IO error in %s, ret %d\n" , __func__, ret); |
362 | return ret; |
363 | } |
364 | |
365 | static const struct sdw_slave_ops rt722_sdca_slave_ops = { |
366 | .read_prop = rt722_sdca_read_prop, |
367 | .interrupt_callback = rt722_sdca_interrupt_callback, |
368 | .update_status = rt722_sdca_update_status, |
369 | }; |
370 | |
371 | static int rt722_sdca_sdw_probe(struct sdw_slave *slave, |
372 | const struct sdw_device_id *id) |
373 | { |
374 | struct regmap *regmap, *mbq_regmap; |
375 | |
376 | /* Regmap Initialization */ |
377 | mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt722_sdca_mbq_regmap); |
378 | if (IS_ERR(ptr: mbq_regmap)) |
379 | return PTR_ERR(ptr: mbq_regmap); |
380 | |
381 | regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap); |
382 | if (IS_ERR(ptr: regmap)) |
383 | return PTR_ERR(ptr: regmap); |
384 | |
385 | return rt722_sdca_init(dev: &slave->dev, regmap, mbq_regmap, slave); |
386 | } |
387 | |
388 | static int rt722_sdca_sdw_remove(struct sdw_slave *slave) |
389 | { |
390 | struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev: &slave->dev); |
391 | |
392 | if (rt722->hw_init) { |
393 | cancel_delayed_work_sync(dwork: &rt722->jack_detect_work); |
394 | cancel_delayed_work_sync(dwork: &rt722->jack_btn_check_work); |
395 | } |
396 | |
397 | if (rt722->first_hw_init) |
398 | pm_runtime_disable(dev: &slave->dev); |
399 | |
400 | mutex_destroy(lock: &rt722->calibrate_mutex); |
401 | mutex_destroy(lock: &rt722->disable_irq_lock); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static const struct sdw_device_id rt722_sdca_id[] = { |
407 | SDW_SLAVE_ENTRY_EXT(0x025d, 0x722, 0x3, 0x1, 0), |
408 | {}, |
409 | }; |
410 | MODULE_DEVICE_TABLE(sdw, rt722_sdca_id); |
411 | |
412 | static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev) |
413 | { |
414 | struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); |
415 | |
416 | if (!rt722->hw_init) |
417 | return 0; |
418 | |
419 | cancel_delayed_work_sync(dwork: &rt722->jack_detect_work); |
420 | cancel_delayed_work_sync(dwork: &rt722->jack_btn_check_work); |
421 | |
422 | regcache_cache_only(map: rt722->regmap, enable: true); |
423 | regcache_cache_only(map: rt722->mbq_regmap, enable: true); |
424 | |
425 | return 0; |
426 | } |
427 | |
428 | static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) |
429 | { |
430 | struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev); |
431 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
432 | int ret1, ret2; |
433 | |
434 | if (!rt722_sdca->hw_init) |
435 | return 0; |
436 | |
437 | /* |
438 | * prevent new interrupts from being handled after the |
439 | * deferred work completes and before the parent disables |
440 | * interrupts on the link |
441 | */ |
442 | mutex_lock(&rt722_sdca->disable_irq_lock); |
443 | rt722_sdca->disable_irq = true; |
444 | ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, |
445 | SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, val: 0); |
446 | ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, |
447 | SDW_SCP_SDCA_INTMASK_SDCA_8, val: 0); |
448 | mutex_unlock(lock: &rt722_sdca->disable_irq_lock); |
449 | |
450 | if (ret1 < 0 || ret2 < 0) { |
451 | /* log but don't prevent suspend from happening */ |
452 | dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:" , __func__); |
453 | } |
454 | |
455 | return rt722_sdca_dev_suspend(dev); |
456 | } |
457 | |
458 | #define RT722_PROBE_TIMEOUT 5000 |
459 | |
460 | static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) |
461 | { |
462 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
463 | struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); |
464 | unsigned long time; |
465 | |
466 | if (!rt722->first_hw_init) |
467 | return 0; |
468 | |
469 | if (!slave->unattach_request) { |
470 | mutex_lock(&rt722->disable_irq_lock); |
471 | if (rt722->disable_irq == true) { |
472 | sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6); |
473 | sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); |
474 | rt722->disable_irq = false; |
475 | } |
476 | mutex_unlock(lock: &rt722->disable_irq_lock); |
477 | goto regmap_sync; |
478 | } |
479 | |
480 | time = wait_for_completion_timeout(x: &slave->initialization_complete, |
481 | timeout: msecs_to_jiffies(RT722_PROBE_TIMEOUT)); |
482 | if (!time) { |
483 | dev_err(&slave->dev, "Initialization not complete, timed out\n" ); |
484 | sdw_show_ping_status(bus: slave->bus, sync_delay: true); |
485 | |
486 | return -ETIMEDOUT; |
487 | } |
488 | |
489 | regmap_sync: |
490 | slave->unattach_request = 0; |
491 | regcache_cache_only(map: rt722->regmap, enable: false); |
492 | regcache_sync(map: rt722->regmap); |
493 | regcache_cache_only(map: rt722->mbq_regmap, enable: false); |
494 | regcache_sync(map: rt722->mbq_regmap); |
495 | return 0; |
496 | } |
497 | |
498 | static const struct dev_pm_ops rt722_sdca_pm = { |
499 | SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume) |
500 | SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL) |
501 | }; |
502 | |
503 | static struct sdw_driver rt722_sdca_sdw_driver = { |
504 | .driver = { |
505 | .name = "rt722-sdca" , |
506 | .owner = THIS_MODULE, |
507 | .pm = &rt722_sdca_pm, |
508 | }, |
509 | .probe = rt722_sdca_sdw_probe, |
510 | .remove = rt722_sdca_sdw_remove, |
511 | .ops = &rt722_sdca_slave_ops, |
512 | .id_table = rt722_sdca_id, |
513 | }; |
514 | module_sdw_driver(rt722_sdca_sdw_driver); |
515 | |
516 | MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver" ); |
517 | MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>" ); |
518 | MODULE_LICENSE("GPL" ); |
519 | |