forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/drivers/media/v4l2-core/v4l2-fwnode.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * V4L2 fwnode binding parsing library
34 *
....@@ -12,10 +13,6 @@
1213 *
1314 * Copyright (C) 2012 Renesas Electronics Corp.
1415 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
15
- *
16
- * This program is free software; you can redistribute it and/or modify
17
- * it under the terms of version 2 of the GNU General Public License as
18
- * published by the Free Software Foundation.
1916 */
2017 #include <linux/acpi.h>
2118 #include <linux/kernel.h>
....@@ -36,194 +33,480 @@
3633 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
3734 V4L2_FWNODE_BUS_TYPE_CSI1,
3835 V4L2_FWNODE_BUS_TYPE_CCP2,
36
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
37
+ V4L2_FWNODE_BUS_TYPE_PARALLEL,
38
+ V4L2_FWNODE_BUS_TYPE_BT656,
3939 NR_OF_V4L2_FWNODE_BUS_TYPE,
4040 };
4141
42
+static const struct v4l2_fwnode_bus_conv {
43
+ enum v4l2_fwnode_bus_type fwnode_bus_type;
44
+ enum v4l2_mbus_type mbus_type;
45
+ const char *name;
46
+} buses[] = {
47
+ {
48
+ V4L2_FWNODE_BUS_TYPE_GUESS,
49
+ V4L2_MBUS_UNKNOWN,
50
+ "not specified",
51
+ }, {
52
+ V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
53
+ V4L2_MBUS_CSI2_CPHY,
54
+ "MIPI CSI-2 C-PHY",
55
+ }, {
56
+ V4L2_FWNODE_BUS_TYPE_CSI1,
57
+ V4L2_MBUS_CSI1,
58
+ "MIPI CSI-1",
59
+ }, {
60
+ V4L2_FWNODE_BUS_TYPE_CCP2,
61
+ V4L2_MBUS_CCP2,
62
+ "compact camera port 2",
63
+ }, {
64
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
65
+ V4L2_MBUS_CSI2_DPHY,
66
+ "MIPI CSI-2 D-PHY",
67
+ }, {
68
+ V4L2_FWNODE_BUS_TYPE_PARALLEL,
69
+ V4L2_MBUS_PARALLEL,
70
+ "parallel",
71
+ }, {
72
+ V4L2_FWNODE_BUS_TYPE_BT656,
73
+ V4L2_MBUS_BT656,
74
+ "Bt.656",
75
+ }
76
+};
77
+
78
+static const struct v4l2_fwnode_bus_conv *
79
+get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
80
+{
81
+ unsigned int i;
82
+
83
+ for (i = 0; i < ARRAY_SIZE(buses); i++)
84
+ if (buses[i].fwnode_bus_type == type)
85
+ return &buses[i];
86
+
87
+ return NULL;
88
+}
89
+
90
+static enum v4l2_mbus_type
91
+v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
92
+{
93
+ const struct v4l2_fwnode_bus_conv *conv =
94
+ get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
95
+
96
+ return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
97
+}
98
+
99
+static const char *
100
+v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
101
+{
102
+ const struct v4l2_fwnode_bus_conv *conv =
103
+ get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
104
+
105
+ return conv ? conv->name : "not found";
106
+}
107
+
108
+static const struct v4l2_fwnode_bus_conv *
109
+get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
110
+{
111
+ unsigned int i;
112
+
113
+ for (i = 0; i < ARRAY_SIZE(buses); i++)
114
+ if (buses[i].mbus_type == type)
115
+ return &buses[i];
116
+
117
+ return NULL;
118
+}
119
+
120
+static const char *
121
+v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
122
+{
123
+ const struct v4l2_fwnode_bus_conv *conv =
124
+ get_v4l2_fwnode_bus_conv_by_mbus(type);
125
+
126
+ return conv ? conv->name : "not found";
127
+}
128
+
42129 static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
43
- struct v4l2_fwnode_endpoint *vep)
130
+ struct v4l2_fwnode_endpoint *vep,
131
+ enum v4l2_mbus_type bus_type)
44132 {
45133 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
46
- bool have_clk_lane = false;
134
+ bool have_clk_lane = false, have_data_lanes = false,
135
+ have_lane_polarities = false;
47136 unsigned int flags = 0, lanes_used = 0;
137
+ u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
138
+ u32 clock_lane = 0;
139
+ unsigned int num_data_lanes = 0;
140
+ bool use_default_lane_mapping = false;
48141 unsigned int i;
49142 u32 v;
50143 int rval;
51144
52
- rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
53
- if (rval > 0) {
54
- u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
145
+ if (bus_type == V4L2_MBUS_CSI2_DPHY ||
146
+ bus_type == V4L2_MBUS_CSI2_CPHY) {
147
+ use_default_lane_mapping = true;
55148
56
- bus->num_data_lanes =
149
+ num_data_lanes = min_t(u32, bus->num_data_lanes,
150
+ V4L2_FWNODE_CSI2_MAX_DATA_LANES);
151
+
152
+ clock_lane = bus->clock_lane;
153
+ if (clock_lane)
154
+ use_default_lane_mapping = false;
155
+
156
+ for (i = 0; i < num_data_lanes; i++) {
157
+ array[i] = bus->data_lanes[i];
158
+ if (array[i])
159
+ use_default_lane_mapping = false;
160
+ }
161
+
162
+ if (use_default_lane_mapping)
163
+ pr_debug("no lane mapping given, using defaults\n");
164
+ }
165
+
166
+ rval = fwnode_property_count_u32(fwnode, "data-lanes");
167
+ if (rval > 0) {
168
+ num_data_lanes =
57169 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
58170
59171 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
60
- bus->num_data_lanes);
172
+ num_data_lanes);
61173
62
- for (i = 0; i < bus->num_data_lanes; i++) {
63
- if (lanes_used & BIT(array[i]))
64
- pr_warn("duplicated lane %u in data-lanes\n",
174
+ have_data_lanes = true;
175
+ if (use_default_lane_mapping) {
176
+ pr_debug("data-lanes property exists; disabling default mapping\n");
177
+ use_default_lane_mapping = false;
178
+ }
179
+ }
180
+
181
+ for (i = 0; i < num_data_lanes; i++) {
182
+ if (lanes_used & BIT(array[i])) {
183
+ if (have_data_lanes || !use_default_lane_mapping)
184
+ pr_warn("duplicated lane %u in data-lanes, using defaults\n",
65185 array[i]);
66
- lanes_used |= BIT(array[i]);
186
+ use_default_lane_mapping = true;
187
+ }
188
+ lanes_used |= BIT(array[i]);
67189
68
- bus->data_lanes[i] = array[i];
190
+ if (have_data_lanes)
191
+ pr_debug("lane %u position %u\n", i, array[i]);
192
+ }
193
+
194
+ rval = fwnode_property_count_u32(fwnode, "lane-polarities");
195
+ if (rval > 0) {
196
+ if (rval != 1 + num_data_lanes /* clock+data */) {
197
+ pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
198
+ 1 + num_data_lanes, rval);
199
+ return -EINVAL;
69200 }
70201
71
- rval = fwnode_property_read_u32_array(fwnode,
72
- "lane-polarities", NULL,
73
- 0);
74
- if (rval > 0) {
75
- if (rval != 1 + bus->num_data_lanes /* clock+data */) {
76
- pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
77
- 1 + bus->num_data_lanes, rval);
78
- return -EINVAL;
79
- }
80
-
81
- fwnode_property_read_u32_array(fwnode,
82
- "lane-polarities", array,
83
- 1 + bus->num_data_lanes);
84
-
85
- for (i = 0; i < 1 + bus->num_data_lanes; i++)
86
- bus->lane_polarities[i] = array[i];
87
- }
88
-
202
+ have_lane_polarities = true;
89203 }
90204
91205 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
92
- if (lanes_used & BIT(v))
93
- pr_warn("duplicated lane %u in clock-lanes\n", v);
94
- lanes_used |= BIT(v);
95
-
96
- bus->clock_lane = v;
206
+ clock_lane = v;
207
+ pr_debug("clock lane position %u\n", v);
97208 have_clk_lane = true;
98209 }
99210
100
- if (fwnode_property_present(fwnode, "clock-noncontinuous"))
101
- flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
102
- else if (have_clk_lane || bus->num_data_lanes > 0)
103
- flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
211
+ if (have_clk_lane && lanes_used & BIT(clock_lane) &&
212
+ !use_default_lane_mapping) {
213
+ pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
214
+ v);
215
+ use_default_lane_mapping = true;
216
+ }
104217
105
- bus->flags = flags;
106
- vep->bus_type = V4L2_MBUS_CSI2;
218
+ if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
219
+ flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
220
+ pr_debug("non-continuous clock\n");
221
+ } else {
222
+ flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
223
+ }
224
+
225
+ if (bus_type == V4L2_MBUS_CSI2_DPHY ||
226
+ bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
227
+ have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
228
+ /* Only D-PHY has a clock lane. */
229
+ unsigned int dfl_data_lane_index =
230
+ bus_type == V4L2_MBUS_CSI2_DPHY;
231
+
232
+ bus->flags = flags;
233
+ if (bus_type == V4L2_MBUS_UNKNOWN)
234
+ vep->bus_type = V4L2_MBUS_CSI2_DPHY;
235
+ bus->num_data_lanes = num_data_lanes;
236
+
237
+ if (use_default_lane_mapping) {
238
+ bus->clock_lane = 0;
239
+ for (i = 0; i < num_data_lanes; i++)
240
+ bus->data_lanes[i] = dfl_data_lane_index + i;
241
+ } else {
242
+ bus->clock_lane = clock_lane;
243
+ for (i = 0; i < num_data_lanes; i++)
244
+ bus->data_lanes[i] = array[i];
245
+ }
246
+
247
+ if (have_lane_polarities) {
248
+ fwnode_property_read_u32_array(fwnode,
249
+ "lane-polarities", array,
250
+ 1 + num_data_lanes);
251
+
252
+ for (i = 0; i < 1 + num_data_lanes; i++) {
253
+ bus->lane_polarities[i] = array[i];
254
+ pr_debug("lane %u polarity %sinverted",
255
+ i, array[i] ? "" : "not ");
256
+ }
257
+ } else {
258
+ pr_debug("no lane polarities defined, assuming not inverted\n");
259
+ }
260
+ }
107261
108262 return 0;
109263 }
110264
111
-static void v4l2_fwnode_endpoint_parse_parallel_bus(
112
- struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
265
+#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
266
+ V4L2_MBUS_HSYNC_ACTIVE_LOW | \
267
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
268
+ V4L2_MBUS_VSYNC_ACTIVE_LOW | \
269
+ V4L2_MBUS_FIELD_EVEN_HIGH | \
270
+ V4L2_MBUS_FIELD_EVEN_LOW)
271
+
272
+static void
273
+v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
274
+ struct v4l2_fwnode_endpoint *vep,
275
+ enum v4l2_mbus_type bus_type)
113276 {
114277 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
115278 unsigned int flags = 0;
116279 u32 v;
117280
118
- if (!fwnode_property_read_u32(fwnode, "hsync-active", &v))
281
+ if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
282
+ flags = bus->flags;
283
+
284
+ if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
285
+ flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
286
+ V4L2_MBUS_HSYNC_ACTIVE_LOW);
119287 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
120288 V4L2_MBUS_HSYNC_ACTIVE_LOW;
289
+ pr_debug("hsync-active %s\n", v ? "high" : "low");
290
+ }
121291
122
- if (!fwnode_property_read_u32(fwnode, "vsync-active", &v))
292
+ if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
293
+ flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
294
+ V4L2_MBUS_VSYNC_ACTIVE_LOW);
123295 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
124296 V4L2_MBUS_VSYNC_ACTIVE_LOW;
297
+ pr_debug("vsync-active %s\n", v ? "high" : "low");
298
+ }
125299
126
- if (!fwnode_property_read_u32(fwnode, "field-even-active", &v))
300
+ if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
301
+ flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
302
+ V4L2_MBUS_FIELD_EVEN_LOW);
127303 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
128304 V4L2_MBUS_FIELD_EVEN_LOW;
129
- if (flags)
130
- vep->bus_type = V4L2_MBUS_PARALLEL;
131
- else
132
- vep->bus_type = V4L2_MBUS_BT656;
305
+ pr_debug("field-even-active %s\n", v ? "high" : "low");
306
+ }
133307
134
- if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v))
308
+ if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
309
+ flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
310
+ V4L2_MBUS_PCLK_SAMPLE_FALLING);
135311 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
136312 V4L2_MBUS_PCLK_SAMPLE_FALLING;
313
+ pr_debug("pclk-sample %s\n", v ? "high" : "low");
314
+ }
137315
138
- if (!fwnode_property_read_u32(fwnode, "data-active", &v))
316
+ if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
317
+ flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
318
+ V4L2_MBUS_DATA_ACTIVE_LOW);
139319 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
140320 V4L2_MBUS_DATA_ACTIVE_LOW;
321
+ pr_debug("data-active %s\n", v ? "high" : "low");
322
+ }
141323
142
- if (fwnode_property_present(fwnode, "slave-mode"))
324
+ if (fwnode_property_present(fwnode, "slave-mode")) {
325
+ pr_debug("slave mode\n");
326
+ flags &= ~V4L2_MBUS_MASTER;
143327 flags |= V4L2_MBUS_SLAVE;
144
- else
328
+ } else {
329
+ flags &= ~V4L2_MBUS_SLAVE;
145330 flags |= V4L2_MBUS_MASTER;
331
+ }
146332
147
- if (!fwnode_property_read_u32(fwnode, "bus-width", &v))
333
+ if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
148334 bus->bus_width = v;
335
+ pr_debug("bus-width %u\n", v);
336
+ }
149337
150
- if (!fwnode_property_read_u32(fwnode, "data-shift", &v))
338
+ if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
151339 bus->data_shift = v;
340
+ pr_debug("data-shift %u\n", v);
341
+ }
152342
153
- if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v))
343
+ if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
344
+ flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
345
+ V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
154346 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
155347 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
348
+ pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
349
+ }
156350
157
- if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v))
351
+ if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
352
+ flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
353
+ V4L2_MBUS_DATA_ENABLE_LOW);
158354 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
159355 V4L2_MBUS_DATA_ENABLE_LOW;
356
+ pr_debug("data-enable-active %s\n", v ? "high" : "low");
357
+ }
160358
161
- bus->flags = flags;
162
-
359
+ switch (bus_type) {
360
+ default:
361
+ bus->flags = flags;
362
+ if (flags & PARALLEL_MBUS_FLAGS)
363
+ vep->bus_type = V4L2_MBUS_PARALLEL;
364
+ else
365
+ vep->bus_type = V4L2_MBUS_BT656;
366
+ break;
367
+ case V4L2_MBUS_PARALLEL:
368
+ vep->bus_type = V4L2_MBUS_PARALLEL;
369
+ bus->flags = flags;
370
+ break;
371
+ case V4L2_MBUS_BT656:
372
+ vep->bus_type = V4L2_MBUS_BT656;
373
+ bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
374
+ break;
375
+ }
163376 }
164377
165378 static void
166379 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
167380 struct v4l2_fwnode_endpoint *vep,
168
- u32 bus_type)
381
+ enum v4l2_mbus_type bus_type)
169382 {
170383 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
171384 u32 v;
172385
173
- if (!fwnode_property_read_u32(fwnode, "clock-inv", &v))
386
+ if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
174387 bus->clock_inv = v;
388
+ pr_debug("clock-inv %u\n", v);
389
+ }
175390
176
- if (!fwnode_property_read_u32(fwnode, "strobe", &v))
391
+ if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
177392 bus->strobe = v;
393
+ pr_debug("strobe %u\n", v);
394
+ }
178395
179
- if (!fwnode_property_read_u32(fwnode, "data-lanes", &v))
396
+ if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
180397 bus->data_lane = v;
398
+ pr_debug("data-lanes %u\n", v);
399
+ }
181400
182
- if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v))
401
+ if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
183402 bus->clock_lane = v;
403
+ pr_debug("clock-lanes %u\n", v);
404
+ }
184405
185
- if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
406
+ if (bus_type == V4L2_MBUS_CCP2)
186407 vep->bus_type = V4L2_MBUS_CCP2;
187408 else
188409 vep->bus_type = V4L2_MBUS_CSI1;
189410 }
190411
191
-int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
192
- struct v4l2_fwnode_endpoint *vep)
412
+static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
413
+ struct v4l2_fwnode_endpoint *vep)
193414 {
194
- u32 bus_type = 0;
415
+ u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
416
+ enum v4l2_mbus_type mbus_type;
195417 int rval;
418
+
419
+ if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
420
+ /* Zero fields from bus union to until the end */
421
+ memset(&vep->bus, 0,
422
+ sizeof(*vep) - offsetof(typeof(*vep), bus));
423
+ }
424
+
425
+ pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
426
+
427
+ /*
428
+ * Zero the fwnode graph endpoint memory in case we don't end up parsing
429
+ * the endpoint.
430
+ */
431
+ memset(&vep->base, 0, sizeof(vep->base));
432
+
433
+ fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
434
+ pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
435
+ v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
436
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type),
437
+ vep->bus_type);
438
+ mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
439
+ if (mbus_type == V4L2_MBUS_INVALID) {
440
+ pr_debug("unsupported bus type %u\n", bus_type);
441
+ return -EINVAL;
442
+ }
443
+
444
+ if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
445
+ if (mbus_type != V4L2_MBUS_UNKNOWN &&
446
+ vep->bus_type != mbus_type) {
447
+ pr_debug("expecting bus type %s\n",
448
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type));
449
+ return -ENXIO;
450
+ }
451
+ } else {
452
+ vep->bus_type = mbus_type;
453
+ }
454
+
455
+ switch (vep->bus_type) {
456
+ case V4L2_MBUS_UNKNOWN:
457
+ rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
458
+ V4L2_MBUS_UNKNOWN);
459
+ if (rval)
460
+ return rval;
461
+
462
+ if (vep->bus_type == V4L2_MBUS_UNKNOWN)
463
+ v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
464
+ V4L2_MBUS_UNKNOWN);
465
+
466
+ pr_debug("assuming media bus type %s (%u)\n",
467
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type),
468
+ vep->bus_type);
469
+
470
+ break;
471
+ case V4L2_MBUS_CCP2:
472
+ case V4L2_MBUS_CSI1:
473
+ v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
474
+
475
+ break;
476
+ case V4L2_MBUS_CSI2_DPHY:
477
+ case V4L2_MBUS_CSI2_CPHY:
478
+ rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
479
+ vep->bus_type);
480
+ if (rval)
481
+ return rval;
482
+
483
+ break;
484
+ case V4L2_MBUS_PARALLEL:
485
+ case V4L2_MBUS_BT656:
486
+ v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
487
+ vep->bus_type);
488
+
489
+ break;
490
+ default:
491
+ pr_warn("unsupported bus type %u\n", mbus_type);
492
+ return -EINVAL;
493
+ }
196494
197495 fwnode_graph_parse_endpoint(fwnode, &vep->base);
198496
199
- /* Zero fields from bus_type to until the end */
200
- memset(&vep->bus_type, 0, sizeof(*vep) -
201
- offsetof(typeof(*vep), bus_type));
497
+ return 0;
498
+}
202499
203
- fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
500
+int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
501
+ struct v4l2_fwnode_endpoint *vep)
502
+{
503
+ int ret;
204504
205
- switch (bus_type) {
206
- case V4L2_FWNODE_BUS_TYPE_GUESS:
207
- rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
208
- if (rval)
209
- return rval;
210
- /*
211
- * Parse the parallel video bus properties only if none
212
- * of the MIPI CSI-2 specific properties were found.
213
- */
214
- if (vep->bus.mipi_csi2.flags == 0)
215
- v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
505
+ ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
216506
217
- return 0;
218
- case V4L2_FWNODE_BUS_TYPE_CCP2:
219
- case V4L2_FWNODE_BUS_TYPE_CSI1:
220
- v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
507
+ pr_debug("===== end parsing endpoint %pfw\n", fwnode);
221508
222
- return 0;
223
- default:
224
- pr_warn("unsupported bus type %u\n", bus_type);
225
- return -EINVAL;
226
- }
509
+ return ret;
227510 }
228511 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
229512
....@@ -233,81 +516,73 @@
233516 return;
234517
235518 kfree(vep->link_frequencies);
236
- kfree(vep);
519
+ vep->link_frequencies = NULL;
237520 }
238521 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
239522
240
-struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
241
- struct fwnode_handle *fwnode)
523
+int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
524
+ struct v4l2_fwnode_endpoint *vep)
242525 {
243
- struct v4l2_fwnode_endpoint *vep;
244526 int rval;
245527
246
- vep = kzalloc(sizeof(*vep), GFP_KERNEL);
247
- if (!vep)
248
- return ERR_PTR(-ENOMEM);
249
-
250
- rval = v4l2_fwnode_endpoint_parse(fwnode, vep);
528
+ rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
251529 if (rval < 0)
252
- goto out_err;
530
+ return rval;
253531
254
- rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
255
- NULL, 0);
532
+ rval = fwnode_property_count_u64(fwnode, "link-frequencies");
256533 if (rval > 0) {
534
+ unsigned int i;
535
+
257536 vep->link_frequencies =
258537 kmalloc_array(rval, sizeof(*vep->link_frequencies),
259538 GFP_KERNEL);
260
- if (!vep->link_frequencies) {
261
- rval = -ENOMEM;
262
- goto out_err;
263
- }
539
+ if (!vep->link_frequencies)
540
+ return -ENOMEM;
264541
265542 vep->nr_of_link_frequencies = rval;
266543
267
- rval = fwnode_property_read_u64_array(
268
- fwnode, "link-frequencies", vep->link_frequencies,
269
- vep->nr_of_link_frequencies);
270
- if (rval < 0)
271
- goto out_err;
544
+ rval = fwnode_property_read_u64_array(fwnode,
545
+ "link-frequencies",
546
+ vep->link_frequencies,
547
+ vep->nr_of_link_frequencies);
548
+ if (rval < 0) {
549
+ v4l2_fwnode_endpoint_free(vep);
550
+ return rval;
551
+ }
552
+
553
+ for (i = 0; i < vep->nr_of_link_frequencies; i++)
554
+ pr_debug("link-frequencies %u value %llu\n", i,
555
+ vep->link_frequencies[i]);
272556 }
273557
274
- return vep;
558
+ pr_debug("===== end parsing endpoint %pfw\n", fwnode);
275559
276
-out_err:
277
- v4l2_fwnode_endpoint_free(vep);
278
- return ERR_PTR(rval);
560
+ return 0;
279561 }
280562 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
281563
282
-int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
564
+int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
283565 struct v4l2_fwnode_link *link)
284566 {
285
- const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
286
- struct fwnode_handle *fwnode;
567
+ struct fwnode_endpoint fwep;
287568
288569 memset(link, 0, sizeof(*link));
289570
290
- fwnode = fwnode_get_parent(__fwnode);
291
- fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
292
- fwnode = fwnode_get_next_parent(fwnode);
293
- if (is_of_node(fwnode) &&
294
- of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
295
- fwnode = fwnode_get_next_parent(fwnode);
296
- link->local_node = fwnode;
571
+ fwnode_graph_parse_endpoint(fwnode, &fwep);
572
+ link->local_id = fwep.id;
573
+ link->local_port = fwep.port;
574
+ link->local_node = fwnode_graph_get_port_parent(fwnode);
297575
298
- fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
576
+ fwnode = fwnode_graph_get_remote_endpoint(fwnode);
299577 if (!fwnode) {
300578 fwnode_handle_put(fwnode);
301579 return -ENOLINK;
302580 }
303581
304
- fwnode = fwnode_get_parent(fwnode);
305
- fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
306
- fwnode = fwnode_get_next_parent(fwnode);
307
- if (is_of_node(fwnode) &&
308
- of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
309
- fwnode = fwnode_get_next_parent(fwnode);
310
- link->remote_node = fwnode;
582
+ fwnode_graph_parse_endpoint(fwnode, &fwep);
583
+ link->remote_id = fwep.id;
584
+ link->remote_port = fwep.port;
585
+ link->remote_node = fwnode_graph_get_port_parent(fwnode);
311586
312587 return 0;
313588 }
....@@ -320,43 +595,223 @@
320595 }
321596 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
322597
323
-static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
324
- unsigned int max_subdevs)
598
+static const struct v4l2_fwnode_connector_conv {
599
+ enum v4l2_connector_type type;
600
+ const char *compatible;
601
+} connectors[] = {
602
+ {
603
+ .type = V4L2_CONN_COMPOSITE,
604
+ .compatible = "composite-video-connector",
605
+ }, {
606
+ .type = V4L2_CONN_SVIDEO,
607
+ .compatible = "svideo-connector",
608
+ },
609
+};
610
+
611
+static enum v4l2_connector_type
612
+v4l2_fwnode_string_to_connector_type(const char *con_str)
325613 {
326
- struct v4l2_async_subdev **subdevs;
614
+ unsigned int i;
327615
328
- if (max_subdevs <= notifier->max_subdevs)
329
- return 0;
616
+ for (i = 0; i < ARRAY_SIZE(connectors); i++)
617
+ if (!strcmp(con_str, connectors[i].compatible))
618
+ return connectors[i].type;
330619
331
- subdevs = kvmalloc_array(
332
- max_subdevs, sizeof(*notifier->subdevs),
333
- GFP_KERNEL | __GFP_ZERO);
334
- if (!subdevs)
335
- return -ENOMEM;
620
+ return V4L2_CONN_UNKNOWN;
621
+}
336622
337
- if (notifier->subdevs) {
338
- memcpy(subdevs, notifier->subdevs,
339
- sizeof(*subdevs) * notifier->num_subdevs);
623
+static void
624
+v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
625
+ struct v4l2_fwnode_connector *vc)
626
+{
627
+ u32 stds;
628
+ int ret;
340629
341
- kvfree(notifier->subdevs);
630
+ ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
631
+
632
+ /* The property is optional. */
633
+ vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
634
+}
635
+
636
+void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
637
+{
638
+ struct v4l2_connector_link *link, *tmp;
639
+
640
+ if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
641
+ return;
642
+
643
+ list_for_each_entry_safe(link, tmp, &connector->links, head) {
644
+ v4l2_fwnode_put_link(&link->fwnode_link);
645
+ list_del(&link->head);
646
+ kfree(link);
342647 }
343648
344
- notifier->subdevs = subdevs;
345
- notifier->max_subdevs = max_subdevs;
649
+ kfree(connector->label);
650
+ connector->label = NULL;
651
+ connector->type = V4L2_CONN_UNKNOWN;
652
+}
653
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
654
+
655
+static enum v4l2_connector_type
656
+v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
657
+{
658
+ const char *type_name;
659
+ int err;
660
+
661
+ if (!fwnode)
662
+ return V4L2_CONN_UNKNOWN;
663
+
664
+ /* The connector-type is stored within the compatible string. */
665
+ err = fwnode_property_read_string(fwnode, "compatible", &type_name);
666
+ if (err)
667
+ return V4L2_CONN_UNKNOWN;
668
+
669
+ return v4l2_fwnode_string_to_connector_type(type_name);
670
+}
671
+
672
+int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
673
+ struct v4l2_fwnode_connector *connector)
674
+{
675
+ struct fwnode_handle *connector_node;
676
+ enum v4l2_connector_type connector_type;
677
+ const char *label;
678
+ int err;
679
+
680
+ if (!fwnode)
681
+ return -EINVAL;
682
+
683
+ memset(connector, 0, sizeof(*connector));
684
+
685
+ INIT_LIST_HEAD(&connector->links);
686
+
687
+ connector_node = fwnode_graph_get_port_parent(fwnode);
688
+ connector_type = v4l2_fwnode_get_connector_type(connector_node);
689
+ if (connector_type == V4L2_CONN_UNKNOWN) {
690
+ fwnode_handle_put(connector_node);
691
+ connector_node = fwnode_graph_get_remote_port_parent(fwnode);
692
+ connector_type = v4l2_fwnode_get_connector_type(connector_node);
693
+ }
694
+
695
+ if (connector_type == V4L2_CONN_UNKNOWN) {
696
+ pr_err("Unknown connector type\n");
697
+ err = -ENOTCONN;
698
+ goto out;
699
+ }
700
+
701
+ connector->type = connector_type;
702
+ connector->name = fwnode_get_name(connector_node);
703
+ err = fwnode_property_read_string(connector_node, "label", &label);
704
+ connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
705
+
706
+ /* Parse the connector specific properties. */
707
+ switch (connector->type) {
708
+ case V4L2_CONN_COMPOSITE:
709
+ case V4L2_CONN_SVIDEO:
710
+ v4l2_fwnode_connector_parse_analog(connector_node, connector);
711
+ break;
712
+ /* Avoid compiler warnings */
713
+ case V4L2_CONN_UNKNOWN:
714
+ break;
715
+ }
716
+
717
+out:
718
+ fwnode_handle_put(connector_node);
719
+
720
+ return err;
721
+}
722
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
723
+
724
+int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
725
+ struct v4l2_fwnode_connector *connector)
726
+{
727
+ struct fwnode_handle *connector_ep;
728
+ struct v4l2_connector_link *link;
729
+ int err;
730
+
731
+ if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
732
+ return -EINVAL;
733
+
734
+ connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
735
+ if (!connector_ep)
736
+ return -ENOTCONN;
737
+
738
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
739
+ if (!link) {
740
+ err = -ENOMEM;
741
+ goto err;
742
+ }
743
+
744
+ err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
745
+ if (err)
746
+ goto err;
747
+
748
+ fwnode_handle_put(connector_ep);
749
+
750
+ list_add(&link->head, &connector->links);
751
+ connector->nr_of_links++;
752
+
753
+ return 0;
754
+
755
+err:
756
+ kfree(link);
757
+ fwnode_handle_put(connector_ep);
758
+
759
+ return err;
760
+}
761
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
762
+
763
+int v4l2_fwnode_device_parse(struct device *dev,
764
+ struct v4l2_fwnode_device_properties *props)
765
+{
766
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
767
+ u32 val;
768
+ int ret;
769
+
770
+ memset(props, 0, sizeof(*props));
771
+
772
+ props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
773
+ ret = fwnode_property_read_u32(fwnode, "orientation", &val);
774
+ if (!ret) {
775
+ switch (val) {
776
+ case V4L2_FWNODE_ORIENTATION_FRONT:
777
+ case V4L2_FWNODE_ORIENTATION_BACK:
778
+ case V4L2_FWNODE_ORIENTATION_EXTERNAL:
779
+ break;
780
+ default:
781
+ dev_warn(dev, "Unsupported device orientation: %u\n", val);
782
+ return -EINVAL;
783
+ }
784
+
785
+ props->orientation = val;
786
+ dev_dbg(dev, "device orientation: %u\n", val);
787
+ }
788
+
789
+ props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
790
+ ret = fwnode_property_read_u32(fwnode, "rotation", &val);
791
+ if (!ret) {
792
+ if (val >= 360) {
793
+ dev_warn(dev, "Unsupported device rotation: %u\n", val);
794
+ return -EINVAL;
795
+ }
796
+
797
+ props->rotation = val;
798
+ dev_dbg(dev, "device rotation: %u\n", val);
799
+ }
346800
347801 return 0;
348802 }
803
+EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
349804
350
-static int v4l2_async_notifier_fwnode_parse_endpoint(
351
- struct device *dev, struct v4l2_async_notifier *notifier,
352
- struct fwnode_handle *endpoint, unsigned int asd_struct_size,
353
- int (*parse_endpoint)(struct device *dev,
354
- struct v4l2_fwnode_endpoint *vep,
355
- struct v4l2_async_subdev *asd))
805
+static int
806
+v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
807
+ struct v4l2_async_notifier *notifier,
808
+ struct fwnode_handle *endpoint,
809
+ unsigned int asd_struct_size,
810
+ parse_endpoint_func parse_endpoint)
356811 {
812
+ struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
357813 struct v4l2_async_subdev *asd;
358
- struct v4l2_fwnode_endpoint *vep;
359
- int ret = 0;
814
+ int ret;
360815
361816 asd = kzalloc(asd_struct_size, GFP_KERNEL);
362817 if (!asd)
....@@ -366,33 +821,37 @@
366821 asd->match.fwnode =
367822 fwnode_graph_get_remote_port_parent(endpoint);
368823 if (!asd->match.fwnode) {
369
- dev_warn(dev, "bad remote port parent\n");
370
- ret = -EINVAL;
824
+ dev_dbg(dev, "no remote endpoint found\n");
825
+ ret = -ENOTCONN;
371826 goto out_err;
372827 }
373828
374
- vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
375
- if (IS_ERR(vep)) {
376
- ret = PTR_ERR(vep);
829
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
830
+ if (ret) {
377831 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
378832 ret);
379833 goto out_err;
380834 }
381835
382
- ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
836
+ ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
383837 if (ret == -ENOTCONN)
384
- dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
385
- vep->base.id);
838
+ dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
839
+ vep.base.id);
386840 else if (ret < 0)
387841 dev_warn(dev,
388842 "driver could not parse port@%u/endpoint@%u (%d)\n",
389
- vep->base.port, vep->base.id, ret);
390
- v4l2_fwnode_endpoint_free(vep);
843
+ vep.base.port, vep.base.id, ret);
844
+ v4l2_fwnode_endpoint_free(&vep);
391845 if (ret < 0)
392846 goto out_err;
393847
394
- notifier->subdevs[notifier->num_subdevs] = asd;
395
- notifier->num_subdevs++;
848
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
849
+ if (ret < 0) {
850
+ /* not an error if asd already exists */
851
+ if (ret == -EEXIST)
852
+ ret = 0;
853
+ goto out_err;
854
+ }
396855
397856 return 0;
398857
....@@ -403,56 +862,21 @@
403862 return ret == -ENOTCONN ? 0 : ret;
404863 }
405864
406
-static int __v4l2_async_notifier_parse_fwnode_endpoints(
407
- struct device *dev, struct v4l2_async_notifier *notifier,
408
- size_t asd_struct_size, unsigned int port, bool has_port,
409
- int (*parse_endpoint)(struct device *dev,
410
- struct v4l2_fwnode_endpoint *vep,
411
- struct v4l2_async_subdev *asd))
865
+static int
866
+__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
867
+ struct v4l2_async_notifier *notifier,
868
+ size_t asd_struct_size,
869
+ unsigned int port,
870
+ bool has_port,
871
+ parse_endpoint_func parse_endpoint)
412872 {
413873 struct fwnode_handle *fwnode;
414
- unsigned int max_subdevs = notifier->max_subdevs;
415
- int ret;
874
+ int ret = 0;
416875
417876 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
418877 return -EINVAL;
419878
420
- for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
421
- dev_fwnode(dev), fwnode)); ) {
422
- struct fwnode_handle *dev_fwnode;
423
- bool is_available;
424
-
425
- dev_fwnode = fwnode_graph_get_port_parent(fwnode);
426
- is_available = fwnode_device_is_available(dev_fwnode);
427
- fwnode_handle_put(dev_fwnode);
428
- if (!is_available)
429
- continue;
430
-
431
- if (has_port) {
432
- struct fwnode_endpoint ep;
433
-
434
- ret = fwnode_graph_parse_endpoint(fwnode, &ep);
435
- if (ret) {
436
- fwnode_handle_put(fwnode);
437
- return ret;
438
- }
439
-
440
- if (ep.port != port)
441
- continue;
442
- }
443
- max_subdevs++;
444
- }
445
-
446
- /* No subdevs to add? Return here. */
447
- if (max_subdevs == notifier->max_subdevs)
448
- return 0;
449
-
450
- ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
451
- if (ret)
452
- return ret;
453
-
454
- for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
455
- dev_fwnode(dev), fwnode)); ) {
879
+ fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
456880 struct fwnode_handle *dev_fwnode;
457881 bool is_available;
458882
....@@ -473,13 +897,11 @@
473897 continue;
474898 }
475899
476
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
477
- ret = -EINVAL;
478
- break;
479
- }
480
-
481
- ret = v4l2_async_notifier_fwnode_parse_endpoint(
482
- dev, notifier, fwnode, asd_struct_size, parse_endpoint);
900
+ ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
901
+ notifier,
902
+ fwnode,
903
+ asd_struct_size,
904
+ parse_endpoint);
483905 if (ret < 0)
484906 break;
485907 }
....@@ -489,27 +911,29 @@
489911 return ret;
490912 }
491913
492
-int v4l2_async_notifier_parse_fwnode_endpoints(
493
- struct device *dev, struct v4l2_async_notifier *notifier,
494
- size_t asd_struct_size,
495
- int (*parse_endpoint)(struct device *dev,
496
- struct v4l2_fwnode_endpoint *vep,
497
- struct v4l2_async_subdev *asd))
914
+int
915
+v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
916
+ struct v4l2_async_notifier *notifier,
917
+ size_t asd_struct_size,
918
+ parse_endpoint_func parse_endpoint)
498919 {
499
- return __v4l2_async_notifier_parse_fwnode_endpoints(
500
- dev, notifier, asd_struct_size, 0, false, parse_endpoint);
920
+ return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
921
+ asd_struct_size, 0,
922
+ false, parse_endpoint);
501923 }
502924 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
503925
504
-int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
505
- struct device *dev, struct v4l2_async_notifier *notifier,
506
- size_t asd_struct_size, unsigned int port,
507
- int (*parse_endpoint)(struct device *dev,
508
- struct v4l2_fwnode_endpoint *vep,
509
- struct v4l2_async_subdev *asd))
926
+int
927
+v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
928
+ struct v4l2_async_notifier *notifier,
929
+ size_t asd_struct_size,
930
+ unsigned int port,
931
+ parse_endpoint_func parse_endpoint)
510932 {
511
- return __v4l2_async_notifier_parse_fwnode_endpoints(
512
- dev, notifier, asd_struct_size, port, true, parse_endpoint);
933
+ return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
934
+ asd_struct_size,
935
+ port, true,
936
+ parse_endpoint);
513937 }
514938 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
515939
....@@ -524,17 +948,18 @@
524948 * -ENOMEM if memory allocation failed
525949 * -EINVAL if property parsing failed
526950 */
527
-static int v4l2_fwnode_reference_parse(
528
- struct device *dev, struct v4l2_async_notifier *notifier,
529
- const char *prop)
951
+static int v4l2_fwnode_reference_parse(struct device *dev,
952
+ struct v4l2_async_notifier *notifier,
953
+ const char *prop)
530954 {
531955 struct fwnode_reference_args args;
532956 unsigned int index;
533957 int ret;
534958
535959 for (index = 0;
536
- !(ret = fwnode_property_get_reference_args(
537
- dev_fwnode(dev), prop, NULL, 0, index, &args));
960
+ !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
961
+ prop, NULL, 0,
962
+ index, &args));
538963 index++)
539964 fwnode_handle_put(args.fwnode);
540965
....@@ -548,38 +973,26 @@
548973 if (ret != -ENOENT && ret != -ENODATA)
549974 return ret;
550975
551
- ret = v4l2_async_notifier_realloc(notifier,
552
- notifier->num_subdevs + index);
553
- if (ret)
554
- return ret;
555
-
556
- for (index = 0; !fwnode_property_get_reference_args(
557
- dev_fwnode(dev), prop, NULL, 0, index, &args);
976
+ for (index = 0;
977
+ !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
978
+ 0, index, &args);
558979 index++) {
559980 struct v4l2_async_subdev *asd;
560981
561
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
562
- ret = -EINVAL;
563
- goto error;
564
- }
982
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
983
+ args.fwnode,
984
+ sizeof(*asd));
985
+ fwnode_handle_put(args.fwnode);
986
+ if (IS_ERR(asd)) {
987
+ /* not an error if asd already exists */
988
+ if (PTR_ERR(asd) == -EEXIST)
989
+ continue;
565990
566
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
567
- if (!asd) {
568
- ret = -ENOMEM;
569
- goto error;
991
+ return PTR_ERR(asd);
570992 }
571
-
572
- notifier->subdevs[notifier->num_subdevs] = asd;
573
- asd->match.fwnode = args.fwnode;
574
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
575
- notifier->num_subdevs++;
576993 }
577994
578995 return 0;
579
-
580
-error:
581
- fwnode_handle_put(args.fwnode);
582
- return ret;
583996 }
584997
585998 /*
....@@ -600,7 +1013,7 @@
6001013 * root node and the value of that property matching with the integer argument
6011014 * of the reference, at the same index.
6021015 *
603
- * The child fwnode reched at the end of the iteration is then returned to the
1016
+ * The child fwnode reached at the end of the iteration is then returned to the
6041017 * caller.
6051018 *
6061019 * The core reason for this is that you cannot refer to just any node in ACPI.
....@@ -611,7 +1024,10 @@
6111024 * underneath the fwnode identified by the previous tuple, etc. until you
6121025 * reached the fwnode you need.
6131026 *
614
- * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
1027
+ * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A
1028
+ * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under
1029
+ * Documentation/firmware-guide/acpi/dsd/ instead and especially graph.txt,
1030
+ * data-node-references.txt and leds.txt .
6151031 *
6161032 * Scope (\_SB.PCI0.I2C2)
6171033 * {
....@@ -738,9 +1154,12 @@
7381154 * -EINVAL if property parsing otherwise failed
7391155 * -ENOMEM if memory allocation failed
7401156 */
741
-static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
742
- struct fwnode_handle *fwnode, const char *prop, unsigned int index,
743
- const char * const *props, unsigned int nprops)
1157
+static struct fwnode_handle *
1158
+v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
1159
+ const char *prop,
1160
+ unsigned int index,
1161
+ const char * const *props,
1162
+ unsigned int nprops)
7441163 {
7451164 struct fwnode_reference_args fwnode_args;
7461165 u64 *args = fwnode_args.args;
....@@ -792,6 +1211,12 @@
7921211 return fwnode;
7931212 }
7941213
1214
+struct v4l2_fwnode_int_props {
1215
+ const char *name;
1216
+ const char * const *props;
1217
+ unsigned int nprops;
1218
+};
1219
+
7951220 /*
7961221 * v4l2_fwnode_reference_parse_int_props - parse references for async
7971222 * sub-devices
....@@ -815,13 +1240,17 @@
8151240 * -EINVAL if property parsing otherwisefailed
8161241 * -ENOMEM if memory allocation failed
8171242 */
818
-static int v4l2_fwnode_reference_parse_int_props(
819
- struct device *dev, struct v4l2_async_notifier *notifier,
820
- const char *prop, const char * const *props, unsigned int nprops)
1243
+static int
1244
+v4l2_fwnode_reference_parse_int_props(struct device *dev,
1245
+ struct v4l2_async_notifier *notifier,
1246
+ const struct v4l2_fwnode_int_props *p)
8211247 {
8221248 struct fwnode_handle *fwnode;
8231249 unsigned int index;
8241250 int ret;
1251
+ const char *prop = p->name;
1252
+ const char * const *props = p->props;
1253
+ unsigned int nprops = p->nprops;
8251254
8261255 index = 0;
8271256 do {
....@@ -843,52 +1272,37 @@
8431272 index++;
8441273 } while (1);
8451274
846
- ret = v4l2_async_notifier_realloc(notifier,
847
- notifier->num_subdevs + index);
848
- if (ret)
849
- return -ENOMEM;
850
-
851
- for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
852
- dev_fwnode(dev), prop, index, props,
853
- nprops))); index++) {
1275
+ for (index = 0;
1276
+ !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1277
+ prop, index,
1278
+ props,
1279
+ nprops)));
1280
+ index++) {
8541281 struct v4l2_async_subdev *asd;
8551282
856
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
857
- ret = -EINVAL;
858
- goto error;
859
- }
1283
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1284
+ sizeof(*asd));
1285
+ fwnode_handle_put(fwnode);
1286
+ if (IS_ERR(asd)) {
1287
+ ret = PTR_ERR(asd);
1288
+ /* not an error if asd already exists */
1289
+ if (ret == -EEXIST)
1290
+ continue;
8601291
861
- asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
862
- if (!asd) {
863
- ret = -ENOMEM;
864
- goto error;
1292
+ return PTR_ERR(asd);
8651293 }
866
-
867
- notifier->subdevs[notifier->num_subdevs] = asd;
868
- asd->match.fwnode = fwnode;
869
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
870
- notifier->num_subdevs++;
8711294 }
8721295
873
- return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
874
-
875
-error:
876
- fwnode_handle_put(fwnode);
877
- return ret;
1296
+ return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
8781297 }
8791298
880
-int v4l2_async_notifier_parse_fwnode_sensor_common(
881
- struct device *dev, struct v4l2_async_notifier *notifier)
1299
+int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev,
1300
+ struct v4l2_async_notifier *notifier)
8821301 {
8831302 static const char * const led_props[] = { "led" };
884
- static const struct {
885
- const char *name;
886
- const char * const *props;
887
- unsigned int nprops;
888
- } props[] = {
1303
+ static const struct v4l2_fwnode_int_props props[] = {
8891304 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
8901305 { "lens-focus", NULL, 0 },
891
- { "ir-cut", NULL, 0 },
8921306 };
8931307 unsigned int i;
8941308
....@@ -896,12 +1310,12 @@
8961310 int ret;
8971311
8981312 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
899
- ret = v4l2_fwnode_reference_parse_int_props(
900
- dev, notifier, props[i].name,
901
- props[i].props, props[i].nprops);
1313
+ ret = v4l2_fwnode_reference_parse_int_props(dev,
1314
+ notifier,
1315
+ &props[i]);
9021316 else
903
- ret = v4l2_fwnode_reference_parse(
904
- dev, notifier, props[i].name);
1317
+ ret = v4l2_fwnode_reference_parse(dev, notifier,
1318
+ props[i].name);
9051319 if (ret && ret != -ENOENT) {
9061320 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
9071321 props[i].name, ret);
....@@ -925,6 +1339,8 @@
9251339 if (!notifier)
9261340 return -ENOMEM;
9271341
1342
+ v4l2_async_notifier_init(notifier);
1343
+
9281344 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
9291345 notifier);
9301346 if (ret < 0)