1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Author: Dan Scally <djrscally@gmail.com> */ |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/cleanup.h> |
6 | #include <linux/device.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/mei_cl_bus.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/pm_runtime.h> |
11 | #include <linux/property.h> |
12 | #include <linux/string.h> |
13 | #include <linux/workqueue.h> |
14 | |
15 | #include <media/ipu-bridge.h> |
16 | #include <media/v4l2-fwnode.h> |
17 | |
18 | /* |
19 | * 92335fcf-3203-4472-af93-7b4453ac29da |
20 | * |
21 | * Used to build MEI CSI device name to lookup MEI CSI device by |
22 | * device_find_child_by_name(). |
23 | */ |
24 | #define MEI_CSI_UUID \ |
25 | UUID_LE(0x92335FCF, 0x3203, 0x4472, \ |
26 | 0xAF, 0x93, 0x7B, 0x44, 0x53, 0xAC, 0x29, 0xDA) |
27 | |
28 | /* |
29 | * IVSC device name |
30 | * |
31 | * Used to match IVSC device by ipu_bridge_match_ivsc_dev() |
32 | */ |
33 | #define IVSC_DEV_NAME "intel_vsc" |
34 | |
35 | /* |
36 | * Extend this array with ACPI Hardware IDs of devices known to be working |
37 | * plus the number of link-frequencies expected by their drivers, along with |
38 | * the frequency values in hertz. This is somewhat opportunistic way of adding |
39 | * support for this for now in the hopes of a better source for the information |
40 | * (possibly some encoded value in the SSDB buffer that we're unaware of) |
41 | * becoming apparent in the future. |
42 | * |
43 | * Do not add an entry for a sensor that is not actually supported. |
44 | */ |
45 | static const struct ipu_sensor_config ipu_supported_sensors[] = { |
46 | /* Omnivision OV5693 */ |
47 | IPU_SENSOR_CONFIG("INT33BE" , 1, 419200000), |
48 | /* Omnivision OV8865 */ |
49 | IPU_SENSOR_CONFIG("INT347A" , 1, 360000000), |
50 | /* Omnivision OV7251 */ |
51 | IPU_SENSOR_CONFIG("INT347E" , 1, 319200000), |
52 | /* Omnivision OV2680 */ |
53 | IPU_SENSOR_CONFIG("OVTI2680" , 1, 331200000), |
54 | /* Omnivision ov8856 */ |
55 | IPU_SENSOR_CONFIG("OVTI8856" , 3, 180000000, 360000000, 720000000), |
56 | /* Omnivision ov2740 */ |
57 | IPU_SENSOR_CONFIG("INT3474" , 1, 180000000), |
58 | /* Hynix hi556 */ |
59 | IPU_SENSOR_CONFIG("INT3537" , 1, 437000000), |
60 | /* Omnivision ov13b10 */ |
61 | IPU_SENSOR_CONFIG("OVTIDB10" , 1, 560000000), |
62 | /* GalaxyCore GC0310 */ |
63 | IPU_SENSOR_CONFIG("INT0310" , 0), |
64 | /* Omnivision ov01a10 */ |
65 | IPU_SENSOR_CONFIG("OVTI01A0" , 1, 400000000), |
66 | }; |
67 | |
68 | static const struct ipu_property_names prop_names = { |
69 | .clock_frequency = "clock-frequency" , |
70 | .rotation = "rotation" , |
71 | .orientation = "orientation" , |
72 | .bus_type = "bus-type" , |
73 | .data_lanes = "data-lanes" , |
74 | .remote_endpoint = "remote-endpoint" , |
75 | .link_frequencies = "link-frequencies" , |
76 | }; |
77 | |
78 | static const char * const ipu_vcm_types[] = { |
79 | "ad5823" , |
80 | "dw9714" , |
81 | "ad5816" , |
82 | "dw9719" , |
83 | "dw9718" , |
84 | "dw9806b" , |
85 | "wv517s" , |
86 | "lc898122xa" , |
87 | "lc898212axb" , |
88 | }; |
89 | |
90 | /* |
91 | * Used to figure out IVSC acpi device by ipu_bridge_get_ivsc_acpi_dev() |
92 | * instead of device and driver match to probe IVSC device. |
93 | */ |
94 | static const struct acpi_device_id ivsc_acpi_ids[] = { |
95 | { "INTC1059" }, |
96 | { "INTC1095" }, |
97 | { "INTC100A" }, |
98 | { "INTC10CF" }, |
99 | }; |
100 | |
101 | static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev) |
102 | { |
103 | acpi_handle handle = acpi_device_handle(adev); |
104 | struct acpi_device *consumer, *ivsc_adev; |
105 | unsigned int i; |
106 | |
107 | for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) { |
108 | const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i]; |
109 | |
110 | for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1) |
111 | /* camera sensor depends on IVSC in DSDT if exist */ |
112 | for_each_acpi_consumer_dev(ivsc_adev, consumer) |
113 | if (consumer->handle == handle) { |
114 | acpi_dev_put(adev: consumer); |
115 | return ivsc_adev; |
116 | } |
117 | } |
118 | |
119 | return NULL; |
120 | } |
121 | |
122 | static int ipu_bridge_match_ivsc_dev(struct device *dev, const void *adev) |
123 | { |
124 | if (ACPI_COMPANION(dev) != adev) |
125 | return 0; |
126 | |
127 | if (!sysfs_streq(s1: dev_name(dev), IVSC_DEV_NAME)) |
128 | return 0; |
129 | |
130 | return 1; |
131 | } |
132 | |
133 | static struct device *ipu_bridge_get_ivsc_csi_dev(struct acpi_device *adev) |
134 | { |
135 | struct device *dev, *csi_dev; |
136 | uuid_le uuid = MEI_CSI_UUID; |
137 | char name[64]; |
138 | |
139 | /* IVSC device on platform bus */ |
140 | dev = bus_find_device(bus: &platform_bus_type, NULL, data: adev, |
141 | match: ipu_bridge_match_ivsc_dev); |
142 | if (dev) { |
143 | snprintf(buf: name, size: sizeof(name), fmt: "%s-%pUl" , dev_name(dev), &uuid); |
144 | |
145 | csi_dev = device_find_child_by_name(parent: dev, name); |
146 | |
147 | put_device(dev); |
148 | |
149 | return csi_dev; |
150 | } |
151 | |
152 | return NULL; |
153 | } |
154 | |
155 | static int ipu_bridge_check_ivsc_dev(struct ipu_sensor *sensor, |
156 | struct acpi_device *sensor_adev) |
157 | { |
158 | struct acpi_device *adev; |
159 | struct device *csi_dev; |
160 | |
161 | adev = ipu_bridge_get_ivsc_acpi_dev(adev: sensor_adev); |
162 | if (adev) { |
163 | csi_dev = ipu_bridge_get_ivsc_csi_dev(adev); |
164 | if (!csi_dev) { |
165 | acpi_dev_put(adev); |
166 | dev_err(&adev->dev, "Failed to find MEI CSI dev\n" ); |
167 | return -ENODEV; |
168 | } |
169 | |
170 | sensor->csi_dev = csi_dev; |
171 | sensor->ivsc_adev = adev; |
172 | } |
173 | |
174 | return 0; |
175 | } |
176 | |
177 | static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, |
178 | void *data, u32 size) |
179 | { |
180 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
181 | union acpi_object *obj; |
182 | acpi_status status; |
183 | int ret = 0; |
184 | |
185 | status = acpi_evaluate_object(object: adev->handle, pathname: id, NULL, return_object_buffer: &buffer); |
186 | if (ACPI_FAILURE(status)) |
187 | return -ENODEV; |
188 | |
189 | obj = buffer.pointer; |
190 | if (!obj) { |
191 | dev_err(&adev->dev, "Couldn't locate ACPI buffer\n" ); |
192 | return -ENODEV; |
193 | } |
194 | |
195 | if (obj->type != ACPI_TYPE_BUFFER) { |
196 | dev_err(&adev->dev, "Not an ACPI buffer\n" ); |
197 | ret = -ENODEV; |
198 | goto out_free_buff; |
199 | } |
200 | |
201 | if (obj->buffer.length > size) { |
202 | dev_err(&adev->dev, "Given buffer is too small\n" ); |
203 | ret = -EINVAL; |
204 | goto out_free_buff; |
205 | } |
206 | |
207 | memcpy(data, obj->buffer.pointer, obj->buffer.length); |
208 | |
209 | out_free_buff: |
210 | kfree(objp: buffer.pointer); |
211 | return ret; |
212 | } |
213 | |
214 | static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, |
215 | struct ipu_sensor_ssdb *ssdb) |
216 | { |
217 | switch (ssdb->degree) { |
218 | case IPU_SENSOR_ROTATION_NORMAL: |
219 | return 0; |
220 | case IPU_SENSOR_ROTATION_INVERTED: |
221 | return 180; |
222 | default: |
223 | dev_warn(&adev->dev, |
224 | "Unknown rotation %d. Assume 0 degree rotation\n" , |
225 | ssdb->degree); |
226 | return 0; |
227 | } |
228 | } |
229 | |
230 | static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev) |
231 | { |
232 | enum v4l2_fwnode_orientation orientation; |
233 | struct acpi_pld_info *pld; |
234 | acpi_status status; |
235 | |
236 | status = acpi_get_physical_device_location(handle: adev->handle, pld: &pld); |
237 | if (ACPI_FAILURE(status)) { |
238 | dev_warn(&adev->dev, "_PLD call failed, using default orientation\n" ); |
239 | return V4L2_FWNODE_ORIENTATION_EXTERNAL; |
240 | } |
241 | |
242 | switch (pld->panel) { |
243 | case ACPI_PLD_PANEL_FRONT: |
244 | orientation = V4L2_FWNODE_ORIENTATION_FRONT; |
245 | break; |
246 | case ACPI_PLD_PANEL_BACK: |
247 | orientation = V4L2_FWNODE_ORIENTATION_BACK; |
248 | break; |
249 | case ACPI_PLD_PANEL_TOP: |
250 | case ACPI_PLD_PANEL_LEFT: |
251 | case ACPI_PLD_PANEL_RIGHT: |
252 | case ACPI_PLD_PANEL_UNKNOWN: |
253 | orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL; |
254 | break; |
255 | default: |
256 | dev_warn(&adev->dev, "Unknown _PLD panel val %d\n" , pld->panel); |
257 | orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL; |
258 | break; |
259 | } |
260 | |
261 | ACPI_FREE(pld); |
262 | return orientation; |
263 | } |
264 | |
265 | int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor) |
266 | { |
267 | struct ipu_sensor_ssdb ssdb = {}; |
268 | int ret; |
269 | |
270 | ret = ipu_bridge_read_acpi_buffer(adev, id: "SSDB" , data: &ssdb, size: sizeof(ssdb)); |
271 | if (ret) |
272 | return ret; |
273 | |
274 | if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) { |
275 | dev_warn(&adev->dev, "Unknown VCM type %d\n" , ssdb.vcmtype); |
276 | ssdb.vcmtype = 0; |
277 | } |
278 | |
279 | if (ssdb.lanes > IPU_MAX_LANES) { |
280 | dev_err(&adev->dev, "Number of lanes in SSDB is invalid\n" ); |
281 | return -EINVAL; |
282 | } |
283 | |
284 | sensor->link = ssdb.link; |
285 | sensor->lanes = ssdb.lanes; |
286 | sensor->mclkspeed = ssdb.mclkspeed; |
287 | sensor->rotation = ipu_bridge_parse_rotation(adev, ssdb: &ssdb); |
288 | sensor->orientation = ipu_bridge_parse_orientation(adev); |
289 | |
290 | if (ssdb.vcmtype) |
291 | sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1]; |
292 | |
293 | return 0; |
294 | } |
295 | EXPORT_SYMBOL_NS_GPL(ipu_bridge_parse_ssdb, INTEL_IPU_BRIDGE); |
296 | |
297 | static void ipu_bridge_create_fwnode_properties( |
298 | struct ipu_sensor *sensor, |
299 | struct ipu_bridge *bridge, |
300 | const struct ipu_sensor_config *cfg) |
301 | { |
302 | struct ipu_property_names *names = &sensor->prop_names; |
303 | struct software_node *nodes = sensor->swnodes; |
304 | |
305 | sensor->prop_names = prop_names; |
306 | |
307 | if (sensor->csi_dev) { |
308 | sensor->local_ref[0] = |
309 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_IVSC_SENSOR_ENDPOINT]); |
310 | sensor->remote_ref[0] = |
311 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_IVSC_IPU_ENDPOINT]); |
312 | sensor->ivsc_sensor_ref[0] = |
313 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_SENSOR_ENDPOINT]); |
314 | sensor->ivsc_ipu_ref[0] = |
315 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_IPU_ENDPOINT]); |
316 | |
317 | sensor->ivsc_sensor_ep_properties[0] = |
318 | PROPERTY_ENTRY_U32(names->bus_type, |
319 | V4L2_FWNODE_BUS_TYPE_CSI2_DPHY); |
320 | sensor->ivsc_sensor_ep_properties[1] = |
321 | PROPERTY_ENTRY_U32_ARRAY_LEN(names->data_lanes, |
322 | bridge->data_lanes, |
323 | sensor->lanes); |
324 | sensor->ivsc_sensor_ep_properties[2] = |
325 | PROPERTY_ENTRY_REF_ARRAY(names->remote_endpoint, |
326 | sensor->ivsc_sensor_ref); |
327 | |
328 | sensor->ivsc_ipu_ep_properties[0] = |
329 | PROPERTY_ENTRY_U32(names->bus_type, |
330 | V4L2_FWNODE_BUS_TYPE_CSI2_DPHY); |
331 | sensor->ivsc_ipu_ep_properties[1] = |
332 | PROPERTY_ENTRY_U32_ARRAY_LEN(names->data_lanes, |
333 | bridge->data_lanes, |
334 | sensor->lanes); |
335 | sensor->ivsc_ipu_ep_properties[2] = |
336 | PROPERTY_ENTRY_REF_ARRAY(names->remote_endpoint, |
337 | sensor->ivsc_ipu_ref); |
338 | } else { |
339 | sensor->local_ref[0] = |
340 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_IPU_ENDPOINT]); |
341 | sensor->remote_ref[0] = |
342 | SOFTWARE_NODE_REFERENCE(&nodes[SWNODE_SENSOR_ENDPOINT]); |
343 | } |
344 | |
345 | sensor->dev_properties[0] = PROPERTY_ENTRY_U32( |
346 | sensor->prop_names.clock_frequency, |
347 | sensor->mclkspeed); |
348 | sensor->dev_properties[1] = PROPERTY_ENTRY_U32( |
349 | sensor->prop_names.rotation, |
350 | sensor->rotation); |
351 | sensor->dev_properties[2] = PROPERTY_ENTRY_U32( |
352 | sensor->prop_names.orientation, |
353 | sensor->orientation); |
354 | if (sensor->vcm_type) { |
355 | sensor->vcm_ref[0] = |
356 | SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]); |
357 | sensor->dev_properties[3] = |
358 | PROPERTY_ENTRY_REF_ARRAY("lens-focus" , sensor->vcm_ref); |
359 | } |
360 | |
361 | sensor->ep_properties[0] = PROPERTY_ENTRY_U32( |
362 | sensor->prop_names.bus_type, |
363 | V4L2_FWNODE_BUS_TYPE_CSI2_DPHY); |
364 | sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN( |
365 | sensor->prop_names.data_lanes, |
366 | bridge->data_lanes, sensor->lanes); |
367 | sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY( |
368 | sensor->prop_names.remote_endpoint, |
369 | sensor->local_ref); |
370 | |
371 | if (cfg->nr_link_freqs > 0) |
372 | sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN( |
373 | sensor->prop_names.link_frequencies, |
374 | cfg->link_freqs, |
375 | cfg->nr_link_freqs); |
376 | |
377 | sensor->ipu_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN( |
378 | sensor->prop_names.data_lanes, |
379 | bridge->data_lanes, sensor->lanes); |
380 | sensor->ipu_properties[1] = PROPERTY_ENTRY_REF_ARRAY( |
381 | sensor->prop_names.remote_endpoint, |
382 | sensor->remote_ref); |
383 | } |
384 | |
385 | static void ipu_bridge_init_swnode_names(struct ipu_sensor *sensor) |
386 | { |
387 | snprintf(buf: sensor->node_names.remote_port, |
388 | size: sizeof(sensor->node_names.remote_port), |
389 | SWNODE_GRAPH_PORT_NAME_FMT, sensor->link); |
390 | snprintf(buf: sensor->node_names.port, |
391 | size: sizeof(sensor->node_names.port), |
392 | SWNODE_GRAPH_PORT_NAME_FMT, 0); /* Always port 0 */ |
393 | snprintf(buf: sensor->node_names.endpoint, |
394 | size: sizeof(sensor->node_names.endpoint), |
395 | SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */ |
396 | if (sensor->vcm_type) { |
397 | /* append link to distinguish nodes with same model VCM */ |
398 | snprintf(buf: sensor->node_names.vcm, size: sizeof(sensor->node_names.vcm), |
399 | fmt: "%s-%u" , sensor->vcm_type, sensor->link); |
400 | } |
401 | |
402 | if (sensor->csi_dev) { |
403 | snprintf(buf: sensor->node_names.ivsc_sensor_port, |
404 | size: sizeof(sensor->node_names.ivsc_sensor_port), |
405 | SWNODE_GRAPH_PORT_NAME_FMT, 0); |
406 | snprintf(buf: sensor->node_names.ivsc_ipu_port, |
407 | size: sizeof(sensor->node_names.ivsc_ipu_port), |
408 | SWNODE_GRAPH_PORT_NAME_FMT, 1); |
409 | } |
410 | } |
411 | |
412 | static void ipu_bridge_init_swnode_group(struct ipu_sensor *sensor) |
413 | { |
414 | struct software_node *nodes = sensor->swnodes; |
415 | |
416 | sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID]; |
417 | sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT]; |
418 | sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT]; |
419 | sensor->group[SWNODE_IPU_PORT] = &nodes[SWNODE_IPU_PORT]; |
420 | sensor->group[SWNODE_IPU_ENDPOINT] = &nodes[SWNODE_IPU_ENDPOINT]; |
421 | if (sensor->vcm_type) |
422 | sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; |
423 | |
424 | if (sensor->csi_dev) { |
425 | sensor->group[SWNODE_IVSC_HID] = |
426 | &nodes[SWNODE_IVSC_HID]; |
427 | sensor->group[SWNODE_IVSC_SENSOR_PORT] = |
428 | &nodes[SWNODE_IVSC_SENSOR_PORT]; |
429 | sensor->group[SWNODE_IVSC_SENSOR_ENDPOINT] = |
430 | &nodes[SWNODE_IVSC_SENSOR_ENDPOINT]; |
431 | sensor->group[SWNODE_IVSC_IPU_PORT] = |
432 | &nodes[SWNODE_IVSC_IPU_PORT]; |
433 | sensor->group[SWNODE_IVSC_IPU_ENDPOINT] = |
434 | &nodes[SWNODE_IVSC_IPU_ENDPOINT]; |
435 | |
436 | if (sensor->vcm_type) |
437 | sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; |
438 | } else { |
439 | if (sensor->vcm_type) |
440 | sensor->group[SWNODE_IVSC_HID] = &nodes[SWNODE_VCM]; |
441 | } |
442 | } |
443 | |
444 | static void ipu_bridge_create_connection_swnodes(struct ipu_bridge *bridge, |
445 | struct ipu_sensor *sensor) |
446 | { |
447 | struct ipu_node_names *names = &sensor->node_names; |
448 | struct software_node *nodes = sensor->swnodes; |
449 | |
450 | ipu_bridge_init_swnode_names(sensor); |
451 | |
452 | nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name, |
453 | sensor->dev_properties); |
454 | nodes[SWNODE_SENSOR_PORT] = NODE_PORT(sensor->node_names.port, |
455 | &nodes[SWNODE_SENSOR_HID]); |
456 | nodes[SWNODE_SENSOR_ENDPOINT] = NODE_ENDPOINT( |
457 | sensor->node_names.endpoint, |
458 | &nodes[SWNODE_SENSOR_PORT], |
459 | sensor->ep_properties); |
460 | nodes[SWNODE_IPU_PORT] = NODE_PORT(sensor->node_names.remote_port, |
461 | &bridge->ipu_hid_node); |
462 | nodes[SWNODE_IPU_ENDPOINT] = NODE_ENDPOINT( |
463 | sensor->node_names.endpoint, |
464 | &nodes[SWNODE_IPU_PORT], |
465 | sensor->ipu_properties); |
466 | |
467 | if (sensor->csi_dev) { |
468 | snprintf(buf: sensor->ivsc_name, size: sizeof(sensor->ivsc_name), fmt: "%s-%u" , |
469 | acpi_device_hid(device: sensor->ivsc_adev), sensor->link); |
470 | |
471 | nodes[SWNODE_IVSC_HID] = NODE_SENSOR(sensor->ivsc_name, |
472 | sensor->ivsc_properties); |
473 | nodes[SWNODE_IVSC_SENSOR_PORT] = |
474 | NODE_PORT(names->ivsc_sensor_port, |
475 | &nodes[SWNODE_IVSC_HID]); |
476 | nodes[SWNODE_IVSC_SENSOR_ENDPOINT] = |
477 | NODE_ENDPOINT(names->endpoint, |
478 | &nodes[SWNODE_IVSC_SENSOR_PORT], |
479 | sensor->ivsc_sensor_ep_properties); |
480 | nodes[SWNODE_IVSC_IPU_PORT] = |
481 | NODE_PORT(names->ivsc_ipu_port, |
482 | &nodes[SWNODE_IVSC_HID]); |
483 | nodes[SWNODE_IVSC_IPU_ENDPOINT] = |
484 | NODE_ENDPOINT(names->endpoint, |
485 | &nodes[SWNODE_IVSC_IPU_PORT], |
486 | sensor->ivsc_ipu_ep_properties); |
487 | } |
488 | |
489 | nodes[SWNODE_VCM] = NODE_VCM(sensor->node_names.vcm); |
490 | |
491 | ipu_bridge_init_swnode_group(sensor); |
492 | } |
493 | |
494 | /* |
495 | * The actual instantiation must be done from a workqueue to avoid |
496 | * a deadlock on taking list_lock from v4l2-async twice. |
497 | */ |
498 | struct ipu_bridge_instantiate_vcm_work_data { |
499 | struct work_struct work; |
500 | struct device *sensor; |
501 | char name[16]; |
502 | struct i2c_board_info board_info; |
503 | }; |
504 | |
505 | static void ipu_bridge_instantiate_vcm_work(struct work_struct *work) |
506 | { |
507 | struct ipu_bridge_instantiate_vcm_work_data *data = |
508 | container_of(work, struct ipu_bridge_instantiate_vcm_work_data, |
509 | work); |
510 | struct acpi_device *adev = ACPI_COMPANION(data->sensor); |
511 | struct i2c_client *vcm_client; |
512 | bool put_fwnode = true; |
513 | int ret; |
514 | |
515 | /* |
516 | * The client may get probed before the device_link gets added below |
517 | * make sure the sensor is powered-up during probe. |
518 | */ |
519 | ret = pm_runtime_get_sync(dev: data->sensor); |
520 | if (ret < 0) { |
521 | dev_err(data->sensor, "Error %d runtime-resuming sensor, cannot instantiate VCM\n" , |
522 | ret); |
523 | goto out_pm_put; |
524 | } |
525 | |
526 | /* |
527 | * Note the client is created only once and then kept around |
528 | * even after a rmmod, just like the software-nodes. |
529 | */ |
530 | vcm_client = i2c_acpi_new_device_by_fwnode(fwnode: acpi_fwnode_handle(adev), |
531 | index: 1, info: &data->board_info); |
532 | if (IS_ERR(ptr: vcm_client)) { |
533 | dev_err(data->sensor, "Error instantiating VCM client: %ld\n" , |
534 | PTR_ERR(vcm_client)); |
535 | goto out_pm_put; |
536 | } |
537 | |
538 | device_link_add(consumer: &vcm_client->dev, supplier: data->sensor, DL_FLAG_PM_RUNTIME); |
539 | |
540 | dev_info(data->sensor, "Instantiated %s VCM\n" , data->board_info.type); |
541 | put_fwnode = false; /* Ownership has passed to the i2c-client */ |
542 | |
543 | out_pm_put: |
544 | pm_runtime_put(dev: data->sensor); |
545 | put_device(dev: data->sensor); |
546 | if (put_fwnode) |
547 | fwnode_handle_put(fwnode: data->board_info.fwnode); |
548 | kfree(objp: data); |
549 | } |
550 | |
551 | int ipu_bridge_instantiate_vcm(struct device *sensor) |
552 | { |
553 | struct ipu_bridge_instantiate_vcm_work_data *data; |
554 | struct fwnode_handle *vcm_fwnode; |
555 | struct i2c_client *vcm_client; |
556 | struct acpi_device *adev; |
557 | char *sep; |
558 | |
559 | adev = ACPI_COMPANION(sensor); |
560 | if (!adev) |
561 | return 0; |
562 | |
563 | vcm_fwnode = fwnode_find_reference(dev_fwnode(sensor), name: "lens-focus" , index: 0); |
564 | if (IS_ERR(ptr: vcm_fwnode)) |
565 | return 0; |
566 | |
567 | /* When reloading modules the client will already exist */ |
568 | vcm_client = i2c_find_device_by_fwnode(fwnode: vcm_fwnode); |
569 | if (vcm_client) { |
570 | fwnode_handle_put(fwnode: vcm_fwnode); |
571 | put_device(dev: &vcm_client->dev); |
572 | return 0; |
573 | } |
574 | |
575 | data = kzalloc(size: sizeof(*data), GFP_KERNEL); |
576 | if (!data) { |
577 | fwnode_handle_put(fwnode: vcm_fwnode); |
578 | return -ENOMEM; |
579 | } |
580 | |
581 | INIT_WORK(&data->work, ipu_bridge_instantiate_vcm_work); |
582 | data->sensor = get_device(dev: sensor); |
583 | snprintf(buf: data->name, size: sizeof(data->name), fmt: "%s-VCM" , |
584 | acpi_dev_name(adev)); |
585 | data->board_info.dev_name = data->name; |
586 | data->board_info.fwnode = vcm_fwnode; |
587 | snprintf(buf: data->board_info.type, size: sizeof(data->board_info.type), |
588 | fmt: "%pfwP" , vcm_fwnode); |
589 | /* Strip "-<link>" postfix */ |
590 | sep = strchrnul(data->board_info.type, '-'); |
591 | *sep = 0; |
592 | |
593 | queue_work(wq: system_long_wq, work: &data->work); |
594 | |
595 | return 0; |
596 | } |
597 | EXPORT_SYMBOL_NS_GPL(ipu_bridge_instantiate_vcm, INTEL_IPU_BRIDGE); |
598 | |
599 | static int ipu_bridge_instantiate_ivsc(struct ipu_sensor *sensor) |
600 | { |
601 | struct fwnode_handle *fwnode; |
602 | |
603 | if (!sensor->csi_dev) |
604 | return 0; |
605 | |
606 | fwnode = software_node_fwnode(node: &sensor->swnodes[SWNODE_IVSC_HID]); |
607 | if (!fwnode) |
608 | return -ENODEV; |
609 | |
610 | set_secondary_fwnode(dev: sensor->csi_dev, fwnode); |
611 | |
612 | return 0; |
613 | } |
614 | |
615 | static void ipu_bridge_unregister_sensors(struct ipu_bridge *bridge) |
616 | { |
617 | struct ipu_sensor *sensor; |
618 | unsigned int i; |
619 | |
620 | for (i = 0; i < bridge->n_sensors; i++) { |
621 | sensor = &bridge->sensors[i]; |
622 | software_node_unregister_node_group(node_group: sensor->group); |
623 | acpi_dev_put(adev: sensor->adev); |
624 | put_device(dev: sensor->csi_dev); |
625 | acpi_dev_put(adev: sensor->ivsc_adev); |
626 | } |
627 | } |
628 | |
629 | static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg, |
630 | struct ipu_bridge *bridge) |
631 | { |
632 | struct fwnode_handle *fwnode, *primary; |
633 | struct ipu_sensor *sensor; |
634 | struct acpi_device *adev; |
635 | int ret; |
636 | |
637 | for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { |
638 | if (!adev->status.enabled) |
639 | continue; |
640 | |
641 | if (bridge->n_sensors >= IPU_MAX_PORTS) { |
642 | acpi_dev_put(adev); |
643 | dev_err(bridge->dev, "Exceeded available IPU ports\n" ); |
644 | return -EINVAL; |
645 | } |
646 | |
647 | sensor = &bridge->sensors[bridge->n_sensors]; |
648 | |
649 | ret = bridge->parse_sensor_fwnode(adev, sensor); |
650 | if (ret) |
651 | goto err_put_adev; |
652 | |
653 | snprintf(buf: sensor->name, size: sizeof(sensor->name), fmt: "%s-%u" , |
654 | cfg->hid, sensor->link); |
655 | |
656 | ret = ipu_bridge_check_ivsc_dev(sensor, sensor_adev: adev); |
657 | if (ret) |
658 | goto err_put_adev; |
659 | |
660 | ipu_bridge_create_fwnode_properties(sensor, bridge, cfg); |
661 | ipu_bridge_create_connection_swnodes(bridge, sensor); |
662 | |
663 | ret = software_node_register_node_group(node_group: sensor->group); |
664 | if (ret) |
665 | goto err_put_ivsc; |
666 | |
667 | fwnode = software_node_fwnode(node: &sensor->swnodes[ |
668 | SWNODE_SENSOR_HID]); |
669 | if (!fwnode) { |
670 | ret = -ENODEV; |
671 | goto err_free_swnodes; |
672 | } |
673 | |
674 | sensor->adev = acpi_dev_get(adev); |
675 | |
676 | primary = acpi_fwnode_handle(adev); |
677 | primary->secondary = fwnode; |
678 | |
679 | ret = ipu_bridge_instantiate_ivsc(sensor); |
680 | if (ret) |
681 | goto err_free_swnodes; |
682 | |
683 | dev_info(bridge->dev, "Found supported sensor %s\n" , |
684 | acpi_dev_name(adev)); |
685 | |
686 | bridge->n_sensors++; |
687 | } |
688 | |
689 | return 0; |
690 | |
691 | err_free_swnodes: |
692 | software_node_unregister_node_group(node_group: sensor->group); |
693 | err_put_ivsc: |
694 | put_device(dev: sensor->csi_dev); |
695 | acpi_dev_put(adev: sensor->ivsc_adev); |
696 | err_put_adev: |
697 | acpi_dev_put(adev); |
698 | return ret; |
699 | } |
700 | |
701 | static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge) |
702 | { |
703 | unsigned int i; |
704 | int ret; |
705 | |
706 | for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) { |
707 | const struct ipu_sensor_config *cfg = |
708 | &ipu_supported_sensors[i]; |
709 | |
710 | ret = ipu_bridge_connect_sensor(cfg, bridge); |
711 | if (ret) |
712 | goto err_unregister_sensors; |
713 | } |
714 | |
715 | return 0; |
716 | |
717 | err_unregister_sensors: |
718 | ipu_bridge_unregister_sensors(bridge); |
719 | return ret; |
720 | } |
721 | |
722 | static int ipu_bridge_ivsc_is_ready(void) |
723 | { |
724 | struct acpi_device *sensor_adev, *adev; |
725 | struct device *csi_dev; |
726 | bool ready = true; |
727 | unsigned int i; |
728 | |
729 | for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) { |
730 | const struct ipu_sensor_config *cfg = |
731 | &ipu_supported_sensors[i]; |
732 | |
733 | for_each_acpi_dev_match(sensor_adev, cfg->hid, NULL, -1) { |
734 | if (!sensor_adev->status.enabled) |
735 | continue; |
736 | |
737 | adev = ipu_bridge_get_ivsc_acpi_dev(adev: sensor_adev); |
738 | if (!adev) |
739 | continue; |
740 | |
741 | csi_dev = ipu_bridge_get_ivsc_csi_dev(adev); |
742 | if (!csi_dev) |
743 | ready = false; |
744 | |
745 | put_device(dev: csi_dev); |
746 | acpi_dev_put(adev); |
747 | } |
748 | } |
749 | |
750 | return ready; |
751 | } |
752 | |
753 | static int ipu_bridge_check_fwnode_graph(struct fwnode_handle *fwnode) |
754 | { |
755 | struct fwnode_handle *endpoint; |
756 | |
757 | if (IS_ERR_OR_NULL(ptr: fwnode)) |
758 | return -EINVAL; |
759 | |
760 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); |
761 | if (endpoint) { |
762 | fwnode_handle_put(fwnode: endpoint); |
763 | return 0; |
764 | } |
765 | |
766 | return ipu_bridge_check_fwnode_graph(fwnode: fwnode->secondary); |
767 | } |
768 | |
769 | static DEFINE_MUTEX(ipu_bridge_mutex); |
770 | |
771 | int ipu_bridge_init(struct device *dev, |
772 | ipu_parse_sensor_fwnode_t parse_sensor_fwnode) |
773 | { |
774 | struct fwnode_handle *fwnode; |
775 | struct ipu_bridge *bridge; |
776 | unsigned int i; |
777 | int ret; |
778 | |
779 | guard(mutex)(T: &ipu_bridge_mutex); |
780 | |
781 | if (!ipu_bridge_check_fwnode_graph(dev_fwnode(dev))) |
782 | return 0; |
783 | |
784 | if (!ipu_bridge_ivsc_is_ready()) |
785 | return -EPROBE_DEFER; |
786 | |
787 | bridge = kzalloc(size: sizeof(*bridge), GFP_KERNEL); |
788 | if (!bridge) |
789 | return -ENOMEM; |
790 | |
791 | strscpy(bridge->ipu_node_name, IPU_HID, |
792 | sizeof(bridge->ipu_node_name)); |
793 | bridge->ipu_hid_node.name = bridge->ipu_node_name; |
794 | bridge->dev = dev; |
795 | bridge->parse_sensor_fwnode = parse_sensor_fwnode; |
796 | |
797 | ret = software_node_register(node: &bridge->ipu_hid_node); |
798 | if (ret < 0) { |
799 | dev_err(dev, "Failed to register the IPU HID node\n" ); |
800 | goto err_free_bridge; |
801 | } |
802 | |
803 | /* |
804 | * Map the lane arrangement, which is fixed for the IPU3 (meaning we |
805 | * only need one, rather than one per sensor). We include it as a |
806 | * member of the struct ipu_bridge rather than a global variable so |
807 | * that it survives if the module is unloaded along with the rest of |
808 | * the struct. |
809 | */ |
810 | for (i = 0; i < IPU_MAX_LANES; i++) |
811 | bridge->data_lanes[i] = i + 1; |
812 | |
813 | ret = ipu_bridge_connect_sensors(bridge); |
814 | if (ret || bridge->n_sensors == 0) |
815 | goto err_unregister_ipu; |
816 | |
817 | dev_info(dev, "Connected %d cameras\n" , bridge->n_sensors); |
818 | |
819 | fwnode = software_node_fwnode(node: &bridge->ipu_hid_node); |
820 | if (!fwnode) { |
821 | dev_err(dev, "Error getting fwnode from ipu software_node\n" ); |
822 | ret = -ENODEV; |
823 | goto err_unregister_sensors; |
824 | } |
825 | |
826 | set_secondary_fwnode(dev, fwnode); |
827 | |
828 | return 0; |
829 | |
830 | err_unregister_sensors: |
831 | ipu_bridge_unregister_sensors(bridge); |
832 | err_unregister_ipu: |
833 | software_node_unregister(node: &bridge->ipu_hid_node); |
834 | err_free_bridge: |
835 | kfree(objp: bridge); |
836 | |
837 | return ret; |
838 | } |
839 | EXPORT_SYMBOL_NS_GPL(ipu_bridge_init, INTEL_IPU_BRIDGE); |
840 | |
841 | MODULE_LICENSE("GPL" ); |
842 | MODULE_DESCRIPTION("Intel IPU Sensors Bridge driver" ); |
843 | |