Commit | Line | Data |
---|---|---|
56d4fe31 VK |
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
2 | // Copyright(c) 2015-17 Intel Corporation. | |
3 | ||
4 | /* | |
5 | * MIPI Discovery And Configuration (DisCo) Specification for SoundWire | |
6 | * specifies properties to be implemented for SoundWire Masters and Slaves. | |
7 | * The DisCo spec doesn't mandate these properties. However, SDW bus cannot | |
8 | * work without knowing these values. | |
9 | * | |
10 | * The helper functions read the Master and Slave properties. Implementers | |
11 | * of Master or Slave drivers can use any of the below three mechanisms: | |
12 | * a) Use these APIs here as .read_prop() callback for Master and Slave | |
13 | * b) Implement own methods and set those as .read_prop(), but invoke | |
14 | * APIs in this file for generic read and override the values with | |
15 | * platform specific data | |
16 | * c) Implement ones own methods which do not use anything provided | |
17 | * here | |
18 | */ | |
19 | ||
20 | #include <linux/device.h> | |
21 | #include <linux/property.h> | |
22 | #include <linux/mod_devicetable.h> | |
23 | #include <linux/soundwire/sdw.h> | |
24 | #include "bus.h" | |
25 | ||
093227bc PLB |
26 | static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode, |
27 | const char *propname) | |
28 | { | |
29 | int ret; | |
30 | u8 val; | |
31 | ||
32 | if (!fwnode_property_present(fwnode, propname)) | |
33 | return false; | |
34 | ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1); | |
35 | if (ret < 0) | |
36 | return false; | |
37 | return !!val; | |
38 | } | |
39 | ||
40 | static bool mipi_device_property_read_bool(const struct device *dev, | |
41 | const char *propname) | |
42 | { | |
43 | return mipi_fwnode_property_read_bool(dev_fwnode(dev), propname); | |
44 | } | |
45 | ||
56d4fe31 VK |
46 | /** |
47 | * sdw_master_read_prop() - Read Master properties | |
48 | * @bus: SDW bus instance | |
49 | */ | |
50 | int sdw_master_read_prop(struct sdw_bus *bus) | |
51 | { | |
52 | struct sdw_master_prop *prop = &bus->prop; | |
53 | struct fwnode_handle *link; | |
89e95be1 | 54 | const char *scales_prop; |
56d4fe31 | 55 | char name[32]; |
a489afc1 PLB |
56 | int nval; |
57 | int ret; | |
58 | int i; | |
56d4fe31 VK |
59 | |
60 | device_property_read_u32(bus->dev, | |
31dba312 PLB |
61 | "mipi-sdw-sw-interface-revision", |
62 | &prop->revision); | |
56d4fe31 VK |
63 | |
64 | /* Find master handle */ | |
65 | snprintf(name, sizeof(name), | |
eadc0049 | 66 | "mipi-sdw-link-%d-subproperties", bus->link_id); |
56d4fe31 VK |
67 | |
68 | link = device_get_named_child_node(bus->dev, name); | |
69 | if (!link) { | |
70 | dev_err(bus->dev, "Master node %s not found\n", name); | |
71 | return -EIO; | |
72 | } | |
73 | ||
093227bc | 74 | if (mipi_fwnode_property_read_bool(link, |
00910f3c | 75 | "mipi-sdw-clock-stop-mode0-supported")) |
53d2e9c3 | 76 | prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0); |
56d4fe31 | 77 | |
093227bc | 78 | if (mipi_fwnode_property_read_bool(link, |
00910f3c | 79 | "mipi-sdw-clock-stop-mode1-supported")) |
53d2e9c3 | 80 | prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1); |
56d4fe31 VK |
81 | |
82 | fwnode_property_read_u32(link, | |
31dba312 | 83 | "mipi-sdw-max-clock-frequency", |
3424305b | 84 | &prop->max_clk_freq); |
56d4fe31 | 85 | |
be46cfba | 86 | nval = fwnode_property_count_u32(link, "mipi-sdw-clock-frequencies-supported"); |
56d4fe31 | 87 | if (nval > 0) { |
3424305b PLB |
88 | prop->num_clk_freq = nval; |
89 | prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq, | |
90 | sizeof(*prop->clk_freq), | |
91 | GFP_KERNEL); | |
e2d8ea0a PLB |
92 | if (!prop->clk_freq) { |
93 | fwnode_handle_put(link); | |
56d4fe31 | 94 | return -ENOMEM; |
e2d8ea0a | 95 | } |
56d4fe31 | 96 | |
a489afc1 | 97 | ret = fwnode_property_read_u32_array(link, |
56d4fe31 | 98 | "mipi-sdw-clock-frequencies-supported", |
3424305b | 99 | prop->clk_freq, prop->num_clk_freq); |
a489afc1 PLB |
100 | if (ret < 0) |
101 | return ret; | |
56d4fe31 VK |
102 | } |
103 | ||
104 | /* | |
105 | * Check the frequencies supported. If FW doesn't provide max | |
106 | * freq, then populate here by checking values. | |
107 | */ | |
3424305b PLB |
108 | if (!prop->max_clk_freq && prop->clk_freq) { |
109 | prop->max_clk_freq = prop->clk_freq[0]; | |
110 | for (i = 1; i < prop->num_clk_freq; i++) { | |
111 | if (prop->clk_freq[i] > prop->max_clk_freq) | |
112 | prop->max_clk_freq = prop->clk_freq[i]; | |
56d4fe31 VK |
113 | } |
114 | } | |
115 | ||
89e95be1 PLB |
116 | scales_prop = "mipi-sdw-supported-clock-scales"; |
117 | nval = fwnode_property_count_u32(link, scales_prop); | |
118 | if (nval == 0) { | |
119 | scales_prop = "mipi-sdw-supported-clock-gears"; | |
120 | nval = fwnode_property_count_u32(link, scales_prop); | |
121 | } | |
56d4fe31 | 122 | if (nval > 0) { |
56d4fe31 VK |
123 | prop->num_clk_gears = nval; |
124 | prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears, | |
31dba312 PLB |
125 | sizeof(*prop->clk_gears), |
126 | GFP_KERNEL); | |
e2d8ea0a PLB |
127 | if (!prop->clk_gears) { |
128 | fwnode_handle_put(link); | |
56d4fe31 | 129 | return -ENOMEM; |
e2d8ea0a | 130 | } |
56d4fe31 | 131 | |
a489afc1 | 132 | ret = fwnode_property_read_u32_array(link, |
89e95be1 | 133 | scales_prop, |
31dba312 PLB |
134 | prop->clk_gears, |
135 | prop->num_clk_gears); | |
a489afc1 PLB |
136 | if (ret < 0) |
137 | return ret; | |
56d4fe31 VK |
138 | } |
139 | ||
140 | fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", | |
31dba312 | 141 | &prop->default_frame_rate); |
56d4fe31 VK |
142 | |
143 | fwnode_property_read_u32(link, "mipi-sdw-default-frame-row-size", | |
31dba312 | 144 | &prop->default_row); |
56d4fe31 VK |
145 | |
146 | fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", | |
31dba312 | 147 | &prop->default_col); |
56d4fe31 | 148 | |
093227bc | 149 | prop->dynamic_frame = mipi_fwnode_property_read_bool(link, |
56d4fe31 VK |
150 | "mipi-sdw-dynamic-frame-shape"); |
151 | ||
152 | fwnode_property_read_u32(link, "mipi-sdw-command-error-threshold", | |
31dba312 | 153 | &prop->err_threshold); |
56d4fe31 | 154 | |
e2d8ea0a PLB |
155 | fwnode_handle_put(link); |
156 | ||
56d4fe31 VK |
157 | return 0; |
158 | } | |
159 | EXPORT_SYMBOL(sdw_master_read_prop); | |
160 | ||
161 | static int sdw_slave_read_dp0(struct sdw_slave *slave, | |
31dba312 PLB |
162 | struct fwnode_handle *port, |
163 | struct sdw_dp0_prop *dp0) | |
56d4fe31 VK |
164 | { |
165 | int nval; | |
a489afc1 | 166 | int ret; |
56d4fe31 VK |
167 | |
168 | fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength", | |
31dba312 | 169 | &dp0->max_word); |
56d4fe31 VK |
170 | |
171 | fwnode_property_read_u32(port, "mipi-sdw-port-min-wordlength", | |
31dba312 | 172 | &dp0->min_word); |
56d4fe31 | 173 | |
be46cfba | 174 | nval = fwnode_property_count_u32(port, "mipi-sdw-port-wordlength-configs"); |
56d4fe31 VK |
175 | if (nval > 0) { |
176 | ||
177 | dp0->num_words = nval; | |
178 | dp0->words = devm_kcalloc(&slave->dev, | |
31dba312 PLB |
179 | dp0->num_words, sizeof(*dp0->words), |
180 | GFP_KERNEL); | |
56d4fe31 VK |
181 | if (!dp0->words) |
182 | return -ENOMEM; | |
183 | ||
a489afc1 | 184 | ret = fwnode_property_read_u32_array(port, |
56d4fe31 VK |
185 | "mipi-sdw-port-wordlength-configs", |
186 | dp0->words, dp0->num_words); | |
a489afc1 PLB |
187 | if (ret < 0) |
188 | return ret; | |
56d4fe31 VK |
189 | } |
190 | ||
093227bc | 191 | dp0->BRA_flow_controlled = mipi_fwnode_property_read_bool(port, |
31dba312 | 192 | "mipi-sdw-bra-flow-controlled"); |
56d4fe31 | 193 | |
093227bc | 194 | dp0->simple_ch_prep_sm = mipi_fwnode_property_read_bool(port, |
31dba312 | 195 | "mipi-sdw-simplified-channel-prepare-sm"); |
56d4fe31 | 196 | |
093227bc | 197 | dp0->imp_def_interrupts = mipi_fwnode_property_read_bool(port, |
31dba312 | 198 | "mipi-sdw-imp-def-dp0-interrupts-supported"); |
56d4fe31 | 199 | |
71b405b1 PLB |
200 | nval = fwnode_property_count_u32(port, "mipi-sdw-lane-list"); |
201 | if (nval > 0) { | |
202 | dp0->num_lanes = nval; | |
203 | dp0->lane_list = devm_kcalloc(&slave->dev, | |
204 | dp0->num_lanes, sizeof(*dp0->lane_list), | |
205 | GFP_KERNEL); | |
206 | if (!dp0->lane_list) | |
207 | return -ENOMEM; | |
208 | ||
209 | ret = fwnode_property_read_u32_array(port, | |
210 | "mipi-sdw-lane-list", | |
211 | dp0->lane_list, dp0->num_lanes); | |
212 | if (ret < 0) | |
213 | return ret; | |
214 | } | |
215 | ||
56d4fe31 VK |
216 | return 0; |
217 | } | |
218 | ||
219 | static int sdw_slave_read_dpn(struct sdw_slave *slave, | |
31dba312 PLB |
220 | struct sdw_dpn_prop *dpn, int count, int ports, |
221 | char *type) | |
56d4fe31 VK |
222 | { |
223 | struct fwnode_handle *node; | |
224 | u32 bit, i = 0; | |
56d4fe31 VK |
225 | unsigned long addr; |
226 | char name[40]; | |
a489afc1 PLB |
227 | int nval; |
228 | int ret; | |
56d4fe31 VK |
229 | |
230 | addr = ports; | |
231 | /* valid ports are 1 to 14 so apply mask */ | |
232 | addr &= GENMASK(14, 1); | |
233 | ||
234 | for_each_set_bit(bit, &addr, 32) { | |
235 | snprintf(name, sizeof(name), | |
31dba312 | 236 | "mipi-sdw-dp-%d-%s-subproperties", bit, type); |
56d4fe31 VK |
237 | |
238 | dpn[i].num = bit; | |
239 | ||
240 | node = device_get_named_child_node(&slave->dev, name); | |
241 | if (!node) { | |
242 | dev_err(&slave->dev, "%s dpN not found\n", name); | |
243 | return -EIO; | |
244 | } | |
245 | ||
246 | fwnode_property_read_u32(node, "mipi-sdw-port-max-wordlength", | |
31dba312 | 247 | &dpn[i].max_word); |
56d4fe31 | 248 | fwnode_property_read_u32(node, "mipi-sdw-port-min-wordlength", |
31dba312 | 249 | &dpn[i].min_word); |
56d4fe31 | 250 | |
be46cfba | 251 | nval = fwnode_property_count_u32(node, "mipi-sdw-port-wordlength-configs"); |
56d4fe31 | 252 | if (nval > 0) { |
56d4fe31 VK |
253 | dpn[i].num_words = nval; |
254 | dpn[i].words = devm_kcalloc(&slave->dev, | |
31dba312 PLB |
255 | dpn[i].num_words, |
256 | sizeof(*dpn[i].words), | |
257 | GFP_KERNEL); | |
e2d8ea0a PLB |
258 | if (!dpn[i].words) { |
259 | fwnode_handle_put(node); | |
56d4fe31 | 260 | return -ENOMEM; |
e2d8ea0a | 261 | } |
56d4fe31 | 262 | |
a489afc1 | 263 | ret = fwnode_property_read_u32_array(node, |
56d4fe31 VK |
264 | "mipi-sdw-port-wordlength-configs", |
265 | dpn[i].words, dpn[i].num_words); | |
a489afc1 PLB |
266 | if (ret < 0) |
267 | return ret; | |
56d4fe31 VK |
268 | } |
269 | ||
270 | fwnode_property_read_u32(node, "mipi-sdw-data-port-type", | |
31dba312 | 271 | &dpn[i].type); |
56d4fe31 VK |
272 | |
273 | fwnode_property_read_u32(node, | |
31dba312 PLB |
274 | "mipi-sdw-max-grouping-supported", |
275 | &dpn[i].max_grouping); | |
56d4fe31 | 276 | |
093227bc | 277 | dpn[i].simple_ch_prep_sm = mipi_fwnode_property_read_bool(node, |
56d4fe31 VK |
278 | "mipi-sdw-simplified-channelprepare-sm"); |
279 | ||
280 | fwnode_property_read_u32(node, | |
31dba312 PLB |
281 | "mipi-sdw-port-channelprepare-timeout", |
282 | &dpn[i].ch_prep_timeout); | |
56d4fe31 VK |
283 | |
284 | fwnode_property_read_u32(node, | |
285 | "mipi-sdw-imp-def-dpn-interrupts-supported", | |
8acbbfec | 286 | &dpn[i].imp_def_interrupts); |
56d4fe31 VK |
287 | |
288 | fwnode_property_read_u32(node, "mipi-sdw-min-channel-number", | |
31dba312 | 289 | &dpn[i].min_ch); |
56d4fe31 VK |
290 | |
291 | fwnode_property_read_u32(node, "mipi-sdw-max-channel-number", | |
31dba312 | 292 | &dpn[i].max_ch); |
56d4fe31 | 293 | |
be46cfba | 294 | nval = fwnode_property_count_u32(node, "mipi-sdw-channel-number-list"); |
56d4fe31 | 295 | if (nval > 0) { |
6bf393c5 PLB |
296 | dpn[i].num_channels = nval; |
297 | dpn[i].channels = devm_kcalloc(&slave->dev, | |
298 | dpn[i].num_channels, | |
299 | sizeof(*dpn[i].channels), | |
31dba312 | 300 | GFP_KERNEL); |
e2d8ea0a PLB |
301 | if (!dpn[i].channels) { |
302 | fwnode_handle_put(node); | |
56d4fe31 | 303 | return -ENOMEM; |
e2d8ea0a | 304 | } |
56d4fe31 | 305 | |
a489afc1 | 306 | ret = fwnode_property_read_u32_array(node, |
56d4fe31 | 307 | "mipi-sdw-channel-number-list", |
6bf393c5 | 308 | dpn[i].channels, dpn[i].num_channels); |
a489afc1 PLB |
309 | if (ret < 0) |
310 | return ret; | |
56d4fe31 VK |
311 | } |
312 | ||
be46cfba | 313 | nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list"); |
56d4fe31 | 314 | if (nval > 0) { |
56d4fe31 VK |
315 | dpn[i].num_ch_combinations = nval; |
316 | dpn[i].ch_combinations = devm_kcalloc(&slave->dev, | |
317 | dpn[i].num_ch_combinations, | |
318 | sizeof(*dpn[i].ch_combinations), | |
319 | GFP_KERNEL); | |
e2d8ea0a PLB |
320 | if (!dpn[i].ch_combinations) { |
321 | fwnode_handle_put(node); | |
56d4fe31 | 322 | return -ENOMEM; |
e2d8ea0a | 323 | } |
56d4fe31 | 324 | |
a489afc1 | 325 | ret = fwnode_property_read_u32_array(node, |
56d4fe31 VK |
326 | "mipi-sdw-channel-combination-list", |
327 | dpn[i].ch_combinations, | |
328 | dpn[i].num_ch_combinations); | |
a489afc1 PLB |
329 | if (ret < 0) |
330 | return ret; | |
56d4fe31 VK |
331 | } |
332 | ||
333 | fwnode_property_read_u32(node, | |
334 | "mipi-sdw-modes-supported", &dpn[i].modes); | |
335 | ||
336 | fwnode_property_read_u32(node, "mipi-sdw-max-async-buffer", | |
31dba312 | 337 | &dpn[i].max_async_buffer); |
56d4fe31 | 338 | |
093227bc | 339 | dpn[i].block_pack_mode = mipi_fwnode_property_read_bool(node, |
56d4fe31 VK |
340 | "mipi-sdw-block-packing-mode"); |
341 | ||
342 | fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type", | |
31dba312 | 343 | &dpn[i].port_encoding); |
56d4fe31 | 344 | |
71b405b1 PLB |
345 | nval = fwnode_property_count_u32(node, "mipi-sdw-lane-list"); |
346 | if (nval > 0) { | |
347 | dpn[i].num_lanes = nval; | |
348 | dpn[i].lane_list = devm_kcalloc(&slave->dev, | |
349 | dpn[i].num_lanes, sizeof(*dpn[i].lane_list), | |
350 | GFP_KERNEL); | |
351 | if (!dpn[i].lane_list) | |
352 | return -ENOMEM; | |
353 | ||
354 | ret = fwnode_property_read_u32_array(node, | |
355 | "mipi-sdw-lane-list", | |
356 | dpn[i].lane_list, dpn[i].num_lanes); | |
357 | if (ret < 0) | |
358 | return ret; | |
359 | } | |
360 | ||
e2d8ea0a PLB |
361 | fwnode_handle_put(node); |
362 | ||
56d4fe31 VK |
363 | i++; |
364 | } | |
365 | ||
366 | return 0; | |
367 | } | |
368 | ||
7533d0df BL |
369 | /* |
370 | * In MIPI DisCo spec for SoundWire, lane mapping for a slave device is done with | |
371 | * mipi-sdw-lane-x-mapping properties, where x is 1..7, and the values for those | |
372 | * properties are mipi-sdw-manager-lane-x or mipi-sdw-peripheral-link-y, where x | |
373 | * is an integer between 1 to 7 if the lane is connected to a manager lane, y is a | |
374 | * character between A to E if the lane is connected to another peripheral lane. | |
375 | */ | |
376 | int sdw_slave_read_lane_mapping(struct sdw_slave *slave) | |
377 | { | |
378 | struct sdw_slave_prop *prop = &slave->prop; | |
379 | struct device *dev = &slave->dev; | |
380 | char prop_name[30]; | |
381 | const char *prop_val; | |
382 | size_t len; | |
383 | int ret, i; | |
384 | u8 lane; | |
385 | ||
386 | for (i = 0; i < SDW_MAX_LANES; i++) { | |
387 | snprintf(prop_name, sizeof(prop_name), "mipi-sdw-lane-%d-mapping", i); | |
388 | ret = device_property_read_string(dev, prop_name, &prop_val); | |
389 | if (ret) | |
390 | continue; | |
391 | ||
392 | len = strlen(prop_val); | |
393 | if (len < 1) | |
394 | return -EINVAL; | |
395 | ||
396 | /* The last character is enough to identify the connection */ | |
397 | ret = kstrtou8(&prop_val[len - 1], 10, &lane); | |
398 | if (ret) | |
399 | return ret; | |
400 | if (in_range(lane, 1, SDW_MAX_LANES - 1)) | |
401 | prop->lane_maps[i] = lane; | |
402 | } | |
403 | return 0; | |
404 | } | |
405 | EXPORT_SYMBOL(sdw_slave_read_lane_mapping); | |
406 | ||
56d4fe31 VK |
407 | /** |
408 | * sdw_slave_read_prop() - Read Slave properties | |
409 | * @slave: SDW Slave | |
410 | */ | |
411 | int sdw_slave_read_prop(struct sdw_slave *slave) | |
412 | { | |
413 | struct sdw_slave_prop *prop = &slave->prop; | |
414 | struct device *dev = &slave->dev; | |
415 | struct fwnode_handle *port; | |
60737558 | 416 | int nval; |
4b230967 | 417 | int ret; |
56d4fe31 VK |
418 | |
419 | device_property_read_u32(dev, "mipi-sdw-sw-interface-revision", | |
31dba312 | 420 | &prop->mipi_revision); |
56d4fe31 | 421 | |
093227bc | 422 | prop->wake_capable = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
423 | "mipi-sdw-wake-up-unavailable"); |
424 | prop->wake_capable = !prop->wake_capable; | |
425 | ||
093227bc | 426 | prop->test_mode_capable = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
427 | "mipi-sdw-test-mode-supported"); |
428 | ||
429 | prop->clk_stop_mode1 = false; | |
093227bc | 430 | if (mipi_device_property_read_bool(dev, |
56d4fe31 VK |
431 | "mipi-sdw-clock-stop-mode1-supported")) |
432 | prop->clk_stop_mode1 = true; | |
433 | ||
093227bc | 434 | prop->simple_clk_stop_capable = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
435 | "mipi-sdw-simplified-clockstopprepare-sm-supported"); |
436 | ||
437 | device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout", | |
31dba312 | 438 | &prop->clk_stop_timeout); |
56d4fe31 | 439 | |
4b230967 PLB |
440 | ret = device_property_read_u32(dev, "mipi-sdw-peripheral-channelprepare-timeout", |
441 | &prop->ch_prep_timeout); | |
442 | if (ret < 0) | |
443 | device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout", | |
444 | &prop->ch_prep_timeout); | |
56d4fe31 VK |
445 | |
446 | device_property_read_u32(dev, | |
447 | "mipi-sdw-clockstopprepare-hard-reset-behavior", | |
448 | &prop->reset_behave); | |
449 | ||
093227bc | 450 | prop->high_PHY_capable = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
451 | "mipi-sdw-highPHY-capable"); |
452 | ||
093227bc | 453 | prop->paging_support = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
454 | "mipi-sdw-paging-support"); |
455 | ||
093227bc | 456 | prop->bank_delay_support = mipi_device_property_read_bool(dev, |
56d4fe31 VK |
457 | "mipi-sdw-bank-delay-support"); |
458 | ||
459 | device_property_read_u32(dev, | |
460 | "mipi-sdw-port15-read-behavior", &prop->p15_behave); | |
461 | ||
462 | device_property_read_u32(dev, "mipi-sdw-master-count", | |
31dba312 | 463 | &prop->master_count); |
56d4fe31 VK |
464 | |
465 | device_property_read_u32(dev, "mipi-sdw-source-port-list", | |
31dba312 | 466 | &prop->source_ports); |
56d4fe31 VK |
467 | |
468 | device_property_read_u32(dev, "mipi-sdw-sink-port-list", | |
31dba312 | 469 | &prop->sink_ports); |
56d4fe31 | 470 | |
543bd28a PLB |
471 | device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list", |
472 | &prop->sdca_interrupt_register_list); | |
473 | ||
474 | prop->commit_register_supported = mipi_device_property_read_bool(dev, | |
475 | "mipi-sdw-commit-register-supported"); | |
476 | ||
1ab88b57 PLB |
477 | /* |
478 | * Read dp0 properties - we don't rely on the 'mipi-sdw-dp-0-supported' | |
479 | * property since the 'mipi-sdw-dp0-subproperties' property is logically | |
480 | * equivalent. | |
481 | */ | |
56d4fe31 VK |
482 | port = device_get_named_child_node(dev, "mipi-sdw-dp-0-subproperties"); |
483 | if (!port) { | |
484 | dev_dbg(dev, "DP0 node not found!!\n"); | |
485 | } else { | |
56d4fe31 | 486 | prop->dp0_prop = devm_kzalloc(&slave->dev, |
31dba312 PLB |
487 | sizeof(*prop->dp0_prop), |
488 | GFP_KERNEL); | |
e2d8ea0a PLB |
489 | if (!prop->dp0_prop) { |
490 | fwnode_handle_put(port); | |
56d4fe31 | 491 | return -ENOMEM; |
e2d8ea0a | 492 | } |
56d4fe31 VK |
493 | |
494 | sdw_slave_read_dp0(slave, port, prop->dp0_prop); | |
e2d8ea0a PLB |
495 | |
496 | fwnode_handle_put(port); | |
56d4fe31 VK |
497 | } |
498 | ||
499 | /* | |
500 | * Based on each DPn port, get source and sink dpn properties. | |
501 | * Also, some ports can operate as both source or sink. | |
502 | */ | |
503 | ||
504 | /* Allocate memory for set bits in port lists */ | |
505 | nval = hweight32(prop->source_ports); | |
506 | prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, | |
31dba312 PLB |
507 | sizeof(*prop->src_dpn_prop), |
508 | GFP_KERNEL); | |
56d4fe31 VK |
509 | if (!prop->src_dpn_prop) |
510 | return -ENOMEM; | |
511 | ||
512 | /* Read dpn properties for source port(s) */ | |
513 | sdw_slave_read_dpn(slave, prop->src_dpn_prop, nval, | |
31dba312 | 514 | prop->source_ports, "source"); |
56d4fe31 VK |
515 | |
516 | nval = hweight32(prop->sink_ports); | |
517 | prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, | |
31dba312 PLB |
518 | sizeof(*prop->sink_dpn_prop), |
519 | GFP_KERNEL); | |
56d4fe31 VK |
520 | if (!prop->sink_dpn_prop) |
521 | return -ENOMEM; | |
522 | ||
523 | /* Read dpn properties for sink port(s) */ | |
524 | sdw_slave_read_dpn(slave, prop->sink_dpn_prop, nval, | |
31dba312 | 525 | prop->sink_ports, "sink"); |
56d4fe31 | 526 | |
7533d0df | 527 | return sdw_slave_read_lane_mapping(slave); |
56d4fe31 VK |
528 | } |
529 | EXPORT_SYMBOL(sdw_slave_read_prop); |