From: Ying Liu <gnuiyl@gmail.com>
To: Philipp Zabel <p.zabel@pengutronix.de>
Cc: linux-media@vger.kernel.org,
Steve Longerbeam <steve_longerbeam@mentor.com>,
Marek Vasut <marex@denx.de>, Hans Verkuil <hverkuil@xs4all.nl>,
Gary Bisson <gary.bisson@boundarydevices.com>,
kernel@pengutronix.de, Sascha Hauer <s.hauer@pengutronix.de>,
Marc Kleine-Budde <mkl@pengutronix.de>
Subject: Re: [PATCH v2 07/21] [media] imx-ipu: Add i.MX IPUv3 CSI subdevice driver
Date: Tue, 8 Nov 2016 15:18:02 +0800 [thread overview]
Message-ID: <CAOcKUNUdDV9O+nYgvEmU6=3-XRYTRHfU9EPeGHTNBaVB83A0hQ@mail.gmail.com> (raw)
In-Reply-To: <1476466481-24030-8-git-send-email-p.zabel@pengutronix.de>
Hi Philipp,
On Sat, Oct 15, 2016 at 1:34 AM, Philipp Zabel <p.zabel@pengutronix.de> wrote:
> This adds a V4L2 subdevice driver for the two CMOS Sensor Interface (CSI)
> modules contained in each IPUv3. These sample video data from the
> parallel CSI0/1 pads or from the the MIPI CSI-2 bridge via IOMUXC video
> bus multiplexers and write to IPU internal FIFOs to deliver data to
> either the IDMAC or IC modules.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
> Changes since v1:
> - Propagate field and colorspace in ipucsi_subdev_set_format.
> - Recursively call s_stream on upstream subdev.
> ---
> drivers/media/platform/imx/Kconfig | 7 +
> drivers/media/platform/imx/Makefile | 1 +
> drivers/media/platform/imx/imx-ipuv3-csi.c | 547 +++++++++++++++++++++++++++++
> 3 files changed, 555 insertions(+)
> create mode 100644 drivers/media/platform/imx/imx-ipuv3-csi.c
>
> diff --git a/drivers/media/platform/imx/Kconfig b/drivers/media/platform/imx/Kconfig
> index 1662bb0b..a88c4f7 100644
> --- a/drivers/media/platform/imx/Kconfig
> +++ b/drivers/media/platform/imx/Kconfig
> @@ -8,3 +8,10 @@ config MEDIA_IMX
>
> config VIDEO_IMX_IPU_COMMON
> tristate
> +
> +config VIDEO_IMX_IPU_CSI
> + tristate "i.MX5/6 CMOS Sensor Interface driver"
> + depends on VIDEO_DEV && IMX_IPUV3_CORE && MEDIA_IMX
Should depend on VIDEO_V4L2_SUBDEV_API, otherwise
v4l2_subdev_get_try_format() would break build.
Regards,
Liu Ying
> + select VIDEO_IMX_IPUV3
> + ---help---
> + This is a v4l2 subdevice driver for two CSI modules in each IPUv3.
> diff --git a/drivers/media/platform/imx/Makefile b/drivers/media/platform/imx/Makefile
> index 0ba601a..82a3616 100644
> --- a/drivers/media/platform/imx/Makefile
> +++ b/drivers/media/platform/imx/Makefile
> @@ -1,2 +1,3 @@
> obj-$(CONFIG_MEDIA_IMX) += imx-media.o
> obj-$(CONFIG_VIDEO_IMX_IPU_COMMON) += imx-ipu.o
> +obj-$(CONFIG_VIDEO_IMX_IPU_CSI) += imx-ipuv3-csi.o
> diff --git a/drivers/media/platform/imx/imx-ipuv3-csi.c b/drivers/media/platform/imx/imx-ipuv3-csi.c
> new file mode 100644
> index 0000000..83e0511
> --- /dev/null
> +++ b/drivers/media/platform/imx/imx-ipuv3-csi.c
> @@ -0,0 +1,547 @@
> +/*
> + * i.MX IPUv3 CSI V4L2 Subdevice Driver
> + *
> + * Copyright (C) 2016, Pengutronix, Philipp Zabel <kernel@pengutronix.de>
> + *
> + * Based on code
> + * Copyright (C) 2006, Sascha Hauer, Pengutronix
> + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
> + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> + * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
> + *
> + * 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 <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/time.h>
> +#include <linux/version.h>
> +#include <linux/videodev2.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-mc.h>
> +#include <media/v4l2-of.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include <video/imx-ipu-v3.h>
> +
> +#include "imx-ipu.h"
> +
> +#define DRIVER_NAME "imx-ipuv3-csi"
> +
> +struct ipucsi {
> + struct v4l2_subdev subdev;
> +
> + struct device *dev;
> + u32 id;
> +
> + struct ipu_csi *csi;
> + struct ipu_soc *ipu;
> + struct v4l2_of_endpoint endpoint;
> + enum ipu_csi_dest csi_dest;
> +
> + struct media_pad subdev_pad[2];
> + struct v4l2_mbus_framefmt format_mbus[2];
> + struct v4l2_fract timeperframe[2];
> +};
> +
> +static int ipu_csi_get_mbus_config(struct ipucsi *ipucsi,
> + struct v4l2_mbus_config *config)
> +{
> + struct v4l2_subdev *sd;
> + struct media_pad *pad;
> + int ret;
> +
> + /*
> + * Retrieve media bus configuration from the entity connected directly
> + * to the CSI subdev sink pad.
> + */
> + pad = media_entity_remote_pad(&ipucsi->subdev_pad[0]);
> + if (!pad) {
> + dev_err(ipucsi->dev,
> + "failed to retrieve mbus config from source entity\n");
> + return -ENODEV;
> + }
> + sd = media_entity_to_v4l2_subdev(pad->entity);
> + ret = v4l2_subdev_call(sd, video, g_mbus_config, config);
> + if (ret == -ENOIOCTLCMD) {
> + /* Fall back to static mbus configuration from device tree */
> + config->type = ipucsi->endpoint.bus_type;
> + config->flags = ipucsi->endpoint.bus.parallel.flags;
> + ret = 0;
> + }
> +
> + return ret;
> +}
> +
> +static struct v4l2_mbus_framefmt *
> +__ipucsi_get_pad_format(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + unsigned int pad, u32 which)
> +{
> + struct ipucsi *ipucsi = container_of(sd, struct ipucsi, subdev);
> +
> + switch (which) {
> + case V4L2_SUBDEV_FORMAT_TRY:
> + return v4l2_subdev_get_try_format(sd, cfg, pad);
> + case V4L2_SUBDEV_FORMAT_ACTIVE:
> + return &ipucsi->format_mbus[pad ? 1 : 0];
> + default:
> + return NULL;
> + }
> +}
> +
> +static int ipucsi_subdev_log_status(struct v4l2_subdev *subdev)
> +{
> + struct ipucsi *ipucsi = container_of(subdev, struct ipucsi, subdev);
> +
> + ipu_csi_dump(ipucsi->csi);
> +
> + return 0;
> +}
> +
> +static int ipucsi_subdev_get_format(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *sdformat)
> +{
> + sdformat->format = *__ipucsi_get_pad_format(sd, cfg, sdformat->pad,
> + sdformat->which);
> + return 0;
> +}
> +
> +static bool ipucsi_mbus_code_supported(const u32 mbus_code)
> +{
> + static const u32 mbus_codes[] = {
> + MEDIA_BUS_FMT_Y8_1X8,
> + MEDIA_BUS_FMT_Y10_1X10,
> + MEDIA_BUS_FMT_Y12_1X12,
> + MEDIA_BUS_FMT_UYVY8_2X8,
> + MEDIA_BUS_FMT_YUYV8_2X8,
> + MEDIA_BUS_FMT_UYVY8_1X16,
> + MEDIA_BUS_FMT_YUYV8_1X16,
> + };
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(mbus_codes); i++) {
> + if (mbus_code == mbus_codes[i])
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static int ipucsi_subdev_set_format(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *sdformat)
> +{
> + struct ipucsi *ipucsi = container_of(sd, struct ipucsi, subdev);
> + struct v4l2_mbus_framefmt *mbusformat;
> + unsigned int width, height;
> + bool supported;
> +
> + supported = ipucsi_mbus_code_supported(sdformat->format.code);
> + if (!supported)
> + return -EINVAL;
> +
> + mbusformat = __ipucsi_get_pad_format(sd, cfg, sdformat->pad,
> + sdformat->which);
> +
> + if (sdformat->pad == 0) {
> + width = clamp_t(unsigned int, sdformat->format.width, 16, 8192);
> + height = clamp_t(unsigned int, sdformat->format.height, 16, 4096);
> + mbusformat->field = sdformat->format.field ?: V4L2_FIELD_NONE;
> + mbusformat->colorspace = sdformat->format.colorspace ?:
> + V4L2_COLORSPACE_SRGB;
> + } else {
> + struct v4l2_mbus_framefmt *infmt = &ipucsi->format_mbus[0];
> +
> + width = infmt->width;
> + height = infmt->height;
> + mbusformat->field = infmt->field;
> + mbusformat->colorspace = infmt->colorspace;
> + }
> +
> + mbusformat->width = width;
> + mbusformat->height = height;
> + mbusformat->code = sdformat->format.code;
> +
> + if (mbusformat->field == V4L2_FIELD_SEQ_TB &&
> + mbusformat->width == 720 && mbusformat->height == 480 &&
> + ipucsi->endpoint.bus_type == V4L2_MBUS_BT656) {
> + /* We capture NTSC bottom field first */
> + mbusformat->field = V4L2_FIELD_SEQ_BT;
> + }
> +
> + sdformat->format = *mbusformat;
> +
> + return 0;
> +}
> +
> +static int ipucsi_subdev_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> + struct ipucsi *ipucsi = container_of(sd, struct ipucsi, subdev);
> + struct v4l2_subdev *upstream_sd;
> + struct media_pad *pad;
> + int ret;
> +
> + pad = media_entity_remote_pad(&sd->entity.pads[0]);
> + if (!pad) {
> + dev_err(ipucsi->dev, "Failed to find remote source pad\n");
> + return -ENOLINK;
> + }
> +
> + if (!is_media_entity_v4l2_subdev(pad->entity)) {
> + dev_err(ipucsi->dev, "Upstream entity is not a v4l2 subdev\n");
> + return -ENODEV;
> + }
> +
> + upstream_sd = media_entity_to_v4l2_subdev(pad->entity);
> +
> + ret = v4l2_subdev_call(upstream_sd, video, s_stream, enable);
> + if (ret)
> + return ret;
> +
> + if (enable) {
> + struct v4l2_mbus_framefmt *fmt = ipucsi->format_mbus;
> + struct v4l2_mbus_config mbus_config;
> + struct v4l2_rect window;
> + bool mux_mct;
> + int ret;
> +
> + ret = ipu_csi_get_mbus_config(ipucsi, &mbus_config);
> + if (ret)
> + return ret;
> +
> + window.left = 0;
> + window.top = 0;
> + window.width = fmt[0].width;
> + window.height = fmt[0].height;
> + ipu_csi_set_window(ipucsi->csi, &window);
> +
> + /* Is CSI data source MCT (MIPI)? */
> + mux_mct = (mbus_config.type == V4L2_MBUS_CSI2);
> +
> + ipu_set_csi_src_mux(ipucsi->ipu, ipucsi->id, mux_mct);
> + if (mux_mct)
> + ipu_csi_set_mipi_datatype(ipucsi->csi, /*VC*/ 0,
> + &fmt[0]);
> +
> + ret = ipu_csi_init_interface(ipucsi->csi, &mbus_config,
> + &fmt[0]);
> + if (ret) {
> + dev_err(ipucsi->dev, "Failed to initialize CSI\n");
> + return ret;
> + }
> +
> + ipu_csi_set_dest(ipucsi->csi, ipucsi->csi_dest);
> +
> + ipu_csi_enable(ipucsi->csi);
> + } else {
> + ipu_csi_disable(ipucsi->csi);
> + }
> +
> + return 0;
> +}
> +
> +static int ipucsi_subdev_g_frame_interval(struct v4l2_subdev *subdev,
> + struct v4l2_subdev_frame_interval *fi)
> +{
> + struct ipucsi *ipucsi = container_of(subdev, struct ipucsi, subdev);
> +
> + if (fi->pad > 4)
> + return -EINVAL;
> +
> + fi->interval = ipucsi->timeperframe[(fi->pad == 0) ? 0 : 1];
> +
> + return 0;
> +}
> +
> +/*
> + * struct ipucsi_skip_desc - CSI frame skipping descriptor
> + * @keep - number of frames kept per max_ratio frames
> + * @max_ratio - width of skip_smfc, written to MAX_RATIO bitfield
> + * @skip_smfc - skip pattern written to the SKIP_SMFC bitfield
> + */
> +struct ipucsi_skip_desc {
> + u8 keep;
> + u8 max_ratio;
> + u8 skip_smfc;
> +};
> +
> +static const struct ipucsi_skip_desc ipucsi_skip[12] = {
> + { 1, 1, 0x00 }, /* Keep all frames */
> + { 5, 6, 0x10 }, /* Skip every sixth frame */
> + { 4, 5, 0x08 }, /* Skip every fifth frame */
> + { 3, 4, 0x04 }, /* Skip every fourth frame */
> + { 2, 3, 0x02 }, /* Skip every third frame */
> + { 3, 5, 0x0a }, /* Skip frames 1 and 3 of every 5 */
> + { 1, 2, 0x01 }, /* Skip every second frame */
> + { 2, 5, 0x0b }, /* Keep frames 1 and 4 of every 5 */
> + { 1, 3, 0x03 }, /* Keep one in three frames */
> + { 1, 4, 0x07 }, /* Keep one in four frames */
> + { 1, 5, 0x0f }, /* Keep one in five frames */
> + { 1, 6, 0x1f }, /* Keep one in six frames */
> +};
> +
> +static int ipucsi_subdev_s_frame_interval(struct v4l2_subdev *subdev,
> + struct v4l2_subdev_frame_interval *fi)
> +{
> + struct ipucsi *ipucsi = container_of(subdev, struct ipucsi, subdev);
> + const struct ipucsi_skip_desc *skip;
> + struct v4l2_fract *want, *in;
> + u32 min_err = UINT_MAX;
> + int i, best_i = 0;
> + u64 want_us;
> +
> + if (fi->pad > 4)
> + return -EINVAL;
> +
> + if (fi->pad == 0) {
> + /* Believe what we are told about the input frame rate */
> + ipucsi->timeperframe[0] = fi->interval;
> + /* Reset output frame rate to input frame rate */
> + ipucsi->timeperframe[1] = fi->interval;
> + return 0;
> + }
> +
> + want = &fi->interval;
> + in = &ipucsi->timeperframe[0];
> +
> + if (want->numerator == 0 || want->denominator == 0 ||
> + in->denominator == 0) {
> + ipucsi->timeperframe[1] = ipucsi->timeperframe[0];
> + fi->interval = ipucsi->timeperframe[1];
> + return 0;
> + }
> +
> + want_us = 1000000ULL * want->numerator;
> + do_div(want_us, want->denominator);
> +
> + /* Find the reduction closest to the requested timeperframe */
> + for (i = 0; i < ARRAY_SIZE(ipucsi_skip); i++) {
> + u64 tmp;
> + u32 err;
> +
> + skip = &ipucsi_skip[i];
> + tmp = 1000000ULL * in->numerator * skip->max_ratio;
> + do_div(tmp, in->denominator * skip->keep);
> + err = (tmp > want_us) ? (tmp - want_us) : (want_us - tmp);
> + if (err < min_err) {
> + min_err = err;
> + best_i = i;
> + }
> + }
> +
> + skip = &ipucsi_skip[best_i];
> +
> + ipu_csi_set_skip_smfc(ipucsi->csi, skip->skip_smfc, skip->max_ratio - 1,
> + 0);
> +
> + fi->interval.numerator = in->numerator * skip->max_ratio;
> + fi->interval.denominator = in->denominator * skip->keep;
> + ipucsi->timeperframe[1] = fi->interval;
> +
> + dev_dbg(ipucsi->dev, "skip: %d/%d -> %d/%d frames:%d pattern:0x%x\n",
> + in->numerator, in->denominator,
> + fi->interval.numerator, fi->interval.denominator,
> + skip->max_ratio, skip->skip_smfc);
> +
> + return 0;
> +}
> +
> +static struct v4l2_subdev_core_ops ipucsi_subdev_core_ops = {
> + .log_status = ipucsi_subdev_log_status,
> +};
> +
> +static struct v4l2_subdev_pad_ops ipucsi_subdev_pad_ops = {
> + .get_fmt = ipucsi_subdev_get_format,
> + .set_fmt = ipucsi_subdev_set_format,
> +};
> +
> +static struct v4l2_subdev_video_ops ipucsi_subdev_video_ops = {
> + .s_stream = ipucsi_subdev_s_stream,
> + .g_frame_interval = ipucsi_subdev_g_frame_interval,
> + .s_frame_interval = ipucsi_subdev_s_frame_interval,
> +};
> +
> +static const struct v4l2_subdev_ops ipucsi_subdev_ops = {
> + .core = &ipucsi_subdev_core_ops,
> + .pad = &ipucsi_subdev_pad_ops,
> + .video = &ipucsi_subdev_video_ops,
> +};
> +
> +static int ipu_csi_link_setup(struct media_entity *entity,
> + const struct media_pad *local,
> + const struct media_pad *remote, u32 flags)
> +{
> + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> + struct ipucsi *ipucsi = container_of(sd, struct ipucsi, subdev);
> +
> + ipucsi->csi_dest = IPU_CSI_DEST_IDMAC;
> +
> + return 0;
> +}
> +
> +struct media_entity_operations ipucsi_entity_ops = {
> + .link_setup = ipu_csi_link_setup,
> + .link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static int ipu_csi_registered(struct v4l2_subdev *sd)
> +{
> + struct ipucsi *ipucsi = container_of(sd, struct ipucsi, subdev);
> + struct device_node *rpp;
> +
> + /*
> + * Add source subdevice to asynchronous subdevice waiting list.
> + */
> + rpp = of_graph_get_remote_port_parent(ipucsi->endpoint.base.local_node);
> + if (rpp) {
> + struct v4l2_async_subdev *asd;
> +
> + asd = devm_kzalloc(sd->dev, sizeof(*asd), GFP_KERNEL);
> + if (!asd) {
> + of_node_put(rpp);
> + return -ENOMEM;
> + }
> +
> + asd->match_type = V4L2_ASYNC_MATCH_OF;
> + asd->match.of.node = rpp;
> +
> + __v4l2_async_notifier_add_subdev(sd->notifier, asd);
> + }
> +
> + return 0;
> +}
> +
> +struct v4l2_subdev_internal_ops ipu_csi_internal_ops = {
> + .registered = ipu_csi_registered,
> +};
> +
> +static int ipucsi_subdev_init(struct ipucsi *ipucsi, struct device_node *node)
> +{
> + struct device_node *endpoint;
> + int ret;
> +
> + v4l2_subdev_init(&ipucsi->subdev, &ipucsi_subdev_ops);
> + ipucsi->subdev.dev = ipucsi->dev;
> +
> + snprintf(ipucsi->subdev.name, sizeof(ipucsi->subdev.name), "%s%d %s%d",
> + "IPU", ipu_get_num(ipucsi->ipu), "CSI", ipucsi->id);
> +
> + endpoint = of_get_next_child(node, NULL);
> + if (endpoint)
> + v4l2_of_parse_endpoint(endpoint, &ipucsi->endpoint);
> +
> + ipucsi->subdev.entity.ops = &ipucsi_entity_ops;
> +
> + ipucsi->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> + ipucsi->subdev.of_node = node;
> +
> + ipucsi->subdev_pad[0].flags = MEDIA_PAD_FL_SINK;
> + ipucsi->subdev_pad[1].flags = MEDIA_PAD_FL_SOURCE;
> + ret = media_entity_pads_init(&ipucsi->subdev.entity, 2,
> + ipucsi->subdev_pad);
> + if (ret < 0)
> + return ret;
> +
> + ipucsi->subdev.internal_ops = &ipu_csi_internal_ops;
> + ret = v4l2_async_register_subdev(&ipucsi->subdev);
> + if (ret < 0) {
> + dev_err(ipucsi->dev, "Failed to register CSI subdev \"%s\": %d\n",
> + ipucsi->subdev.name, ret);
> + }
> +
> + return ret;
> +}
> +
> +static u64 camera_mask = DMA_BIT_MASK(32);
> +
> +static int ipucsi_probe(struct platform_device *pdev)
> +{
> + struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
> + struct ipu_soc *ipu = dev_get_drvdata(pdev->dev.parent);
> + struct ipucsi *ipucsi;
> + int ret;
> + struct device_node *node;
> +
> + pdev->dev.dma_mask = &camera_mask;
> + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> + if (!pdata)
> + return -EINVAL;
> +
> + ipucsi = devm_kzalloc(&pdev->dev, sizeof(*ipucsi), GFP_KERNEL);
> + if (!ipucsi)
> + return -ENOMEM;
> +
> + ipucsi->ipu = ipu;
> + ipucsi->id = pdata->csi;
> + ipucsi->dev = &pdev->dev;
> +
> + node = of_graph_get_port_by_id(pdev->dev.parent->of_node, ipucsi->id);
> + if (!node) {
> + dev_err(&pdev->dev, "cannot find node port@%d\n", ipucsi->id);
> + return -ENODEV;
> + }
> +
> + ipucsi->csi = ipu_csi_get(ipu, ipucsi->id);
> + if (IS_ERR(ipucsi->csi))
> + return PTR_ERR(ipucsi->csi);
> +
> + ret = ipucsi_subdev_init(ipucsi, node);
> + if (ret)
> + return ret;
> +
> + of_node_put(node);
> +
> + platform_set_drvdata(pdev, ipucsi);
> +
> + dev_info(&pdev->dev, "loaded\n");
> +
> + return 0;
> +}
> +
> +static struct platform_driver ipucsi_driver = {
> + .driver = {
> + .name = DRIVER_NAME,
> + },
> + .probe = ipucsi_probe,
> +};
> +
> +static int __init ipucsi_init(void)
> +{
> + return platform_driver_register(&ipucsi_driver);
> +}
> +
> +static void __exit ipucsi_exit(void)
> +{
> + return platform_driver_unregister(&ipucsi_driver);
> +}
> +
> +subsys_initcall(ipucsi_init);
> +module_exit(ipucsi_exit);
> +
> +MODULE_DESCRIPTION("i.MX IPUv3 capture interface driver");
> +MODULE_AUTHOR("Sascha Hauer, Pengutronix");
> +MODULE_AUTHOR("Philipp Zabel, Pengutronix");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> --
> 2.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2016-11-08 7:18 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-14 17:34 [PATCH v2 00/21] Basic i.MX IPUv3 capture support Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 01/21] [media] v4l2-async: move code out of v4l2_async_notifier_register into v4l2_async_test_nofity_all Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 02/21] [media] v4l2-async: allow subdevices to add further subdevices to the notifier waiting list Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 03/21] [media] v4l: of: add v4l2_of_subdev_registered Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 04/21] [media] v4l2-async: add new subdevices to the tail of subdev_list Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 05/21] [media] imx: Add i.MX SoC wide media device driver Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 06/21] [media] imx: Add IPUv3 media common code Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 07/21] [media] imx-ipu: Add i.MX IPUv3 CSI subdevice driver Philipp Zabel
2016-11-08 7:18 ` Ying Liu [this message]
2016-10-14 17:34 ` [PATCH v2 08/21] [media] imx: Add i.MX IPUv3 capture driver Philipp Zabel
2016-10-17 11:32 ` Jack Mitchell
2016-10-17 11:35 ` Marek Vasut
2016-10-17 11:40 ` Jack Mitchell
2016-10-17 12:12 ` Philipp Zabel
2016-10-19 16:22 ` Jack Mitchell
2016-10-19 19:25 ` Marek Vasut
2016-10-26 11:29 ` Jack Mitchell
2016-11-08 7:21 ` Ying Liu
2016-10-14 17:34 ` [PATCH v2 09/21] [media] platform: add video-multiplexer subdevice driver Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 10/21] [media] imx: Add i.MX MIPI CSI-2 " Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 11/21] [media] tc358743: put lanes in STOP state before starting streaming Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 12/21] ARM: dts: imx6qdl: Add capture-subsystem node Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 13/21] ARM: dts: imx6qdl: Add mipi_ipu1/2 multiplexers, mipi_csi, and their connections Philipp Zabel
2016-11-08 8:23 ` Ying Liu
2016-10-14 17:34 ` [PATCH v2 14/21] ARM: dts: imx6qdl: Add MIPI CSI-2 D-PHY compatible and clocks Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 15/21] ARM: dts: nitrogen6x: Add dtsi for BD_HDMI_MIPI HDMI to MIPI CSI-2 receiver board Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 16/21] gpu: ipuv3: add ipu_csi_set_downsize Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 17/21] [media] imx-ipuv3-csi: support downsizing Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 18/21] [media] add mux and video interface bridge entity functions Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 19/21] [media] video-multiplexer: set entity function to mux Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 20/21] [media] imx: Set i.MX MIPI CSI-2 entity function to bridge Philipp Zabel
2016-10-14 17:34 ` [PATCH v2 21/21] [media] tc358743: set entity function to video interface bridge Philipp Zabel
2016-10-17 10:18 ` [PATCH v2 00/21] Basic i.MX IPUv3 capture support Gary Bisson
2016-10-17 12:41 ` Philipp Zabel
2016-10-19 21:30 ` Sakari Ailus
[not found] ` <CAH-u=807nRYzza0kTfOMv1AiWazk6FGJyz6W5_bYw7v9nOrccA@mail.gmail.com>
2016-12-29 15:10 ` Jean-Michel Hautbois
2016-12-29 20:51 ` Robert Schwebel
2016-12-30 19:06 ` Marek Vasut
2016-12-30 20:26 ` Steve Longerbeam
2017-01-02 13:51 ` Jean-Michel Hautbois
2017-01-02 14:45 ` Hans Verkuil
2017-01-02 14:59 ` Jean-Michel Hautbois
2017-01-02 19:19 ` Fabio Estevam
2017-01-02 19:20 ` Steve Longerbeam
2017-01-02 17:04 ` Fabio Estevam
2017-01-02 19:17 ` Steve Longerbeam
2017-01-09 19:43 ` Philipp Zabel
2017-01-10 0:15 ` Steve Longerbeam
2017-01-10 23:52 ` Steve Longerbeam
2017-01-11 9:12 ` Jean-Michel Hautbois
2017-01-11 12:10 ` Philipp Zabel
2017-01-12 23:22 ` Steve Longerbeam
2017-01-12 23:43 ` Steve Longerbeam
2017-01-13 2:22 ` Steve Longerbeam
2017-01-13 11:18 ` Philipp Zabel
2017-01-13 11:04 ` Philipp Zabel
2017-01-13 11:05 ` Philipp Zabel
2017-01-14 20:26 ` Steve Longerbeam
2017-01-16 11:49 ` Philipp Zabel
2017-01-11 12:11 ` Philipp Zabel
2017-01-24 18:11 ` Philipp Zabel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAOcKUNUdDV9O+nYgvEmU6=3-XRYTRHfU9EPeGHTNBaVB83A0hQ@mail.gmail.com' \
--to=gnuiyl@gmail.com \
--cc=gary.bisson@boundarydevices.com \
--cc=hverkuil@xs4all.nl \
--cc=kernel@pengutronix.de \
--cc=linux-media@vger.kernel.org \
--cc=marex@denx.de \
--cc=mkl@pengutronix.de \
--cc=p.zabel@pengutronix.de \
--cc=s.hauer@pengutronix.de \
--cc=steve_longerbeam@mentor.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).