blob: 99dc0b6baaaee70e1e03b8c9cf15fbd340e3774d [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 Ailus26c11262018-07-17 12:17:02 -040045static const struct v4l2_fwnode_bus_conv {
46 enum v4l2_fwnode_bus_type fwnode_bus_type;
47 enum v4l2_mbus_type mbus_type;
48 const char *name;
49} busses[] = {
50 {
51 V4L2_FWNODE_BUS_TYPE_GUESS,
52 V4L2_MBUS_UNKNOWN,
53 "not specified",
54 }, {
55 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
56 V4L2_MBUS_CSI2_CPHY,
57 "MIPI CSI-2 C-PHY",
58 }, {
59 V4L2_FWNODE_BUS_TYPE_CSI1,
60 V4L2_MBUS_CSI1,
61 "MIPI CSI-1",
62 }, {
63 V4L2_FWNODE_BUS_TYPE_CCP2,
64 V4L2_MBUS_CCP2,
65 "compact camera port 2",
66 }, {
67 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
68 V4L2_MBUS_CSI2_DPHY,
69 "MIPI CSI-2 D-PHY",
70 }, {
71 V4L2_FWNODE_BUS_TYPE_PARALLEL,
72 V4L2_MBUS_PARALLEL,
73 "parallel",
74 }, {
75 V4L2_FWNODE_BUS_TYPE_BT656,
76 V4L2_MBUS_BT656,
77 "Bt.656",
78 }
79};
80
81static const struct v4l2_fwnode_bus_conv *
82get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
83{
84 unsigned int i;
85
86 for (i = 0; i < ARRAY_SIZE(busses); i++)
87 if (busses[i].fwnode_bus_type == type)
88 return &busses[i];
89
90 return NULL;
91}
92
93static enum v4l2_mbus_type
94v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
95{
96 const struct v4l2_fwnode_bus_conv *conv =
97 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
98
99 return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
100}
101
Sakari Ailusf3112732017-02-20 05:42:09 -0500102static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
Sakari Ailus276565e2018-07-18 09:33:45 -0400103 struct v4l2_fwnode_endpoint *vep,
Sakari Ailus26c11262018-07-17 12:17:02 -0400104 enum v4l2_mbus_type bus_type)
Sakari Ailusca50c192016-08-12 08:05:51 -0300105{
106 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
Sakari Ailusb4357d22018-07-20 09:57:48 -0400107 bool have_clk_lane = false, have_data_lanes = false,
108 have_lane_polarities = false;
Sakari Ailusca50c192016-08-12 08:05:51 -0300109 unsigned int flags = 0, lanes_used = 0;
Sakari Ailus276565e2018-07-18 09:33:45 -0400110 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
Sakari Ailusb4357d22018-07-20 09:57:48 -0400111 u32 clock_lane = 0;
Sakari Ailus276565e2018-07-18 09:33:45 -0400112 unsigned int num_data_lanes = 0;
Sakari Ailusb4357d22018-07-20 09:57:48 -0400113 bool use_default_lane_mapping = false;
Sakari Ailusca50c192016-08-12 08:05:51 -0300114 unsigned int i;
115 u32 v;
116 int rval;
117
Sakari Ailus26c11262018-07-17 12:17:02 -0400118 if (bus_type == V4L2_MBUS_CSI2_DPHY) {
Sakari Ailusb4357d22018-07-20 09:57:48 -0400119 use_default_lane_mapping = true;
120
Sakari Ailus276565e2018-07-18 09:33:45 -0400121 num_data_lanes = min_t(u32, bus->num_data_lanes,
122 V4L2_FWNODE_CSI2_MAX_DATA_LANES);
123
Sakari Ailusb4357d22018-07-20 09:57:48 -0400124 clock_lane = bus->clock_lane;
125 if (clock_lane)
126 use_default_lane_mapping = false;
127
128 for (i = 0; i < num_data_lanes; i++) {
Sakari Ailusc2475ae2018-07-20 06:14:14 -0400129 array[i] = bus->data_lanes[i];
Sakari Ailusb4357d22018-07-20 09:57:48 -0400130 if (array[i])
131 use_default_lane_mapping = false;
132 }
133
134 if (use_default_lane_mapping)
135 pr_debug("using default lane mapping\n");
Sakari Ailusc2475ae2018-07-20 06:14:14 -0400136 }
137
Sakari Ailusca50c192016-08-12 08:05:51 -0300138 rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
139 if (rval > 0) {
Sakari Ailus276565e2018-07-18 09:33:45 -0400140 num_data_lanes =
Sakari Ailusad3cdf32017-08-14 06:43:07 -0400141 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
Sakari Ailusca50c192016-08-12 08:05:51 -0300142
143 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
Sakari Ailus276565e2018-07-18 09:33:45 -0400144 num_data_lanes);
Sakari Ailusb4357d22018-07-20 09:57:48 -0400145
146 have_data_lanes = true;
Sakari Ailusc2475ae2018-07-20 06:14:14 -0400147 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300148
Sakari Ailusc2475ae2018-07-20 06:14:14 -0400149 for (i = 0; i < num_data_lanes; i++) {
Sakari Ailusb4357d22018-07-20 09:57:48 -0400150 if (lanes_used & BIT(array[i])) {
151 if (have_data_lanes || !use_default_lane_mapping)
152 pr_warn("duplicated lane %u in data-lanes, using defaults\n",
153 array[i]);
154 use_default_lane_mapping = true;
155 }
Sakari Ailusc2475ae2018-07-20 06:14:14 -0400156 lanes_used |= BIT(array[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -0300157
Sakari Ailusb4357d22018-07-20 09:57:48 -0400158 if (have_data_lanes)
159 pr_debug("lane %u position %u\n", i, array[i]);
Sakari Ailus276565e2018-07-18 09:33:45 -0400160 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300161
Sakari Ailus276565e2018-07-18 09:33:45 -0400162 rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL,
163 0);
164 if (rval > 0) {
165 if (rval != 1 + num_data_lanes /* clock+data */) {
166 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
167 1 + num_data_lanes, rval);
168 return -EINVAL;
Sakari Ailusca50c192016-08-12 08:05:51 -0300169 }
Sakari Ailusb24f0212017-08-14 06:15:21 -0400170
Sakari Ailusaf11a742018-07-03 07:06:20 -0400171 have_lane_polarities = true;
Sakari Ailusca50c192016-08-12 08:05:51 -0300172 }
173
174 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
Sakari Ailusb4357d22018-07-20 09:57:48 -0400175 clock_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500176 pr_debug("clock lane position %u\n", v);
Sakari Ailusb4357d22018-07-20 09:57:48 -0400177 have_clk_lane = true;
178 }
179
180 if (lanes_used & BIT(clock_lane)) {
181 if (have_clk_lane || !use_default_lane_mapping)
182 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
183 v);
184 use_default_lane_mapping = true;
Sakari Ailusca50c192016-08-12 08:05:51 -0300185 }
186
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500187 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300188 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500189 pr_debug("non-continuous clock\n");
Sakari Ailusd4865322018-07-20 05:04:29 -0400190 } else {
Sakari Ailusca50c192016-08-12 08:05:51 -0300191 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500192 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300193
Sakari Ailus26c11262018-07-17 12:17:02 -0400194 if (bus_type == V4L2_MBUS_CSI2_DPHY || lanes_used ||
Sakari Ailus276565e2018-07-18 09:33:45 -0400195 have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
Sakari Ailus2835b5b2018-07-31 06:43:14 -0400196 bus->flags = flags;
197 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
Sakari Ailus276565e2018-07-18 09:33:45 -0400198 bus->num_data_lanes = num_data_lanes;
Sakari Ailusb4357d22018-07-20 09:57:48 -0400199
200 if (use_default_lane_mapping) {
201 bus->clock_lane = 0;
202 for (i = 0; i < num_data_lanes; i++)
203 bus->data_lanes[i] = 1 + i;
204 } else {
205 bus->clock_lane = clock_lane;
206 for (i = 0; i < num_data_lanes; i++)
207 bus->data_lanes[i] = array[i];
208 }
Sakari Ailusaf11a742018-07-03 07:06:20 -0400209
210 if (have_lane_polarities) {
211 fwnode_property_read_u32_array(fwnode,
212 "lane-polarities", array,
213 1 + num_data_lanes);
214
215 for (i = 0; i < 1 + num_data_lanes; i++) {
216 bus->lane_polarities[i] = array[i];
217 pr_debug("lane %u polarity %sinverted",
218 i, array[i] ? "" : "not ");
219 }
220 } else {
221 pr_debug("no lane polarities defined, assuming not inverted\n");
222 }
Sakari Ailus2835b5b2018-07-31 06:43:14 -0400223 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300224
225 return 0;
226}
227
Sakari Ailus175b18b2018-01-02 08:14:30 -0500228#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
229 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
230 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
231 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
232 V4L2_MBUS_FIELD_EVEN_HIGH | \
233 V4L2_MBUS_FIELD_EVEN_LOW)
234
Sakari Ailusca50c192016-08-12 08:05:51 -0300235static void v4l2_fwnode_endpoint_parse_parallel_bus(
Sakari Ailus175b18b2018-01-02 08:14:30 -0500236 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep,
Sakari Ailus26c11262018-07-17 12:17:02 -0400237 enum v4l2_mbus_type bus_type)
Sakari Ailusca50c192016-08-12 08:05:51 -0300238{
239 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
240 unsigned int flags = 0;
241 u32 v;
242
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500243 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300244 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
245 V4L2_MBUS_HSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500246 pr_debug("hsync-active %s\n", v ? "high" : "low");
247 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300248
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500249 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300250 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
251 V4L2_MBUS_VSYNC_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500252 pr_debug("vsync-active %s\n", v ? "high" : "low");
253 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300254
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500255 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300256 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
257 V4L2_MBUS_FIELD_EVEN_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500258 pr_debug("field-even-active %s\n", v ? "high" : "low");
259 }
260
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500261 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300262 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
263 V4L2_MBUS_PCLK_SAMPLE_FALLING;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500264 pr_debug("pclk-sample %s\n", v ? "high" : "low");
265 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300266
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500267 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300268 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
269 V4L2_MBUS_DATA_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500270 pr_debug("data-active %s\n", v ? "high" : "low");
271 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300272
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500273 if (fwnode_property_present(fwnode, "slave-mode")) {
274 pr_debug("slave mode\n");
Sakari Ailusca50c192016-08-12 08:05:51 -0300275 flags |= V4L2_MBUS_SLAVE;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500276 } else {
Sakari Ailusca50c192016-08-12 08:05:51 -0300277 flags |= V4L2_MBUS_MASTER;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500278 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300279
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500280 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300281 bus->bus_width = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500282 pr_debug("bus-width %u\n", v);
283 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300284
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500285 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300286 bus->data_shift = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500287 pr_debug("data-shift %u\n", v);
288 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300289
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500290 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
Sakari Ailusca50c192016-08-12 08:05:51 -0300291 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
292 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500293 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
294 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300295
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500296 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400297 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
298 V4L2_MBUS_DATA_ENABLE_LOW;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500299 pr_debug("data-enable-active %s\n", v ? "high" : "low");
300 }
Jacopo Mondi9b04fcc2018-07-09 10:19:19 -0400301
Sakari Ailus175b18b2018-01-02 08:14:30 -0500302 switch (bus_type) {
303 default:
304 bus->flags = flags;
305 if (flags & PARALLEL_MBUS_FLAGS)
306 vep->bus_type = V4L2_MBUS_PARALLEL;
307 else
308 vep->bus_type = V4L2_MBUS_BT656;
309 break;
Sakari Ailus26c11262018-07-17 12:17:02 -0400310 case V4L2_MBUS_PARALLEL:
Sakari Ailus2835b5b2018-07-31 06:43:14 -0400311 vep->bus_type = V4L2_MBUS_PARALLEL;
Sakari Ailus175b18b2018-01-02 08:14:30 -0500312 bus->flags = flags;
313 break;
Sakari Ailus26c11262018-07-17 12:17:02 -0400314 case V4L2_MBUS_BT656:
Sakari Ailus2835b5b2018-07-31 06:43:14 -0400315 vep->bus_type = V4L2_MBUS_BT656;
Sakari Ailus175b18b2018-01-02 08:14:30 -0500316 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
317 break;
318 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300319}
320
Mauro Carvalho Chehababc5b2c2017-07-20 16:27:27 -0400321static void
322v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
323 struct v4l2_fwnode_endpoint *vep,
Sakari Ailus26c11262018-07-17 12:17:02 -0400324 enum v4l2_mbus_type bus_type)
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500325{
326 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
327 u32 v;
328
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500329 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500330 bus->clock_inv = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500331 pr_debug("clock-inv %u\n", v);
332 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500333
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500334 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500335 bus->strobe = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500336 pr_debug("strobe %u\n", v);
337 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500338
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500339 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500340 bus->data_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500341 pr_debug("data-lanes %u\n", v);
342 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500343
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500344 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500345 bus->clock_lane = v;
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500346 pr_debug("clock-lanes %u\n", v);
347 }
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500348
Sakari Ailus26c11262018-07-17 12:17:02 -0400349 if (bus_type == V4L2_MBUS_CCP2)
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500350 vep->bus_type = V4L2_MBUS_CCP2;
351 else
352 vep->bus_type = V4L2_MBUS_CSI1;
353}
354
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500355static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
356 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -0300357{
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500358 u32 bus_type = 0;
Sakari Ailus26c11262018-07-17 12:17:02 -0400359 enum v4l2_mbus_type mbus_type;
Sakari Ailusca50c192016-08-12 08:05:51 -0300360 int rval;
361
Sakari Ailus9a5b4b72018-07-31 05:21:53 -0400362 if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
363 /* Zero fields from bus union to until the end */
364 memset(&vep->bus, 0,
365 sizeof(*vep) - offsetof(typeof(*vep), bus));
366 }
367
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500368 pr_debug("===== begin V4L2 endpoint properties\n");
369
Sakari Ailus32593dd2018-07-18 09:20:34 -0400370 /*
371 * Zero the fwnode graph endpoint memory in case we don't end up parsing
372 * the endpoint.
373 */
374 memset(&vep->base, 0, sizeof(vep->base));
Sakari Ailusca50c192016-08-12 08:05:51 -0300375
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500376 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
377
Sakari Ailus26c11262018-07-17 12:17:02 -0400378 mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
379
380 switch (mbus_type) {
381 case V4L2_MBUS_UNKNOWN:
Sakari Ailus276565e2018-07-18 09:33:45 -0400382 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
Sakari Ailus26c11262018-07-17 12:17:02 -0400383 mbus_type);
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500384 if (rval)
385 return rval;
Sakari Ailus2835b5b2018-07-31 06:43:14 -0400386
387 if (vep->bus_type == V4L2_MBUS_UNKNOWN)
Sakari Ailus175b18b2018-01-02 08:14:30 -0500388 v4l2_fwnode_endpoint_parse_parallel_bus(
389 fwnode, vep, V4L2_MBUS_UNKNOWN);
Sakari Ailusca50c192016-08-12 08:05:51 -0300390
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500391 break;
Sakari Ailus26c11262018-07-17 12:17:02 -0400392 case V4L2_MBUS_CCP2:
393 case V4L2_MBUS_CSI1:
394 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, mbus_type);
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500395
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500396 break;
Sakari Ailus26c11262018-07-17 12:17:02 -0400397 case V4L2_MBUS_CSI2_DPHY:
Sakari Ailus175b18b2018-01-02 08:14:30 -0500398 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
Sakari Ailus276565e2018-07-18 09:33:45 -0400399 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
Sakari Ailus26c11262018-07-17 12:17:02 -0400400 mbus_type);
Sakari Ailus175b18b2018-01-02 08:14:30 -0500401 if (rval)
402 return rval;
403
404 break;
Sakari Ailus26c11262018-07-17 12:17:02 -0400405 case V4L2_MBUS_PARALLEL:
406 case V4L2_MBUS_BT656:
407 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep, mbus_type);
Sakari Ailus175b18b2018-01-02 08:14:30 -0500408
409 break;
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500410 default:
Sakari Ailus26c11262018-07-17 12:17:02 -0400411 pr_warn("unsupported bus type %u\n", mbus_type);
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500412 return -EINVAL;
413 }
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500414
Sakari Ailus32593dd2018-07-18 09:20:34 -0400415 fwnode_graph_parse_endpoint(fwnode, &vep->base);
416
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500417 return 0;
418}
419
420int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
421 struct v4l2_fwnode_endpoint *vep)
422{
423 int ret;
424
425 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
426
427 pr_debug("===== end V4L2 endpoint properties\n");
428
429 return ret;
Sakari Ailusca50c192016-08-12 08:05:51 -0300430}
431EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
432
Sakari Ailusca50c192016-08-12 08:05:51 -0300433void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
434{
435 if (IS_ERR_OR_NULL(vep))
436 return;
437
438 kfree(vep->link_frequencies);
Sakari Ailusca50c192016-08-12 08:05:51 -0300439}
440EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
441
Sakari Ailus6970d372018-06-02 12:19:35 -0400442int v4l2_fwnode_endpoint_alloc_parse(
443 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -0300444{
Sakari Ailusca50c192016-08-12 08:05:51 -0300445 int rval;
446
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500447 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
Sakari Ailusca50c192016-08-12 08:05:51 -0300448 if (rval < 0)
Sakari Ailus6970d372018-06-02 12:19:35 -0400449 return rval;
Sakari Ailusca50c192016-08-12 08:05:51 -0300450
451 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
452 NULL, 0);
Sakari Ailus06f81522017-06-20 09:14:43 -0400453 if (rval > 0) {
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500454 unsigned int i;
455
Sakari Ailus06f81522017-06-20 09:14:43 -0400456 vep->link_frequencies =
457 kmalloc_array(rval, sizeof(*vep->link_frequencies),
458 GFP_KERNEL);
Sakari Ailus6970d372018-06-02 12:19:35 -0400459 if (!vep->link_frequencies)
460 return -ENOMEM;
Sakari Ailusca50c192016-08-12 08:05:51 -0300461
Sakari Ailus06f81522017-06-20 09:14:43 -0400462 vep->nr_of_link_frequencies = rval;
463
464 rval = fwnode_property_read_u64_array(
465 fwnode, "link-frequencies", vep->link_frequencies,
466 vep->nr_of_link_frequencies);
Sakari Ailus6970d372018-06-02 12:19:35 -0400467 if (rval < 0) {
468 v4l2_fwnode_endpoint_free(vep);
469 return rval;
470 }
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500471
472 for (i = 0; i < vep->nr_of_link_frequencies; i++)
473 pr_info("link-frequencies %u value %llu\n", i,
474 vep->link_frequencies[i]);
Sakari Ailusca50c192016-08-12 08:05:51 -0300475 }
476
Sakari Ailusc8677aa2017-12-04 16:25:06 -0500477 pr_debug("===== end V4L2 endpoint properties\n");
478
Sakari Ailus6970d372018-06-02 12:19:35 -0400479 return 0;
Sakari Ailusca50c192016-08-12 08:05:51 -0300480}
481EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
482
Sakari Ailusca50c192016-08-12 08:05:51 -0300483int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
484 struct v4l2_fwnode_link *link)
485{
486 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
487 struct fwnode_handle *fwnode;
488
489 memset(link, 0, sizeof(*link));
490
491 fwnode = fwnode_get_parent(__fwnode);
492 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
493 fwnode = fwnode_get_next_parent(fwnode);
494 if (is_of_node(fwnode) &&
495 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
496 fwnode = fwnode_get_next_parent(fwnode);
497 link->local_node = fwnode;
498
499 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
500 if (!fwnode) {
501 fwnode_handle_put(fwnode);
502 return -ENOLINK;
503 }
504
505 fwnode = fwnode_get_parent(fwnode);
506 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
507 fwnode = fwnode_get_next_parent(fwnode);
508 if (is_of_node(fwnode) &&
509 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
510 fwnode = fwnode_get_next_parent(fwnode);
511 link->remote_node = fwnode;
512
513 return 0;
514}
515EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
516
Sakari Ailusca50c192016-08-12 08:05:51 -0300517void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
518{
519 fwnode_handle_put(link->local_node);
520 fwnode_handle_put(link->remote_node);
521}
522EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
523
Sakari Ailus9ca46532017-08-17 11:28:21 -0400524static int v4l2_async_notifier_fwnode_parse_endpoint(
525 struct device *dev, struct v4l2_async_notifier *notifier,
526 struct fwnode_handle *endpoint, unsigned int asd_struct_size,
527 int (*parse_endpoint)(struct device *dev,
528 struct v4l2_fwnode_endpoint *vep,
529 struct v4l2_async_subdev *asd))
530{
Sakari Ailus6970d372018-06-02 12:19:35 -0400531 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
Sakari Ailus9ca46532017-08-17 11:28:21 -0400532 struct v4l2_async_subdev *asd;
Sakari Ailus6970d372018-06-02 12:19:35 -0400533 int ret;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400534
535 asd = kzalloc(asd_struct_size, GFP_KERNEL);
536 if (!asd)
537 return -ENOMEM;
538
539 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400540 asd->match.fwnode =
Sakari Ailus9ca46532017-08-17 11:28:21 -0400541 fwnode_graph_get_remote_port_parent(endpoint);
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400542 if (!asd->match.fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400543 dev_warn(dev, "bad remote port parent\n");
Steve Longerbeam4382f372018-09-29 15:54:04 -0400544 ret = -ENOTCONN;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400545 goto out_err;
546 }
547
Sakari Ailus6970d372018-06-02 12:19:35 -0400548 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
549 if (ret) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400550 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
551 ret);
552 goto out_err;
553 }
554
Sakari Ailus6970d372018-06-02 12:19:35 -0400555 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400556 if (ret == -ENOTCONN)
Sakari Ailus6970d372018-06-02 12:19:35 -0400557 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
558 vep.base.id);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400559 else if (ret < 0)
560 dev_warn(dev,
561 "driver could not parse port@%u/endpoint@%u (%d)\n",
Sakari Ailus6970d372018-06-02 12:19:35 -0400562 vep.base.port, vep.base.id, ret);
563 v4l2_fwnode_endpoint_free(&vep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400564 if (ret < 0)
565 goto out_err;
566
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400567 ret = v4l2_async_notifier_add_subdev(notifier, asd);
568 if (ret < 0) {
569 /* not an error if asd already exists */
570 if (ret == -EEXIST)
571 ret = 0;
572 goto out_err;
573 }
Sakari Ailus9ca46532017-08-17 11:28:21 -0400574
575 return 0;
576
577out_err:
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -0400578 fwnode_handle_put(asd->match.fwnode);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400579 kfree(asd);
580
581 return ret == -ENOTCONN ? 0 : ret;
582}
583
584static int __v4l2_async_notifier_parse_fwnode_endpoints(
585 struct device *dev, struct v4l2_async_notifier *notifier,
586 size_t asd_struct_size, unsigned int port, bool has_port,
587 int (*parse_endpoint)(struct device *dev,
588 struct v4l2_fwnode_endpoint *vep,
589 struct v4l2_async_subdev *asd))
590{
591 struct fwnode_handle *fwnode;
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400592 int ret = 0;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400593
594 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
595 return -EINVAL;
596
Sakari Ailus106ee382017-12-21 07:11:19 -0500597 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
Sakari Ailus9ca46532017-08-17 11:28:21 -0400598 struct fwnode_handle *dev_fwnode;
599 bool is_available;
600
601 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
602 is_available = fwnode_device_is_available(dev_fwnode);
603 fwnode_handle_put(dev_fwnode);
604 if (!is_available)
605 continue;
606
607 if (has_port) {
608 struct fwnode_endpoint ep;
609
610 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400611 if (ret)
612 break;
613
614 if (ep.port != port)
615 continue;
616 }
617
618 ret = v4l2_async_notifier_fwnode_parse_endpoint(
619 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
620 if (ret < 0)
621 break;
622 }
623
624 fwnode_handle_put(fwnode);
625
626 return ret;
627}
628
629int v4l2_async_notifier_parse_fwnode_endpoints(
630 struct device *dev, struct v4l2_async_notifier *notifier,
631 size_t asd_struct_size,
632 int (*parse_endpoint)(struct device *dev,
633 struct v4l2_fwnode_endpoint *vep,
634 struct v4l2_async_subdev *asd))
635{
636 return __v4l2_async_notifier_parse_fwnode_endpoints(
637 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
638}
639EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
640
641int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
642 struct device *dev, struct v4l2_async_notifier *notifier,
643 size_t asd_struct_size, unsigned int port,
644 int (*parse_endpoint)(struct device *dev,
645 struct v4l2_fwnode_endpoint *vep,
646 struct v4l2_async_subdev *asd))
647{
648 return __v4l2_async_notifier_parse_fwnode_endpoints(
649 dev, notifier, asd_struct_size, port, true, parse_endpoint);
650}
651EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
652
Sakari Ailusd8428532017-06-20 07:47:24 -0400653/*
654 * v4l2_fwnode_reference_parse - parse references for async sub-devices
655 * @dev: the device node the properties of which are parsed for references
656 * @notifier: the async notifier where the async subdevs will be added
657 * @prop: the name of the property
658 *
659 * Return: 0 on success
660 * -ENOENT if no entries were found
661 * -ENOMEM if memory allocation failed
662 * -EINVAL if property parsing failed
663 */
664static int v4l2_fwnode_reference_parse(
665 struct device *dev, struct v4l2_async_notifier *notifier,
666 const char *prop)
667{
668 struct fwnode_reference_args args;
669 unsigned int index;
670 int ret;
671
672 for (index = 0;
673 !(ret = fwnode_property_get_reference_args(
674 dev_fwnode(dev), prop, NULL, 0, index, &args));
675 index++)
676 fwnode_handle_put(args.fwnode);
677
678 if (!index)
679 return -ENOENT;
680
681 /*
682 * Note that right now both -ENODATA and -ENOENT may signal
683 * out-of-bounds access. Return the error in cases other than that.
684 */
685 if (ret != -ENOENT && ret != -ENODATA)
686 return ret;
687
Sakari Ailusd8428532017-06-20 07:47:24 -0400688 for (index = 0; !fwnode_property_get_reference_args(
689 dev_fwnode(dev), prop, NULL, 0, index, &args);
690 index++) {
691 struct v4l2_async_subdev *asd;
692
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400693 asd = v4l2_async_notifier_add_fwnode_subdev(
694 notifier, args.fwnode, sizeof(*asd));
695 if (IS_ERR(asd)) {
696 ret = PTR_ERR(asd);
697 /* not an error if asd already exists */
698 if (ret == -EEXIST) {
699 fwnode_handle_put(args.fwnode);
700 continue;
701 }
702
Sakari Ailusd8428532017-06-20 07:47:24 -0400703 goto error;
704 }
Sakari Ailusd8428532017-06-20 07:47:24 -0400705 }
706
707 return 0;
708
709error:
710 fwnode_handle_put(args.fwnode);
711 return ret;
712}
713
Sakari Ailusa1699a42017-06-22 08:03:28 -0400714/*
715 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
716 * arguments
717 * @fwnode: fwnode to read @prop from
718 * @notifier: notifier for @dev
719 * @prop: the name of the property
720 * @index: the index of the reference to get
721 * @props: the array of integer property names
722 * @nprops: the number of integer property names in @nprops
723 *
724 * First find an fwnode referred to by the reference at @index in @prop.
725 *
726 * Then under that fwnode, @nprops times, for each property in @props,
727 * iteratively follow child nodes starting from fwnode such that they have the
728 * property in @props array at the index of the child node distance from the
729 * root node and the value of that property matching with the integer argument
730 * of the reference, at the same index.
731 *
732 * The child fwnode reched at the end of the iteration is then returned to the
733 * caller.
734 *
735 * The core reason for this is that you cannot refer to just any node in ACPI.
736 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
737 * provide a list of (property name, property value) tuples where each tuple
738 * uniquely identifies a child node. The first tuple identifies a child directly
739 * underneath the device fwnode, the next tuple identifies a child node
740 * underneath the fwnode identified by the previous tuple, etc. until you
741 * reached the fwnode you need.
742 *
743 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
744 *
745 * Scope (\_SB.PCI0.I2C2)
746 * {
747 * Device (CAM0)
748 * {
749 * Name (_DSD, Package () {
750 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
751 * Package () {
752 * Package () {
753 * "compatible",
754 * Package () { "nokia,smia" }
755 * },
756 * },
757 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
758 * Package () {
759 * Package () { "port0", "PRT0" },
760 * }
761 * })
762 * Name (PRT0, Package() {
763 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
764 * Package () {
765 * Package () { "port", 0 },
766 * },
767 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
768 * Package () {
769 * Package () { "endpoint0", "EP00" },
770 * }
771 * })
772 * Name (EP00, Package() {
773 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
774 * Package () {
775 * Package () { "endpoint", 0 },
776 * Package () {
777 * "remote-endpoint",
778 * Package() {
779 * \_SB.PCI0.ISP, 4, 0
780 * }
781 * },
782 * }
783 * })
784 * }
785 * }
786 *
787 * Scope (\_SB.PCI0)
788 * {
789 * Device (ISP)
790 * {
791 * Name (_DSD, Package () {
792 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
793 * Package () {
794 * Package () { "port4", "PRT4" },
795 * }
796 * })
797 *
798 * Name (PRT4, Package() {
799 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
800 * Package () {
801 * Package () { "port", 4 },
802 * },
803 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
804 * Package () {
805 * Package () { "endpoint0", "EP40" },
806 * }
807 * })
808 *
809 * Name (EP40, Package() {
810 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
811 * Package () {
812 * Package () { "endpoint", 0 },
813 * Package () {
814 * "remote-endpoint",
815 * Package () {
816 * \_SB.PCI0.I2C2.CAM0,
817 * 0, 0
818 * }
819 * },
820 * }
821 * })
822 * }
823 * }
824 *
825 * From the EP40 node under ISP device, you could parse the graph remote
826 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
827 *
828 * @fwnode: fwnode referring to EP40 under ISP.
829 * @prop: "remote-endpoint"
830 * @index: 0
831 * @props: "port", "endpoint"
832 * @nprops: 2
833 *
834 * And you'd get back fwnode referring to EP00 under CAM0.
835 *
836 * The same works the other way around: if you use EP00 under CAM0 as the
837 * fwnode, you'll get fwnode referring to EP40 under ISP.
838 *
839 * The same example in DT syntax would look like this:
840 *
841 * cam: cam0 {
842 * compatible = "nokia,smia";
843 *
844 * port {
845 * port = <0>;
846 * endpoint {
847 * endpoint = <0>;
848 * remote-endpoint = <&isp 4 0>;
849 * };
850 * };
851 * };
852 *
853 * isp: isp {
854 * ports {
855 * port@4 {
856 * port = <4>;
857 * endpoint {
858 * endpoint = <0>;
859 * remote-endpoint = <&cam 0 0>;
860 * };
861 * };
862 * };
863 * };
864 *
865 * Return: 0 on success
866 * -ENOENT if no entries (or the property itself) were found
867 * -EINVAL if property parsing otherwise failed
868 * -ENOMEM if memory allocation failed
869 */
870static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
871 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
872 const char * const *props, unsigned int nprops)
873{
874 struct fwnode_reference_args fwnode_args;
Sakari Ailus977d5ad2018-07-17 17:19:11 +0300875 u64 *args = fwnode_args.args;
Sakari Ailusa1699a42017-06-22 08:03:28 -0400876 struct fwnode_handle *child;
877 int ret;
878
879 /*
880 * Obtain remote fwnode as well as the integer arguments.
881 *
882 * Note that right now both -ENODATA and -ENOENT may signal
883 * out-of-bounds access. Return -ENOENT in that case.
884 */
885 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
886 index, &fwnode_args);
887 if (ret)
888 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
889
890 /*
891 * Find a node in the tree under the referred fwnode corresponding to
892 * the integer arguments.
893 */
894 fwnode = fwnode_args.fwnode;
895 while (nprops--) {
896 u32 val;
897
898 /* Loop over all child nodes under fwnode. */
899 fwnode_for_each_child_node(fwnode, child) {
900 if (fwnode_property_read_u32(child, *props, &val))
901 continue;
902
903 /* Found property, see if its value matches. */
904 if (val == *args)
905 break;
906 }
907
908 fwnode_handle_put(fwnode);
909
910 /* No property found; return an error here. */
911 if (!child) {
912 fwnode = ERR_PTR(-ENOENT);
913 break;
914 }
915
916 props++;
917 args++;
918 fwnode = child;
919 }
920
921 return fwnode;
922}
923
924/*
925 * v4l2_fwnode_reference_parse_int_props - parse references for async
926 * sub-devices
927 * @dev: struct device pointer
928 * @notifier: notifier for @dev
929 * @prop: the name of the property
930 * @props: the array of integer property names
931 * @nprops: the number of integer properties
932 *
933 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
934 * property @prop with integer arguments with child nodes matching in properties
935 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
936 * accordingly.
937 *
938 * While it is technically possible to use this function on DT, it is only
939 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
940 * on ACPI the references are limited to devices.
941 *
942 * Return: 0 on success
943 * -ENOENT if no entries (or the property itself) were found
944 * -EINVAL if property parsing otherwisefailed
945 * -ENOMEM if memory allocation failed
946 */
947static int v4l2_fwnode_reference_parse_int_props(
948 struct device *dev, struct v4l2_async_notifier *notifier,
949 const char *prop, const char * const *props, unsigned int nprops)
950{
951 struct fwnode_handle *fwnode;
952 unsigned int index;
953 int ret;
954
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400955 index = 0;
956 do {
957 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
958 prop, index,
959 props, nprops);
960 if (IS_ERR(fwnode)) {
961 /*
962 * Note that right now both -ENODATA and -ENOENT may
963 * signal out-of-bounds access. Return the error in
964 * cases other than that.
965 */
966 if (PTR_ERR(fwnode) != -ENOENT &&
967 PTR_ERR(fwnode) != -ENODATA)
968 return PTR_ERR(fwnode);
969 break;
970 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400971 fwnode_handle_put(fwnode);
Mauro Carvalho Chehab9879c9d2018-04-04 07:21:04 -0400972 index++;
973 } while (1);
Sakari Ailusa1699a42017-06-22 08:03:28 -0400974
Sakari Ailusa1699a42017-06-22 08:03:28 -0400975 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
976 dev_fwnode(dev), prop, index, props,
977 nprops))); index++) {
978 struct v4l2_async_subdev *asd;
979
Steve Longerbeameae2aed2018-09-29 15:54:08 -0400980 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
981 sizeof(*asd));
982 if (IS_ERR(asd)) {
983 ret = PTR_ERR(asd);
984 /* not an error if asd already exists */
985 if (ret == -EEXIST) {
986 fwnode_handle_put(fwnode);
987 continue;
988 }
989
Sakari Ailusa1699a42017-06-22 08:03:28 -0400990 goto error;
991 }
Sakari Ailusa1699a42017-06-22 08:03:28 -0400992 }
993
994 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
995
996error:
997 fwnode_handle_put(fwnode);
998 return ret;
999}
1000
Sakari Ailus7a9ec802017-09-06 08:35:42 -04001001int v4l2_async_notifier_parse_fwnode_sensor_common(
1002 struct device *dev, struct v4l2_async_notifier *notifier)
1003{
1004 static const char * const led_props[] = { "led" };
1005 static const struct {
1006 const char *name;
1007 const char * const *props;
1008 unsigned int nprops;
1009 } props[] = {
1010 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
1011 { "lens-focus", NULL, 0 },
1012 };
1013 unsigned int i;
1014
1015 for (i = 0; i < ARRAY_SIZE(props); i++) {
1016 int ret;
1017
1018 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1019 ret = v4l2_fwnode_reference_parse_int_props(
1020 dev, notifier, props[i].name,
1021 props[i].props, props[i].nprops);
1022 else
1023 ret = v4l2_fwnode_reference_parse(
1024 dev, notifier, props[i].name);
1025 if (ret && ret != -ENOENT) {
1026 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1027 props[i].name, ret);
1028 return ret;
1029 }
1030 }
1031
1032 return 0;
1033}
1034EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
1035
Sakari Ailusaef69d52017-09-24 18:47:44 -04001036int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
1037{
1038 struct v4l2_async_notifier *notifier;
1039 int ret;
1040
1041 if (WARN_ON(!sd->dev))
1042 return -ENODEV;
1043
1044 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1045 if (!notifier)
1046 return -ENOMEM;
1047
Steve Longerbeameae2aed2018-09-29 15:54:08 -04001048 v4l2_async_notifier_init(notifier);
1049
Sakari Ailusaef69d52017-09-24 18:47:44 -04001050 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
1051 notifier);
1052 if (ret < 0)
1053 goto out_cleanup;
1054
1055 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1056 if (ret < 0)
1057 goto out_cleanup;
1058
1059 ret = v4l2_async_register_subdev(sd);
1060 if (ret < 0)
1061 goto out_unregister;
1062
1063 sd->subdev_notifier = notifier;
1064
1065 return 0;
1066
1067out_unregister:
1068 v4l2_async_notifier_unregister(notifier);
1069
1070out_cleanup:
1071 v4l2_async_notifier_cleanup(notifier);
1072 kfree(notifier);
1073
1074 return ret;
1075}
1076EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
1077
Steve Longerbeam1634f0e2018-09-29 15:54:09 -04001078int v4l2_async_register_fwnode_subdev(
1079 struct v4l2_subdev *sd, size_t asd_struct_size,
1080 unsigned int *ports, unsigned int num_ports,
1081 int (*parse_endpoint)(struct device *dev,
1082 struct v4l2_fwnode_endpoint *vep,
1083 struct v4l2_async_subdev *asd))
1084{
1085 struct v4l2_async_notifier *notifier;
1086 struct device *dev = sd->dev;
1087 struct fwnode_handle *fwnode;
1088 int ret;
1089
1090 if (WARN_ON(!dev))
1091 return -ENODEV;
1092
1093 fwnode = dev_fwnode(dev);
1094 if (!fwnode_device_is_available(fwnode))
1095 return -ENODEV;
1096
1097 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1098 if (!notifier)
1099 return -ENOMEM;
1100
1101 v4l2_async_notifier_init(notifier);
1102
1103 if (!ports) {
1104 ret = v4l2_async_notifier_parse_fwnode_endpoints(
1105 dev, notifier, asd_struct_size, parse_endpoint);
1106 if (ret < 0)
1107 goto out_cleanup;
1108 } else {
1109 unsigned int i;
1110
1111 for (i = 0; i < num_ports; i++) {
1112 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
1113 dev, notifier, asd_struct_size,
1114 ports[i], parse_endpoint);
1115 if (ret < 0)
1116 goto out_cleanup;
1117 }
1118 }
1119
1120 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1121 if (ret < 0)
1122 goto out_cleanup;
1123
1124 ret = v4l2_async_register_subdev(sd);
1125 if (ret < 0)
1126 goto out_unregister;
1127
1128 sd->subdev_notifier = notifier;
1129
1130 return 0;
1131
1132out_unregister:
1133 v4l2_async_notifier_unregister(notifier);
1134out_cleanup:
1135 v4l2_async_notifier_cleanup(notifier);
1136 kfree(notifier);
1137
1138 return ret;
1139}
1140EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
1141
Sakari Ailusca50c192016-08-12 08:05:51 -03001142MODULE_LICENSE("GPL");
1143MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1144MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1145MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");