[PATCH 05/14] media: add a V4L2 OF parser
Guennadi Liakhovetski
g.liakhovetski at gmx.de
Tue Oct 2 19:49:37 EST 2012
Hi Sylwester
On Mon, 1 Oct 2012, Sylwester Nawrocki wrote:
> On 09/27/2012 04:07 PM, Guennadi Liakhovetski wrote:
> > Add a V4L2 OF parser, implementing bindings, documented in
> > Documentation/devicetree/bindings/media/v4l2.txt.
> >
> > Signed-off-by: Guennadi Liakhovetski<g.liakhovetski at gmx.de>
> > ---
> > drivers/media/v4l2-core/Makefile | 3 +
> > drivers/media/v4l2-core/v4l2-of.c | 190 +++++++++++++++++++++++++++++++++++++
> > include/media/v4l2-of.h | 62 ++++++++++++
> > 3 files changed, 255 insertions(+), 0 deletions(-)
> > create mode 100644 drivers/media/v4l2-core/v4l2-of.c
> > create mode 100644 include/media/v4l2-of.h
> >
> > diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> > index c2d61d4..00f64d6 100644
> > --- a/drivers/media/v4l2-core/Makefile
> > +++ b/drivers/media/v4l2-core/Makefile
> > @@ -9,6 +9,9 @@ videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
> > ifeq ($(CONFIG_COMPAT),y)
> > videodev-objs += v4l2-compat-ioctl32.o
> > endif
> > +ifeq ($(CONFIG_OF),y)
> > + videodev-objs += v4l2-of.o
> > +endif
> >
> > obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
> > obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
> > diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
> > new file mode 100644
> > index 0000000..f45d64b
> > --- /dev/null
> > +++ b/drivers/media/v4l2-core/v4l2-of.c
> > @@ -0,0 +1,190 @@
> > +/*
> > + * V4L2 OF binding parsing library
> > + *
> > + * Copyright (C) 2012 Renesas Electronics Corp.
> > + * Author: Guennadi Liakhovetski<g.liakhovetski at gmx.de>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of version 2 of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + */
> > +#include<linux/kernel.h>
> > +#include<linux/module.h>
> > +#include<linux/of.h>
> > +#include<linux/types.h>
> > +
> > +#include<media/v4l2-of.h>
> > +
> > +/*
> > + * All properties are optional. If none are found, we don't set any flags. This
> > + * means, the port has a static configuration and no properties have to be
> > + * specified explicitly.
> > + * If any properties are found, that identify the bus as parallel, and
> > + * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise the
> > + * bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
> > + * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
> > + * The caller should hold a reference to "node."
> > + */
> > +void v4l2_of_parse_link(const struct device_node *node,
> > + struct v4l2_of_link *link)
> > +{
> > + const struct device_node *port_node = of_get_parent(node);
> > + int size;
> > + unsigned int v;
> > + u32 data_lanes[ARRAY_SIZE(link->mipi_csi_2.data_lanes)];
> > + bool data_lanes_present;
> > +
> > + memset(link, 0, sizeof(*link));
> > +
> > + link->local_node = node;
> > +
> > + /* Doesn't matter, whether the below two calls succeed */
> > + of_property_read_u32(port_node, "reg",&link->port);
> > + of_property_read_u32(node, "reg",&link->addr);
> > +
> > + if (!of_property_read_u32(node, "bus-width",&v))
> > + link->parallel.bus_width = v;
> > +
> > + if (!of_property_read_u32(node, "data-shift",&v))
> > + link->parallel.data_shift = v;
> > +
> > + if (!of_property_read_u32(node, "hsync-active",&v))
> > + link->mbus_flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
> > + V4L2_MBUS_HSYNC_ACTIVE_LOW;
> > +
> > + if (!of_property_read_u32(node, "vsync-active",&v))
> > + link->mbus_flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
> > + V4L2_MBUS_VSYNC_ACTIVE_LOW;
> > +
> > + if (!of_property_read_u32(node, "data-active",&v))
> > + link->mbus_flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
> > + V4L2_MBUS_DATA_ACTIVE_LOW;
> > +
> > + if (!of_property_read_u32(node, "pclk-sample",&v))
> > + link->mbus_flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
> > + V4L2_MBUS_PCLK_SAMPLE_FALLING;
> > +
> > + if (!of_property_read_u32(node, "field-even-active",&v))
> > + link->mbus_flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
> > + V4L2_MBUS_FIELD_EVEN_LOW;
> > +
> > + if (of_get_property(node, "slave-mode",&size))
> > + link->mbus_flags |= V4L2_MBUS_SLAVE;
> > +
> > + /* If any parallel-bus properties have been found, skip serial ones */
> > + if (link->parallel.bus_width || link->parallel.data_shift ||
> > + link->mbus_flags) {
> > + /* Default parallel bus-master */
> > + if (!(link->mbus_flags& V4L2_MBUS_SLAVE))
> > + link->mbus_flags |= V4L2_MBUS_MASTER;
> > + return;
> > + }
> > +
> > + if (!of_property_read_u32(node, "clock-lanes",&v))
> > + link->mipi_csi_2.clock_lane = v;
> > +
> > + if (!of_property_read_u32_array(node, "data-lanes", data_lanes,
> > + ARRAY_SIZE(data_lanes))) {
> > + int i;
> > + for (i = 0; i< ARRAY_SIZE(data_lanes); i++)
> > + link->mipi_csi_2.data_lanes[i] = data_lanes[i];
>
> It doesn't look like what we aimed for. The data-lanes array is supposed
> to be of variable length, thus I don't think it can be parsed like that.
> Or am I missing something ? I think we need more something like below
> (based on of_property_read_u32_array(), not tested):
Ok, you're right, that my version only was suitable for fixed-size arrays,
which wasn't our goal. But I don't think we should go down to manually
parsing property data. How about (tested;-))
data = of_find_property(node, "data-lanes", NULL);
if (data) {
int i = 0;
const __be32 *lane = NULL;
do {
lane = of_prop_next_u32(data, lane, &data_lanes[i]);
} while (lane && i++ < ARRAY_SIZE(data_lanes));
link->mipi_csi_2.num_data_lanes = i;
while (i--)
link->mipi_csi_2.data_lanes[i] = data_lanes[i];
}
> void v4l2_of_parse_mipi_csi2(const struct device_node *node,
> struct mipi_csi2 *mipi_csi2)
> {
> struct property *prop = of_find_property(node, "data-lanes", NULL);
> u8 *out_data_lanes = mipi_csi_2->data_lanes;
> int num_lanes;
> const __be32 *val;
>
> if (!prop)
> return;
>
> mipi_csi2->num_lanes = 0;
>
> if (WARN (!prop->value, "Empty data-lanes property\n"))
> return;
>
> num_lanes = prop->length / sizeof(u32);
> if (WARN_ON(num_lanes > ARRAY_SIZE(mipi_csi_2->data_lanes))
> num_lanes = ARRAY_SIZE(mipi_csi_2->data_lanes);
>
> val = prop->value;
> while (num_lanes--)
> *out_data_lanes++ = be32_to_cpup(val++);
>
> mipi_csi2->num_lanes = num_lanes;
> }
>
> v4l2_of_parse_mipi_csi2(node, &link->mipi_csi2);
[snip]
> > +struct v4l2_of_link {
> > + unsigned int port;
> > + unsigned int addr;
> > + struct list_head head;
> > + const struct device_node *local_node;
> > + const __be32 *remote;
> > + unsigned int mbus_flags;
> > + union {
> > + struct {
> > + unsigned char bus_width;
> > + unsigned char data_shift;
> > + } parallel;
> > + struct {
> > + unsigned char data_lanes[4];
>
> Some devices are interested only in absolute number of lanes.
> I can't see how we could specify the number of data lanes here.
> Shouldn't something like 'unsigned char num_data_lanes;' be
> added to this structure ?
Yes, good point. As you see above, I've added it.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
More information about the devicetree-discuss
mailing list