media: atomisp: csi2-bridge: Add dev_name() to acpi_handle_info() logging
[platform/kernel/linux-starfive.git] / drivers / staging / media / atomisp / pci / atomisp_csi2_bridge.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Code to build software firmware node graph for atomisp2 connected sensors
4  * from ACPI tables.
5  *
6  * Copyright (C) 2023 Hans de Goede <hdegoede@redhat.com>
7  *
8  * Based on drivers/media/pci/intel/ipu3/cio2-bridge.c written by:
9  * Dan Scally <djrscally@gmail.com>
10  */
11
12 #include <linux/acpi.h>
13 #include <linux/clk.h>
14 #include <linux/device.h>
15 #include <linux/dmi.h>
16 #include <linux/property.h>
17
18 #include <media/ipu-bridge.h>
19 #include <media/v4l2-fwnode.h>
20
21 #include "atomisp_cmd.h"
22 #include "atomisp_csi2.h"
23 #include "atomisp_internal.h"
24
25 #define PMC_CLK_RATE_19_2MHZ                    19200000
26
27 /*
28  * 79234640-9e10-4fea-a5c1-b5aa8b19756f
29  * This _DSM GUID returns information about the GPIO lines mapped to a sensor.
30  * Function number 1 returns a count of the GPIO lines that are mapped.
31  * Subsequent functions return 32 bit ints encoding information about the GPIO.
32  */
33 static const guid_t intel_sensor_gpio_info_guid =
34         GUID_INIT(0x79234640, 0x9e10, 0x4fea,
35                   0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
36
37 #define INTEL_GPIO_DSM_TYPE_SHIFT                       0
38 #define INTEL_GPIO_DSM_TYPE_MASK                        GENMASK(7, 0)
39 #define INTEL_GPIO_DSM_PIN_SHIFT                        8
40 #define INTEL_GPIO_DSM_PIN_MASK                         GENMASK(15, 8)
41 #define INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT              24
42 #define INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK               GENMASK(31, 24)
43
44 #define INTEL_GPIO_DSM_TYPE(x) \
45         (((x) & INTEL_GPIO_DSM_TYPE_MASK) >> INTEL_GPIO_DSM_TYPE_SHIFT)
46 #define INTEL_GPIO_DSM_PIN(x) \
47         (((x) & INTEL_GPIO_DSM_PIN_MASK) >> INTEL_GPIO_DSM_PIN_SHIFT)
48 #define INTEL_GPIO_DSM_SENSOR_ON_VAL(x) \
49         (((x) & INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK) >> INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT)
50
51 /*
52  * 822ace8f-2814-4174-a56b-5f029fe079ee
53  * This _DSM GUID returns a string from the sensor device, which acts as a
54  * module identifier.
55  */
56 static const guid_t intel_sensor_module_guid =
57         GUID_INIT(0x822ace8f, 0x2814, 0x4174,
58                   0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
59
60 /*
61  * dc2f6c4f-045b-4f1d-97b9-882a6860a4be
62  * This _DSM GUID returns a package with n*2 strings, with each set of 2 strings
63  * forming a key, value pair for settings like e.g. "CsiLanes" = "1".
64  */
65 static const guid_t atomisp_dsm_guid =
66         GUID_INIT(0xdc2f6c4f, 0x045b, 0x4f1d,
67                   0x97, 0xb9, 0x88, 0x2a, 0x68, 0x60, 0xa4, 0xbe);
68
69 struct atomisp_sensor_config {
70         int lanes;
71 };
72
73 #define ATOMISP_SENSOR_CONFIG(_HID, _LANES)                             \
74 {                                                                       \
75         .id = _HID,                                                     \
76         .driver_data = (long)&((const struct atomisp_sensor_config) {   \
77                 .lanes = _LANES,                                        \
78         })                                                              \
79 }
80
81 /*
82  * gmin_cfg parsing code. This is a cleaned up version of the gmin_cfg parsing
83  * code from atomisp_gmin_platform.c.
84  * Once all sensors are moved to v4l2-async probing atomisp_gmin_platform.c can
85  * be removed and the duplication of this code goes away.
86  */
87 struct gmin_cfg_var {
88         const char *acpi_dev_name;
89         const char *key;
90         const char *val;
91 };
92
93 static struct gmin_cfg_var lenovo_ideapad_miix_310_vars[] = {
94         /* _DSM contains the wrong CsiPort! */
95         { "OVTI2680:01", "CsiPort", "0" },
96         {}
97 };
98
99 static const struct dmi_system_id gmin_cfg_dmi_overrides[] = {
100         {
101                 /* Lenovo Ideapad Miix 310 */
102                 .matches = {
103                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
104                         DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10"),
105                 },
106                 .driver_data = lenovo_ideapad_miix_310_vars,
107         },
108         {}
109 };
110
111 static char *gmin_cfg_get_dsm(struct acpi_device *adev, const char *key)
112 {
113         union acpi_object *obj, *key_el, *val_el;
114         char *val = NULL;
115         int i;
116
117         obj = acpi_evaluate_dsm_typed(adev->handle, &atomisp_dsm_guid, 0, 0,
118                                       NULL, ACPI_TYPE_PACKAGE);
119         if (!obj)
120                 return NULL;
121
122         for (i = 0; i < obj->package.count - 1; i += 2) {
123                 key_el = &obj->package.elements[i + 0];
124                 val_el = &obj->package.elements[i + 1];
125
126                 if (key_el->type != ACPI_TYPE_STRING || val_el->type != ACPI_TYPE_STRING)
127                         break;
128
129                 if (!strcmp(key_el->string.pointer, key)) {
130                         val = kstrdup(val_el->string.pointer, GFP_KERNEL);
131                         if (!val)
132                                 break;
133
134                         acpi_handle_info(adev->handle, "%s: Using DSM entry %s=%s\n",
135                                          dev_name(&adev->dev), key, val);
136                         break;
137                 }
138         }
139
140         ACPI_FREE(obj);
141         return val;
142 }
143
144 static char *gmin_cfg_get_dmi_override(struct acpi_device *adev, const char *key)
145 {
146         const struct dmi_system_id *id;
147         struct gmin_cfg_var *gv;
148
149         id = dmi_first_match(gmin_cfg_dmi_overrides);
150         if (!id)
151                 return NULL;
152
153         for (gv = id->driver_data; gv->acpi_dev_name; gv++) {
154                 if (strcmp(gv->acpi_dev_name, acpi_dev_name(adev)))
155                         continue;
156
157                 if (strcmp(key, gv->key))
158                         continue;
159
160                 acpi_handle_info(adev->handle, "%s: Using DMI entry %s=%s\n",
161                                  dev_name(&adev->dev), key, gv->val);
162                 return kstrdup(gv->val, GFP_KERNEL);
163         }
164
165         return NULL;
166 }
167
168 static char *gmin_cfg_get(struct acpi_device *adev, const char *key)
169 {
170         char *val;
171
172         val = gmin_cfg_get_dmi_override(adev, key);
173         if (val)
174                 return val;
175
176         return gmin_cfg_get_dsm(adev, key);
177 }
178
179 static int gmin_cfg_get_int(struct acpi_device *adev, const char *key, int default_val)
180 {
181         char *str_val;
182         long int_val;
183         int ret;
184
185         str_val = gmin_cfg_get(adev, key);
186         if (!str_val)
187                 goto out_use_default;
188
189         ret = kstrtoul(str_val, 0, &int_val);
190         kfree(str_val);
191         if (ret)
192                 goto out_use_default;
193
194         return int_val;
195
196 out_use_default:
197         acpi_handle_info(adev->handle, "%s: Using default %s=%d\n",
198                          dev_name(&adev->dev), key, default_val);
199         return default_val;
200 }
201
202 static int atomisp_csi2_get_pmc_clk_nr_from_acpi_pr0(struct acpi_device *adev)
203 {
204         /* ACPI_PATH_SEGMENT_LENGTH is guaranteed to be big enough for name + 0 term. */
205         char name[ACPI_PATH_SEGMENT_LENGTH];
206         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
207         struct acpi_buffer b_name = { sizeof(name), name };
208         union acpi_object *package, *element;
209         int i, ret = -ENOENT;
210         acpi_handle rhandle;
211         acpi_status status;
212         u8 clock_num;
213
214         status = acpi_evaluate_object_typed(adev->handle, "_PR0", NULL, &buffer, ACPI_TYPE_PACKAGE);
215         if (ACPI_FAILURE(status))
216                 return -ENOENT;
217
218         package = buffer.pointer;
219         for (i = 0; i < package->package.count; i++) {
220                 element = &package->package.elements[i];
221
222                 if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
223                         continue;
224
225                 rhandle = element->reference.handle;
226                 if (!rhandle)
227                         continue;
228
229                 acpi_get_name(rhandle, ACPI_SINGLE_NAME, &b_name);
230
231                 if (str_has_prefix(name, "CLK") && !kstrtou8(&name[3], 10, &clock_num) &&
232                     clock_num <= 4) {
233                         ret = clock_num;
234                         break;
235                 }
236         }
237
238         ACPI_FREE(buffer.pointer);
239
240         if (ret < 0)
241                 acpi_handle_warn(adev->handle, "%s: Could not find PMC clk in _PR0\n",
242                                  dev_name(&adev->dev));
243
244         return ret;
245 }
246
247 static int atomisp_csi2_set_pmc_clk_freq(struct acpi_device *adev, int clock_num)
248 {
249         struct clk *clk;
250         char name[14];
251         int ret;
252
253         if (clock_num < 0)
254                 return 0;
255
256         snprintf(name, sizeof(name), "pmc_plt_clk_%d", clock_num);
257
258         clk = clk_get(NULL, name);
259         if (IS_ERR(clk)) {
260                 ret = PTR_ERR(clk);
261                 acpi_handle_err(adev->handle, "%s: Error getting clk %s: %d\n",
262                                 dev_name(&adev->dev), name, ret);
263                 return ret;
264         }
265
266         /*
267          * The firmware might enable the clock at boot, to change
268          * the rate we must ensure the clock is disabled.
269          */
270         ret = clk_prepare_enable(clk);
271         if (!ret)
272                 clk_disable_unprepare(clk);
273         if (!ret)
274                 ret = clk_set_rate(clk, PMC_CLK_RATE_19_2MHZ);
275         if (ret)
276                 acpi_handle_err(adev->handle, "%s: Error setting clk-rate for %s: %d\n",
277                                 dev_name(&adev->dev), name, ret);
278
279         clk_put(clk);
280         return ret;
281 }
282
283 static int atomisp_csi2_get_port(struct acpi_device *adev, int clock_num)
284 {
285         int port;
286
287         /*
288          * Compare clock-number to the PMC-clock used for CsiPort 1
289          * in the CHT/BYT reference designs.
290          */
291         if (IS_ISP2401)
292                 port = clock_num == 4 ? 1 : 0;
293         else
294                 port = clock_num == 0 ? 1 : 0;
295
296         /* Intel DSM or DMI quirk overrides _PR0 CLK derived default */
297         return gmin_cfg_get_int(adev, "CsiPort", port);
298 }
299
300 /* Note this always returns 1 to continue looping so that res_count is accurate */
301 static int atomisp_csi2_handle_acpi_gpio_res(struct acpi_resource *ares, void *_data)
302 {
303         struct atomisp_csi2_acpi_gpio_parsing_data *data = _data;
304         struct acpi_resource_gpio *agpio;
305         const char *name;
306         bool active_low;
307         unsigned int i;
308         u32 settings = 0;
309         u16 pin;
310
311         if (!acpi_gpio_get_io_resource(ares, &agpio))
312                 return 1; /* Not a GPIO, continue the loop */
313
314         data->res_count++;
315
316         pin = agpio->pin_table[0];
317         for (i = 0; i < data->settings_count; i++) {
318                 if (INTEL_GPIO_DSM_PIN(data->settings[i]) == pin) {
319                         settings = data->settings[i];
320                         break;
321                 }
322         }
323
324         if (i == data->settings_count) {
325                 acpi_handle_warn(data->adev->handle,
326                                  "%s: Could not find DSM GPIO settings for pin %u\n",
327                                  dev_name(&data->adev->dev), pin);
328                 return 1;
329         }
330
331         switch (INTEL_GPIO_DSM_TYPE(settings)) {
332         case 0:
333                 name = "reset-gpios";
334                 break;
335         case 1:
336                 name = "powerdown-gpios";
337                 break;
338         default:
339                 acpi_handle_warn(data->adev->handle, "%s: Unknown GPIO type 0x%02lx for pin %u\n",
340                                  dev_name(&data->adev->dev),
341                                  INTEL_GPIO_DSM_TYPE(settings), pin);
342                 return 1;
343         }
344
345         /*
346          * Both reset and power-down need to be logical false when the sensor
347          * is on (sensor should not be in reset and not be powered-down). So
348          * when the sensor-on-value (which is the physical pin value) is high,
349          * then the signal is active-low.
350          */
351         active_low = INTEL_GPIO_DSM_SENSOR_ON_VAL(settings);
352
353         i = data->map_count;
354         if (i == CSI2_MAX_ACPI_GPIOS)
355                 return 1;
356
357         /* res_count is already incremented */
358         data->map->params[i].crs_entry_index = data->res_count - 1;
359         data->map->params[i].active_low = active_low;
360         data->map->mapping[i].name = name;
361         data->map->mapping[i].data = &data->map->params[i];
362         data->map->mapping[i].size = 1;
363         data->map_count++;
364
365         acpi_handle_info(data->adev->handle, "%s: %s crs %d %s pin %u active-%s\n",
366                          dev_name(&data->adev->dev), name,
367                          data->res_count - 1, agpio->resource_source.string_ptr,
368                          pin, active_low ? "low" : "high");
369
370         return 1;
371 }
372
373 /*
374  * Helper function to create an ACPI GPIO lookup table for sensor reset and
375  * powerdown signals on Intel Bay Trail (BYT) and Cherry Trail (CHT) devices,
376  * including setting the correct polarity for the GPIO.
377  *
378  * This uses the "79234640-9e10-4fea-a5c1-b5aa8b19756f" DSM method directly
379  * on the sensor device's ACPI node. This is different from later Intel
380  * hardware which has a separate INT3472 acpi_device with this info.
381  *
382  * This function must be called before creating the sw-noded describing
383  * the fwnode graph endpoint. And sensor drivers used on these devices
384  * must return -EPROBE_DEFER when there is no endpoint description yet.
385  * Together this guarantees that the GPIO lookups are in place before
386  * the sensor driver tries to get GPIOs with gpiod_get().
387  *
388  * Note this code uses the same DSM GUID as the int3472_gpio_guid in
389  * the INT3472 discrete.c code and there is some overlap, but there are
390  * enough differences that it is difficult to share the code.
391  */
392 static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev)
393 {
394         struct atomisp_csi2_acpi_gpio_parsing_data data = { };
395         LIST_HEAD(resource_list);
396         union acpi_object *obj;
397         unsigned int i, j;
398         int ret;
399
400         obj = acpi_evaluate_dsm_typed(adev->handle, &intel_sensor_module_guid,
401                                       0x00, 1, NULL, ACPI_TYPE_STRING);
402         if (obj) {
403                 acpi_handle_info(adev->handle, "%s: Sensor module id: '%s'\n",
404                                  dev_name(&adev->dev), obj->string.pointer);
405                 ACPI_FREE(obj);
406         }
407
408         /*
409          * First get the GPIO-settings count and then get count GPIO-settings
410          * values. Note the order of these may differ from the order in which
411          * the GPIOs are listed on the ACPI resources! So we first store them all
412          * and then enumerate the ACPI resources and match them up by pin number.
413          */
414         obj = acpi_evaluate_dsm_typed(adev->handle,
415                                       &intel_sensor_gpio_info_guid, 0x00, 1,
416                                       NULL, ACPI_TYPE_INTEGER);
417         if (!obj) {
418                 acpi_handle_err(adev->handle, "%s: No _DSM entry for GPIO pin count\n",
419                                 dev_name(&adev->dev));
420                 return -EIO;
421         }
422
423         data.settings_count = obj->integer.value;
424         ACPI_FREE(obj);
425
426         if (data.settings_count > CSI2_MAX_ACPI_GPIOS) {
427                 acpi_handle_err(adev->handle, "%s: Too many GPIOs %u > %u\n",
428                                 dev_name(&adev->dev), data.settings_count,
429                                 CSI2_MAX_ACPI_GPIOS);
430                 return -EOVERFLOW;
431         }
432
433         for (i = 0; i < data.settings_count; i++) {
434                 /*
435                  * i + 2 because the index of this _DSM function is 1-based
436                  * and the first function is just a count.
437                  */
438                 obj = acpi_evaluate_dsm_typed(adev->handle,
439                                               &intel_sensor_gpio_info_guid,
440                                               0x00, i + 2,
441                                               NULL, ACPI_TYPE_INTEGER);
442                 if (!obj) {
443                         acpi_handle_err(adev->handle, "%s: No _DSM entry for pin %u\n",
444                                         dev_name(&adev->dev), i);
445                         return -EIO;
446                 }
447
448                 data.settings[i] = obj->integer.value;
449                 ACPI_FREE(obj);
450         }
451
452         /* Since we match up by pin-number the pin-numbers must be unique */
453         for (i = 0; i < data.settings_count; i++) {
454                 for (j = i + 1; j < data.settings_count; j++) {
455                         if (INTEL_GPIO_DSM_PIN(data.settings[i]) !=
456                             INTEL_GPIO_DSM_PIN(data.settings[j]))
457                                 continue;
458
459                         acpi_handle_err(adev->handle, "%s: Duplicate pin number %lu\n",
460                                         dev_name(&adev->dev),
461                                         INTEL_GPIO_DSM_PIN(data.settings[i]));
462                         return -EIO;
463                 }
464         }
465
466         data.map = kzalloc(sizeof(*data.map), GFP_KERNEL);
467         if (!data.map)
468                 return -ENOMEM;
469
470         /* Now parse the ACPI resources and build the lookup table */
471         data.adev = adev;
472         ret = acpi_dev_get_resources(adev, &resource_list,
473                                      atomisp_csi2_handle_acpi_gpio_res, &data);
474         if (ret < 0)
475                 return ret;
476
477         acpi_dev_free_resource_list(&resource_list);
478
479         if (data.map_count != data.settings_count ||
480             data.res_count != data.settings_count)
481                 acpi_handle_warn(adev->handle, "%s: ACPI GPIO resources vs DSM GPIO-info count mismatch (dsm: %d res: %d map %d\n",
482                                  dev_name(&adev->dev), data.settings_count,
483                                  data.res_count, data.map_count);
484
485         ret = acpi_dev_add_driver_gpios(adev, data.map->mapping);
486         if (ret)
487                 acpi_handle_err(adev->handle, "%s: Error adding driver GPIOs: %d\n",
488                                 dev_name(&adev->dev), ret);
489
490         return ret;
491 }
492
493 static const struct acpi_device_id atomisp_sensor_configs[] = {
494         ATOMISP_SENSOR_CONFIG("INT33BE", 2),    /* OV5693 */
495         {}
496 };
497
498 static int atomisp_csi2_parse_sensor_fwnode(struct acpi_device *adev,
499                                             struct ipu_sensor *sensor)
500 {
501         const struct acpi_device_id *id;
502         int ret, clock_num;
503         int lanes = 1;
504
505         id = acpi_match_acpi_device(atomisp_sensor_configs, adev);
506         if (id) {
507                 struct atomisp_sensor_config *cfg =
508                         (struct atomisp_sensor_config *)id->driver_data;
509
510                 lanes = cfg->lanes;
511         }
512
513         /*
514          * ACPI takes care of turning the PMC clock on and off, but on BYT
515          * the clock defaults to 25 MHz instead of the expected 19.2 MHz.
516          * Get the PMC-clock number from ACPI PR0 method and set it to 19.2 MHz.
517          * The PMC-clock number is also used to determine the default CSI port.
518          */
519         clock_num = atomisp_csi2_get_pmc_clk_nr_from_acpi_pr0(adev);
520
521         ret = atomisp_csi2_set_pmc_clk_freq(adev, clock_num);
522         if (ret)
523                 return ret;
524
525         sensor->link = atomisp_csi2_get_port(adev, clock_num);
526         if (sensor->link >= ATOMISP_CAMERA_NR_PORTS) {
527                 acpi_handle_err(adev->handle, "%s: Invalid port: %u\n",
528                                 dev_name(&adev->dev), sensor->link);
529                 return -EINVAL;
530         }
531
532         sensor->lanes = gmin_cfg_get_int(adev, "CsiLanes", lanes);
533         if (sensor->lanes > IPU_MAX_LANES) {
534                 acpi_handle_err(adev->handle, "%s: Invalid lane-count: %d\n",
535                                 dev_name(&adev->dev), sensor->lanes);
536                 return -EINVAL;
537         }
538
539         ret = atomisp_csi2_add_gpio_mappings(adev);
540         if (ret)
541                 return ret;
542
543         sensor->mclkspeed = PMC_CLK_RATE_19_2MHZ;
544         sensor->rotation = 0;
545         sensor->orientation = (sensor->link == 1) ?
546                 V4L2_FWNODE_ORIENTATION_BACK : V4L2_FWNODE_ORIENTATION_FRONT;
547
548         return 0;
549 }
550
551 int atomisp_csi2_bridge_init(struct atomisp_device *isp)
552 {
553         struct device *dev = isp->dev;
554         struct fwnode_handle *fwnode;
555
556         /*
557          * This function is intended to run only once and then leave
558          * the created nodes attached even after a rmmod, therefore:
559          * 1. The bridge memory is leaked deliberately on success
560          * 2. If a secondary fwnode is already set exit early.
561          */
562         fwnode = dev_fwnode(dev);
563         if (fwnode && fwnode->secondary)
564                 return 0;
565
566         return ipu_bridge_init(dev, atomisp_csi2_parse_sensor_fwnode);
567 }
568
569 /******* V4L2 sub-device asynchronous registration callbacks***********/
570
571 struct sensor_async_subdev {
572         struct v4l2_async_connection asd;
573         int port;
574 };
575
576 #define to_sensor_asd(a)        container_of(a, struct sensor_async_subdev, asd)
577 #define notifier_to_atomisp(n)  container_of(n, struct atomisp_device, notifier)
578
579 /* .bound() notifier callback when a match is found */
580 static int atomisp_notifier_bound(struct v4l2_async_notifier *notifier,
581                                   struct v4l2_subdev *sd,
582                                   struct v4l2_async_connection *asd)
583 {
584         struct atomisp_device *isp = notifier_to_atomisp(notifier);
585         struct sensor_async_subdev *s_asd = to_sensor_asd(asd);
586
587         if (s_asd->port >= ATOMISP_CAMERA_NR_PORTS) {
588                 dev_err(isp->dev, "port %d not supported\n", s_asd->port);
589                 return -EINVAL;
590         }
591
592         if (isp->sensor_subdevs[s_asd->port]) {
593                 dev_err(isp->dev, "port %d already has a sensor attached\n", s_asd->port);
594                 return -EBUSY;
595         }
596
597         isp->sensor_subdevs[s_asd->port] = sd;
598         return 0;
599 }
600
601 /* The .unbind callback */
602 static void atomisp_notifier_unbind(struct v4l2_async_notifier *notifier,
603                                     struct v4l2_subdev *sd,
604                                     struct v4l2_async_connection *asd)
605 {
606         struct atomisp_device *isp = notifier_to_atomisp(notifier);
607         struct sensor_async_subdev *s_asd = to_sensor_asd(asd);
608
609         isp->sensor_subdevs[s_asd->port] = NULL;
610 }
611
612 /* .complete() is called after all subdevices have been located */
613 static int atomisp_notifier_complete(struct v4l2_async_notifier *notifier)
614 {
615         struct atomisp_device *isp = notifier_to_atomisp(notifier);
616
617         return atomisp_register_device_nodes(isp);
618 }
619
620 static const struct v4l2_async_notifier_operations atomisp_async_ops = {
621         .bound = atomisp_notifier_bound,
622         .unbind = atomisp_notifier_unbind,
623         .complete = atomisp_notifier_complete,
624 };
625
626 int atomisp_csi2_bridge_parse_firmware(struct atomisp_device *isp)
627 {
628         int i, mipi_port, ret;
629
630         v4l2_async_nf_init(&isp->notifier, &isp->v4l2_dev);
631         isp->notifier.ops = &atomisp_async_ops;
632
633         for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
634                 struct v4l2_fwnode_endpoint vep = {
635                         .bus_type = V4L2_MBUS_CSI2_DPHY,
636                 };
637                 struct sensor_async_subdev *s_asd;
638                 struct fwnode_handle *ep;
639
640                 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev), i, 0,
641                                                      FWNODE_GRAPH_ENDPOINT_NEXT);
642                 if (!ep)
643                         continue;
644
645                 ret = v4l2_fwnode_endpoint_parse(ep, &vep);
646                 if (ret)
647                         goto err_parse;
648
649                 if (vep.base.port >= ATOMISP_CAMERA_NR_PORTS) {
650                         dev_err(isp->dev, "port %d not supported\n", vep.base.port);
651                         ret = -EINVAL;
652                         goto err_parse;
653                 }
654
655                 mipi_port = atomisp_port_to_mipi_port(isp, vep.base.port);
656                 isp->sensor_lanes[mipi_port] = vep.bus.mipi_csi2.num_data_lanes;
657
658                 s_asd = v4l2_async_nf_add_fwnode_remote(&isp->notifier, ep,
659                                                         struct sensor_async_subdev);
660                 if (IS_ERR(s_asd)) {
661                         ret = PTR_ERR(s_asd);
662                         goto err_parse;
663                 }
664
665                 s_asd->port = vep.base.port;
666
667                 fwnode_handle_put(ep);
668                 continue;
669
670 err_parse:
671                 fwnode_handle_put(ep);
672                 return ret;
673         }
674
675         return 0;
676 }