blob: ab457cf36ba5d84499ff33242ac1ece8175c339e [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
Sakari Ailus106ee382017-12-21 07:11:19 -0500459 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400460 struct fwnode_handle *dev_fwnode;
461 bool is_available;
462
463 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
464 is_available = fwnode_device_is_available(dev_fwnode);
465 fwnode_handle_put(dev_fwnode);
466 if (!is_available)
467 continue;
468
469 if (has_port) {
470 struct fwnode_endpoint ep;
471
472 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400473 if (ret)
474 break;
475
476 if (ep.port != port)
477 continue;
478 }
479
480 ret = v4l2_async_notifier_fwnode_parse_endpoint(
481 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
482 if (ret < 0)
483 break;
484 }
485
486 fwnode_handle_put(fwnode);
487
488 return ret;
489}
490
491int v4l2_async_notifier_parse_fwnode_endpoints(
492 struct device *dev, struct v4l2_async_notifier *notifier,
493 size_t asd_struct_size,
494 int (*parse_endpoint)(struct device *dev,
495 struct v4l2_fwnode_endpoint *vep,
496 struct v4l2_async_subdev *asd))
497{
498 return __v4l2_async_notifier_parse_fwnode_endpoints(
499 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
500}
501EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
502
503int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
504 struct device *dev, struct v4l2_async_notifier *notifier,
505 size_t asd_struct_size, unsigned int port,
506 int (*parse_endpoint)(struct device *dev,
507 struct v4l2_fwnode_endpoint *vep,
508 struct v4l2_async_subdev *asd))
509{
510 return __v4l2_async_notifier_parse_fwnode_endpoints(
511 dev, notifier, asd_struct_size, port, true, parse_endpoint);
512}
513EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
514
Sakari Ailusd8428532017-06-20 07:47:24 -0400515/*
516 * v4l2_fwnode_reference_parse - parse references for async sub-devices
517 * @dev: the device node the properties of which are parsed for references
518 * @notifier: the async notifier where the async subdevs will be added
519 * @prop: the name of the property
520 *
521 * Return: 0 on success
522 * -ENOENT if no entries were found
523 * -ENOMEM if memory allocation failed
524 * -EINVAL if property parsing failed
525 */
526static int v4l2_fwnode_reference_parse(
527 struct device *dev, struct v4l2_async_notifier *notifier,
528 const char *prop)
529{
530 struct fwnode_reference_args args;
531 unsigned int index;
532 int ret;
533
534 for (index = 0;
535 !(ret = fwnode_property_get_reference_args(
536 dev_fwnode(dev), prop, NULL, 0, index, &args));
537 index++)
538 fwnode_handle_put(args.fwnode);
539
540 if (!index)
541 return -ENOENT;
542
543 /*
544 * Note that right now both -ENODATA and -ENOENT may signal
545 * out-of-bounds access. Return the error in cases other than that.
546 */
547 if (ret != -ENOENT && ret != -ENODATA)
548 return ret;
549
Sakari Ailusd8428532017-06-20 07:47:24 -0400550 for (index = 0; !fwnode_property_get_reference_args(
551 dev_fwnode(dev), prop, NULL, 0, index, &args);
552 index++) {
553 struct v4l2_async_subdev *asd;
554
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400555 asd = v4l2_async_notifier_add_fwnode_subdev(
556 notifier, args.fwnode, sizeof(*asd));
557 if (IS_ERR(asd)) {
558 ret = PTR_ERR(asd);
559 /* not an error if asd already exists */
560 if (ret == -EEXIST) {
561 fwnode_handle_put(args.fwnode);
562 continue;
563 }
564
Sakari Ailusd8428532017-06-20 07:47:24 -0400565 goto error;
566 }
Sakari Ailusd8428532017-06-20 07:47:24 -0400567 }
568
569 return 0;
570
571error:
572 fwnode_handle_put(args.fwnode);
573 return ret;
574}
575
Sakari Ailusa1699a42017-06-22 08:03:28 -0400576/*
577 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
578 * arguments
579 * @fwnode: fwnode to read @prop from
580 * @notifier: notifier for @dev
581 * @prop: the name of the property
582 * @index: the index of the reference to get
583 * @props: the array of integer property names
584 * @nprops: the number of integer property names in @nprops
585 *
586 * First find an fwnode referred to by the reference at @index in @prop.
587 *
588 * Then under that fwnode, @nprops times, for each property in @props,
589 * iteratively follow child nodes starting from fwnode such that they have the
590 * property in @props array at the index of the child node distance from the
591 * root node and the value of that property matching with the integer argument
592 * of the reference, at the same index.
593 *
594 * The child fwnode reched at the end of the iteration is then returned to the
595 * caller.
596 *
597 * The core reason for this is that you cannot refer to just any node in ACPI.
598 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
599 * provide a list of (property name, property value) tuples where each tuple
600 * uniquely identifies a child node. The first tuple identifies a child directly
601 * underneath the device fwnode, the next tuple identifies a child node
602 * underneath the fwnode identified by the previous tuple, etc. until you
603 * reached the fwnode you need.
604 *
605 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
606 *
607 * Scope (\_SB.PCI0.I2C2)
608 * {
609 * Device (CAM0)
610 * {
611 * Name (_DSD, Package () {
612 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
613 * Package () {
614 * Package () {
615 * "compatible",
616 * Package () { "nokia,smia" }
617 * },
618 * },
619 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
620 * Package () {
621 * Package () { "port0", "PRT0" },
622 * }
623 * })
624 * Name (PRT0, Package() {
625 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
626 * Package () {
627 * Package () { "port", 0 },
628 * },
629 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
630 * Package () {
631 * Package () { "endpoint0", "EP00" },
632 * }
633 * })
634 * Name (EP00, Package() {
635 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
636 * Package () {
637 * Package () { "endpoint", 0 },
638 * Package () {
639 * "remote-endpoint",
640 * Package() {
641 * \_SB.PCI0.ISP, 4, 0
642 * }
643 * },
644 * }
645 * })
646 * }
647 * }
648 *
649 * Scope (\_SB.PCI0)
650 * {
651 * Device (ISP)
652 * {
653 * Name (_DSD, Package () {
654 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
655 * Package () {
656 * Package () { "port4", "PRT4" },
657 * }
658 * })
659 *
660 * Name (PRT4, Package() {
661 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
662 * Package () {
663 * Package () { "port", 4 },
664 * },
665 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
666 * Package () {
667 * Package () { "endpoint0", "EP40" },
668 * }
669 * })
670 *
671 * Name (EP40, Package() {
672 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
673 * Package () {
674 * Package () { "endpoint", 0 },
675 * Package () {
676 * "remote-endpoint",
677 * Package () {
678 * \_SB.PCI0.I2C2.CAM0,
679 * 0, 0
680 * }
681 * },
682 * }
683 * })
684 * }
685 * }
686 *
687 * From the EP40 node under ISP device, you could parse the graph remote
688 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
689 *
690 * @fwnode: fwnode referring to EP40 under ISP.
691 * @prop: "remote-endpoint"
692 * @index: 0
693 * @props: "port", "endpoint"
694 * @nprops: 2
695 *
696 * And you'd get back fwnode referring to EP00 under CAM0.
697 *
698 * The same works the other way around: if you use EP00 under CAM0 as the
699 * fwnode, you'll get fwnode referring to EP40 under ISP.
700 *
701 * The same example in DT syntax would look like this:
702 *
703 * cam: cam0 {
704 * compatible = "nokia,smia";
705 *
706 * port {
707 * port = <0>;
708 * endpoint {
709 * endpoint = <0>;
710 * remote-endpoint = <&isp 4 0>;
711 * };
712 * };
713 * };
714 *
715 * isp: isp {
716 * ports {
717 * port@4 {
718 * port = <4>;
719 * endpoint {
720 * endpoint = <0>;
721 * remote-endpoint = <&cam 0 0>;
722 * };
723 * };
724 * };
725 * };
726 *
727 * Return: 0 on success
728 * -ENOENT if no entries (or the property itself) were found
729 * -EINVAL if property parsing otherwise failed
730 * -ENOMEM if memory allocation failed
731 */
732static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
733 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
734 const char * const *props, unsigned int nprops)
735{
736 struct fwnode_reference_args fwnode_args;
Sakari Ailus977d5ad2018-07-17 17:19:11 +0300737 u64 *args = fwnode_args.args;
Sakari Ailusa1699a42017-06-22 08:03:28 -0400738 struct fwnode_handle *child;
739 int ret;
740
741 /*
742 * Obtain remote fwnode as well as the integer arguments.
743 *
744 * Note that right now both -ENODATA and -ENOENT may signal
745 * out-of-bounds access. Return -ENOENT in that case.
746 */
747 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
748 index, &fwnode_args);
749 if (ret)
750 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
751
752 /*
753 * Find a node in the tree under the referred fwnode corresponding to
754 * the integer arguments.
755 */
756 fwnode = fwnode_args.fwnode;
757 while (nprops--) {
758 u32 val;
759
760 /* Loop over all child nodes under fwnode. */
761 fwnode_for_each_child_node(fwnode, child) {
762 if (fwnode_property_read_u32(child, *props, &val))
763 continue;
764
765 /* Found property, see if its value matches. */
766 if (val == *args)
767 break;
768 }
769
770 fwnode_handle_put(fwnode);
771
772 /* No property found; return an error here. */
773 if (!child) {
774 fwnode = ERR_PTR(-ENOENT);
775 break;
776 }
777
778 props++;
779 args++;
780 fwnode = child;
781 }
782
783 return fwnode;
784}
785
786/*
787 * v4l2_fwnode_reference_parse_int_props - parse references for async
788 * sub-devices
789 * @dev: struct device pointer
790 * @notifier: notifier for @dev
791 * @prop: the name of the property
792 * @props: the array of integer property names
793 * @nprops: the number of integer properties
794 *
795 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
796 * property @prop with integer arguments with child nodes matching in properties
797 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
798 * accordingly.
799 *
800 * While it is technically possible to use this function on DT, it is only
801 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
802 * on ACPI the references are limited to devices.
803 *
804 * Return: 0 on success
805 * -ENOENT if no entries (or the property itself) were found
806 * -EINVAL if property parsing otherwisefailed
807 * -ENOMEM if memory allocation failed
808 */
809static int v4l2_fwnode_reference_parse_int_props(
810 struct device *dev, struct v4l2_async_notifier *notifier,
811 const char *prop, const char * const *props, unsigned int nprops)
812{
813 struct fwnode_handle *fwnode;
814 unsigned int index;
815 int ret;
816
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400817 index = 0;
818 do {
819 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
820 prop, index,
821 props, nprops);
822 if (IS_ERR(fwnode)) {
823 /*
824 * Note that right now both -ENODATA and -ENOENT may
825 * signal out-of-bounds access. Return the error in
826 * cases other than that.
827 */
828 if (PTR_ERR(fwnode) != -ENOENT &&
829 PTR_ERR(fwnode) != -ENODATA)
830 return PTR_ERR(fwnode);
831 break;
832 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400833 fwnode_handle_put(fwnode);
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400834 index++;
835 } while (1);
Sakari Ailusa1699a42017-06-22 08:03:28 -0400836
Sakari Ailusa1699a42017-06-22 08:03:28 -0400837 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
838 dev_fwnode(dev), prop, index, props,
839 nprops))); index++) {
840 struct v4l2_async_subdev *asd;
841
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400842 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
843 sizeof(*asd));
844 if (IS_ERR(asd)) {
845 ret = PTR_ERR(asd);
846 /* not an error if asd already exists */
847 if (ret == -EEXIST) {
848 fwnode_handle_put(fwnode);
849 continue;
850 }
851
Sakari Ailusa1699a42017-06-22 08:03:28 -0400852 goto error;
853 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400854 }
855
856 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
857
858error:
859 fwnode_handle_put(fwnode);
860 return ret;
861}
862
Sakari Ailus7a9ec802017-09-06 08:35:42 -0400863int v4l2_async_notifier_parse_fwnode_sensor_common(
864 struct device *dev, struct v4l2_async_notifier *notifier)
865{
866 static const char * const led_props[] = { "led" };
867 static const struct {
868 const char *name;
869 const char * const *props;
870 unsigned int nprops;
871 } props[] = {
872 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
873 { "lens-focus", NULL, 0 },
874 };
875 unsigned int i;
876
877 for (i = 0; i < ARRAY_SIZE(props); i++) {
878 int ret;
879
880 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
881 ret = v4l2_fwnode_reference_parse_int_props(
882 dev, notifier, props[i].name,
883 props[i].props, props[i].nprops);
884 else
885 ret = v4l2_fwnode_reference_parse(
886 dev, notifier, props[i].name);
887 if (ret && ret != -ENOENT) {
888 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
889 props[i].name, ret);
890 return ret;
891 }
892 }
893
894 return 0;
895}
896EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
897
Sakari Ailusaef69d52017-09-24 18:47:44 -0400898int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
899{
900 struct v4l2_async_notifier *notifier;
901 int ret;
902
903 if (WARN_ON(!sd->dev))
904 return -ENODEV;
905
906 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
907 if (!notifier)
908 return -ENOMEM;
909
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400910 v4l2_async_notifier_init(notifier);
911
Sakari Ailusaef69d52017-09-24 18:47:44 -0400912 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
913 notifier);
914 if (ret < 0)
915 goto out_cleanup;
916
917 ret = v4l2_async_subdev_notifier_register(sd, notifier);
918 if (ret < 0)
919 goto out_cleanup;
920
921 ret = v4l2_async_register_subdev(sd);
922 if (ret < 0)
923 goto out_unregister;
924
925 sd->subdev_notifier = notifier;
926
927 return 0;
928
929out_unregister:
930 v4l2_async_notifier_unregister(notifier);
931
932out_cleanup:
933 v4l2_async_notifier_cleanup(notifier);
934 kfree(notifier);
935
936 return ret;
937}
938EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
939
Steve Longerbeam1634f0e2018-09-29 15:54:09 -0400940int v4l2_async_register_fwnode_subdev(
941 struct v4l2_subdev *sd, size_t asd_struct_size,
942 unsigned int *ports, unsigned int num_ports,
943 int (*parse_endpoint)(struct device *dev,
944 struct v4l2_fwnode_endpoint *vep,
945 struct v4l2_async_subdev *asd))
946{
947 struct v4l2_async_notifier *notifier;
948 struct device *dev = sd->dev;
949 struct fwnode_handle *fwnode;
950 int ret;
951
952 if (WARN_ON(!dev))
953 return -ENODEV;
954
955 fwnode = dev_fwnode(dev);
956 if (!fwnode_device_is_available(fwnode))
957 return -ENODEV;
958
959 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
960 if (!notifier)
961 return -ENOMEM;
962
963 v4l2_async_notifier_init(notifier);
964
965 if (!ports) {
966 ret = v4l2_async_notifier_parse_fwnode_endpoints(
967 dev, notifier, asd_struct_size, parse_endpoint);
968 if (ret < 0)
969 goto out_cleanup;
970 } else {
971 unsigned int i;
972
973 for (i = 0; i < num_ports; i++) {
974 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
975 dev, notifier, asd_struct_size,
976 ports[i], parse_endpoint);
977 if (ret < 0)
978 goto out_cleanup;
979 }
980 }
981
982 ret = v4l2_async_subdev_notifier_register(sd, notifier);
983 if (ret < 0)
984 goto out_cleanup;
985
986 ret = v4l2_async_register_subdev(sd);
987 if (ret < 0)
988 goto out_unregister;
989
990 sd->subdev_notifier = notifier;
991
992 return 0;
993
994out_unregister:
995 v4l2_async_notifier_unregister(notifier);
996out_cleanup:
997 v4l2_async_notifier_cleanup(notifier);
998 kfree(notifier);
999
1000 return ret;
1001}
1002EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
1003
Sakari Ailusca50c192016-08-12 08:05:51 -03001004MODULE_LICENSE("GPL");
1005MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1006MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1007MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");