blob: 54162217bb368f3c121923634e67e7a629c3aabb [file] [log] [blame]
Sakari Ailusca50c192016-08-12 08:05:51 -03001/*
2 * V4L2 fwnode binding parsing library
3 *
4 * The origins of the V4L2 fwnode library are in V4L2 OF library that
5 * formerly was located in v4l2-of.c.
6 *
7 * Copyright (c) 2016 Intel Corporation.
8 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
9 *
10 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
11 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
12 *
13 * Copyright (C) 2012 Renesas Electronics Corp.
14 * 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.
19 */
20#include <linux/acpi.h>
21#include <linux/kernel.h>
Sakari Ailus9ca46532017-08-17 11:28:21 -040022#include <linux/mm.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030023#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/property.h>
26#include <linux/slab.h>
27#include <linux/string.h>
28#include <linux/types.h>
29
Sakari Ailus9ca46532017-08-17 11:28:21 -040030#include <media/v4l2-async.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030031#include <media/v4l2-fwnode.h>
Sakari Ailusaef69d52017-09-24 18:47:44 -040032#include <media/v4l2-subdev.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030033
Sakari Ailuse07a41f2015-02-25 14:51:01 -050034enum v4l2_fwnode_bus_type {
35 V4L2_FWNODE_BUS_TYPE_GUESS = 0,
36 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
37 V4L2_FWNODE_BUS_TYPE_CSI1,
38 V4L2_FWNODE_BUS_TYPE_CCP2,
Sakari Ailusbf638562018-07-03 17:40:37 -040039 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
40 V4L2_FWNODE_BUS_TYPE_PARALLEL,
41 V4L2_FWNODE_BUS_TYPE_BT656,
Sakari Ailuse07a41f2015-02-25 14:51:01 -050042 NR_OF_V4L2_FWNODE_BUS_TYPE,
43};
44
Sakari Ailusf3112732017-02-20 05:42:09 -050045static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
46 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -030047{
48 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
49 bool have_clk_lane = false;
50 unsigned int flags = 0, lanes_used = 0;
51 unsigned int i;
52 u32 v;
53 int rval;
54
55 rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
56 if (rval > 0) {
Sakari Ailusad3cdf32017-08-14 06:43:07 -040057 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
Sakari Ailusca50c192016-08-12 08:05:51 -030058
Sakari Ailusad3cdf32017-08-14 06:43:07 -040059 bus->num_data_lanes =
60 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
Sakari Ailusca50c192016-08-12 08:05:51 -030061
62 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
63 bus->num_data_lanes);
64
65 for (i = 0; i < bus->num_data_lanes; i++) {
66 if (lanes_used & BIT(array[i]))
67 pr_warn("duplicated lane %u in data-lanes\n",
68 array[i]);
69 lanes_used |= BIT(array[i]);
70
71 bus->data_lanes[i] = array[i];
Sakari Ailusc8677aa2017-12-04 16:25:06 -050072 pr_debug("lane %u position %u\n", i, array[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -030073 }
Sakari Ailusca50c192016-08-12 08:05:51 -030074
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040075 rval = fwnode_property_read_u32_array(fwnode,
Sakari Ailusb24f0212017-08-14 06:15:21 -040076 "lane-polarities", NULL,
77 0);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040078 if (rval > 0) {
Sakari Ailusb24f0212017-08-14 06:15:21 -040079 if (rval != 1 + bus->num_data_lanes /* clock+data */) {
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040080 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
81 1 + bus->num_data_lanes, rval);
82 return -EINVAL;
83 }
Sakari Ailusca50c192016-08-12 08:05:51 -030084
Sakari Ailusb24f0212017-08-14 06:15:21 -040085 fwnode_property_read_u32_array(fwnode,
86 "lane-polarities", array,
87 1 + bus->num_data_lanes);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040088
Sakari Ailusc8677aa2017-12-04 16:25:06 -050089 for (i = 0; i < 1 + bus->num_data_lanes; i++) {
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040090 bus->lane_polarities[i] = array[i];
Sakari Ailusc8677aa2017-12-04 16:25:06 -050091 pr_debug("lane %u polarity %sinverted",
92 i, array[i] ? "" : "not ");
93 }
94 } else {
95 pr_debug("no lane polarities defined, assuming not inverted\n");
Sakari Ailusca50c192016-08-12 08:05:51 -030096 }
Sakari Ailusb24f0212017-08-14 06:15:21 -040097
Sakari Ailusca50c192016-08-12 08:05:51 -030098 }
99
100 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
101 if (lanes_used & BIT(v))
102 pr_warn("duplicated lane %u in clock-lanes\n", v);
103 lanes_used |= BIT(v);
104
105 bus->clock_lane = v;
106 have_clk_lane = true;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500107 pr_debug("clock lane position %u\n", v);
Sakari Ailusca50c192016-08-12 08:05:51 -0300108 }
109
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500110 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300111 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500112 pr_debug("non-continuous clock\n");
Sakari Ailusd4865322018-07-20 05:04:29 -0400113 } else {
Sakari Ailusca50c192016-08-12 08:05:51 -0300114 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500115 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300116
117 bus->flags = flags;
Sakari Ailus2d95e7e2018-07-03 17:19:27 -0400118 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
Sakari Ailusca50c192016-08-12 08:05:51 -0300119
120 return 0;
121}
122
123static void v4l2_fwnode_endpoint_parse_parallel_bus(
124 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
125{
126 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
127 unsigned int flags = 0;
128 u32 v;
129
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500130 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300131 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
132 V4L2_MBUS_HSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500133 pr_debug("hsync-active %s\n", v ? "high" : "low");
134 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300135
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500136 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300137 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
138 V4L2_MBUS_VSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500139 pr_debug("vsync-active %s\n", v ? "high" : "low");
140 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300141
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500142 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300143 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
144 V4L2_MBUS_FIELD_EVEN_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500145 pr_debug("field-even-active %s\n", v ? "high" : "low");
146 }
147
Sakari Ailusca50c192016-08-12 08:05:51 -0300148 if (flags)
149 vep->bus_type = V4L2_MBUS_PARALLEL;
150 else
151 vep->bus_type = V4L2_MBUS_BT656;
152
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500153 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300154 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
155 V4L2_MBUS_PCLK_SAMPLE_FALLING;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500156 pr_debug("pclk-sample %s\n", v ? "high" : "low");
157 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300158
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500159 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300160 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
161 V4L2_MBUS_DATA_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500162 pr_debug("data-active %s\n", v ? "high" : "low");
163 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300164
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500165 if (fwnode_property_present(fwnode, "slave-mode")) {
166 pr_debug("slave mode\n");
Sakari Ailusca50c192016-08-12 08:05:51 -0300167 flags |= V4L2_MBUS_SLAVE;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500168 } else {
Sakari Ailusca50c192016-08-12 08:05:51 -0300169 flags |= V4L2_MBUS_MASTER;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500170 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300171
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500172 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300173 bus->bus_width = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500174 pr_debug("bus-width %u\n", v);
175 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300176
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500177 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300178 bus->data_shift = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500179 pr_debug("data-shift %u\n", v);
180 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300181
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500182 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300183 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
184 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500185 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
186 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300187
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500188 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400189 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
190 V4L2_MBUS_DATA_ENABLE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500191 pr_debug("data-enable-active %s\n", v ? "high" : "low");
192 }
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400193
Sakari Ailusca50c192016-08-12 08:05:51 -0300194 bus->flags = flags;
195
196}
197
Mauro Carvalho Chehababc5b2c2017-07-20 16:27:27 -0400198static void
199v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
200 struct v4l2_fwnode_endpoint *vep,
201 u32 bus_type)
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500202{
203 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
204 u32 v;
205
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500206 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500207 bus->clock_inv = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500208 pr_debug("clock-inv %u\n", v);
209 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500210
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500211 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500212 bus->strobe = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500213 pr_debug("strobe %u\n", v);
214 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500215
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500216 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500217 bus->data_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500218 pr_debug("data-lanes %u\n", v);
219 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500220
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500221 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500222 bus->clock_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500223 pr_debug("clock-lanes %u\n", v);
224 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500225
226 if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
227 vep->bus_type = V4L2_MBUS_CCP2;
228 else
229 vep->bus_type = V4L2_MBUS_CSI1;
230}
231
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500232static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
233 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -0300234{
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500235 u32 bus_type = 0;
Sakari Ailusca50c192016-08-12 08:05:51 -0300236 int rval;
237
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500238 pr_debug("===== begin V4L2 endpoint properties\n");
239
Sakari Ailusca50c192016-08-12 08:05:51 -0300240 fwnode_graph_parse_endpoint(fwnode, &vep->base);
241
242 /* Zero fields from bus_type to until the end */
243 memset(&vep->bus_type, 0, sizeof(*vep) -
244 offsetof(typeof(*vep), bus_type));
245
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500246 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
247
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500248 switch (bus_type) {
249 case V4L2_FWNODE_BUS_TYPE_GUESS:
250 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
251 if (rval)
252 return rval;
253 /*
254 * Parse the parallel video bus properties only if none
255 * of the MIPI CSI-2 specific properties were found.
256 */
257 if (vep->bus.mipi_csi2.flags == 0)
258 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300259
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500260 break;
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500261 case V4L2_FWNODE_BUS_TYPE_CCP2:
262 case V4L2_FWNODE_BUS_TYPE_CSI1:
263 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
264
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500265 break;
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500266 default:
267 pr_warn("unsupported bus type %u\n", bus_type);
268 return -EINVAL;
269 }
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500270
271 return 0;
272}
273
274int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
275 struct v4l2_fwnode_endpoint *vep)
276{
277 int ret;
278
279 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
280
281 pr_debug("===== end V4L2 endpoint properties\n");
282
283 return ret;
Sakari Ailusca50c192016-08-12 08:05:51 -0300284}
285EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
286
Sakari Ailusca50c192016-08-12 08:05:51 -0300287void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
288{
289 if (IS_ERR_OR_NULL(vep))
290 return;
291
292 kfree(vep->link_frequencies);
293 kfree(vep);
294}
295EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
296
Sakari Ailusca50c192016-08-12 08:05:51 -0300297struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
298 struct fwnode_handle *fwnode)
299{
300 struct v4l2_fwnode_endpoint *vep;
301 int rval;
302
303 vep = kzalloc(sizeof(*vep), GFP_KERNEL);
304 if (!vep)
305 return ERR_PTR(-ENOMEM);
306
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500307 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300308 if (rval < 0)
309 goto out_err;
310
311 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
312 NULL, 0);
Sakari Ailus06f81522017-06-20 09:14:43 -0400313 if (rval > 0) {
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500314 unsigned int i;
315
Sakari Ailus06f81522017-06-20 09:14:43 -0400316 vep->link_frequencies =
317 kmalloc_array(rval, sizeof(*vep->link_frequencies),
318 GFP_KERNEL);
319 if (!vep->link_frequencies) {
320 rval = -ENOMEM;
321 goto out_err;
322 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300323
Sakari Ailus06f81522017-06-20 09:14:43 -0400324 vep->nr_of_link_frequencies = rval;
325
326 rval = fwnode_property_read_u64_array(
327 fwnode, "link-frequencies", vep->link_frequencies,
328 vep->nr_of_link_frequencies);
329 if (rval < 0)
330 goto out_err;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500331
332 for (i = 0; i < vep->nr_of_link_frequencies; i++)
333 pr_info("link-frequencies %u value %llu\n", i,
334 vep->link_frequencies[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -0300335 }
336
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500337 pr_debug("===== end V4L2 endpoint properties\n");
338
Sakari Ailusca50c192016-08-12 08:05:51 -0300339 return vep;
340
341out_err:
342 v4l2_fwnode_endpoint_free(vep);
343 return ERR_PTR(rval);
344}
345EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
346
Sakari Ailusca50c192016-08-12 08:05:51 -0300347int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
348 struct v4l2_fwnode_link *link)
349{
350 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
351 struct fwnode_handle *fwnode;
352
353 memset(link, 0, sizeof(*link));
354
355 fwnode = fwnode_get_parent(__fwnode);
356 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
357 fwnode = fwnode_get_next_parent(fwnode);
358 if (is_of_node(fwnode) &&
359 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
360 fwnode = fwnode_get_next_parent(fwnode);
361 link->local_node = fwnode;
362
363 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
364 if (!fwnode) {
365 fwnode_handle_put(fwnode);
366 return -ENOLINK;
367 }
368
369 fwnode = fwnode_get_parent(fwnode);
370 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
371 fwnode = fwnode_get_next_parent(fwnode);
372 if (is_of_node(fwnode) &&
373 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
374 fwnode = fwnode_get_next_parent(fwnode);
375 link->remote_node = fwnode;
376
377 return 0;
378}
379EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
380
Sakari Ailusca50c192016-08-12 08:05:51 -0300381void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
382{
383 fwnode_handle_put(link->local_node);
384 fwnode_handle_put(link->remote_node);
385}
386EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
387
Sakari Ailus9ca46532017-08-17 11:28:21 -0400388static int v4l2_async_notifier_fwnode_parse_endpoint(
389 struct device *dev, struct v4l2_async_notifier *notifier,
390 struct fwnode_handle *endpoint, unsigned int asd_struct_size,
391 int (*parse_endpoint)(struct device *dev,
392 struct v4l2_fwnode_endpoint *vep,
393 struct v4l2_async_subdev *asd))
394{
395 struct v4l2_async_subdev *asd;
396 struct v4l2_fwnode_endpoint *vep;
397 int ret = 0;
398
399 asd = kzalloc(asd_struct_size, GFP_KERNEL);
400 if (!asd)
401 return -ENOMEM;
402
403 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400404 asd->match.fwnode =
Sakari Ailus9ca46532017-08-17 11:28:21 -0400405 fwnode_graph_get_remote_port_parent(endpoint);
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400406 if (!asd->match.fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400407 dev_warn(dev, "bad remote port parent\n");
Steve Longerbeam4382f372018-09-29 15:54:04 -0400408 ret = -ENOTCONN;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400409 goto out_err;
410 }
411
412 vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
413 if (IS_ERR(vep)) {
414 ret = PTR_ERR(vep);
415 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
416 ret);
417 goto out_err;
418 }
419
420 ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
421 if (ret == -ENOTCONN)
422 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
423 vep->base.id);
424 else if (ret < 0)
425 dev_warn(dev,
426 "driver could not parse port@%u/endpoint@%u (%d)\n",
427 vep->base.port, vep->base.id, ret);
428 v4l2_fwnode_endpoint_free(vep);
429 if (ret < 0)
430 goto out_err;
431
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400432 ret = v4l2_async_notifier_add_subdev(notifier, asd);
433 if (ret < 0) {
434 /* not an error if asd already exists */
435 if (ret == -EEXIST)
436 ret = 0;
437 goto out_err;
438 }
Sakari Ailus9ca46532017-08-17 11:28:21 -0400439
440 return 0;
441
442out_err:
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400443 fwnode_handle_put(asd->match.fwnode);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400444 kfree(asd);
445
446 return ret == -ENOTCONN ? 0 : ret;
447}
448
449static int __v4l2_async_notifier_parse_fwnode_endpoints(
450 struct device *dev, struct v4l2_async_notifier *notifier,
451 size_t asd_struct_size, unsigned int port, bool has_port,
452 int (*parse_endpoint)(struct device *dev,
453 struct v4l2_fwnode_endpoint *vep,
454 struct v4l2_async_subdev *asd))
455{
456 struct fwnode_handle *fwnode;
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400457 int ret = 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400458
459 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
460 return -EINVAL;
461
Sakari Ailus106ee382017-12-21 07:11:19 -0500462 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400463 struct fwnode_handle *dev_fwnode;
464 bool is_available;
465
466 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
467 is_available = fwnode_device_is_available(dev_fwnode);
468 fwnode_handle_put(dev_fwnode);
469 if (!is_available)
470 continue;
471
472 if (has_port) {
473 struct fwnode_endpoint ep;
474
475 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400476 if (ret)
477 break;
478
479 if (ep.port != port)
480 continue;
481 }
482
483 ret = v4l2_async_notifier_fwnode_parse_endpoint(
484 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
485 if (ret < 0)
486 break;
487 }
488
489 fwnode_handle_put(fwnode);
490
491 return ret;
492}
493
494int v4l2_async_notifier_parse_fwnode_endpoints(
495 struct device *dev, struct v4l2_async_notifier *notifier,
496 size_t asd_struct_size,
497 int (*parse_endpoint)(struct device *dev,
498 struct v4l2_fwnode_endpoint *vep,
499 struct v4l2_async_subdev *asd))
500{
501 return __v4l2_async_notifier_parse_fwnode_endpoints(
502 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
503}
504EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
505
506int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
507 struct device *dev, struct v4l2_async_notifier *notifier,
508 size_t asd_struct_size, unsigned int port,
509 int (*parse_endpoint)(struct device *dev,
510 struct v4l2_fwnode_endpoint *vep,
511 struct v4l2_async_subdev *asd))
512{
513 return __v4l2_async_notifier_parse_fwnode_endpoints(
514 dev, notifier, asd_struct_size, port, true, parse_endpoint);
515}
516EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
517
Sakari Ailusd8428532017-06-20 07:47:24 -0400518/*
519 * v4l2_fwnode_reference_parse - parse references for async sub-devices
520 * @dev: the device node the properties of which are parsed for references
521 * @notifier: the async notifier where the async subdevs will be added
522 * @prop: the name of the property
523 *
524 * Return: 0 on success
525 * -ENOENT if no entries were found
526 * -ENOMEM if memory allocation failed
527 * -EINVAL if property parsing failed
528 */
529static int v4l2_fwnode_reference_parse(
530 struct device *dev, struct v4l2_async_notifier *notifier,
531 const char *prop)
532{
533 struct fwnode_reference_args args;
534 unsigned int index;
535 int ret;
536
537 for (index = 0;
538 !(ret = fwnode_property_get_reference_args(
539 dev_fwnode(dev), prop, NULL, 0, index, &args));
540 index++)
541 fwnode_handle_put(args.fwnode);
542
543 if (!index)
544 return -ENOENT;
545
546 /*
547 * Note that right now both -ENODATA and -ENOENT may signal
548 * out-of-bounds access. Return the error in cases other than that.
549 */
550 if (ret != -ENOENT && ret != -ENODATA)
551 return ret;
552
Sakari Ailusd8428532017-06-20 07:47:24 -0400553 for (index = 0; !fwnode_property_get_reference_args(
554 dev_fwnode(dev), prop, NULL, 0, index, &args);
555 index++) {
556 struct v4l2_async_subdev *asd;
557
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400558 asd = v4l2_async_notifier_add_fwnode_subdev(
559 notifier, args.fwnode, sizeof(*asd));
560 if (IS_ERR(asd)) {
561 ret = PTR_ERR(asd);
562 /* not an error if asd already exists */
563 if (ret == -EEXIST) {
564 fwnode_handle_put(args.fwnode);
565 continue;
566 }
567
Sakari Ailusd8428532017-06-20 07:47:24 -0400568 goto error;
569 }
Sakari Ailusd8428532017-06-20 07:47:24 -0400570 }
571
572 return 0;
573
574error:
575 fwnode_handle_put(args.fwnode);
576 return ret;
577}
578
Sakari Ailusa1699a42017-06-22 08:03:28 -0400579/*
580 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
581 * arguments
582 * @fwnode: fwnode to read @prop from
583 * @notifier: notifier for @dev
584 * @prop: the name of the property
585 * @index: the index of the reference to get
586 * @props: the array of integer property names
587 * @nprops: the number of integer property names in @nprops
588 *
589 * First find an fwnode referred to by the reference at @index in @prop.
590 *
591 * Then under that fwnode, @nprops times, for each property in @props,
592 * iteratively follow child nodes starting from fwnode such that they have the
593 * property in @props array at the index of the child node distance from the
594 * root node and the value of that property matching with the integer argument
595 * of the reference, at the same index.
596 *
597 * The child fwnode reched at the end of the iteration is then returned to the
598 * caller.
599 *
600 * The core reason for this is that you cannot refer to just any node in ACPI.
601 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
602 * provide a list of (property name, property value) tuples where each tuple
603 * uniquely identifies a child node. The first tuple identifies a child directly
604 * underneath the device fwnode, the next tuple identifies a child node
605 * underneath the fwnode identified by the previous tuple, etc. until you
606 * reached the fwnode you need.
607 *
608 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
609 *
610 * Scope (\_SB.PCI0.I2C2)
611 * {
612 * Device (CAM0)
613 * {
614 * Name (_DSD, Package () {
615 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
616 * Package () {
617 * Package () {
618 * "compatible",
619 * Package () { "nokia,smia" }
620 * },
621 * },
622 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
623 * Package () {
624 * Package () { "port0", "PRT0" },
625 * }
626 * })
627 * Name (PRT0, Package() {
628 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
629 * Package () {
630 * Package () { "port", 0 },
631 * },
632 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
633 * Package () {
634 * Package () { "endpoint0", "EP00" },
635 * }
636 * })
637 * Name (EP00, Package() {
638 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
639 * Package () {
640 * Package () { "endpoint", 0 },
641 * Package () {
642 * "remote-endpoint",
643 * Package() {
644 * \_SB.PCI0.ISP, 4, 0
645 * }
646 * },
647 * }
648 * })
649 * }
650 * }
651 *
652 * Scope (\_SB.PCI0)
653 * {
654 * Device (ISP)
655 * {
656 * Name (_DSD, Package () {
657 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
658 * Package () {
659 * Package () { "port4", "PRT4" },
660 * }
661 * })
662 *
663 * Name (PRT4, Package() {
664 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
665 * Package () {
666 * Package () { "port", 4 },
667 * },
668 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
669 * Package () {
670 * Package () { "endpoint0", "EP40" },
671 * }
672 * })
673 *
674 * Name (EP40, Package() {
675 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
676 * Package () {
677 * Package () { "endpoint", 0 },
678 * Package () {
679 * "remote-endpoint",
680 * Package () {
681 * \_SB.PCI0.I2C2.CAM0,
682 * 0, 0
683 * }
684 * },
685 * }
686 * })
687 * }
688 * }
689 *
690 * From the EP40 node under ISP device, you could parse the graph remote
691 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
692 *
693 * @fwnode: fwnode referring to EP40 under ISP.
694 * @prop: "remote-endpoint"
695 * @index: 0
696 * @props: "port", "endpoint"
697 * @nprops: 2
698 *
699 * And you'd get back fwnode referring to EP00 under CAM0.
700 *
701 * The same works the other way around: if you use EP00 under CAM0 as the
702 * fwnode, you'll get fwnode referring to EP40 under ISP.
703 *
704 * The same example in DT syntax would look like this:
705 *
706 * cam: cam0 {
707 * compatible = "nokia,smia";
708 *
709 * port {
710 * port = <0>;
711 * endpoint {
712 * endpoint = <0>;
713 * remote-endpoint = <&isp 4 0>;
714 * };
715 * };
716 * };
717 *
718 * isp: isp {
719 * ports {
720 * port@4 {
721 * port = <4>;
722 * endpoint {
723 * endpoint = <0>;
724 * remote-endpoint = <&cam 0 0>;
725 * };
726 * };
727 * };
728 * };
729 *
730 * Return: 0 on success
731 * -ENOENT if no entries (or the property itself) were found
732 * -EINVAL if property parsing otherwise failed
733 * -ENOMEM if memory allocation failed
734 */
735static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
736 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
737 const char * const *props, unsigned int nprops)
738{
739 struct fwnode_reference_args fwnode_args;
Sakari Ailus977d5ad2018-07-17 17:19:11 +0300740 u64 *args = fwnode_args.args;
Sakari Ailusa1699a42017-06-22 08:03:28 -0400741 struct fwnode_handle *child;
742 int ret;
743
744 /*
745 * Obtain remote fwnode as well as the integer arguments.
746 *
747 * Note that right now both -ENODATA and -ENOENT may signal
748 * out-of-bounds access. Return -ENOENT in that case.
749 */
750 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
751 index, &fwnode_args);
752 if (ret)
753 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
754
755 /*
756 * Find a node in the tree under the referred fwnode corresponding to
757 * the integer arguments.
758 */
759 fwnode = fwnode_args.fwnode;
760 while (nprops--) {
761 u32 val;
762
763 /* Loop over all child nodes under fwnode. */
764 fwnode_for_each_child_node(fwnode, child) {
765 if (fwnode_property_read_u32(child, *props, &val))
766 continue;
767
768 /* Found property, see if its value matches. */
769 if (val == *args)
770 break;
771 }
772
773 fwnode_handle_put(fwnode);
774
775 /* No property found; return an error here. */
776 if (!child) {
777 fwnode = ERR_PTR(-ENOENT);
778 break;
779 }
780
781 props++;
782 args++;
783 fwnode = child;
784 }
785
786 return fwnode;
787}
788
789/*
790 * v4l2_fwnode_reference_parse_int_props - parse references for async
791 * sub-devices
792 * @dev: struct device pointer
793 * @notifier: notifier for @dev
794 * @prop: the name of the property
795 * @props: the array of integer property names
796 * @nprops: the number of integer properties
797 *
798 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
799 * property @prop with integer arguments with child nodes matching in properties
800 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
801 * accordingly.
802 *
803 * While it is technically possible to use this function on DT, it is only
804 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
805 * on ACPI the references are limited to devices.
806 *
807 * Return: 0 on success
808 * -ENOENT if no entries (or the property itself) were found
809 * -EINVAL if property parsing otherwisefailed
810 * -ENOMEM if memory allocation failed
811 */
812static int v4l2_fwnode_reference_parse_int_props(
813 struct device *dev, struct v4l2_async_notifier *notifier,
814 const char *prop, const char * const *props, unsigned int nprops)
815{
816 struct fwnode_handle *fwnode;
817 unsigned int index;
818 int ret;
819
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400820 index = 0;
821 do {
822 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
823 prop, index,
824 props, nprops);
825 if (IS_ERR(fwnode)) {
826 /*
827 * Note that right now both -ENODATA and -ENOENT may
828 * signal out-of-bounds access. Return the error in
829 * cases other than that.
830 */
831 if (PTR_ERR(fwnode) != -ENOENT &&
832 PTR_ERR(fwnode) != -ENODATA)
833 return PTR_ERR(fwnode);
834 break;
835 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400836 fwnode_handle_put(fwnode);
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400837 index++;
838 } while (1);
Sakari Ailusa1699a42017-06-22 08:03:28 -0400839
Sakari Ailusa1699a42017-06-22 08:03:28 -0400840 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
841 dev_fwnode(dev), prop, index, props,
842 nprops))); index++) {
843 struct v4l2_async_subdev *asd;
844
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400845 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
846 sizeof(*asd));
847 if (IS_ERR(asd)) {
848 ret = PTR_ERR(asd);
849 /* not an error if asd already exists */
850 if (ret == -EEXIST) {
851 fwnode_handle_put(fwnode);
852 continue;
853 }
854
Sakari Ailusa1699a42017-06-22 08:03:28 -0400855 goto error;
856 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400857 }
858
859 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
860
861error:
862 fwnode_handle_put(fwnode);
863 return ret;
864}
865
Sakari Ailus7a9ec802017-09-06 08:35:42 -0400866int v4l2_async_notifier_parse_fwnode_sensor_common(
867 struct device *dev, struct v4l2_async_notifier *notifier)
868{
869 static const char * const led_props[] = { "led" };
870 static const struct {
871 const char *name;
872 const char * const *props;
873 unsigned int nprops;
874 } props[] = {
875 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
876 { "lens-focus", NULL, 0 },
877 };
878 unsigned int i;
879
880 for (i = 0; i < ARRAY_SIZE(props); i++) {
881 int ret;
882
883 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
884 ret = v4l2_fwnode_reference_parse_int_props(
885 dev, notifier, props[i].name,
886 props[i].props, props[i].nprops);
887 else
888 ret = v4l2_fwnode_reference_parse(
889 dev, notifier, props[i].name);
890 if (ret && ret != -ENOENT) {
891 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
892 props[i].name, ret);
893 return ret;
894 }
895 }
896
897 return 0;
898}
899EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
900
Sakari Ailusaef69d52017-09-24 18:47:44 -0400901int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
902{
903 struct v4l2_async_notifier *notifier;
904 int ret;
905
906 if (WARN_ON(!sd->dev))
907 return -ENODEV;
908
909 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
910 if (!notifier)
911 return -ENOMEM;
912
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400913 v4l2_async_notifier_init(notifier);
914
Sakari Ailusaef69d52017-09-24 18:47:44 -0400915 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
916 notifier);
917 if (ret < 0)
918 goto out_cleanup;
919
920 ret = v4l2_async_subdev_notifier_register(sd, notifier);
921 if (ret < 0)
922 goto out_cleanup;
923
924 ret = v4l2_async_register_subdev(sd);
925 if (ret < 0)
926 goto out_unregister;
927
928 sd->subdev_notifier = notifier;
929
930 return 0;
931
932out_unregister:
933 v4l2_async_notifier_unregister(notifier);
934
935out_cleanup:
936 v4l2_async_notifier_cleanup(notifier);
937 kfree(notifier);
938
939 return ret;
940}
941EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
942
Steve Longerbeam1634f0e2018-09-29 15:54:09 -0400943int v4l2_async_register_fwnode_subdev(
944 struct v4l2_subdev *sd, size_t asd_struct_size,
945 unsigned int *ports, unsigned int num_ports,
946 int (*parse_endpoint)(struct device *dev,
947 struct v4l2_fwnode_endpoint *vep,
948 struct v4l2_async_subdev *asd))
949{
950 struct v4l2_async_notifier *notifier;
951 struct device *dev = sd->dev;
952 struct fwnode_handle *fwnode;
953 int ret;
954
955 if (WARN_ON(!dev))
956 return -ENODEV;
957
958 fwnode = dev_fwnode(dev);
959 if (!fwnode_device_is_available(fwnode))
960 return -ENODEV;
961
962 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
963 if (!notifier)
964 return -ENOMEM;
965
966 v4l2_async_notifier_init(notifier);
967
968 if (!ports) {
969 ret = v4l2_async_notifier_parse_fwnode_endpoints(
970 dev, notifier, asd_struct_size, parse_endpoint);
971 if (ret < 0)
972 goto out_cleanup;
973 } else {
974 unsigned int i;
975
976 for (i = 0; i < num_ports; i++) {
977 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
978 dev, notifier, asd_struct_size,
979 ports[i], parse_endpoint);
980 if (ret < 0)
981 goto out_cleanup;
982 }
983 }
984
985 ret = v4l2_async_subdev_notifier_register(sd, notifier);
986 if (ret < 0)
987 goto out_cleanup;
988
989 ret = v4l2_async_register_subdev(sd);
990 if (ret < 0)
991 goto out_unregister;
992
993 sd->subdev_notifier = notifier;
994
995 return 0;
996
997out_unregister:
998 v4l2_async_notifier_unregister(notifier);
999out_cleanup:
1000 v4l2_async_notifier_cleanup(notifier);
1001 kfree(notifier);
1002
1003 return ret;
1004}
1005EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
1006
Sakari Ailusca50c192016-08-12 08:05:51 -03001007MODULE_LICENSE("GPL");
1008MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1009MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1010MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");