aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@iki.fi>2015-03-22 16:48:26 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-04-27 15:04:28 -0400
commit698da18e082c8fdfa675bee6338e3f9864d5d7ee (patch)
tree36400cabe4da4f3c47b8588e81cf6797f3197d0e
parent161aadaec11cd0f610950da56f82bd1778be4156 (diff)
[media] v4l: of: Parse variable length properties --- link-frequencies
The link-frequencies property is a variable length array of link frequencies in an endpoint. The array is needed by an increasing number of drivers, so it makes sense to add it to struct v4l2_of_endpoint. However, the length of the array is variable and the size of struct v4l2_of_endpoint is fixed since it is allocated by the caller. The options here are 1. to define a fixed maximum limit of link frequencies that has to be the global maximum of all boards. This is seen as problematic since the maximum could be largish, and everyone hitting the problem would need to submit a patch to fix it, or 2. parse the property in every driver. This doesn't sound appealing as two of the three implementations submitted to linux-media were wrong, and one of them was even merged before this was noticed, or 3. change the interface so that allocating and releasing memory according to the size of the array is possible. This is what the patch does. v4l2_of_alloc_parse_endpoint() is just like v4l2_of_parse_endpoint(), but it will allocate the memory resources needed to store struct v4l2_of_endpoint and the additional arrays pointed to by this struct. A corresponding release function v4l2_of_free_endpoint() is provided to release the memory allocated by v4l2_of_alloc_parse_endpoint(). In addition to this, the link-frequencies property is parsed as well, and the result is stored to struct v4l2_of_endpoint field link_frequencies. Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Tested-by: Lad, Prabhakar <prabhakar.csengg@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c87
-rw-r--r--include/media/v4l2-of.h17
2 files changed, 104 insertions, 0 deletions
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
index 3ac634891f75..c52fb9620e11 100644
--- a/drivers/media/v4l2-core/v4l2-of.c
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/of.h> 16#include <linux/of.h>
17#include <linux/slab.h>
17#include <linux/string.h> 18#include <linux/string.h>
18#include <linux/types.h> 19#include <linux/types.h>
19 20
@@ -141,6 +142,10 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
141 * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. 142 * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
142 * The caller should hold a reference to @node. 143 * The caller should hold a reference to @node.
143 * 144 *
145 * NOTE: This function does not parse properties the size of which is
146 * variable without a low fixed limit. Please use
147 * v4l2_of_alloc_parse_endpoint() in new drivers instead.
148 *
144 * Return: 0. 149 * Return: 0.
145 */ 150 */
146int v4l2_of_parse_endpoint(const struct device_node *node, 151int v4l2_of_parse_endpoint(const struct device_node *node,
@@ -167,6 +172,88 @@ int v4l2_of_parse_endpoint(const struct device_node *node,
167} 172}
168EXPORT_SYMBOL(v4l2_of_parse_endpoint); 173EXPORT_SYMBOL(v4l2_of_parse_endpoint);
169 174
175/*
176 * v4l2_of_free_endpoint() - free the endpoint acquired by
177 * v4l2_of_alloc_parse_endpoint()
178 * @endpoint - the endpoint the resources of which are to be released
179 *
180 * It is safe to call this function with NULL argument or on an
181 * endpoint the parsing of which failed.
182 */
183void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint)
184{
185 if (IS_ERR_OR_NULL(endpoint))
186 return;
187
188 kfree(endpoint->link_frequencies);
189 kfree(endpoint);
190}
191EXPORT_SYMBOL(v4l2_of_free_endpoint);
192
193/**
194 * v4l2_of_alloc_parse_endpoint() - parse all endpoint node properties
195 * @node: pointer to endpoint device_node
196 *
197 * All properties are optional. If none are found, we don't set any flags.
198 * This means the port has a static configuration and no properties have
199 * to be specified explicitly.
200 * If any properties that identify the bus as parallel are found and
201 * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise
202 * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
203 * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
204 * The caller should hold a reference to @node.
205 *
206 * v4l2_of_alloc_parse_endpoint() has two important differences to
207 * v4l2_of_parse_endpoint():
208 *
209 * 1. It also parses variable size data and
210 *
211 * 2. The memory it has allocated to store the variable size data must
212 * be freed using v4l2_of_free_endpoint() when no longer needed.
213 *
214 * Return: Pointer to v4l2_of_endpoint if successful, on error a
215 * negative error code.
216 */
217struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint(
218 const struct device_node *node)
219{
220 struct v4l2_of_endpoint *endpoint;
221 int len;
222 int rval;
223
224 endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
225 if (!endpoint)
226 return ERR_PTR(-ENOMEM);
227
228 rval = v4l2_of_parse_endpoint(node, endpoint);
229 if (rval < 0)
230 goto out_err;
231
232 if (of_get_property(node, "link-frequencies", &len)) {
233 endpoint->link_frequencies = kmalloc(len, GFP_KERNEL);
234 if (!endpoint->link_frequencies) {
235 rval = -ENOMEM;
236 goto out_err;
237 }
238
239 endpoint->nr_of_link_frequencies =
240 len / sizeof(*endpoint->link_frequencies);
241
242 rval = of_property_read_u64_array(
243 node, "link-frequencies", endpoint->link_frequencies,
244 endpoint->nr_of_link_frequencies);
245 if (rval < 0)
246 goto out_err;
247 }
248
249 return endpoint;
250
251out_err:
252 v4l2_of_free_endpoint(endpoint);
253 return ERR_PTR(rval);
254}
255EXPORT_SYMBOL(v4l2_of_alloc_parse_endpoint);
256
170/** 257/**
171 * v4l2_of_parse_link() - parse a link between two endpoints 258 * v4l2_of_parse_link() - parse a link between two endpoints
172 * @node: pointer to the endpoint at the local end of the link 259 * @node: pointer to the endpoint at the local end of the link
diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h
index 6c85c079544f..241e98aee40e 100644
--- a/include/media/v4l2-of.h
+++ b/include/media/v4l2-of.h
@@ -57,6 +57,8 @@ struct v4l2_of_bus_parallel {
57 * @base: struct of_endpoint containing port, id, and local of_node 57 * @base: struct of_endpoint containing port, id, and local of_node
58 * @bus_type: bus type 58 * @bus_type: bus type
59 * @bus: bus configuration data structure 59 * @bus: bus configuration data structure
60 * @link_frequencies: array of supported link frequencies
61 * @nr_of_link_frequencies: number of elements in link_frequenccies array
60 */ 62 */
61struct v4l2_of_endpoint { 63struct v4l2_of_endpoint {
62 struct of_endpoint base; 64 struct of_endpoint base;
@@ -66,6 +68,8 @@ struct v4l2_of_endpoint {
66 struct v4l2_of_bus_parallel parallel; 68 struct v4l2_of_bus_parallel parallel;
67 struct v4l2_of_bus_mipi_csi2 mipi_csi2; 69 struct v4l2_of_bus_mipi_csi2 mipi_csi2;
68 } bus; 70 } bus;
71 u64 *link_frequencies;
72 unsigned int nr_of_link_frequencies;
69}; 73};
70 74
71/** 75/**
@@ -85,6 +89,9 @@ struct v4l2_of_link {
85#ifdef CONFIG_OF 89#ifdef CONFIG_OF
86int v4l2_of_parse_endpoint(const struct device_node *node, 90int v4l2_of_parse_endpoint(const struct device_node *node,
87 struct v4l2_of_endpoint *endpoint); 91 struct v4l2_of_endpoint *endpoint);
92struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint(
93 const struct device_node *node);
94void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint);
88int v4l2_of_parse_link(const struct device_node *node, 95int v4l2_of_parse_link(const struct device_node *node,
89 struct v4l2_of_link *link); 96 struct v4l2_of_link *link);
90void v4l2_of_put_link(struct v4l2_of_link *link); 97void v4l2_of_put_link(struct v4l2_of_link *link);
@@ -96,6 +103,16 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node,
96 return -ENOSYS; 103 return -ENOSYS;
97} 104}
98 105
106struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint(
107 const struct device_node *node)
108{
109 return NULL;
110}
111
112static void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint)
113{
114}
115
99static inline int v4l2_of_parse_link(const struct device_node *node, 116static inline int v4l2_of_parse_link(const struct device_node *node,
100 struct v4l2_of_link *link) 117 struct v4l2_of_link *link)
101{ 118{