1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver |
4 | // |
5 | // Copyright(c) 2020 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.h> |
13 | #include <linux/soundwire/sdw_type.h> |
14 | #include <linux/soundwire/sdw_registers.h> |
15 | #include <linux/module.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/regmap.h> |
18 | #include <sound/soc.h> |
19 | #include "rt715-sdca.h" |
20 | #include "rt715-sdca-sdw.h" |
21 | |
22 | static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg) |
23 | { |
24 | switch (reg) { |
25 | case 0x201a ... 0x2027: |
26 | case 0x2029 ... 0x202a: |
27 | case 0x202d ... 0x2034: |
28 | case 0x2200 ... 0x2204: |
29 | case 0x2206 ... 0x2212: |
30 | case 0x2230 ... 0x2239: |
31 | case 0x2f5b: |
32 | case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, |
33 | RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): |
34 | return true; |
35 | default: |
36 | return false; |
37 | } |
38 | } |
39 | |
40 | static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg) |
41 | { |
42 | switch (reg) { |
43 | case 0x201b: |
44 | case 0x201c: |
45 | case 0x201d: |
46 | case 0x201f: |
47 | case 0x2021: |
48 | case 0x2023: |
49 | case 0x2230: |
50 | case 0x202d ... 0x202f: /* BRA */ |
51 | case 0x2200 ... 0x2212: /* i2c debug */ |
52 | case 0x2f07: |
53 | case 0x2f1b ... 0x2f1e: |
54 | case 0x2f30 ... 0x2f34: |
55 | case 0x2f50 ... 0x2f51: |
56 | case 0x2f53 ... 0x2f59: |
57 | case 0x2f5c ... 0x2f5f: |
58 | case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, |
59 | RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */ |
60 | return true; |
61 | default: |
62 | return false; |
63 | } |
64 | } |
65 | |
66 | static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg) |
67 | { |
68 | switch (reg) { |
69 | case 0x2000000: |
70 | case 0x200002b: |
71 | case 0x2000036: |
72 | case 0x2000037: |
73 | case 0x2000039: |
74 | case 0x2000044: |
75 | case 0x6100000: |
76 | return true; |
77 | default: |
78 | return false; |
79 | } |
80 | } |
81 | |
82 | static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) |
83 | { |
84 | switch (reg) { |
85 | case 0x2000000: |
86 | return true; |
87 | default: |
88 | return false; |
89 | } |
90 | } |
91 | |
92 | static const struct regmap_config rt715_sdca_regmap = { |
93 | .reg_bits = 32, |
94 | .val_bits = 8, |
95 | .readable_reg = rt715_sdca_readable_register, |
96 | .volatile_reg = rt715_sdca_volatile_register, |
97 | .max_register = 0x43ffffff, |
98 | .reg_defaults = rt715_reg_defaults_sdca, |
99 | .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca), |
100 | .cache_type = REGCACHE_MAPLE, |
101 | .use_single_read = true, |
102 | .use_single_write = true, |
103 | }; |
104 | |
105 | static const struct regmap_config rt715_sdca_mbq_regmap = { |
106 | .name = "sdw-mbq" , |
107 | .reg_bits = 32, |
108 | .val_bits = 16, |
109 | .readable_reg = rt715_sdca_mbq_readable_register, |
110 | .volatile_reg = rt715_sdca_mbq_volatile_register, |
111 | .max_register = 0x43ffffff, |
112 | .reg_defaults = rt715_mbq_reg_defaults_sdca, |
113 | .num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca), |
114 | .cache_type = REGCACHE_MAPLE, |
115 | .use_single_read = true, |
116 | .use_single_write = true, |
117 | }; |
118 | |
119 | static int rt715_sdca_update_status(struct sdw_slave *slave, |
120 | enum sdw_slave_status status) |
121 | { |
122 | struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev: &slave->dev); |
123 | |
124 | /* |
125 | * Perform initialization only if slave status is present and |
126 | * hw_init flag is false |
127 | */ |
128 | if (rt715->hw_init || status != SDW_SLAVE_ATTACHED) |
129 | return 0; |
130 | |
131 | /* perform I/O transfers required for Slave initialization */ |
132 | return rt715_sdca_io_init(dev: &slave->dev, slave); |
133 | } |
134 | |
135 | static int rt715_sdca_read_prop(struct sdw_slave *slave) |
136 | { |
137 | struct sdw_slave_prop *prop = &slave->prop; |
138 | int nval, i; |
139 | u32 bit; |
140 | unsigned long addr; |
141 | struct sdw_dpn_prop *dpn; |
142 | |
143 | prop->paging_support = true; |
144 | |
145 | /* first we need to allocate memory for set bits in port lists */ |
146 | prop->source_ports = 0x50;/* BITMAP: 01010000 */ |
147 | prop->sink_ports = 0x0; /* BITMAP: 00000000 */ |
148 | |
149 | nval = hweight32(prop->source_ports); |
150 | prop->src_dpn_prop = devm_kcalloc(dev: &slave->dev, n: nval, |
151 | size: sizeof(*prop->src_dpn_prop), |
152 | GFP_KERNEL); |
153 | if (!prop->src_dpn_prop) |
154 | return -ENOMEM; |
155 | |
156 | dpn = prop->src_dpn_prop; |
157 | i = 0; |
158 | addr = prop->source_ports; |
159 | for_each_set_bit(bit, &addr, 32) { |
160 | dpn[i].num = bit; |
161 | dpn[i].simple_ch_prep_sm = true; |
162 | dpn[i].ch_prep_timeout = 10; |
163 | i++; |
164 | } |
165 | |
166 | /* set the timeout values */ |
167 | prop->clk_stop_timeout = 200; |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | static const struct sdw_slave_ops rt715_sdca_slave_ops = { |
173 | .read_prop = rt715_sdca_read_prop, |
174 | .update_status = rt715_sdca_update_status, |
175 | }; |
176 | |
177 | static int rt715_sdca_sdw_probe(struct sdw_slave *slave, |
178 | const struct sdw_device_id *id) |
179 | { |
180 | struct regmap *mbq_regmap, *regmap; |
181 | |
182 | /* Regmap Initialization */ |
183 | mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); |
184 | if (IS_ERR(ptr: mbq_regmap)) |
185 | return PTR_ERR(ptr: mbq_regmap); |
186 | |
187 | regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap); |
188 | if (IS_ERR(ptr: regmap)) |
189 | return PTR_ERR(ptr: regmap); |
190 | |
191 | return rt715_sdca_init(dev: &slave->dev, mbq_regmap, regmap, slave); |
192 | } |
193 | |
194 | static int rt715_sdca_sdw_remove(struct sdw_slave *slave) |
195 | { |
196 | pm_runtime_disable(dev: &slave->dev); |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | static const struct sdw_device_id rt715_sdca_id[] = { |
202 | SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0), |
203 | SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0), |
204 | {}, |
205 | }; |
206 | MODULE_DEVICE_TABLE(sdw, rt715_sdca_id); |
207 | |
208 | static int __maybe_unused rt715_dev_suspend(struct device *dev) |
209 | { |
210 | struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); |
211 | |
212 | if (!rt715->hw_init) |
213 | return 0; |
214 | |
215 | regcache_cache_only(map: rt715->regmap, enable: true); |
216 | regcache_mark_dirty(map: rt715->regmap); |
217 | regcache_cache_only(map: rt715->mbq_regmap, enable: true); |
218 | regcache_mark_dirty(map: rt715->mbq_regmap); |
219 | |
220 | return 0; |
221 | } |
222 | |
223 | #define RT715_PROBE_TIMEOUT 5000 |
224 | |
225 | static int __maybe_unused rt715_dev_resume(struct device *dev) |
226 | { |
227 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
228 | struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); |
229 | unsigned long time; |
230 | |
231 | if (!rt715->first_hw_init) |
232 | return 0; |
233 | |
234 | if (!slave->unattach_request) |
235 | goto regmap_sync; |
236 | |
237 | time = wait_for_completion_timeout(x: &slave->enumeration_complete, |
238 | timeout: msecs_to_jiffies(RT715_PROBE_TIMEOUT)); |
239 | if (!time) { |
240 | dev_err(&slave->dev, "%s: Enumeration not complete, timed out\n" , __func__); |
241 | sdw_show_ping_status(bus: slave->bus, sync_delay: true); |
242 | |
243 | return -ETIMEDOUT; |
244 | } |
245 | |
246 | regmap_sync: |
247 | slave->unattach_request = 0; |
248 | regcache_cache_only(map: rt715->regmap, enable: false); |
249 | regcache_sync_region(map: rt715->regmap, |
250 | SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, |
251 | CH_00), |
252 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, |
253 | RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); |
254 | regcache_cache_only(map: rt715->mbq_regmap, enable: false); |
255 | regcache_sync_region(map: rt715->mbq_regmap, min: 0x2000000, max: 0x61020ff); |
256 | regcache_sync_region(map: rt715->mbq_regmap, |
257 | SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, |
258 | CH_00), |
259 | SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, |
260 | RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | static const struct dev_pm_ops rt715_pm = { |
266 | SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) |
267 | SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) |
268 | }; |
269 | |
270 | static struct sdw_driver rt715_sdw_driver = { |
271 | .driver = { |
272 | .name = "rt715-sdca" , |
273 | .owner = THIS_MODULE, |
274 | .pm = &rt715_pm, |
275 | }, |
276 | .probe = rt715_sdca_sdw_probe, |
277 | .remove = rt715_sdca_sdw_remove, |
278 | .ops = &rt715_sdca_slave_ops, |
279 | .id_table = rt715_sdca_id, |
280 | }; |
281 | module_sdw_driver(rt715_sdw_driver); |
282 | |
283 | MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA" ); |
284 | MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>" ); |
285 | MODULE_LICENSE("GPL v2" ); |
286 | |