blob: fc8c63eba10ba5fc34525c4340870be492008084 [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,
39 NR_OF_V4L2_FWNODE_BUS_TYPE,
40};
41
Sakari Ailusf3112732017-02-20 05:42:09 -050042static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
43 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -030044{
45 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
46 bool have_clk_lane = false;
47 unsigned int flags = 0, lanes_used = 0;
48 unsigned int i;
49 u32 v;
50 int rval;
51
52 rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
53 if (rval > 0) {
Sakari Ailusad3cdf32017-08-14 06:43:07 -040054 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
Sakari Ailusca50c192016-08-12 08:05:51 -030055
Sakari Ailusad3cdf32017-08-14 06:43:07 -040056 bus->num_data_lanes =
57 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
Sakari Ailusca50c192016-08-12 08:05:51 -030058
59 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
60 bus->num_data_lanes);
61
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",
65 array[i]);
66 lanes_used |= BIT(array[i]);
67
68 bus->data_lanes[i] = array[i];
Sakari Ailusc8677aa2017-12-04 16:25:06 -050069 pr_debug("lane %u position %u\n", i, array[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -030070 }
Sakari Ailusca50c192016-08-12 08:05:51 -030071
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040072 rval = fwnode_property_read_u32_array(fwnode,
Sakari Ailusb24f0212017-08-14 06:15:21 -040073 "lane-polarities", NULL,
74 0);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040075 if (rval > 0) {
Sakari Ailusb24f0212017-08-14 06:15:21 -040076 if (rval != 1 + bus->num_data_lanes /* clock+data */) {
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040077 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
78 1 + bus->num_data_lanes, rval);
79 return -EINVAL;
80 }
Sakari Ailusca50c192016-08-12 08:05:51 -030081
Sakari Ailusb24f0212017-08-14 06:15:21 -040082 fwnode_property_read_u32_array(fwnode,
83 "lane-polarities", array,
84 1 + bus->num_data_lanes);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040085
Sakari Ailusc8677aa2017-12-04 16:25:06 -050086 for (i = 0; i < 1 + bus->num_data_lanes; i++) {
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040087 bus->lane_polarities[i] = array[i];
Sakari Ailusc8677aa2017-12-04 16:25:06 -050088 pr_debug("lane %u polarity %sinverted",
89 i, array[i] ? "" : "not ");
90 }
91 } else {
92 pr_debug("no lane polarities defined, assuming not inverted\n");
Sakari Ailusca50c192016-08-12 08:05:51 -030093 }
Sakari Ailusb24f0212017-08-14 06:15:21 -040094
Sakari Ailusca50c192016-08-12 08:05:51 -030095 }
96
97 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
98 if (lanes_used & BIT(v))
99 pr_warn("duplicated lane %u in clock-lanes\n", v);
100 lanes_used |= BIT(v);
101
102 bus->clock_lane = v;
103 have_clk_lane = true;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500104 pr_debug("clock lane position %u\n", v);
Sakari Ailusca50c192016-08-12 08:05:51 -0300105 }
106
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500107 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300108 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500109 pr_debug("non-continuous clock\n");
110 } else if (have_clk_lane || bus->num_data_lanes > 0) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300111 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500112 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300113
114 bus->flags = flags;
115 vep->bus_type = V4L2_MBUS_CSI2;
116
117 return 0;
118}
119
120static void v4l2_fwnode_endpoint_parse_parallel_bus(
121 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
122{
123 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
124 unsigned int flags = 0;
125 u32 v;
126
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500127 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300128 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
129 V4L2_MBUS_HSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500130 pr_debug("hsync-active %s\n", v ? "high" : "low");
131 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300132
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500133 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300134 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
135 V4L2_MBUS_VSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500136 pr_debug("vsync-active %s\n", v ? "high" : "low");
137 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300138
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500139 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300140 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
141 V4L2_MBUS_FIELD_EVEN_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500142 pr_debug("field-even-active %s\n", v ? "high" : "low");
143 }
144
Sakari Ailusca50c192016-08-12 08:05:51 -0300145 if (flags)
146 vep->bus_type = V4L2_MBUS_PARALLEL;
147 else
148 vep->bus_type = V4L2_MBUS_BT656;
149
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500150 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300151 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
152 V4L2_MBUS_PCLK_SAMPLE_FALLING;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500153 pr_debug("pclk-sample %s\n", v ? "high" : "low");
154 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300155
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500156 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300157 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
158 V4L2_MBUS_DATA_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500159 pr_debug("data-active %s\n", v ? "high" : "low");
160 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300161
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500162 if (fwnode_property_present(fwnode, "slave-mode")) {
163 pr_debug("slave mode\n");
Sakari Ailusca50c192016-08-12 08:05:51 -0300164 flags |= V4L2_MBUS_SLAVE;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500165 } else {
Sakari Ailusca50c192016-08-12 08:05:51 -0300166 flags |= V4L2_MBUS_MASTER;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500167 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300168
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500169 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300170 bus->bus_width = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500171 pr_debug("bus-width %u\n", v);
172 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300173
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500174 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300175 bus->data_shift = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500176 pr_debug("data-shift %u\n", v);
177 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300178
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500179 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300180 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
181 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500182 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
183 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300184
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500185 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400186 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
187 V4L2_MBUS_DATA_ENABLE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500188 pr_debug("data-enable-active %s\n", v ? "high" : "low");
189 }
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400190
Sakari Ailusca50c192016-08-12 08:05:51 -0300191 bus->flags = flags;
192
193}
194
Mauro Carvalho Chehababc5b2c2017-07-20 16:27:27 -0400195static void
196v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
197 struct v4l2_fwnode_endpoint *vep,
198 u32 bus_type)
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500199{
200 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
201 u32 v;
202
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500203 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500204 bus->clock_inv = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500205 pr_debug("clock-inv %u\n", v);
206 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500207
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500208 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500209 bus->strobe = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500210 pr_debug("strobe %u\n", v);
211 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500212
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500213 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500214 bus->data_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500215 pr_debug("data-lanes %u\n", v);
216 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500217
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500218 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500219 bus->clock_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500220 pr_debug("clock-lanes %u\n", v);
221 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500222
223 if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
224 vep->bus_type = V4L2_MBUS_CCP2;
225 else
226 vep->bus_type = V4L2_MBUS_CSI1;
227}
228
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500229static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
230 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -0300231{
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500232 u32 bus_type = 0;
Sakari Ailusca50c192016-08-12 08:05:51 -0300233 int rval;
234
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500235 pr_debug("===== begin V4L2 endpoint properties\n");
236
Sakari Ailusca50c192016-08-12 08:05:51 -0300237 fwnode_graph_parse_endpoint(fwnode, &vep->base);
238
239 /* Zero fields from bus_type to until the end */
240 memset(&vep->bus_type, 0, sizeof(*vep) -
241 offsetof(typeof(*vep), bus_type));
242
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500243 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
244
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500245 switch (bus_type) {
246 case V4L2_FWNODE_BUS_TYPE_GUESS:
247 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
248 if (rval)
249 return rval;
250 /*
251 * Parse the parallel video bus properties only if none
252 * of the MIPI CSI-2 specific properties were found.
253 */
254 if (vep->bus.mipi_csi2.flags == 0)
255 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300256
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500257 break;
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500258 case V4L2_FWNODE_BUS_TYPE_CCP2:
259 case V4L2_FWNODE_BUS_TYPE_CSI1:
260 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
261
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500262 break;
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500263 default:
264 pr_warn("unsupported bus type %u\n", bus_type);
265 return -EINVAL;
266 }
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500267
268 return 0;
269}
270
271int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
272 struct v4l2_fwnode_endpoint *vep)
273{
274 int ret;
275
276 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
277
278 pr_debug("===== end V4L2 endpoint properties\n");
279
280 return ret;
Sakari Ailusca50c192016-08-12 08:05:51 -0300281}
282EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
283
Sakari Ailusca50c192016-08-12 08:05:51 -0300284void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
285{
286 if (IS_ERR_OR_NULL(vep))
287 return;
288
289 kfree(vep->link_frequencies);
290 kfree(vep);
291}
292EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
293
Sakari Ailusca50c192016-08-12 08:05:51 -0300294struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
295 struct fwnode_handle *fwnode)
296{
297 struct v4l2_fwnode_endpoint *vep;
298 int rval;
299
300 vep = kzalloc(sizeof(*vep), GFP_KERNEL);
301 if (!vep)
302 return ERR_PTR(-ENOMEM);
303
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500304 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300305 if (rval < 0)
306 goto out_err;
307
308 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
309 NULL, 0);
Sakari Ailus06f81522017-06-20 09:14:43 -0400310 if (rval > 0) {
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500311 unsigned int i;
312
Sakari Ailus06f81522017-06-20 09:14:43 -0400313 vep->link_frequencies =
314 kmalloc_array(rval, sizeof(*vep->link_frequencies),
315 GFP_KERNEL);
316 if (!vep->link_frequencies) {
317 rval = -ENOMEM;
318 goto out_err;
319 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300320
Sakari Ailus06f81522017-06-20 09:14:43 -0400321 vep->nr_of_link_frequencies = rval;
322
323 rval = fwnode_property_read_u64_array(
324 fwnode, "link-frequencies", vep->link_frequencies,
325 vep->nr_of_link_frequencies);
326 if (rval < 0)
327 goto out_err;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500328
329 for (i = 0; i < vep->nr_of_link_frequencies; i++)
330 pr_info("link-frequencies %u value %llu\n", i,
331 vep->link_frequencies[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -0300332 }
333
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500334 pr_debug("===== end V4L2 endpoint properties\n");
335
Sakari Ailusca50c192016-08-12 08:05:51 -0300336 return vep;
337
338out_err:
339 v4l2_fwnode_endpoint_free(vep);
340 return ERR_PTR(rval);
341}
342EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
343
Sakari Ailusca50c192016-08-12 08:05:51 -0300344int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
345 struct v4l2_fwnode_link *link)
346{
347 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
348 struct fwnode_handle *fwnode;
349
350 memset(link, 0, sizeof(*link));
351
352 fwnode = fwnode_get_parent(__fwnode);
353 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
354 fwnode = fwnode_get_next_parent(fwnode);
355 if (is_of_node(fwnode) &&
356 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
357 fwnode = fwnode_get_next_parent(fwnode);
358 link->local_node = fwnode;
359
360 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
361 if (!fwnode) {
362 fwnode_handle_put(fwnode);
363 return -ENOLINK;
364 }
365
366 fwnode = fwnode_get_parent(fwnode);
367 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
368 fwnode = fwnode_get_next_parent(fwnode);
369 if (is_of_node(fwnode) &&
370 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
371 fwnode = fwnode_get_next_parent(fwnode);
372 link->remote_node = fwnode;
373
374 return 0;
375}
376EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
377
Sakari Ailusca50c192016-08-12 08:05:51 -0300378void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
379{
380 fwnode_handle_put(link->local_node);
381 fwnode_handle_put(link->remote_node);
382}
383EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
384
Sakari Ailus9ca46532017-08-17 11:28:21 -0400385static int v4l2_async_notifier_fwnode_parse_endpoint(
386 struct device *dev, struct v4l2_async_notifier *notifier,
387 struct fwnode_handle *endpoint, unsigned int asd_struct_size,
388 int (*parse_endpoint)(struct device *dev,
389 struct v4l2_fwnode_endpoint *vep,
390 struct v4l2_async_subdev *asd))
391{
392 struct v4l2_async_subdev *asd;
393 struct v4l2_fwnode_endpoint *vep;
394 int ret = 0;
395
396 asd = kzalloc(asd_struct_size, GFP_KERNEL);
397 if (!asd)
398 return -ENOMEM;
399
400 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400401 asd->match.fwnode =
Sakari Ailus9ca46532017-08-17 11:28:21 -0400402 fwnode_graph_get_remote_port_parent(endpoint);
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400403 if (!asd->match.fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400404 dev_warn(dev, "bad remote port parent\n");
Steve Longerbeam4382f372018-09-29 15:54:04 -0400405 ret = -ENOTCONN;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400406 goto out_err;
407 }
408
409 vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
410 if (IS_ERR(vep)) {
411 ret = PTR_ERR(vep);
412 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
413 ret);
414 goto out_err;
415 }
416
417 ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
418 if (ret == -ENOTCONN)
419 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
420 vep->base.id);
421 else if (ret < 0)
422 dev_warn(dev,
423 "driver could not parse port@%u/endpoint@%u (%d)\n",
424 vep->base.port, vep->base.id, ret);
425 v4l2_fwnode_endpoint_free(vep);
426 if (ret < 0)
427 goto out_err;
428
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400429 ret = v4l2_async_notifier_add_subdev(notifier, asd);
430 if (ret < 0) {
431 /* not an error if asd already exists */
432 if (ret == -EEXIST)
433 ret = 0;
434 goto out_err;
435 }
Sakari Ailus9ca46532017-08-17 11:28:21 -0400436
437 return 0;
438
439out_err:
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400440 fwnode_handle_put(asd->match.fwnode);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400441 kfree(asd);
442
443 return ret == -ENOTCONN ? 0 : ret;
444}
445
446static int __v4l2_async_notifier_parse_fwnode_endpoints(
447 struct device *dev, struct v4l2_async_notifier *notifier,
448 size_t asd_struct_size, unsigned int port, bool has_port,
449 int (*parse_endpoint)(struct device *dev,
450 struct v4l2_fwnode_endpoint *vep,
451 struct v4l2_async_subdev *asd))
452{
453 struct fwnode_handle *fwnode;
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400454 int ret = 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400455
456 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
457 return -EINVAL;
458
459 for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
460 dev_fwnode(dev), fwnode)); ) {
461 struct fwnode_handle *dev_fwnode;
462 bool is_available;
463
464 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
465 is_available = fwnode_device_is_available(dev_fwnode);
466 fwnode_handle_put(dev_fwnode);
467 if (!is_available)
468 continue;
469
470 if (has_port) {
471 struct fwnode_endpoint ep;
472
473 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400474 if (ret)
475 break;
476
477 if (ep.port != port)
478 continue;
479 }
480
481 ret = v4l2_async_notifier_fwnode_parse_endpoint(
482 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
483 if (ret < 0)
484 break;
485 }
486
487 fwnode_handle_put(fwnode);
488
489 return ret;
490}
491
492int 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))
498{
499 return __v4l2_async_notifier_parse_fwnode_endpoints(
500 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
501}
502EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
503
504int 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))
510{
511 return __v4l2_async_notifier_parse_fwnode_endpoints(
512 dev, notifier, asd_struct_size, port, true, parse_endpoint);
513}
514EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
515
Sakari Ailusd8428532017-06-20 07:47:24 -0400516/*
517 * v4l2_fwnode_reference_parse - parse references for async sub-devices
518 * @dev: the device node the properties of which are parsed for references
519 * @notifier: the async notifier where the async subdevs will be added
520 * @prop: the name of the property
521 *
522 * Return: 0 on success
523 * -ENOENT if no entries were found
524 * -ENOMEM if memory allocation failed
525 * -EINVAL if property parsing failed
526 */
527static int v4l2_fwnode_reference_parse(
528 struct device *dev, struct v4l2_async_notifier *notifier,
529 const char *prop)
530{
531 struct fwnode_reference_args args;
532 unsigned int index;
533 int ret;
534
535 for (index = 0;
536 !(ret = fwnode_property_get_reference_args(
537 dev_fwnode(dev), prop, NULL, 0, index, &args));
538 index++)
539 fwnode_handle_put(args.fwnode);
540
541 if (!index)
542 return -ENOENT;
543
544 /*
545 * Note that right now both -ENODATA and -ENOENT may signal
546 * out-of-bounds access. Return the error in cases other than that.
547 */
548 if (ret != -ENOENT && ret != -ENODATA)
549 return ret;
550
Sakari Ailusd8428532017-06-20 07:47:24 -0400551 for (index = 0; !fwnode_property_get_reference_args(
552 dev_fwnode(dev), prop, NULL, 0, index, &args);
553 index++) {
554 struct v4l2_async_subdev *asd;
555
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400556 asd = v4l2_async_notifier_add_fwnode_subdev(
557 notifier, args.fwnode, sizeof(*asd));
558 if (IS_ERR(asd)) {
559 ret = PTR_ERR(asd);
560 /* not an error if asd already exists */
561 if (ret == -EEXIST) {
562 fwnode_handle_put(args.fwnode);
563 continue;
564 }
565
Sakari Ailusd8428532017-06-20 07:47:24 -0400566 goto error;
567 }
Sakari Ailusd8428532017-06-20 07:47:24 -0400568 }
569
570 return 0;
571
572error:
573 fwnode_handle_put(args.fwnode);
574 return ret;
575}
576
Sakari Ailusa1699a42017-06-22 08:03:28 -0400577/*
578 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
579 * arguments
580 * @fwnode: fwnode to read @prop from
581 * @notifier: notifier for @dev
582 * @prop: the name of the property
583 * @index: the index of the reference to get
584 * @props: the array of integer property names
585 * @nprops: the number of integer property names in @nprops
586 *
587 * First find an fwnode referred to by the reference at @index in @prop.
588 *
589 * Then under that fwnode, @nprops times, for each property in @props,
590 * iteratively follow child nodes starting from fwnode such that they have the
591 * property in @props array at the index of the child node distance from the
592 * root node and the value of that property matching with the integer argument
593 * of the reference, at the same index.
594 *
595 * The child fwnode reched at the end of the iteration is then returned to the
596 * caller.
597 *
598 * The core reason for this is that you cannot refer to just any node in ACPI.
599 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
600 * provide a list of (property name, property value) tuples where each tuple
601 * uniquely identifies a child node. The first tuple identifies a child directly
602 * underneath the device fwnode, the next tuple identifies a child node
603 * underneath the fwnode identified by the previous tuple, etc. until you
604 * reached the fwnode you need.
605 *
606 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
607 *
608 * Scope (\_SB.PCI0.I2C2)
609 * {
610 * Device (CAM0)
611 * {
612 * Name (_DSD, Package () {
613 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
614 * Package () {
615 * Package () {
616 * "compatible",
617 * Package () { "nokia,smia" }
618 * },
619 * },
620 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
621 * Package () {
622 * Package () { "port0", "PRT0" },
623 * }
624 * })
625 * Name (PRT0, Package() {
626 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
627 * Package () {
628 * Package () { "port", 0 },
629 * },
630 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
631 * Package () {
632 * Package () { "endpoint0", "EP00" },
633 * }
634 * })
635 * Name (EP00, Package() {
636 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
637 * Package () {
638 * Package () { "endpoint", 0 },
639 * Package () {
640 * "remote-endpoint",
641 * Package() {
642 * \_SB.PCI0.ISP, 4, 0
643 * }
644 * },
645 * }
646 * })
647 * }
648 * }
649 *
650 * Scope (\_SB.PCI0)
651 * {
652 * Device (ISP)
653 * {
654 * Name (_DSD, Package () {
655 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
656 * Package () {
657 * Package () { "port4", "PRT4" },
658 * }
659 * })
660 *
661 * Name (PRT4, Package() {
662 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
663 * Package () {
664 * Package () { "port", 4 },
665 * },
666 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
667 * Package () {
668 * Package () { "endpoint0", "EP40" },
669 * }
670 * })
671 *
672 * Name (EP40, Package() {
673 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
674 * Package () {
675 * Package () { "endpoint", 0 },
676 * Package () {
677 * "remote-endpoint",
678 * Package () {
679 * \_SB.PCI0.I2C2.CAM0,
680 * 0, 0
681 * }
682 * },
683 * }
684 * })
685 * }
686 * }
687 *
688 * From the EP40 node under ISP device, you could parse the graph remote
689 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
690 *
691 * @fwnode: fwnode referring to EP40 under ISP.
692 * @prop: "remote-endpoint"
693 * @index: 0
694 * @props: "port", "endpoint"
695 * @nprops: 2
696 *
697 * And you'd get back fwnode referring to EP00 under CAM0.
698 *
699 * The same works the other way around: if you use EP00 under CAM0 as the
700 * fwnode, you'll get fwnode referring to EP40 under ISP.
701 *
702 * The same example in DT syntax would look like this:
703 *
704 * cam: cam0 {
705 * compatible = "nokia,smia";
706 *
707 * port {
708 * port = <0>;
709 * endpoint {
710 * endpoint = <0>;
711 * remote-endpoint = <&isp 4 0>;
712 * };
713 * };
714 * };
715 *
716 * isp: isp {
717 * ports {
718 * port@4 {
719 * port = <4>;
720 * endpoint {
721 * endpoint = <0>;
722 * remote-endpoint = <&cam 0 0>;
723 * };
724 * };
725 * };
726 * };
727 *
728 * Return: 0 on success
729 * -ENOENT if no entries (or the property itself) were found
730 * -EINVAL if property parsing otherwise failed
731 * -ENOMEM if memory allocation failed
732 */
733static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
734 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
735 const char * const *props, unsigned int nprops)
736{
737 struct fwnode_reference_args fwnode_args;
Sakari Ailus977d5ad2018-07-17 17:19:11 +0300738 u64 *args = fwnode_args.args;
Sakari Ailusa1699a42017-06-22 08:03:28 -0400739 struct fwnode_handle *child;
740 int ret;
741
742 /*
743 * Obtain remote fwnode as well as the integer arguments.
744 *
745 * Note that right now both -ENODATA and -ENOENT may signal
746 * out-of-bounds access. Return -ENOENT in that case.
747 */
748 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
749 index, &fwnode_args);
750 if (ret)
751 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
752
753 /*
754 * Find a node in the tree under the referred fwnode corresponding to
755 * the integer arguments.
756 */
757 fwnode = fwnode_args.fwnode;
758 while (nprops--) {
759 u32 val;
760
761 /* Loop over all child nodes under fwnode. */
762 fwnode_for_each_child_node(fwnode, child) {
763 if (fwnode_property_read_u32(child, *props, &val))
764 continue;
765
766 /* Found property, see if its value matches. */
767 if (val == *args)
768 break;
769 }
770
771 fwnode_handle_put(fwnode);
772
773 /* No property found; return an error here. */
774 if (!child) {
775 fwnode = ERR_PTR(-ENOENT);
776 break;
777 }
778
779 props++;
780 args++;
781 fwnode = child;
782 }
783
784 return fwnode;
785}
786
787/*
788 * v4l2_fwnode_reference_parse_int_props - parse references for async
789 * sub-devices
790 * @dev: struct device pointer
791 * @notifier: notifier for @dev
792 * @prop: the name of the property
793 * @props: the array of integer property names
794 * @nprops: the number of integer properties
795 *
796 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
797 * property @prop with integer arguments with child nodes matching in properties
798 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
799 * accordingly.
800 *
801 * While it is technically possible to use this function on DT, it is only
802 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
803 * on ACPI the references are limited to devices.
804 *
805 * Return: 0 on success
806 * -ENOENT if no entries (or the property itself) were found
807 * -EINVAL if property parsing otherwisefailed
808 * -ENOMEM if memory allocation failed
809 */
810static int v4l2_fwnode_reference_parse_int_props(
811 struct device *dev, struct v4l2_async_notifier *notifier,
812 const char *prop, const char * const *props, unsigned int nprops)
813{
814 struct fwnode_handle *fwnode;
815 unsigned int index;
816 int ret;
817
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400818 index = 0;
819 do {
820 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
821 prop, index,
822 props, nprops);
823 if (IS_ERR(fwnode)) {
824 /*
825 * Note that right now both -ENODATA and -ENOENT may
826 * signal out-of-bounds access. Return the error in
827 * cases other than that.
828 */
829 if (PTR_ERR(fwnode) != -ENOENT &&
830 PTR_ERR(fwnode) != -ENODATA)
831 return PTR_ERR(fwnode);
832 break;
833 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400834 fwnode_handle_put(fwnode);
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400835 index++;
836 } while (1);
Sakari Ailusa1699a42017-06-22 08:03:28 -0400837
Sakari Ailusa1699a42017-06-22 08:03:28 -0400838 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
839 dev_fwnode(dev), prop, index, props,
840 nprops))); index++) {
841 struct v4l2_async_subdev *asd;
842
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400843 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
844 sizeof(*asd));
845 if (IS_ERR(asd)) {
846 ret = PTR_ERR(asd);
847 /* not an error if asd already exists */
848 if (ret == -EEXIST) {
849 fwnode_handle_put(fwnode);
850 continue;
851 }
852
Sakari Ailusa1699a42017-06-22 08:03:28 -0400853 goto error;
854 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400855 }
856
857 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
858
859error:
860 fwnode_handle_put(fwnode);
861 return ret;
862}
863
Sakari Ailus7a9ec802017-09-06 08:35:42 -0400864int v4l2_async_notifier_parse_fwnode_sensor_common(
865 struct device *dev, struct v4l2_async_notifier *notifier)
866{
867 static const char * const led_props[] = { "led" };
868 static const struct {
869 const char *name;
870 const char * const *props;
871 unsigned int nprops;
872 } props[] = {
873 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
874 { "lens-focus", NULL, 0 },
875 };
876 unsigned int i;
877
878 for (i = 0; i < ARRAY_SIZE(props); i++) {
879 int ret;
880
881 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
882 ret = v4l2_fwnode_reference_parse_int_props(
883 dev, notifier, props[i].name,
884 props[i].props, props[i].nprops);
885 else
886 ret = v4l2_fwnode_reference_parse(
887 dev, notifier, props[i].name);
888 if (ret && ret != -ENOENT) {
889 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
890 props[i].name, ret);
891 return ret;
892 }
893 }
894
895 return 0;
896}
897EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
898
Sakari Ailusaef69d52017-09-24 18:47:44 -0400899int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
900{
901 struct v4l2_async_notifier *notifier;
902 int ret;
903
904 if (WARN_ON(!sd->dev))
905 return -ENODEV;
906
907 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
908 if (!notifier)
909 return -ENOMEM;
910
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400911 v4l2_async_notifier_init(notifier);
912
Sakari Ailusaef69d52017-09-24 18:47:44 -0400913 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
914 notifier);
915 if (ret < 0)
916 goto out_cleanup;
917
918 ret = v4l2_async_subdev_notifier_register(sd, notifier);
919 if (ret < 0)
920 goto out_cleanup;
921
922 ret = v4l2_async_register_subdev(sd);
923 if (ret < 0)
924 goto out_unregister;
925
926 sd->subdev_notifier = notifier;
927
928 return 0;
929
930out_unregister:
931 v4l2_async_notifier_unregister(notifier);
932
933out_cleanup:
934 v4l2_async_notifier_cleanup(notifier);
935 kfree(notifier);
936
937 return ret;
938}
939EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
940
Steve Longerbeam1634f0e2018-09-29 15:54:09 -0400941int v4l2_async_register_fwnode_subdev(
942 struct v4l2_subdev *sd, size_t asd_struct_size,
943 unsigned int *ports, unsigned int num_ports,
944 int (*parse_endpoint)(struct device *dev,
945 struct v4l2_fwnode_endpoint *vep,
946 struct v4l2_async_subdev *asd))
947{
948 struct v4l2_async_notifier *notifier;
949 struct device *dev = sd->dev;
950 struct fwnode_handle *fwnode;
951 int ret;
952
953 if (WARN_ON(!dev))
954 return -ENODEV;
955
956 fwnode = dev_fwnode(dev);
957 if (!fwnode_device_is_available(fwnode))
958 return -ENODEV;
959
960 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
961 if (!notifier)
962 return -ENOMEM;
963
964 v4l2_async_notifier_init(notifier);
965
966 if (!ports) {
967 ret = v4l2_async_notifier_parse_fwnode_endpoints(
968 dev, notifier, asd_struct_size, parse_endpoint);
969 if (ret < 0)
970 goto out_cleanup;
971 } else {
972 unsigned int i;
973
974 for (i = 0; i < num_ports; i++) {
975 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
976 dev, notifier, asd_struct_size,
977 ports[i], parse_endpoint);
978 if (ret < 0)
979 goto out_cleanup;
980 }
981 }
982
983 ret = v4l2_async_subdev_notifier_register(sd, notifier);
984 if (ret < 0)
985 goto out_cleanup;
986
987 ret = v4l2_async_register_subdev(sd);
988 if (ret < 0)
989 goto out_unregister;
990
991 sd->subdev_notifier = notifier;
992
993 return 0;
994
995out_unregister:
996 v4l2_async_notifier_unregister(notifier);
997out_cleanup:
998 v4l2_async_notifier_cleanup(notifier);
999 kfree(notifier);
1000
1001 return ret;
1002}
1003EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
1004
Sakari Ailusca50c192016-08-12 08:05:51 -03001005MODULE_LICENSE("GPL");
1006MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1007MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1008MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");