From f867ba2a2cf1eb05bb2b4396ae30f2174326c2b7 Mon Sep 17 00:00:00 2001 From: Bhanu Murthy V Date: Thu, 1 Oct 2015 14:32:03 -0700 Subject: [PATCH] media: v4l2-core: Migration from upstream Adds required upstream files to support unified VI driver Add minimal changes in existing files without breaking the current interface Bug 1617777 Change-Id: Iaa2b63aed4ac028fd3b3a7920a3781d7186ca03f Signed-off-by: Bhanu Murthy V Reviewed-on: http://git-master/r/786823 (cherry picked from commit 230d024056fb256a741ac4da94624f463cad6574) Reviewed-on: http://git-master/r/832143 GVS: Gerrit_Virtual_Submit Reviewed-by: David Wang (SW-TEGRA) Reviewed-by: Jihoon Bang --- drivers/media/v4l2-core/Makefile | 3 +- drivers/media/v4l2-core/v4l2-async.c | 327 ++++++++++++++++ drivers/media/v4l2-core/v4l2-of.c | 285 ++++++++------ drivers/media/v4l2-core/videobuf2-core.c | 16 + drivers/of/base.c | 162 ++++++++ include/linux/gpio/consumer.h | 454 +++++++++++++++++++++++ include/linux/of.h | 11 + include/linux/of_graph.h | 94 +++++ include/media/v4l2-async.h | 97 +++++ include/media/v4l2-mediabus.h | 3 + include/media/v4l2-of.h | 69 ++-- include/media/v4l2-subdev.h | 71 +++- include/media/videobuf2-core.h | 23 +- include/uapi/linux/media-bus-format.h | 137 +++++++ include/uapi/linux/v4l2-common.h | 12 + include/uapi/linux/v4l2-mediabus.h | 1 + include/uapi/linux/v4l2-subdev.h | 3 +- include/uapi/linux/videodev2.h | 7 + 18 files changed, 1622 insertions(+), 153 deletions(-) create mode 100644 drivers/media/v4l2-core/v4l2-async.c create mode 100644 include/linux/gpio/consumer.h create mode 100644 include/linux/of_graph.h create mode 100644 include/media/v4l2-async.h create mode 100644 include/uapi/linux/media-bus-format.h diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index aa50c46314b..8cbbadde05b 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -5,7 +5,8 @@ tuner-objs := tuner-core.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \ + v4l2-async.o ifeq ($(CONFIG_COMPAT),y) videodev-objs += v4l2-compat-ioctl32.o endif diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c new file mode 100644 index 00000000000..5bada202b2d --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -0,0 +1,327 @@ +/* + * V4L2 asynchronous subdevice registration API + * + * Copyright (C) 2012-2013, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) +{ +#if IS_ENABLED(CONFIG_I2C) + struct i2c_client *client = i2c_verify_client(sd->dev); + return client && + asd->match.i2c.adapter_id == client->adapter->nr && + asd->match.i2c.address == client->addr; +#else + return false; +#endif +} + +static bool match_devname(struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + return !strcmp(asd->match.device_name.name, dev_name(sd->dev)); +} + +static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) +{ + return sd->of_node == asd->match.of.node; +} + +static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) +{ + if (!asd->match.custom.match) + /* Match always */ + return true; + + return asd->match.custom.match(sd->dev, asd); +} + +static LIST_HEAD(subdev_list); +static LIST_HEAD(notifier_list); +static DEFINE_MUTEX(list_lock); + +static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd) +{ + bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *); + struct v4l2_async_subdev *asd; + + list_for_each_entry(asd, ¬ifier->waiting, list) { + /* bus_type has been verified valid before */ + switch (asd->match_type) { + case V4L2_ASYNC_MATCH_CUSTOM: + match = match_custom; + break; + case V4L2_ASYNC_MATCH_DEVNAME: + match = match_devname; + break; + case V4L2_ASYNC_MATCH_I2C: + match = match_i2c; + break; + case V4L2_ASYNC_MATCH_OF: + match = match_of; + break; + default: + /* Cannot happen, unless someone breaks us */ + WARN_ON(true); + return NULL; + } + + /* match cannot be NULL here */ + if (match(sd, asd)) + return asd; + } + + return NULL; +} + +static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + int ret; + + /* Remove from the waiting list */ + list_del(&asd->list); + sd->asd = asd; + sd->notifier = notifier; + + if (notifier->bound) { + ret = notifier->bound(notifier, sd, asd); + if (ret < 0) + return ret; + } + /* Move from the global subdevice list to notifier's done */ + list_move(&sd->async_list, ¬ifier->done); + + ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); + if (ret < 0) { + if (notifier->unbind) + notifier->unbind(notifier, sd, asd); + return ret; + } + + if (list_empty(¬ifier->waiting) && notifier->complete) + return notifier->complete(notifier); + + return 0; +} + +static void v4l2_async_cleanup(struct v4l2_subdev *sd) +{ + v4l2_device_unregister_subdev(sd); + /* Subdevice driver will reprobe and put the subdev back onto the list */ + list_del_init(&sd->async_list); + sd->asd = NULL; + sd->dev = NULL; +} + +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, + struct v4l2_async_notifier *notifier) +{ + struct v4l2_subdev *sd, *tmp; + struct v4l2_async_subdev *asd; + int i; + + if (!notifier->num_subdevs || notifier->num_subdevs > V4L2_MAX_SUBDEVS) + return -EINVAL; + + notifier->v4l2_dev = v4l2_dev; + INIT_LIST_HEAD(¬ifier->waiting); + INIT_LIST_HEAD(¬ifier->done); + + for (i = 0; i < notifier->num_subdevs; i++) { + asd = notifier->subdevs[i]; + + switch (asd->match_type) { + case V4L2_ASYNC_MATCH_CUSTOM: + case V4L2_ASYNC_MATCH_DEVNAME: + case V4L2_ASYNC_MATCH_I2C: + case V4L2_ASYNC_MATCH_OF: + break; + default: + dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL, + "Invalid match type %u on %p\n", + asd->match_type, asd); + return -EINVAL; + } + list_add_tail(&asd->list, ¬ifier->waiting); + } + + mutex_lock(&list_lock); + + /* Keep also completed notifiers on the list */ + list_add(¬ifier->list, ¬ifier_list); + + list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { + int ret; + + asd = v4l2_async_belongs(notifier, sd); + if (!asd) + continue; + + ret = v4l2_async_test_notify(notifier, sd, asd); + if (ret < 0) { + mutex_unlock(&list_lock); + return ret; + } + } + + mutex_unlock(&list_lock); + + return 0; +} +EXPORT_SYMBOL(v4l2_async_notifier_register); + +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) +{ + struct v4l2_subdev *sd, *tmp; + unsigned int notif_n_subdev = notifier->num_subdevs; + unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS); + struct device **dev; + int i = 0; + + if (!notifier->v4l2_dev) + return; + + dev = kmalloc(n_subdev * sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(notifier->v4l2_dev->dev, + "Failed to allocate device cache!\n"); + } + + mutex_lock(&list_lock); + + list_del(¬ifier->list); + + list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { + struct device *d; + + d = get_device(sd->dev); + + v4l2_async_cleanup(sd); + + /* If we handled USB devices, we'd have to lock the parent too */ + device_release_driver(d); + + if (notifier->unbind) + notifier->unbind(notifier, sd, sd->asd); + + /* + * Store device at the device cache, in order to call + * put_device() on the final step + */ + if (dev) + dev[i++] = d; + else + put_device(d); + } + + mutex_unlock(&list_lock); + + /* + * Call device_attach() to reprobe devices + * + * NOTE: If dev allocation fails, i is 0, and the whole loop won't be + * executed. + */ + while (i--) { + struct device *d = dev[i]; + + if (d && device_attach(d) < 0) { + const char *name = "(none)"; + int lock = device_trylock(d); + + if (lock && d->driver) + name = d->driver->name; + dev_err(d, "Failed to re-probe to %s\n", name); + if (lock) + device_unlock(d); + } + put_device(d); + } + kfree(dev); + + notifier->v4l2_dev = NULL; + + /* + * Don't care about the waiting list, it is initialised and populated + * upon notifier registration. + */ +} +EXPORT_SYMBOL(v4l2_async_notifier_unregister); + +int v4l2_async_register_subdev(struct v4l2_subdev *sd) +{ + struct v4l2_async_notifier *notifier; + + /* + * No reference taken. The reference is held by the device + * (struct v4l2_subdev.dev), and async sub-device does not + * exist independently of the device at any point of time. + */ + if (!sd->of_node && sd->dev) + sd->of_node = sd->dev->of_node; + + mutex_lock(&list_lock); + + INIT_LIST_HEAD(&sd->async_list); + + list_for_each_entry(notifier, ¬ifier_list, list) { + struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); + if (asd) { + int ret = v4l2_async_test_notify(notifier, sd, asd); + mutex_unlock(&list_lock); + return ret; + } + } + + /* None matched, wait for hot-plugging */ + list_add(&sd->async_list, &subdev_list); + + mutex_unlock(&list_lock); + + return 0; +} +EXPORT_SYMBOL(v4l2_async_register_subdev); + +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) +{ + struct v4l2_async_notifier *notifier = sd->notifier; + + if (!sd->asd) { + if (!list_empty(&sd->async_list)) + v4l2_async_cleanup(sd); + return; + } + + mutex_lock(&list_lock); + + list_add(&sd->asd->list, ¬ifier->waiting); + + v4l2_async_cleanup(sd); + + if (notifier->unbind) + notifier->unbind(notifier, sd, sd->asd); + + mutex_unlock(&list_lock); +} +EXPORT_SYMBOL(v4l2_async_unregister_subdev); diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index aa59639d013..570746853b4 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -14,16 +14,17 @@ #include #include #include +#include #include #include +#include #include -static void v4l2_of_parse_csi_bus(const struct device_node *node, - struct v4l2_of_endpoint *endpoint) +static int v4l2_of_parse_csi_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) { struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; - u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; struct property *prop; bool have_clk_lane = false; unsigned int flags = 0; @@ -32,16 +33,34 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, prop = of_find_property(node, "data-lanes", NULL); if (prop) { const __be32 *lane = NULL; - int i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { - lane = of_prop_next_u32(prop, lane, &data_lanes[i]); + for (i = 0; i < ARRAY_SIZE(bus->data_lanes); i++) { + lane = of_prop_next_u32(prop, lane, &v); if (!lane) break; + bus->data_lanes[i] = v; } bus->num_data_lanes = i; - while (i--) - bus->data_lanes[i] = data_lanes[i]; + } + + prop = of_find_property(node, "lane-polarities", NULL); + if (prop) { + const __be32 *polarity = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bus->lane_polarities); i++) { + polarity = of_prop_next_u32(prop, polarity, &v); + if (!polarity) + break; + bus->lane_polarities[i] = v; + } + + if (i < 1 + bus->num_data_lanes /* clock + data */) { + pr_warn("%s: too few lane-polarities entries (need %u, got %u)\n", + node->full_name, 1 + bus->num_data_lanes, i); + return -EINVAL; + } } if (!of_property_read_u32(node, "clock-lanes", &v)) { @@ -56,6 +75,8 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, bus->flags = flags; endpoint->bus_type = V4L2_MBUS_CSI2; + + return 0; } static void v4l2_of_parse_parallel_bus(const struct device_node *node, @@ -73,10 +94,6 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH : V4L2_MBUS_VSYNC_ACTIVE_LOW; - if (!of_property_read_u32(node, "pclk-sample", &v)) - flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : - V4L2_MBUS_PCLK_SAMPLE_FALLING; - if (!of_property_read_u32(node, "field-even-active", &v)) flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH : V4L2_MBUS_FIELD_EVEN_LOW; @@ -85,6 +102,10 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, else endpoint->bus_type = V4L2_MBUS_BT656; + if (!of_property_read_u32(node, "pclk-sample", &v)) + flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : + V4L2_MBUS_PCLK_SAMPLE_FALLING; + if (!of_property_read_u32(node, "data-active", &v)) flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH : V4L2_MBUS_DATA_ACTIVE_LOW; @@ -100,6 +121,10 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, if (!of_property_read_u32(node, "data-shift", &v)) bus->data_shift = v; + if (!of_property_read_u32(node, "sync-on-green-active", &v)) + flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH : + V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW; + bus->flags = flags; } @@ -117,23 +142,26 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, * 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. + * + * NOTE: This function does not parse properties the size of which is + * variable without a low fixed limit. Please use + * v4l2_of_alloc_parse_endpoint() in new drivers instead. + * + * Return: 0. */ -void v4l2_of_parse_endpoint(const struct device_node *node, - struct v4l2_of_endpoint *endpoint) +int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) { - struct device_node *port_node = of_get_parent(node); - - memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); + int rval; - endpoint->local_node = node; - /* - * It doesn't matter whether the two calls below succeed. - * If they don't then the default value 0 is used. - */ - of_property_read_u32(port_node, "reg", &endpoint->port); - of_property_read_u32(node, "reg", &endpoint->id); + of_graph_parse_endpoint(node, &endpoint->base); + /* Zero fields from bus_type to until the end */ + memset(&endpoint->bus_type, 0, sizeof(*endpoint) - + offsetof(typeof(*endpoint), bus_type)); - v4l2_of_parse_csi_bus(node, endpoint); + rval = v4l2_of_parse_csi_bus(node, endpoint); + if (rval) + return rval; /* * Parse the parallel video bus properties only if none * of the MIPI CSI-2 specific properties were found. @@ -141,126 +169,149 @@ void v4l2_of_parse_endpoint(const struct device_node *node, if (endpoint->bus.mipi_csi2.flags == 0) v4l2_of_parse_parallel_bus(node, endpoint); - of_node_put(port_node); + return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); -/** - * v4l2_of_get_next_endpoint() - get next endpoint node - * @parent: pointer to the parent device node - * @prev: previous endpoint node, or NULL to get first +/* + * v4l2_of_free_endpoint() - free the endpoint acquired by + * v4l2_of_alloc_parse_endpoint() + * @endpoint - the endpoint the resources of which are to be released * - * Return: An 'endpoint' node pointer with refcount incremented. Refcount - * of the passed @prev node is not decremented, the caller have to use - * of_node_put() on it when done. + * It is safe to call this function with NULL argument or on an + * endpoint the parsing of which failed. */ -struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, - struct device_node *prev) +void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint) { - struct device_node *endpoint; - struct device_node *port = NULL; - - if (!parent) - return NULL; - - if (!prev) { - struct device_node *node; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ - node = of_get_child_by_name(parent, "ports"); - if (node) - parent = node; - - for_each_child_of_node(parent, node) { - if (!of_node_cmp(node->name, "port")) { - port = node; - break; - } - } - if (port) { - /* Found a port, get an endpoint. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } else { - endpoint = NULL; - } + if (!endpoint) + return; + + kfree(endpoint->link_frequencies); + kfree(endpoint); +} +EXPORT_SYMBOL(v4l2_of_free_endpoint); - if (!endpoint) - pr_err("%s(): no endpoint nodes specified for %s\n", - __func__, parent->full_name); - } else { - port = of_get_parent(prev); - if (!port) - /* Hm, has someone given us the root node ?... */ - return NULL; - - /* Avoid dropping prev node refcount to 0. */ - of_node_get(prev); - endpoint = of_get_next_child(port, prev); - if (endpoint) { - of_node_put(port); - return endpoint; +/** + * v4l2_of_alloc_parse_endpoint() - parse all endpoint node properties + * @node: pointer to endpoint device_node + * + * 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 that identify the bus as parallel are found 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. + * + * v4l2_of_alloc_parse_endpoint() has two important differences to + * v4l2_of_parse_endpoint(): + * + * 1. It also parses variable size data and + * + * 2. The memory it has allocated to store the variable size data must + * be freed using v4l2_of_free_endpoint() when no longer needed. + * + * Return: Pointer to v4l2_of_endpoint if successful, on error a + * negative error code. + */ +struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint( + const struct device_node *node) +{ + struct v4l2_of_endpoint *endpoint; + int len; + int rval; + + endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); + if (!endpoint) + return -ENOMEM; + + rval = v4l2_of_parse_endpoint(node, endpoint); + if (rval < 0) + goto out_err; + + if (of_get_property(node, "link-frequencies", &len)) { + endpoint->link_frequencies = kmalloc(len, GFP_KERNEL); + if (!endpoint->link_frequencies) { + rval = -ENOMEM; + goto out_err; } - /* No more endpoints under this port, try the next one. */ - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (of_node_cmp(port->name, "port")); + endpoint->nr_of_link_frequencies = + len / sizeof(*endpoint->link_frequencies); - /* Pick up the first endpoint in this port. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); + rval = of_property_read_u64_array( + node, "link-frequencies", endpoint->link_frequencies, + endpoint->nr_of_link_frequencies); + if (rval < 0) + goto out_err; } return endpoint; + +out_err: + v4l2_of_free_endpoint(endpoint); + return rval; } -EXPORT_SYMBOL(v4l2_of_get_next_endpoint); +EXPORT_SYMBOL(v4l2_of_alloc_parse_endpoint); /** - * v4l2_of_get_remote_port_parent() - get remote port's parent node - * @node: pointer to a local endpoint device_node + * v4l2_of_parse_link() - parse a link between two endpoints + * @node: pointer to the endpoint at the local end of the link + * @link: pointer to the V4L2 OF link data structure + * + * Fill the link structure with the local and remote nodes and port numbers. + * The local_node and remote_node fields are set to point to the local and + * remote port's parent nodes respectively (the port parent node being the + * parent node of the port node if that node isn't a 'ports' node, or the + * grand-parent node of the port node otherwise). * - * Return: Remote device node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. + * A reference is taken to both the local and remote nodes, the caller must use + * v4l2_of_put_link() to drop the references when done with the link. + * + * Return: 0 on success, or -ENOLINK if the remote endpoint can't be found. */ -struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node) +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) { struct device_node *np; - unsigned int depth; - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); + memset(link, 0, sizeof(*link)); - /* Walk 3 levels up only if there is 'ports' node. */ - for (depth = 3; depth && np; depth--) { + np = of_get_parent(node); + of_property_read_u32(np, "reg", &link->local_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) np = of_get_next_parent(np); - if (depth == 2 && of_node_cmp(np->name, "ports")) - break; + link->local_node = np; + + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) { + of_node_put(link->local_node); + return -ENOLINK; } - return np; + + np = of_get_parent(np); + of_property_read_u32(np, "reg", &link->remote_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->remote_node = np; + + return 0; } -EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); +EXPORT_SYMBOL(v4l2_of_parse_link); /** - * v4l2_of_get_remote_port() - get remote port node - * @node: pointer to a local endpoint device_node + * v4l2_of_put_link() - drop references to nodes in a link + * @link: pointer to the V4L2 OF link data structure * - * Return: Remote port node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. + * Drop references to the local and remote nodes in the link. This function must + * be called on every link parsed with v4l2_of_parse_link(). */ -struct device_node *v4l2_of_get_remote_port(const struct device_node *node) +void v4l2_of_put_link(struct v4l2_of_link *link) { - struct device_node *np; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - if (!np) - return NULL; - return of_get_parent(np); + of_node_put(link->local_node); + of_node_put(link->remote_node); } -EXPORT_SYMBOL(v4l2_of_get_remote_port); +EXPORT_SYMBOL(v4l2_of_put_link); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 5e47ba479e5..fbadb03d2be 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2592,6 +2592,22 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) } EXPORT_SYMBOL_GPL(vb2_fop_mmap); +int _vb2_fop_release(struct file *file, struct mutex *lock) +{ + struct video_device *vdev = video_devdata(file); + + if (lock) + mutex_lock(lock); + if (file->private_data == vdev->queue->owner) { + vb2_queue_release(vdev->queue); + vdev->queue->owner = NULL; + } + if (lock) + mutex_unlock(lock); + return v4l2_fh_release(file); +} +EXPORT_SYMBOL_GPL(_vb2_fop_release); + int vb2_fop_release(struct file *file) { struct video_device *vdev = video_devdata(file); diff --git a/drivers/of/base.c b/drivers/of/base.c index db192638a9b..a44706dc1fe 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1736,3 +1737,164 @@ const char *of_prop_next_string(struct property *prop, const char *cur) return curv; } EXPORT_SYMBOL_GPL(of_prop_next_string); + + +/** + * of_graph_parse_endpoint() - parse common endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the OF endpoint data structure + * + * The caller should hold a reference to @node. + */ +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n", + __func__, node->full_name); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + of_node_put(port_node); + + return 0; +} +EXPORT_SYMBOL(of_graph_parse_endpoint); + +/** + * of_property_read_u64_array - Find and read an array of 64 bit integers + * from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_values: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 64-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_values is modified only if a valid u64 value can be decoded. + */ +int of_property_read_u64_array(const struct device_node *np, + const char *propname, u64 *out_values, + size_t sz) +{ + const __be32 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) { + *out_values++ = of_read_number(val, 2); + val += 2; + } + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u64_array); + + +/** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port; + + if (!parent) + return NULL; + + /* + * Start by locating the port node. If no previous endpoint is specified + * search for the first port node, otherwise get the previous endpoint + * parent port node. + */ + if (!prev) { + struct device_node *node; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + port = of_get_child_by_name(parent, "port"); + of_node_put(node); + + if (!port) { + pr_err("%s(): no port node found in %s\n", + __func__, parent->full_name); + return NULL; + } + } else { + port = of_get_parent(prev); + if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n", + __func__, prev->full_name)) + return NULL; + } + + while (1) { + /* + * Now that we have a port node, get the next endpoint by + * getting the next child. If the previous endpoint is NULL this + * will return the first child. + */ + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + prev = NULL; + + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + } +} +EXPORT_SYMBOL(of_graph_get_next_endpoint); + +/** + * of_graph_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(of_graph_get_remote_port_parent); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h new file mode 100644 index 00000000000..14cac67c201 --- /dev/null +++ b/include/linux/gpio/consumer.h @@ -0,0 +1,454 @@ +#ifndef __LINUX_GPIO_CONSUMER_H +#define __LINUX_GPIO_CONSUMER_H + +#include +#include +#include + +struct device; + +/** + * Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are + * preferable to the old integer-based handles. + * + * Contrary to integers, a pointer to a gpio_desc is guaranteed to be valid + * until the GPIO is released. + */ +struct gpio_desc; + +/** + * Struct containing an array of descriptors that can be obtained using + * gpiod_get_array(). + */ +struct gpio_descs { + unsigned int ndescs; + struct gpio_desc *desc[]; +}; + +#define GPIOD_FLAGS_BIT_DIR_SET BIT(0) +#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) +#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) + +/** + * Optional flags that can be passed to one of gpiod_* to configure direction + * and output value. These values cannot be OR'd. + */ +enum gpiod_flags { + GPIOD_ASIS = 0, + GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET, + GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, + GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | + GPIOD_FLAGS_BIT_DIR_VAL, +}; + +#ifdef CONFIG_GPIOLIB + +/* Return the number of GPIOs associated with a device / function */ +int gpiod_count(struct device *dev, const char *con_id); + +/* Acquire and dispose GPIOs */ +struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +void gpiod_put(struct gpio_desc *desc); +void gpiod_put_array(struct gpio_descs *descs); + +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags); +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags); +void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs); + +int gpiod_get_direction(struct gpio_desc *desc); +int gpiod_direction_input(struct gpio_desc *desc); +int gpiod_direction_output(struct gpio_desc *desc, int value); +int gpiod_direction_output_raw(struct gpio_desc *desc, int value); + +/* Value get/set from non-sleeping context */ +int gpiod_get_value(const struct gpio_desc *desc); +void gpiod_set_value(struct gpio_desc *desc, int value); +void gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array); +int gpiod_get_raw_value(const struct gpio_desc *desc); +void gpiod_set_raw_value(struct gpio_desc *desc, int value); +void gpiod_set_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); + +/* Value get/set from sleeping context */ +int gpiod_get_value_cansleep(const struct gpio_desc *desc); +void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +void gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); +int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); +void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); +void gpiod_set_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); + +int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); + +int gpiod_is_active_low(const struct gpio_desc *desc); +int gpiod_cansleep(const struct gpio_desc *desc); + +int gpiod_to_irq(const struct gpio_desc *desc); + +/* Convert between the old gpio_ and new gpiod_ interfaces */ +struct gpio_desc *gpio_to_desc(unsigned gpio); +int desc_to_gpio(const struct gpio_desc *desc); + +/* Child properties interface */ +struct fwnode_handle; + +struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, + const char *propname); +struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, + const char *con_id, + struct fwnode_handle *child); +#else /* CONFIG_GPIOLIB */ + +static inline int gpiod_count(struct device *dev, const char *con_id) +{ + return 0; +} + +static inline struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} +static inline struct gpio_desc *__must_check +gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void gpiod_put(struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline void gpiod_put_array(struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} +static inline +struct gpio_desc *__must_check +devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline void devm_gpiod_put_array(struct device *dev, + struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + + +static inline int gpiod_get_direction(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} +static inline int gpiod_direction_input(struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} +static inline int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} +static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + + +static inline int gpiod_get_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline void gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline int gpiod_get_raw_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline void gpiod_set_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline void gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, + int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline void gpiod_set_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + +static inline int gpiod_is_active_low(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline int gpiod_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} + +static inline int gpiod_to_irq(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -EINVAL; +} + +static inline struct gpio_desc *gpio_to_desc(unsigned gpio) +{ + return ERR_PTR(-EINVAL); +} +static inline int desc_to_gpio(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -EINVAL; +} + +/* Child properties interface */ +struct fwnode_handle; + +static inline struct gpio_desc *fwnode_get_named_gpiod( + struct fwnode_handle *fwnode, const char *propname) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *devm_get_gpiod_from_child( + struct device *dev, const char *con_id, struct fwnode_handle *child) +{ + return ERR_PTR(-ENOSYS); +} + +#endif /* CONFIG_GPIOLIB */ + +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) + +int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +void gpiod_unexport(struct gpio_desc *desc); + +#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + return -ENOSYS; +} + +static inline void gpiod_unexport(struct gpio_desc *desc) +{ +} + +#endif /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +#endif diff --git a/include/linux/of.h b/include/linux/of.h index adac5c58537..017190a0926 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -260,6 +260,10 @@ extern int of_property_read_u32_array(const struct device_node *np, size_t sz); extern int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value); +extern int of_property_read_u64_array(const struct device_node *np, + const char *propname, + u64 *out_values, + size_t sz); extern int of_property_read_string(struct device_node *np, const char *propname, @@ -455,6 +459,13 @@ static inline int of_property_read_u32_array(const struct device_node *np, return -ENOSYS; } +static inline int of_property_read_u64_array(const struct device_node *np, + const char *propname, + u64 *out_values, size_t sz) +{ + return -ENOSYS; +} + static inline int of_property_read_string(struct device_node *np, const char *propname, const char **out_string) diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h new file mode 100644 index 00000000000..f8bcd0e21a2 --- /dev/null +++ b/include/linux/of_graph.h @@ -0,0 +1,94 @@ +/* + * OF graph binding parsing helpers + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * + * Copyright (C) 2012 Renesas Electronics Corp. + * Author: Guennadi Liakhovetski + * + * 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. + */ +#ifndef __LINUX_OF_GRAPH_H +#define __LINUX_OF_GRAPH_H + +#include + +/** + * struct of_endpoint - the OF graph endpoint data structure + * @port: identifier (value of reg property) of a port this endpoint belongs to + * @id: identifier (value of reg property) of this endpoint + * @local_node: pointer to device_node of this endpoint + */ +struct of_endpoint { + unsigned int port; + unsigned int id; + const struct device_node *local_node; +}; + +/** + * for_each_endpoint_of_node - iterate over every endpoint in a device node + * @parent: parent device node containing ports and endpoints + * @child: loop variable pointing to the current endpoint node + * + * When breaking out of the loop, of_node_put(child) has to be called manually. + */ +#define for_each_endpoint_of_node(parent, child) \ + for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \ + child = of_graph_get_next_endpoint(parent, child)) + +#ifdef CONFIG_OF +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint); +struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *previous); +struct device_node *of_graph_get_endpoint_by_regs( + const struct device_node *parent, int port_reg, int reg); +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node); +struct device_node *of_graph_get_remote_port(const struct device_node *node); +#else + +static inline int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + return -ENOSYS; +} + +static inline struct device_node *of_graph_get_port_by_id( + struct device_node *node, u32 id) +{ + return NULL; +} + +static inline struct device_node *of_graph_get_next_endpoint( + const struct device_node *parent, + struct device_node *previous) +{ + return NULL; +} + +static inline struct device_node *of_graph_get_endpoint_by_regs( + const struct device_node *parent, int port_reg, int reg) +{ + return NULL; +} + +static inline struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + return NULL; +} + +static inline struct device_node *of_graph_get_remote_port( + const struct device_node *node) +{ + return NULL; +} + +#endif /* CONFIG_OF */ + +#endif /* __LINUX_OF_GRAPH_H */ diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h new file mode 100644 index 00000000000..768356917be --- /dev/null +++ b/include/media/v4l2-async.h @@ -0,0 +1,97 @@ +/* + * V4L2 asynchronous subdevice registration API + * + * Copyright (C) 2012-2013, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef V4L2_ASYNC_H +#define V4L2_ASYNC_H + +#include +#include + +struct device; +struct device_node; +struct v4l2_device; +struct v4l2_subdev; +struct v4l2_async_notifier; + +/* A random max subdevice number, used to allocate an array on stack */ +#define V4L2_MAX_SUBDEVS 128U + +enum v4l2_async_match_type { + V4L2_ASYNC_MATCH_CUSTOM, + V4L2_ASYNC_MATCH_DEVNAME, + V4L2_ASYNC_MATCH_I2C, + V4L2_ASYNC_MATCH_OF, +}; + +/** + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge + * @bus_type: subdevice bus type to select the appropriate matching method + * @match: union of per-bus type matching data sets + * @list: used to link struct v4l2_async_subdev objects, waiting to be + * probed, to a notifier->waiting list + */ +struct v4l2_async_subdev { + enum v4l2_async_match_type match_type; + union { + struct { + const struct device_node *node; + } of; + struct { + const char *name; + } device_name; + struct { + int adapter_id; + unsigned short address; + } i2c; + struct { + bool (*match)(struct device *, + struct v4l2_async_subdev *); + void *priv; + } custom; + } match; + + /* v4l2-async core private: not to be used by drivers */ + struct list_head list; +}; + +/** + * v4l2_async_notifier - v4l2_device notifier data + * @num_subdevs:number of subdevices + * @subdevs: array of pointers to subdevice descriptors + * @v4l2_dev: pointer to struct v4l2_device + * @waiting: list of struct v4l2_async_subdev, waiting for their drivers + * @done: list of struct v4l2_subdev, already probed + * @list: member in a global list of notifiers + * @bound: a subdevice driver has successfully probed one of subdevices + * @complete: all subdevices have been probed successfully + * @unbind: a subdevice is leaving + */ +struct v4l2_async_notifier { + unsigned int num_subdevs; + struct v4l2_async_subdev **subdevs; + struct v4l2_device *v4l2_dev; + struct list_head waiting; + struct list_head done; + struct list_head list; + int (*bound)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); + int (*complete)(struct v4l2_async_notifier *notifier); + void (*unbind)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); +}; + +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, + struct v4l2_async_notifier *notifier); +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); +int v4l2_async_register_subdev(struct v4l2_subdev *sd); +void v4l2_async_unregister_subdev(struct v4l2_subdev *sd); +#endif diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 83ae07e5335..395c4a95a42 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -40,6 +40,9 @@ #define V4L2_MBUS_FIELD_EVEN_HIGH (1 << 10) /* FIELD = 1/0 - Field1 (odd)/Field2 (even) */ #define V4L2_MBUS_FIELD_EVEN_LOW (1 << 11) +/* Active state of Sync-on-green (SoG) signal, 0/1 for LOW/HIGH respectively. */ +#define V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH (1 << 12) +#define V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW (1 << 13) /* Serial flags */ /* How many lanes the client can use */ diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 3a8a84124b4..4dc34b245d4 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -28,12 +29,15 @@ struct device_node; * @data_lanes: an array of physical data lane indexes * @clock_lane: physical lane index of the clock lane * @num_data_lanes: number of data lanes + * @lane_polarities: polarity of the lanes. The order is the same of + * the physical lanes. */ struct v4l2_of_bus_mipi_csi2 { unsigned int flags; unsigned char data_lanes[4]; unsigned char clock_lane; unsigned short num_data_lanes; + bool lane_polarities[5]; }; /** @@ -50,35 +54,47 @@ struct v4l2_of_bus_parallel { /** * struct v4l2_of_endpoint - the endpoint data structure - * @port: identifier (value of reg property) of a port this endpoint belongs to - * @id: identifier (value of reg property) of this endpoint - * @local_node: pointer to device_node of this endpoint - * @remote: phandle to remote endpoint node + * @base: struct of_endpoint containing port, id, and local of_node * @bus_type: bus type * @bus: bus configuration data structure - * @head: list head for this structure + * @link_frequencies: array of supported link frequencies + * @nr_of_link_frequencies: number of elements in link_frequenccies array */ struct v4l2_of_endpoint { - unsigned int port; - unsigned int id; - const struct device_node *local_node; - const __be32 *remote; + struct of_endpoint base; + /* Fields below this line will be zeroed by v4l2_of_parse_endpoint() */ enum v4l2_mbus_type bus_type; union { struct v4l2_of_bus_parallel parallel; struct v4l2_of_bus_mipi_csi2 mipi_csi2; } bus; - struct list_head head; + u64 *link_frequencies; + unsigned int nr_of_link_frequencies; +}; + +/** + * struct v4l2_of_link - a link between two endpoints + * @local_node: pointer to device_node of this endpoint + * @local_port: identifier of the port this endpoint belongs to + * @remote_node: pointer to device_node of the remote endpoint + * @remote_port: identifier of the port the remote endpoint belongs to + */ +struct v4l2_of_link { + struct device_node *local_node; + unsigned int local_port; + struct device_node *remote_node; + unsigned int remote_port; }; #ifdef CONFIG_OF -void v4l2_of_parse_endpoint(const struct device_node *node, - struct v4l2_of_endpoint *link); -struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, - struct device_node *previous); -struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node); -struct device_node *v4l2_of_get_remote_port(const struct device_node *node); +int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint); +struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint( + const struct device_node *node); +void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint); +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link); +void v4l2_of_put_link(struct v4l2_of_link *link); #else /* CONFIG_OF */ static inline int v4l2_of_parse_endpoint(const struct device_node *node, @@ -87,23 +103,24 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node, return -ENOSYS; } -static inline struct device_node *v4l2_of_get_next_endpoint( - const struct device_node *parent, - struct device_node *previous) +static inline struct v4l2_of_endpoint *v4l2_of_alloc_parse_endpoint( + const struct device_node *node) { return NULL; } -static inline struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node) +static inline void v4l2_of_free_endpoint(struct v4l2_of_endpoint *endpoint) { - return NULL; } -static inline struct device_node *v4l2_of_get_remote_port( - const struct device_node *node) +static inline int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + return -ENOSYS; +} + +static inline void v4l2_of_put_link(struct v4l2_of_link *link) { - return NULL; } #endif /* CONFIG_OF */ diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5298d678d0f..a2e20089577 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #define V4L2_SUBDEV_IR_TX_NOTIFY _IOW('v', 1, u32) #define V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ 0x00000001 +#define V4L2_DEVICE_NOTIFY_EVENT _IOW('v', 2, struct v4l2_event) + struct v4l2_device; struct v4l2_ctrl_handler; struct v4l2_event_subscription; @@ -163,6 +166,10 @@ struct v4l2_subdev_core_ops { int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); +#ifdef CONFIG_COMPAT + long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, + unsigned long arg); +#endif #ifdef CONFIG_VIDEO_ADV_DEBUG int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg); @@ -193,6 +200,7 @@ struct v4l2_subdev_tuner_ops { int (*s_radio)(struct v4l2_subdev *sd); int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); + int (*enum_freq_bands)(struct v4l2_subdev *sd, struct v4l2_frequency_band *band); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt); int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); @@ -230,15 +238,18 @@ struct v4l2_subdev_audio_ops { /* Indicates the @length field specifies maximum data length. */ #define V4L2_MBUS_FRAME_DESC_FL_LEN_MAX (1U << 0) -/* Indicates user defined data format, i.e. non standard frame format. */ +/* + * Indicates that the format does not have line offsets, i.e. the + * receiver should use 1D DMA. + */ #define V4L2_MBUS_FRAME_DESC_FL_BLOB (1U << 1) /** * struct v4l2_mbus_frame_desc_entry - media bus frame description structure * @flags: V4L2_MBUS_FRAME_DESC_FL_* flags * @pixelcode: media bus pixel code, valid if FRAME_DESC_FL_BLOB is not set - * @length: number of octets per frame, valid for compressed or unspecified - * formats + * @length: number of octets per frame, valid if V4L2_MBUS_FRAME_DESC_FL_BLOB + * is set */ struct v4l2_mbus_frame_desc_entry { u16 flags; @@ -265,8 +276,11 @@ struct v4l2_mbus_frame_desc { g_std_output: get current standard for video OUTPUT devices. This is ignored by video input devices. - g_tvnorms_output: get v4l2_std_id with all standards supported by video - OUTPUT device. This is ignored by video input devices. + g_tvnorms: get v4l2_std_id with all standards supported by the video + CAPTURE device. This is ignored by video output devices. + + g_tvnorms_output: get v4l2_std_id with all standards supported by the video + OUTPUT device. This is ignored by video capture devices. s_crystal_freq: sets the frequency of the crystal used to generate the clocks in Hz. An extra flags field allows device specific configuration @@ -306,9 +320,12 @@ struct v4l2_mbus_frame_desc { struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags); + int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); + int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std); int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std); int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std); + int (*g_tvnorms)(struct v4l2_subdev *sd, v4l2_std_id *std); int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std); int (*g_input_status)(struct v4l2_subdev *sd, u32 *status); int (*s_stream)(struct v4l2_subdev *sd, int enable); @@ -477,6 +494,18 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/* + * Used for storing subdev pad information. This structure only needs + * to be passed to the pad op if the 'which' field of the main argument + * is set to V4L2_SUBDEV_FORMAT_TRY. For V4L2_SUBDEV_FORMAT_ACTIVE it is + * safe to pass NULL. + */ +struct v4l2_subdev_pad_config { + struct v4l2_mbus_framefmt try_fmt; + struct v4l2_rect try_crop; + struct v4l2_rect try_compose; +}; + /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * @get_frame_desc: get the current low level media bus frame parameters. @@ -504,8 +533,12 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_selection *sel); int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_selection *sel); - int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid); - int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid); + int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); + int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); + int (*dv_timings_cap)(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap); + int (*enum_dv_timings)(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings); #ifdef CONFIG_MEDIA_CONTROLLER int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link, struct v4l2_subdev_format *source_fmt, @@ -560,6 +593,17 @@ struct v4l2_subdev_internal_ops { /* Set this flag if this subdev generates events. */ #define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3) +struct regulator_bulk_data; + +struct v4l2_subdev_platform_data { + /* Optional regulators uset to power on/off the subdevice */ + struct regulator_bulk_data *regulators; + int num_regulators; + + /* Per-subdevice data, specific for a certain video host device */ + void *host_priv; +}; + /* Each instance of a subdev driver should create this struct, either stand-alone or embedded in a larger struct. */ @@ -569,6 +613,7 @@ struct v4l2_subdev { #endif struct list_head list; struct module *owner; + bool owner_v4l2_dev; u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; @@ -585,6 +630,18 @@ struct v4l2_subdev { void *host_priv; /* subdev device node */ struct video_device *devnode; + /* pointer to the physical device, if any */ + struct device *dev; + /* The device_node of the subdev, usually the same as dev->of_node. */ + struct device_node *of_node; + /* Links this subdev to a global subdev_list or @notifier->done list. */ + struct list_head async_list; + /* Pointer to respective struct v4l2_async_subdev. */ + struct v4l2_async_subdev *asd; + /* Pointer to the managing notifier. */ + struct v4l2_async_notifier *notifier; + /* common part of subdevice platform data */ + struct v4l2_subdev_platform_data *pdata; }; #define media_entity_to_v4l2_subdev(ent) \ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 2cc4e0df9c5..7e0c34569a9 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -353,7 +353,10 @@ struct vb2_queue { unsigned int plane_sizes[VIDEO_MAX_PLANES]; unsigned int streaming:1; - unsigned int waiting_for_buffers:1; + unsigned int start_streaming_called:1; + unsigned int error:1; + unsigned int waiting_for_buffers:1; + unsigned int last_buffer_dequeued:1; struct vb2_fileio_data *fileio; }; @@ -464,6 +467,24 @@ vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no) return 0; } +/** + * vb2_start_streaming_called() - return streaming status of driver + * @q: videobuf queue + */ +static inline bool vb2_start_streaming_called(struct vb2_queue *q) +{ + return q->start_streaming_called; +} + +/** + * vb2_clear_last_buffer_dequeued() - clear last buffer dequeued flag of queue + * @q: videobuf queue + */ +static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q) +{ + q->last_buffer_dequeued = false; +} + /* * The following functions are not part of the vb2 core API, but are simple * helper functions that you can use in your struct v4l2_file_operations, diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h new file mode 100644 index 00000000000..190d491d5b1 --- /dev/null +++ b/include/uapi/linux/media-bus-format.h @@ -0,0 +1,137 @@ +/* + * Media Bus API header + * + * Copyright (C) 2009, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MEDIA_BUS_FORMAT_H +#define __LINUX_MEDIA_BUS_FORMAT_H + +/* + * These bus formats uniquely identify data formats on the data bus. Format 0 + * is reserved, MEDIA_BUS_FMT_FIXED shall be used by host-client pairs, where + * the data format is fixed. Additionally, "2X8" means that one pixel is + * transferred in two 8-bit samples, "BE" or "LE" specify in which order those + * samples are transferred over the bus: "LE" means that the least significant + * bits are transferred first, "BE" means that the most significant bits are + * transferred first, and "PADHI" and "PADLO" define which bits - low or high, + * in the incomplete high byte, are filled with padding bits. + * + * The bus formats are grouped by type, bus_width, bits per component, samples + * per pixel and order of subsamples. Numerical values are sorted using generic + * numerical sort order (8 thus comes before 10). + * + * As their value can't change when a new bus format is inserted in the + * enumeration, the bus formats are explicitly given a numerical value. The next + * free values for each category are listed below, update them when inserting + * new pixel codes. + */ + +#define MEDIA_BUS_FMT_FIXED 0x0001 + +/* RGB - next is 0x1018 */ +#define MEDIA_BUS_FMT_RGB444_1X12 0x1016 +#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 +#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 +#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 +#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 +#define MEDIA_BUS_FMT_RGB565_1X16 0x1017 +#define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 +#define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 +#define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 +#define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 +#define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RBG888_1X24 0x100e +#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 +#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 +#define MEDIA_BUS_FMT_BGR888_1X24 0x1013 +#define MEDIA_BUS_FMT_GBR888_1X24 0x1014 +#define MEDIA_BUS_FMT_RGB888_1X24 0x100a +#define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b +#define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c +#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG 0x1011 +#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 +#define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d +#define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f + +/* YUV (including grey) - next is 0x2026 */ +#define MEDIA_BUS_FMT_Y8_1X8 0x2001 +#define MEDIA_BUS_FMT_UV8_1X8 0x2015 +#define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 +#define MEDIA_BUS_FMT_VYUY8_1_5X8 0x2003 +#define MEDIA_BUS_FMT_YUYV8_1_5X8 0x2004 +#define MEDIA_BUS_FMT_YVYU8_1_5X8 0x2005 +#define MEDIA_BUS_FMT_UYVY8_2X8 0x2006 +#define MEDIA_BUS_FMT_VYUY8_2X8 0x2007 +#define MEDIA_BUS_FMT_YUYV8_2X8 0x2008 +#define MEDIA_BUS_FMT_YVYU8_2X8 0x2009 +#define MEDIA_BUS_FMT_Y10_1X10 0x200a +#define MEDIA_BUS_FMT_UYVY10_2X10 0x2018 +#define MEDIA_BUS_FMT_VYUY10_2X10 0x2019 +#define MEDIA_BUS_FMT_YUYV10_2X10 0x200b +#define MEDIA_BUS_FMT_YVYU10_2X10 0x200c +#define MEDIA_BUS_FMT_Y12_1X12 0x2013 +#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c +#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d +#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e +#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f +#define MEDIA_BUS_FMT_UYVY8_1X16 0x200f +#define MEDIA_BUS_FMT_VYUY8_1X16 0x2010 +#define MEDIA_BUS_FMT_YUYV8_1X16 0x2011 +#define MEDIA_BUS_FMT_YVYU8_1X16 0x2012 +#define MEDIA_BUS_FMT_YDYUYDYV8_1X16 0x2014 +#define MEDIA_BUS_FMT_UYVY10_1X20 0x201a +#define MEDIA_BUS_FMT_VYUY10_1X20 0x201b +#define MEDIA_BUS_FMT_YUYV10_1X20 0x200d +#define MEDIA_BUS_FMT_YVYU10_1X20 0x200e +#define MEDIA_BUS_FMT_VUY8_1X24 0x2024 +#define MEDIA_BUS_FMT_YUV8_1X24 0x2025 +#define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 +#define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 +#define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 +#define MEDIA_BUS_FMT_YVYU12_1X24 0x2023 +#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 +#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 + +/* Bayer - next is 0x3019 */ +#define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 +#define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 +#define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 +#define MEDIA_BUS_FMT_SRGGB8_1X8 0x3014 +#define MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 0x3015 +#define MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 0x3016 +#define MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 0x3017 +#define MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 0x3018 +#define MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 0x300b +#define MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 0x300c +#define MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 0x3009 +#define MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 0x300d +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE 0x3003 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE 0x3004 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE 0x3005 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE 0x3006 +#define MEDIA_BUS_FMT_SBGGR10_1X10 0x3007 +#define MEDIA_BUS_FMT_SGBRG10_1X10 0x300e +#define MEDIA_BUS_FMT_SGRBG10_1X10 0x300a +#define MEDIA_BUS_FMT_SRGGB10_1X10 0x300f +#define MEDIA_BUS_FMT_SBGGR12_1X12 0x3008 +#define MEDIA_BUS_FMT_SGBRG12_1X12 0x3010 +#define MEDIA_BUS_FMT_SGRBG12_1X12 0x3011 +#define MEDIA_BUS_FMT_SRGGB12_1X12 0x3012 + +/* JPEG compressed formats - next is 0x4002 */ +#define MEDIA_BUS_FMT_JPEG_1X8 0x4001 + +/* Vendor specific formats - next is 0x5002 */ + +/* S5C73M3 sensor specific interleaved UYVY and JPEG */ +#define MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8 0x5001 + +/* HSV - next is 0x6002 */ +#define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 + +#endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h index 4f0667e010d..15273987093 100644 --- a/include/uapi/linux/v4l2-common.h +++ b/include/uapi/linux/v4l2-common.h @@ -29,6 +29,8 @@ #ifndef __V4L2_COMMON__ #define __V4L2_COMMON__ +#include + /* * * Selection interface definitions @@ -41,6 +43,8 @@ #define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 /* Cropping bounds */ #define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 +/* Native frame size */ +#define V4L2_SEL_TGT_NATIVE_SIZE 0x0003 /* Current composing area */ #define V4L2_SEL_TGT_COMPOSE 0x0100 /* Default composing area */ @@ -68,4 +72,12 @@ #define V4L2_SUBDEV_SEL_FLAG_SIZE_LE V4L2_SEL_FLAG_LE #define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG +struct v4l2_edid { + __u32 pad; + __u32 start_block; + __u32 blocks; + __u32 reserved[5]; + __u8 *edid; +}; + #endif /* __V4L2_COMMON__ */ diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h index b1fedf8a540..3fe39ea2727 100644 --- a/include/uapi/linux/v4l2-mediabus.h +++ b/include/uapi/linux/v4l2-mediabus.h @@ -11,6 +11,7 @@ #ifndef __LINUX_V4L2_MEDIABUS_H #define __LINUX_V4L2_MEDIABUS_H +#include #include #include diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index a33c4daadce..8cb7cbcd027 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -74,7 +74,8 @@ struct v4l2_subdev_mbus_code_enum { __u32 pad; __u32 index; __u32 code; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index f40b41c7e10..51f3740432f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -685,6 +685,13 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x0000 #define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 #define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x4000 +/* Timestamp sources. */ +#define V4L2_BUF_FLAG_TSTAMP_SRC_MASK 0x00070000 +#define V4L2_BUF_FLAG_TSTAMP_SRC_EOF 0x00000000 +#define V4L2_BUF_FLAG_TSTAMP_SRC_SOE 0x00010000 +/* mem2mem encoder/decoder */ +#define V4L2_BUF_FLAG_LAST 0x00100000 + /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor -- 2.39.2