blob: d6ba3e5d4356594d2c36beedffd662920d88a194 [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);
Sakari Ailusca50c192016-08-12 08:05:51 -0300293}
294EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
295
Sakari Ailus6970d372018-06-02 12:19:35 -0400296int v4l2_fwnode_endpoint_alloc_parse(
297 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -0300298{
Sakari Ailusca50c192016-08-12 08:05:51 -0300299 int rval;
300
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500301 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300302 if (rval < 0)
Sakari Ailus6970d372018-06-02 12:19:35 -0400303 return rval;
Sakari Ailusca50c192016-08-12 08:05:51 -0300304
305 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
306 NULL, 0);
Sakari Ailus06f81522017-06-20 09:14:43 -0400307 if (rval > 0) {
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500308 unsigned int i;
309
Sakari Ailus06f81522017-06-20 09:14:43 -0400310 vep->link_frequencies =
311 kmalloc_array(rval, sizeof(*vep->link_frequencies),
312 GFP_KERNEL);
Sakari Ailus6970d372018-06-02 12:19:35 -0400313 if (!vep->link_frequencies)
314 return -ENOMEM;
Sakari Ailusca50c192016-08-12 08:05:51 -0300315
Sakari Ailus06f81522017-06-20 09:14:43 -0400316 vep->nr_of_link_frequencies = rval;
317
318 rval = fwnode_property_read_u64_array(
319 fwnode, "link-frequencies", vep->link_frequencies,
320 vep->nr_of_link_frequencies);
Sakari Ailus6970d372018-06-02 12:19:35 -0400321 if (rval < 0) {
322 v4l2_fwnode_endpoint_free(vep);
323 return rval;
324 }
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500325
326 for (i = 0; i < vep->nr_of_link_frequencies; i++)
327 pr_info("link-frequencies %u value %llu\n", i,
328 vep->link_frequencies[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -0300329 }
330
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500331 pr_debug("===== end V4L2 endpoint properties\n");
332
Sakari Ailus6970d372018-06-02 12:19:35 -0400333 return 0;
Sakari Ailusca50c192016-08-12 08:05:51 -0300334}
335EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
336
Sakari Ailusca50c192016-08-12 08:05:51 -0300337int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
338 struct v4l2_fwnode_link *link)
339{
340 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
341 struct fwnode_handle *fwnode;
342
343 memset(link, 0, sizeof(*link));
344
345 fwnode = fwnode_get_parent(__fwnode);
346 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
347 fwnode = fwnode_get_next_parent(fwnode);
348 if (is_of_node(fwnode) &&
349 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
350 fwnode = fwnode_get_next_parent(fwnode);
351 link->local_node = fwnode;
352
353 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
354 if (!fwnode) {
355 fwnode_handle_put(fwnode);
356 return -ENOLINK;
357 }
358
359 fwnode = fwnode_get_parent(fwnode);
360 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
361 fwnode = fwnode_get_next_parent(fwnode);
362 if (is_of_node(fwnode) &&
363 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
364 fwnode = fwnode_get_next_parent(fwnode);
365 link->remote_node = fwnode;
366
367 return 0;
368}
369EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
370
Sakari Ailusca50c192016-08-12 08:05:51 -0300371void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
372{
373 fwnode_handle_put(link->local_node);
374 fwnode_handle_put(link->remote_node);
375}
376EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
377
Sakari Ailus9ca46532017-08-17 11:28:21 -0400378static int v4l2_async_notifier_fwnode_parse_endpoint(
379 struct device *dev, struct v4l2_async_notifier *notifier,
380 struct fwnode_handle *endpoint, unsigned int asd_struct_size,
381 int (*parse_endpoint)(struct device *dev,
382 struct v4l2_fwnode_endpoint *vep,
383 struct v4l2_async_subdev *asd))
384{
Sakari Ailus6970d372018-06-02 12:19:35 -0400385 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
Sakari Ailus9ca46532017-08-17 11:28:21 -0400386 struct v4l2_async_subdev *asd;
Sakari Ailus6970d372018-06-02 12:19:35 -0400387 int ret;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400388
389 asd = kzalloc(asd_struct_size, GFP_KERNEL);
390 if (!asd)
391 return -ENOMEM;
392
393 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400394 asd->match.fwnode =
Sakari Ailus9ca46532017-08-17 11:28:21 -0400395 fwnode_graph_get_remote_port_parent(endpoint);
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400396 if (!asd->match.fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400397 dev_warn(dev, "bad remote port parent\n");
Steve Longerbeam4382f372018-09-29 15:54:04 -0400398 ret = -ENOTCONN;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400399 goto out_err;
400 }
401
Sakari Ailus6970d372018-06-02 12:19:35 -0400402 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
403 if (ret) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400404 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
405 ret);
406 goto out_err;
407 }
408
Sakari Ailus6970d372018-06-02 12:19:35 -0400409 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400410 if (ret == -ENOTCONN)
Sakari Ailus6970d372018-06-02 12:19:35 -0400411 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
412 vep.base.id);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400413 else if (ret < 0)
414 dev_warn(dev,
415 "driver could not parse port@%u/endpoint@%u (%d)\n",
Sakari Ailus6970d372018-06-02 12:19:35 -0400416 vep.base.port, vep.base.id, ret);
417 v4l2_fwnode_endpoint_free(&vep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400418 if (ret < 0)
419 goto out_err;
420
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400421 ret = v4l2_async_notifier_add_subdev(notifier, asd);
422 if (ret < 0) {
423 /* not an error if asd already exists */
424 if (ret == -EEXIST)
425 ret = 0;
426 goto out_err;
427 }
Sakari Ailus9ca46532017-08-17 11:28:21 -0400428
429 return 0;
430
431out_err:
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400432 fwnode_handle_put(asd->match.fwnode);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400433 kfree(asd);
434
435 return ret == -ENOTCONN ? 0 : ret;
436}
437
438static int __v4l2_async_notifier_parse_fwnode_endpoints(
439 struct device *dev, struct v4l2_async_notifier *notifier,
440 size_t asd_struct_size, unsigned int port, bool has_port,
441 int (*parse_endpoint)(struct device *dev,
442 struct v4l2_fwnode_endpoint *vep,
443 struct v4l2_async_subdev *asd))
444{
445 struct fwnode_handle *fwnode;
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400446 int ret = 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400447
448 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
449 return -EINVAL;
450
Sakari Ailus106ee382017-12-21 07:11:19 -0500451 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400452 struct fwnode_handle *dev_fwnode;
453 bool is_available;
454
455 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
456 is_available = fwnode_device_is_available(dev_fwnode);
457 fwnode_handle_put(dev_fwnode);
458 if (!is_available)
459 continue;
460
461 if (has_port) {
462 struct fwnode_endpoint ep;
463
464 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400465 if (ret)
466 break;
467
468 if (ep.port != port)
469 continue;
470 }
471
472 ret = v4l2_async_notifier_fwnode_parse_endpoint(
473 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
474 if (ret < 0)
475 break;
476 }
477
478 fwnode_handle_put(fwnode);
479
480 return ret;
481}
482
483int v4l2_async_notifier_parse_fwnode_endpoints(
484 struct device *dev, struct v4l2_async_notifier *notifier,
485 size_t asd_struct_size,
486 int (*parse_endpoint)(struct device *dev,
487 struct v4l2_fwnode_endpoint *vep,
488 struct v4l2_async_subdev *asd))
489{
490 return __v4l2_async_notifier_parse_fwnode_endpoints(
491 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
492}
493EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
494
495int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
496 struct device *dev, struct v4l2_async_notifier *notifier,
497 size_t asd_struct_size, unsigned int port,
498 int (*parse_endpoint)(struct device *dev,
499 struct v4l2_fwnode_endpoint *vep,
500 struct v4l2_async_subdev *asd))
501{
502 return __v4l2_async_notifier_parse_fwnode_endpoints(
503 dev, notifier, asd_struct_size, port, true, parse_endpoint);
504}
505EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
506
Sakari Ailusd8428532017-06-20 07:47:24 -0400507/*
508 * v4l2_fwnode_reference_parse - parse references for async sub-devices
509 * @dev: the device node the properties of which are parsed for references
510 * @notifier: the async notifier where the async subdevs will be added
511 * @prop: the name of the property
512 *
513 * Return: 0 on success
514 * -ENOENT if no entries were found
515 * -ENOMEM if memory allocation failed
516 * -EINVAL if property parsing failed
517 */
518static int v4l2_fwnode_reference_parse(
519 struct device *dev, struct v4l2_async_notifier *notifier,
520 const char *prop)
521{
522 struct fwnode_reference_args args;
523 unsigned int index;
524 int ret;
525
526 for (index = 0;
527 !(ret = fwnode_property_get_reference_args(
528 dev_fwnode(dev), prop, NULL, 0, index, &args));
529 index++)
530 fwnode_handle_put(args.fwnode);
531
532 if (!index)
533 return -ENOENT;
534
535 /*
536 * Note that right now both -ENODATA and -ENOENT may signal
537 * out-of-bounds access. Return the error in cases other than that.
538 */
539 if (ret != -ENOENT && ret != -ENODATA)
540 return ret;
541
Sakari Ailusd8428532017-06-20 07:47:24 -0400542 for (index = 0; !fwnode_property_get_reference_args(
543 dev_fwnode(dev), prop, NULL, 0, index, &args);
544 index++) {
545 struct v4l2_async_subdev *asd;
546
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400547 asd = v4l2_async_notifier_add_fwnode_subdev(
548 notifier, args.fwnode, sizeof(*asd));
549 if (IS_ERR(asd)) {
550 ret = PTR_ERR(asd);
551 /* not an error if asd already exists */
552 if (ret == -EEXIST) {
553 fwnode_handle_put(args.fwnode);
554 continue;
555 }
556
Sakari Ailusd8428532017-06-20 07:47:24 -0400557 goto error;
558 }
Sakari Ailusd8428532017-06-20 07:47:24 -0400559 }
560
561 return 0;
562
563error:
564 fwnode_handle_put(args.fwnode);
565 return ret;
566}
567
Sakari Ailusa1699a42017-06-22 08:03:28 -0400568/*
569 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
570 * arguments
571 * @fwnode: fwnode to read @prop from
572 * @notifier: notifier for @dev
573 * @prop: the name of the property
574 * @index: the index of the reference to get
575 * @props: the array of integer property names
576 * @nprops: the number of integer property names in @nprops
577 *
578 * First find an fwnode referred to by the reference at @index in @prop.
579 *
580 * Then under that fwnode, @nprops times, for each property in @props,
581 * iteratively follow child nodes starting from fwnode such that they have the
582 * property in @props array at the index of the child node distance from the
583 * root node and the value of that property matching with the integer argument
584 * of the reference, at the same index.
585 *
586 * The child fwnode reched at the end of the iteration is then returned to the
587 * caller.
588 *
589 * The core reason for this is that you cannot refer to just any node in ACPI.
590 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
591 * provide a list of (property name, property value) tuples where each tuple
592 * uniquely identifies a child node. The first tuple identifies a child directly
593 * underneath the device fwnode, the next tuple identifies a child node
594 * underneath the fwnode identified by the previous tuple, etc. until you
595 * reached the fwnode you need.
596 *
597 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
598 *
599 * Scope (\_SB.PCI0.I2C2)
600 * {
601 * Device (CAM0)
602 * {
603 * Name (_DSD, Package () {
604 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
605 * Package () {
606 * Package () {
607 * "compatible",
608 * Package () { "nokia,smia" }
609 * },
610 * },
611 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
612 * Package () {
613 * Package () { "port0", "PRT0" },
614 * }
615 * })
616 * Name (PRT0, Package() {
617 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
618 * Package () {
619 * Package () { "port", 0 },
620 * },
621 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
622 * Package () {
623 * Package () { "endpoint0", "EP00" },
624 * }
625 * })
626 * Name (EP00, Package() {
627 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
628 * Package () {
629 * Package () { "endpoint", 0 },
630 * Package () {
631 * "remote-endpoint",
632 * Package() {
633 * \_SB.PCI0.ISP, 4, 0
634 * }
635 * },
636 * }
637 * })
638 * }
639 * }
640 *
641 * Scope (\_SB.PCI0)
642 * {
643 * Device (ISP)
644 * {
645 * Name (_DSD, Package () {
646 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
647 * Package () {
648 * Package () { "port4", "PRT4" },
649 * }
650 * })
651 *
652 * Name (PRT4, Package() {
653 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
654 * Package () {
655 * Package () { "port", 4 },
656 * },
657 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
658 * Package () {
659 * Package () { "endpoint0", "EP40" },
660 * }
661 * })
662 *
663 * Name (EP40, Package() {
664 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
665 * Package () {
666 * Package () { "endpoint", 0 },
667 * Package () {
668 * "remote-endpoint",
669 * Package () {
670 * \_SB.PCI0.I2C2.CAM0,
671 * 0, 0
672 * }
673 * },
674 * }
675 * })
676 * }
677 * }
678 *
679 * From the EP40 node under ISP device, you could parse the graph remote
680 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
681 *
682 * @fwnode: fwnode referring to EP40 under ISP.
683 * @prop: "remote-endpoint"
684 * @index: 0
685 * @props: "port", "endpoint"
686 * @nprops: 2
687 *
688 * And you'd get back fwnode referring to EP00 under CAM0.
689 *
690 * The same works the other way around: if you use EP00 under CAM0 as the
691 * fwnode, you'll get fwnode referring to EP40 under ISP.
692 *
693 * The same example in DT syntax would look like this:
694 *
695 * cam: cam0 {
696 * compatible = "nokia,smia";
697 *
698 * port {
699 * port = <0>;
700 * endpoint {
701 * endpoint = <0>;
702 * remote-endpoint = <&isp 4 0>;
703 * };
704 * };
705 * };
706 *
707 * isp: isp {
708 * ports {
709 * port@4 {
710 * port = <4>;
711 * endpoint {
712 * endpoint = <0>;
713 * remote-endpoint = <&cam 0 0>;
714 * };
715 * };
716 * };
717 * };
718 *
719 * Return: 0 on success
720 * -ENOENT if no entries (or the property itself) were found
721 * -EINVAL if property parsing otherwise failed
722 * -ENOMEM if memory allocation failed
723 */
724static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
725 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
726 const char * const *props, unsigned int nprops)
727{
728 struct fwnode_reference_args fwnode_args;
Sakari Ailus977d5ad2018-07-17 17:19:11 +0300729 u64 *args = fwnode_args.args;
Sakari Ailusa1699a42017-06-22 08:03:28 -0400730 struct fwnode_handle *child;
731 int ret;
732
733 /*
734 * Obtain remote fwnode as well as the integer arguments.
735 *
736 * Note that right now both -ENODATA and -ENOENT may signal
737 * out-of-bounds access. Return -ENOENT in that case.
738 */
739 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
740 index, &fwnode_args);
741 if (ret)
742 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
743
744 /*
745 * Find a node in the tree under the referred fwnode corresponding to
746 * the integer arguments.
747 */
748 fwnode = fwnode_args.fwnode;
749 while (nprops--) {
750 u32 val;
751
752 /* Loop over all child nodes under fwnode. */
753 fwnode_for_each_child_node(fwnode, child) {
754 if (fwnode_property_read_u32(child, *props, &val))
755 continue;
756
757 /* Found property, see if its value matches. */
758 if (val == *args)
759 break;
760 }
761
762 fwnode_handle_put(fwnode);
763
764 /* No property found; return an error here. */
765 if (!child) {
766 fwnode = ERR_PTR(-ENOENT);
767 break;
768 }
769
770 props++;
771 args++;
772 fwnode = child;
773 }
774
775 return fwnode;
776}
777
778/*
779 * v4l2_fwnode_reference_parse_int_props - parse references for async
780 * sub-devices
781 * @dev: struct device pointer
782 * @notifier: notifier for @dev
783 * @prop: the name of the property
784 * @props: the array of integer property names
785 * @nprops: the number of integer properties
786 *
787 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
788 * property @prop with integer arguments with child nodes matching in properties
789 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
790 * accordingly.
791 *
792 * While it is technically possible to use this function on DT, it is only
793 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
794 * on ACPI the references are limited to devices.
795 *
796 * Return: 0 on success
797 * -ENOENT if no entries (or the property itself) were found
798 * -EINVAL if property parsing otherwisefailed
799 * -ENOMEM if memory allocation failed
800 */
801static int v4l2_fwnode_reference_parse_int_props(
802 struct device *dev, struct v4l2_async_notifier *notifier,
803 const char *prop, const char * const *props, unsigned int nprops)
804{
805 struct fwnode_handle *fwnode;
806 unsigned int index;
807 int ret;
808
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400809 index = 0;
810 do {
811 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
812 prop, index,
813 props, nprops);
814 if (IS_ERR(fwnode)) {
815 /*
816 * Note that right now both -ENODATA and -ENOENT may
817 * signal out-of-bounds access. Return the error in
818 * cases other than that.
819 */
820 if (PTR_ERR(fwnode) != -ENOENT &&
821 PTR_ERR(fwnode) != -ENODATA)
822 return PTR_ERR(fwnode);
823 break;
824 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400825 fwnode_handle_put(fwnode);
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400826 index++;
827 } while (1);
Sakari Ailusa1699a42017-06-22 08:03:28 -0400828
Sakari Ailusa1699a42017-06-22 08:03:28 -0400829 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
830 dev_fwnode(dev), prop, index, props,
831 nprops))); index++) {
832 struct v4l2_async_subdev *asd;
833
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400834 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
835 sizeof(*asd));
836 if (IS_ERR(asd)) {
837 ret = PTR_ERR(asd);
838 /* not an error if asd already exists */
839 if (ret == -EEXIST) {
840 fwnode_handle_put(fwnode);
841 continue;
842 }
843
Sakari Ailusa1699a42017-06-22 08:03:28 -0400844 goto error;
845 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400846 }
847
848 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
849
850error:
851 fwnode_handle_put(fwnode);
852 return ret;
853}
854
Sakari Ailus7a9ec802017-09-06 08:35:42 -0400855int v4l2_async_notifier_parse_fwnode_sensor_common(
856 struct device *dev, struct v4l2_async_notifier *notifier)
857{
858 static const char * const led_props[] = { "led" };
859 static const struct {
860 const char *name;
861 const char * const *props;
862 unsigned int nprops;
863 } props[] = {
864 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
865 { "lens-focus", NULL, 0 },
866 };
867 unsigned int i;
868
869 for (i = 0; i < ARRAY_SIZE(props); i++) {
870 int ret;
871
872 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
873 ret = v4l2_fwnode_reference_parse_int_props(
874 dev, notifier, props[i].name,
875 props[i].props, props[i].nprops);
876 else
877 ret = v4l2_fwnode_reference_parse(
878 dev, notifier, props[i].name);
879 if (ret && ret != -ENOENT) {
880 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
881 props[i].name, ret);
882 return ret;
883 }
884 }
885
886 return 0;
887}
888EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
889
Sakari Ailusaef69d52017-09-24 18:47:44 -0400890int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
891{
892 struct v4l2_async_notifier *notifier;
893 int ret;
894
895 if (WARN_ON(!sd->dev))
896 return -ENODEV;
897
898 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
899 if (!notifier)
900 return -ENOMEM;
901
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400902 v4l2_async_notifier_init(notifier);
903
Sakari Ailusaef69d52017-09-24 18:47:44 -0400904 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
905 notifier);
906 if (ret < 0)
907 goto out_cleanup;
908
909 ret = v4l2_async_subdev_notifier_register(sd, notifier);
910 if (ret < 0)
911 goto out_cleanup;
912
913 ret = v4l2_async_register_subdev(sd);
914 if (ret < 0)
915 goto out_unregister;
916
917 sd->subdev_notifier = notifier;
918
919 return 0;
920
921out_unregister:
922 v4l2_async_notifier_unregister(notifier);
923
924out_cleanup:
925 v4l2_async_notifier_cleanup(notifier);
926 kfree(notifier);
927
928 return ret;
929}
930EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
931
Steve Longerbeam1634f0e2018-09-29 15:54:09 -0400932int v4l2_async_register_fwnode_subdev(
933 struct v4l2_subdev *sd, size_t asd_struct_size,
934 unsigned int *ports, unsigned int num_ports,
935 int (*parse_endpoint)(struct device *dev,
936 struct v4l2_fwnode_endpoint *vep,
937 struct v4l2_async_subdev *asd))
938{
939 struct v4l2_async_notifier *notifier;
940 struct device *dev = sd->dev;
941 struct fwnode_handle *fwnode;
942 int ret;
943
944 if (WARN_ON(!dev))
945 return -ENODEV;
946
947 fwnode = dev_fwnode(dev);
948 if (!fwnode_device_is_available(fwnode))
949 return -ENODEV;
950
951 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
952 if (!notifier)
953 return -ENOMEM;
954
955 v4l2_async_notifier_init(notifier);
956
957 if (!ports) {
958 ret = v4l2_async_notifier_parse_fwnode_endpoints(
959 dev, notifier, asd_struct_size, parse_endpoint);
960 if (ret < 0)
961 goto out_cleanup;
962 } else {
963 unsigned int i;
964
965 for (i = 0; i < num_ports; i++) {
966 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
967 dev, notifier, asd_struct_size,
968 ports[i], parse_endpoint);
969 if (ret < 0)
970 goto out_cleanup;
971 }
972 }
973
974 ret = v4l2_async_subdev_notifier_register(sd, notifier);
975 if (ret < 0)
976 goto out_cleanup;
977
978 ret = v4l2_async_register_subdev(sd);
979 if (ret < 0)
980 goto out_unregister;
981
982 sd->subdev_notifier = notifier;
983
984 return 0;
985
986out_unregister:
987 v4l2_async_notifier_unregister(notifier);
988out_cleanup:
989 v4l2_async_notifier_cleanup(notifier);
990 kfree(notifier);
991
992 return ret;
993}
994EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
995
Sakari Ailusca50c192016-08-12 08:05:51 -0300996MODULE_LICENSE("GPL");
997MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
998MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
999MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");