]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/v4l2-core/v4l2-fwnode.c
ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
[mirror_ubuntu-artful-kernel.git] / drivers / media / v4l2-core / v4l2-fwnode.c
CommitLineData
ca50c197
SA
1/*
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>
22#include <linux/module.h>
23#include <linux/of.h>
24#include <linux/property.h>
25#include <linux/slab.h>
26#include <linux/string.h>
27#include <linux/types.h>
28
29#include <media/v4l2-fwnode.h>
30
31static int v4l2_fwnode_endpoint_parse_csi_bus(struct fwnode_handle *fwnode,
32 struct v4l2_fwnode_endpoint *vep)
33{
34 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
35 bool have_clk_lane = false;
36 unsigned int flags = 0, lanes_used = 0;
37 unsigned int i;
38 u32 v;
39 int rval;
40
41 rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
42 if (rval > 0) {
43 u32 array[ARRAY_SIZE(bus->data_lanes)];
44
45 bus->num_data_lanes =
46 min_t(int, ARRAY_SIZE(bus->data_lanes), rval);
47
48 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
49 bus->num_data_lanes);
50
51 for (i = 0; i < bus->num_data_lanes; i++) {
52 if (lanes_used & BIT(array[i]))
53 pr_warn("duplicated lane %u in data-lanes\n",
54 array[i]);
55 lanes_used |= BIT(array[i]);
56
57 bus->data_lanes[i] = array[i];
58 }
59 }
60
61 rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL,
62 0);
63 if (rval > 0) {
64 u32 array[ARRAY_SIZE(bus->lane_polarities)];
65
66 if (rval < 1 + bus->num_data_lanes /* clock + data */) {
67 pr_warn("too few lane-polarities entries (need %u, got %u)\n",
68 1 + bus->num_data_lanes, rval);
69 return -EINVAL;
70 }
71
72 fwnode_property_read_u32_array(fwnode, "lane-polarities", array,
73 1 + bus->num_data_lanes);
74
75 for (i = 0; i < 1 + bus->num_data_lanes; i++)
76 bus->lane_polarities[i] = array[i];
77 }
78
79 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
80 if (lanes_used & BIT(v))
81 pr_warn("duplicated lane %u in clock-lanes\n", v);
82 lanes_used |= BIT(v);
83
84 bus->clock_lane = v;
85 have_clk_lane = true;
86 }
87
88 if (fwnode_property_present(fwnode, "clock-noncontinuous"))
89 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
90 else if (have_clk_lane || bus->num_data_lanes > 0)
91 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
92
93 bus->flags = flags;
94 vep->bus_type = V4L2_MBUS_CSI2;
95
96 return 0;
97}
98
99static void v4l2_fwnode_endpoint_parse_parallel_bus(
100 struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
101{
102 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
103 unsigned int flags = 0;
104 u32 v;
105
106 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v))
107 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
108 V4L2_MBUS_HSYNC_ACTIVE_LOW;
109
110 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v))
111 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
112 V4L2_MBUS_VSYNC_ACTIVE_LOW;
113
114 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v))
115 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
116 V4L2_MBUS_FIELD_EVEN_LOW;
117 if (flags)
118 vep->bus_type = V4L2_MBUS_PARALLEL;
119 else
120 vep->bus_type = V4L2_MBUS_BT656;
121
122 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v))
123 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
124 V4L2_MBUS_PCLK_SAMPLE_FALLING;
125
126 if (!fwnode_property_read_u32(fwnode, "data-active", &v))
127 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
128 V4L2_MBUS_DATA_ACTIVE_LOW;
129
130 if (fwnode_property_present(fwnode, "slave-mode"))
131 flags |= V4L2_MBUS_SLAVE;
132 else
133 flags |= V4L2_MBUS_MASTER;
134
135 if (!fwnode_property_read_u32(fwnode, "bus-width", &v))
136 bus->bus_width = v;
137
138 if (!fwnode_property_read_u32(fwnode, "data-shift", &v))
139 bus->data_shift = v;
140
141 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v))
142 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
143 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
144
145 bus->flags = flags;
146
147}
148
149/**
150 * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
151 * @fwnode: pointer to the endpoint's fwnode handle
152 * @vep: pointer to the V4L2 fwnode data structure
153 *
154 * All properties are optional. If none are found, we don't set any flags. This
155 * means the port has a static configuration and no properties have to be
156 * specified explicitly. If any properties that identify the bus as parallel
157 * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
158 * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
159 * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
160 * reference to @fwnode.
161 *
162 * NOTE: This function does not parse properties the size of which is variable
163 * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
164 * new drivers instead.
165 *
166 * Return: 0 on success or a negative error code on failure.
167 */
168int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
169 struct v4l2_fwnode_endpoint *vep)
170{
171 int rval;
172
173 fwnode_graph_parse_endpoint(fwnode, &vep->base);
174
175 /* Zero fields from bus_type to until the end */
176 memset(&vep->bus_type, 0, sizeof(*vep) -
177 offsetof(typeof(*vep), bus_type));
178
179 rval = v4l2_fwnode_endpoint_parse_csi_bus(fwnode, vep);
180 if (rval)
181 return rval;
182 /*
183 * Parse the parallel video bus properties only if none
184 * of the MIPI CSI-2 specific properties were found.
185 */
186 if (vep->bus.mipi_csi2.flags == 0)
187 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
188
189 return 0;
190}
191EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
192
193/*
194 * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
195 * v4l2_fwnode_endpoint_alloc_parse()
196 * @vep - the V4L2 fwnode the resources of which are to be released
197 *
198 * It is safe to call this function with NULL argument or on a V4L2 fwnode the
199 * parsing of which failed.
200 */
201void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
202{
203 if (IS_ERR_OR_NULL(vep))
204 return;
205
206 kfree(vep->link_frequencies);
207 kfree(vep);
208}
209EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
210
211/**
212 * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
213 * @fwnode: pointer to the endpoint's fwnode handle
214 *
215 * All properties are optional. If none are found, we don't set any flags. This
216 * means the port has a static configuration and no properties have to be
217 * specified explicitly. If any properties that identify the bus as parallel
218 * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
219 * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
220 * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
221 * reference to @fwnode.
222 *
223 * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
224 * v4l2_fwnode_endpoint_parse():
225 *
226 * 1. It also parses variable size data.
227 *
228 * 2. The memory it has allocated to store the variable size data must be freed
229 * using v4l2_fwnode_endpoint_free() when no longer needed.
230 *
231 * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
232 * on error.
233 */
234struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
235 struct fwnode_handle *fwnode)
236{
237 struct v4l2_fwnode_endpoint *vep;
238 int rval;
239
240 vep = kzalloc(sizeof(*vep), GFP_KERNEL);
241 if (!vep)
242 return ERR_PTR(-ENOMEM);
243
244 rval = v4l2_fwnode_endpoint_parse(fwnode, vep);
245 if (rval < 0)
246 goto out_err;
247
248 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
249 NULL, 0);
250 if (rval < 0)
251 goto out_err;
252
253 vep->link_frequencies =
254 kmalloc_array(rval, sizeof(*vep->link_frequencies), GFP_KERNEL);
255 if (!vep->link_frequencies) {
256 rval = -ENOMEM;
257 goto out_err;
258 }
259
260 vep->nr_of_link_frequencies = rval;
261
262 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
263 vep->link_frequencies,
264 vep->nr_of_link_frequencies);
265 if (rval < 0)
266 goto out_err;
267
268 return vep;
269
270out_err:
271 v4l2_fwnode_endpoint_free(vep);
272 return ERR_PTR(rval);
273}
274EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
275
276/**
277 * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
278 * @__fwnode: pointer to the endpoint's fwnode at the local end of the link
279 * @link: pointer to the V4L2 fwnode link data structure
280 *
281 * Fill the link structure with the local and remote nodes and port numbers.
282 * The local_node and remote_node fields are set to point to the local and
283 * remote port's parent nodes respectively (the port parent node being the
284 * parent node of the port node if that node isn't a 'ports' node, or the
285 * grand-parent node of the port node otherwise).
286 *
287 * A reference is taken to both the local and remote nodes, the caller must use
288 * v4l2_fwnode_endpoint_put_link() to drop the references when done with the
289 * link.
290 *
291 * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
292 * found.
293 */
294int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
295 struct v4l2_fwnode_link *link)
296{
297 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
298 struct fwnode_handle *fwnode;
299
300 memset(link, 0, sizeof(*link));
301
302 fwnode = fwnode_get_parent(__fwnode);
303 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
304 fwnode = fwnode_get_next_parent(fwnode);
305 if (is_of_node(fwnode) &&
306 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
307 fwnode = fwnode_get_next_parent(fwnode);
308 link->local_node = fwnode;
309
310 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
311 if (!fwnode) {
312 fwnode_handle_put(fwnode);
313 return -ENOLINK;
314 }
315
316 fwnode = fwnode_get_parent(fwnode);
317 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
318 fwnode = fwnode_get_next_parent(fwnode);
319 if (is_of_node(fwnode) &&
320 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
321 fwnode = fwnode_get_next_parent(fwnode);
322 link->remote_node = fwnode;
323
324 return 0;
325}
326EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
327
328/**
329 * v4l2_fwnode_put_link() - drop references to nodes in a link
330 * @link: pointer to the V4L2 fwnode link data structure
331 *
332 * Drop references to the local and remote nodes in the link. This function
333 * must be called on every link parsed with v4l2_fwnode_parse_link().
334 */
335void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
336{
337 fwnode_handle_put(link->local_node);
338 fwnode_handle_put(link->remote_node);
339}
340EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
341
342MODULE_LICENSE("GPL");
343MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
344MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
345MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");