Devicetree
 help / color / mirror / Atom feed
* [PATCH v6 05/13] clk: imx7d: reset parent for mipi csi root
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media
In-Reply-To: <20180522145245.3143-1-rui.silva@linaro.org>

To guarantee that we do not get Overflow in image FIFO the outer bandwidth has
to be faster than inputer bandwidth. For that it must be possible to set a
faster frequency clock. So set new parent to sys_pfd3 clock for the mipi csi
block.

Acked-by: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
 drivers/clk/imx/clk-imx7d.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index f7f4db2e6fa6..27877d05faa2 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -891,6 +891,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
 	clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
 
+	clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+
 	/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
 	clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
 
-- 
2.17.0

^ permalink raw reply related

* [PATCH v6 04/13] clk: imx7d: fix mipi dphy div parent
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media
In-Reply-To: <20180522145245.3143-1-rui.silva@linaro.org>

Fix the mipi dphy root divider to mipi_dphy_pre_div, this would remove a orphan
clock and set the correct parent.

before:
cat clk_orphan_summary
                                 enable  prepare  protect
   clock                          count    count    count        rate   accuracy   phase
----------------------------------------------------------------------------------------
 mipi_dphy_post_div                   1        1        0           0          0 0
    mipi_dphy_root_clk                1        1        0           0          0 0

cat clk_dump | grep mipi_dphy
mipi_dphy_post_div                    1        1        0           0          0 0
    mipi_dphy_root_clk                1        1        0           0          0 0

after:
cat clk_dump | grep mipi_dphy
   mipi_dphy_src                     1        1        0    24000000          0 0
       mipi_dphy_cg                  1        1        0    24000000          0 0
          mipi_dphy_pre_div          1        1        0    24000000          0 0
             mipi_dphy_post_div      1        1        0    24000000          0 0
                mipi_dphy_root_clk   1        1        0    24000000          0 0

Fixes: 8f6d8094b215 ("ARM: imx: add imx7d clk tree support")
Acked-by: Dong Aisheng <Aisheng.dong@nxp.com>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
 drivers/clk/imx/clk-imx7d.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 975a20d3cc94..f7f4db2e6fa6 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -729,7 +729,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
 	clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
 	clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
 	clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
-	clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_csi_dphy_div", base + 0xa480, 0, 6);
+	clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
 	clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
 	clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
 	clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
-- 
2.17.0

^ permalink raw reply related

* [PATCH v6 03/13] media: staging/imx7: add imx7 CSI subdev driver
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media
In-Reply-To: <20180522145245.3143-1-rui.silva@linaro.org>

This add the media entity subdevice and control driver for the i.MX7
CMOS Sensor Interface.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
 drivers/staging/media/imx/Kconfig          |    9 +-
 drivers/staging/media/imx/Makefile         |    2 +
 drivers/staging/media/imx/imx7-media-csi.c | 1352 ++++++++++++++++++++
 3 files changed, 1362 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/media/imx/imx7-media-csi.c

diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index bfc17de56b17..40a11f988fc6 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -11,7 +11,7 @@ config VIDEO_IMX_MEDIA
 	  driver for the i.MX5/6 SOC.
 
 if VIDEO_IMX_MEDIA
-menu "i.MX5/6 Media Sub devices"
+menu "i.MX5/6/7 Media Sub devices"
 
 config VIDEO_IMX_CSI
 	tristate "i.MX5/6 Camera Sensor Interface driver"
@@ -20,5 +20,12 @@ config VIDEO_IMX_CSI
 	---help---
 	  A video4linux camera sensor interface driver for i.MX5/6.
 
+config VIDEO_IMX7_CSI
+	tristate "i.MX7 Camera Sensor Interface driver"
+	depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C
+	default y
+	---help---
+	  A video4linux camera sensor interface driver for i.MX7.
+
 endmenu
 endif
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index a30b3033f9a3..074f016d3519 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -12,3 +12,5 @@ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-ic.o
 
 obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o
 obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
+
+obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
new file mode 100644
index 000000000000..7facb7fcbc67
--- /dev/null
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -0,0 +1,1352 @@
+// SPDX-License-Identifier: GPL
+/*
+ * V4L2 Capture CSI Subdev for Freescale i.MX7 SOC
+ *
+ * Copyright (c) 2018 Linaro Ltd
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <media/imx.h>
+#include "imx-media.h"
+
+#define IMX7_CSI_PAD_SINK	0
+#define IMX7_CSI_PAD_SRC	1
+#define IMX7_CSI_PADS_NUM	2
+
+/* reset values */
+#define CSICR1_RESET_VAL	0x40000800
+#define CSICR2_RESET_VAL	0x0
+#define CSICR3_RESET_VAL	0x0
+
+/* csi control reg 1 */
+#define BIT_SWAP16_EN		BIT(31)
+#define BIT_EXT_VSYNC		BIT(30)
+#define BIT_EOF_INT_EN		BIT(29)
+#define BIT_PRP_IF_EN		BIT(28)
+#define BIT_CCIR_MODE		BIT(27)
+#define BIT_COF_INT_EN		BIT(26)
+#define BIT_SF_OR_INTEN		BIT(25)
+#define BIT_RF_OR_INTEN		BIT(24)
+#define BIT_SFF_DMA_DONE_INTEN  BIT(22)
+#define BIT_STATFF_INTEN	BIT(21)
+#define BIT_FB2_DMA_DONE_INTEN  BIT(20)
+#define BIT_FB1_DMA_DONE_INTEN  BIT(19)
+#define BIT_RXFF_INTEN		BIT(18)
+#define BIT_SOF_POL		BIT(17)
+#define BIT_SOF_INTEN		BIT(16)
+#define BIT_MCLKDIV		(0xF << 12)
+#define BIT_HSYNC_POL		BIT(11)
+#define BIT_CCIR_EN		BIT(10)
+#define BIT_MCLKEN		BIT(9)
+#define BIT_FCC			BIT(8)
+#define BIT_PACK_DIR		BIT(7)
+#define BIT_CLR_STATFIFO	BIT(6)
+#define BIT_CLR_RXFIFO		BIT(5)
+#define BIT_GCLK_MODE		BIT(4)
+#define BIT_INV_DATA		BIT(3)
+#define BIT_INV_PCLK		BIT(2)
+#define BIT_REDGE		BIT(1)
+#define BIT_PIXEL_BIT		BIT(0)
+
+#define SHIFT_MCLKDIV		12
+
+/* control reg 3 */
+#define BIT_FRMCNT		(0xFFFF << 16)
+#define BIT_FRMCNT_RST		BIT(15)
+#define BIT_DMA_REFLASH_RFF	BIT(14)
+#define BIT_DMA_REFLASH_SFF	BIT(13)
+#define BIT_DMA_REQ_EN_RFF	BIT(12)
+#define BIT_DMA_REQ_EN_SFF	BIT(11)
+#define BIT_STATFF_LEVEL	(0x7 << 8)
+#define BIT_HRESP_ERR_EN	BIT(7)
+#define BIT_RXFF_LEVEL		(0x7 << 4)
+#define BIT_TWO_8BIT_SENSOR	BIT(3)
+#define BIT_ZERO_PACK_EN	BIT(2)
+#define BIT_ECC_INT_EN		BIT(1)
+#define BIT_ECC_AUTO_EN		BIT(0)
+
+#define SHIFT_FRMCNT		16
+#define SHIFT_RXFIFO_LEVEL	4
+
+/* csi status reg */
+#define BIT_ADDR_CH_ERR_INT	BIT(28)
+#define BIT_FIELD0_INT		BIT(27)
+#define BIT_FIELD1_INT		BIT(26)
+#define BIT_SFF_OR_INT		BIT(25)
+#define BIT_RFF_OR_INT		BIT(24)
+#define BIT_DMA_TSF_DONE_SFF	BIT(22)
+#define BIT_STATFF_INT		BIT(21)
+#define BIT_DMA_TSF_DONE_FB2	BIT(20)
+#define BIT_DMA_TSF_DONE_FB1	BIT(19)
+#define BIT_RXFF_INT		BIT(18)
+#define BIT_EOF_INT		BIT(17)
+#define BIT_SOF_INT		BIT(16)
+#define BIT_F2_INT		BIT(15)
+#define BIT_F1_INT		BIT(14)
+#define BIT_COF_INT		BIT(13)
+#define BIT_HRESP_ERR_INT	BIT(7)
+#define BIT_ECC_INT		BIT(1)
+#define BIT_DRDY		BIT(0)
+
+/* csi control reg 18 */
+#define BIT_CSI_HW_ENABLE		BIT(31)
+#define BIT_MIPI_DATA_FORMAT_RAW8	(0x2a << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW10	(0x2b << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW12	(0x2c << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW14	(0x2d << 25)
+#define BIT_MIPI_DATA_FORMAT_YUV422_8B	(0x1e << 25)
+#define BIT_MIPI_DATA_FORMAT_MASK	(0x3F << 25)
+#define BIT_MIPI_DATA_FORMAT_OFFSET	25
+#define BIT_DATA_FROM_MIPI		BIT(22)
+#define BIT_MIPI_YU_SWAP		BIT(21)
+#define BIT_MIPI_DOUBLE_CMPNT		BIT(20)
+#define BIT_BASEADDR_CHG_ERR_EN		BIT(9)
+#define BIT_BASEADDR_SWITCH_SEL		BIT(5)
+#define BIT_BASEADDR_SWITCH_EN		BIT(4)
+#define BIT_PARALLEL24_EN		BIT(3)
+#define BIT_DEINTERLACE_EN		BIT(2)
+#define BIT_TVDECODER_IN_EN		BIT(1)
+#define BIT_NTSC_EN			BIT(0)
+
+#define CSI_MCLK_VF		1
+#define CSI_MCLK_ENC		2
+#define CSI_MCLK_RAW		4
+#define CSI_MCLK_I2C		8
+
+#define CSI_CSICR1		0x0
+#define CSI_CSICR2		0x4
+#define CSI_CSICR3		0x8
+#define CSI_STATFIFO		0xC
+#define CSI_CSIRXFIFO		0x10
+#define CSI_CSIRXCNT		0x14
+#define CSI_CSISR		0x18
+
+#define CSI_CSIDBG		0x1C
+#define CSI_CSIDMASA_STATFIFO	0x20
+#define CSI_CSIDMATS_STATFIFO	0x24
+#define CSI_CSIDMASA_FB1	0x28
+#define CSI_CSIDMASA_FB2	0x2C
+#define CSI_CSIFBUF_PARA	0x30
+#define CSI_CSIIMAG_PARA	0x34
+
+#define CSI_CSICR18		0x48
+#define CSI_CSICR19		0x4c
+
+struct imx7_csi {
+	struct device *dev;
+	struct imx_media_dev *md;
+	struct v4l2_subdev sd;
+	struct imx_media_video_dev *vdev;
+	struct imx_media_dev *imxmd;
+	struct media_pad pad[IMX7_CSI_PADS_NUM];
+
+	struct mutex lock;
+	spinlock_t irqlock;
+
+	struct v4l2_subdev *src_sd;
+
+	struct media_entity *sink;
+
+	struct v4l2_fwnode_endpoint upstream_ep;
+
+	struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
+	const struct imx_media_pixfmt *cc[IMX7_CSI_PADS_NUM];
+	struct v4l2_fract frame_interval[IMX7_CSI_PADS_NUM];
+
+	struct v4l2_ctrl_handler ctrl_hdlr;
+
+	void __iomem *regbase;
+	int irq;
+
+	struct clk *clk_disp_axi;
+	struct clk *clk_disp_dcic;
+	struct clk *clk_csi_mclk;
+
+	/* active vb2 buffers to send to video dev sink */
+	struct imx_media_buffer *active_vb2_buf[2];
+	struct imx_media_dma_buf underrun_buf;
+
+	int buf_num;
+	u32 frame_sequence;
+
+	bool last_eof;
+	bool is_init;
+	bool is_streaming;
+	bool is_csi2;
+
+	struct completion last_eof_completion;
+};
+
+#define imx7_csi_reg_read(_csi, _offset) __raw_readl(_csi->regbase + _offset)
+#define imx7_csi_reg_write(_csi, _val, _offset) \
+	__raw_writel(_val, _csi->regbase + _offset)
+
+static void imx7_csi_clk_enable(struct imx7_csi *csi)
+{
+	clk_prepare_enable(csi->clk_disp_axi);
+	clk_prepare_enable(csi->clk_disp_dcic);
+	clk_prepare_enable(csi->clk_csi_mclk);
+}
+
+static void imx7_csi_clk_disable(struct imx7_csi *csi)
+{
+	clk_disable_unprepare(csi->clk_csi_mclk);
+	clk_disable_unprepare(csi->clk_disp_dcic);
+	clk_disable_unprepare(csi->clk_disp_axi);
+}
+
+static void imx7_csi_hw_reset(struct imx7_csi *csi)
+{
+	imx7_csi_reg_write(csi,
+			   imx7_csi_reg_read(csi, CSI_CSICR3) | BIT_FRMCNT_RST,
+			   CSI_CSICR3);
+
+	imx7_csi_reg_write(csi, CSICR1_RESET_VAL, CSI_CSICR1);
+	imx7_csi_reg_write(csi, CSICR2_RESET_VAL, CSI_CSICR2);
+	imx7_csi_reg_write(csi, CSICR3_RESET_VAL, CSI_CSICR3);
+}
+
+static unsigned long imx7_csi_irq_clear(struct imx7_csi *csi)
+{
+	unsigned long isr;
+
+	isr = imx7_csi_reg_read(csi, CSI_CSISR);
+	imx7_csi_reg_write(csi, isr, CSI_CSISR);
+
+	return isr;
+}
+
+static void imx7_csi_init_interface(struct imx7_csi *csi)
+{
+	unsigned int val = 0;
+	unsigned int imag_para;
+
+	val = BIT_SOF_POL | BIT_REDGE | BIT_GCLK_MODE | BIT_HSYNC_POL |
+		BIT_FCC | 1 << SHIFT_MCLKDIV | BIT_MCLKEN;
+	imx7_csi_reg_write(csi, val, CSI_CSICR1);
+
+	imag_para = (800 << 16) | 600;
+	imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
+
+	val = BIT_DMA_REFLASH_RFF;
+	imx7_csi_reg_write(csi, val, CSI_CSICR3);
+}
+
+static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
+{
+	unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+
+	cr1 |= BIT_SOF_INTEN;
+	cr1 |= BIT_RFF_OR_INT;
+
+	/* still capture needs DMA interrupt */
+	cr1 |= BIT_FB1_DMA_DONE_INTEN;
+	cr1 |= BIT_FB2_DMA_DONE_INTEN;
+
+	cr1 |= BIT_EOF_INT_EN;
+
+	imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+}
+
+static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
+{
+	unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+
+	cr1 &= ~BIT_SOF_INTEN;
+	cr1 &= ~BIT_RFF_OR_INT;
+	cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
+	cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
+	cr1 &= ~BIT_EOF_INT_EN;
+
+	imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+}
+
+static void imx7_csi_hw_enable(struct imx7_csi *csi)
+{
+	unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+	cr |= BIT_CSI_HW_ENABLE;
+
+	imx7_csi_reg_write(csi, cr, CSI_CSICR18);
+}
+
+static void imx7_csi_hw_disable(struct imx7_csi *csi)
+{
+	unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+	cr &= ~BIT_CSI_HW_ENABLE;
+
+	imx7_csi_reg_write(csi, cr, CSI_CSICR18);
+}
+
+static void imx7_csi_dma_reflash(struct imx7_csi *csi)
+{
+	unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+	cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+	cr3 |= BIT_DMA_REFLASH_RFF;
+	imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+}
+
+static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi)
+{
+	unsigned long cr1;
+
+	cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+	imx7_csi_reg_write(csi, cr1 & ~BIT_FCC, CSI_CSICR1);
+	cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+	imx7_csi_reg_write(csi, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+	cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+	imx7_csi_reg_write(csi, cr1 | BIT_FCC, CSI_CSICR1);
+}
+
+static void imx7_csi_buf_stride_set(struct imx7_csi *csi, u32 stride)
+{
+	imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA);
+}
+
+static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable)
+{
+	unsigned long cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+	if (enable)
+		cr18 |= BIT_DEINTERLACE_EN;
+	else
+		cr18 &= ~BIT_DEINTERLACE_EN;
+
+	imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
+}
+
+static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
+{
+	unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+	unsigned long cr2 = imx7_csi_reg_read(csi, CSI_CSICR2);
+
+	/* Burst Type of DMA Transfer from RxFIFO. INCR16 */
+	cr2 |= 0xC0000000;
+
+	cr3 |= BIT_DMA_REQ_EN_RFF;
+	cr3 |= BIT_HRESP_ERR_EN;
+	cr3 &= ~BIT_RXFF_LEVEL;
+	cr3 |= 0x2 << 4;
+
+	imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+	imx7_csi_reg_write(csi, cr2, CSI_CSICR2);
+}
+
+static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
+{
+	unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+
+	cr3 &= ~BIT_DMA_REQ_EN_RFF;
+	cr3 &= ~BIT_HRESP_ERR_EN;
+	imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+}
+
+static void imx7_csi_set_imagpara(struct imx7_csi *csi, int width, int height)
+{
+	int imag_para;
+	int rx_count;
+
+	rx_count = (width * height) >> 2;
+	imx7_csi_reg_write(csi, rx_count, CSI_CSIRXCNT);
+
+	imag_para = (width << 16) | height;
+	imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
+
+	/* reflash the embedded DMA controller */
+	imx7_csi_dma_reflash(csi);
+}
+
+static void imx7_csi_sw_reset(struct imx7_csi *csi)
+{
+	imx7_csi_hw_disable(csi);
+
+	imx7_csi_rx_fifo_clear(csi);
+
+	imx7_csi_dma_reflash(csi);
+
+	usleep_range(2000, 3000);
+
+	imx7_csi_irq_clear(csi);
+
+	imx7_csi_hw_enable(csi);
+}
+
+static void imx7_csi_error_recovery(struct imx7_csi *csi)
+{
+	imx7_csi_hw_disable(csi);
+
+	imx7_csi_rx_fifo_clear(csi);
+
+	imx7_csi_dma_reflash(csi);
+
+	imx7_csi_hw_enable(csi);
+}
+
+static void imx7_csi_init(struct imx7_csi *csi)
+{
+	if (csi->is_init)
+		return;
+
+	imx7_csi_clk_enable(csi);
+	imx7_csi_hw_reset(csi);
+	imx7_csi_init_interface(csi);
+	imx7_csi_dmareq_rff_enable(csi);
+
+	csi->is_init = true;
+}
+
+static void imx7_csi_deinit(struct imx7_csi *csi)
+{
+	if (!csi->is_init)
+		return;
+
+	imx7_csi_hw_reset(csi);
+	imx7_csi_init_interface(csi);
+	imx7_csi_dmareq_rff_disable(csi);
+	imx7_csi_clk_disable(csi);
+
+	csi->is_init = false;
+}
+
+static int imx7_csi_get_upstream_endpoint(struct imx7_csi *csi,
+					  struct v4l2_fwnode_endpoint *ep,
+					  bool skip_mux)
+{
+	struct device_node *endpoint, *port;
+	struct media_entity *src;
+	struct v4l2_subdev *sd;
+	struct media_pad *pad;
+
+	if (!csi->src_sd)
+		return -EPIPE;
+
+	src = &csi->src_sd->entity;
+
+skip_video_mux:
+	/* get source pad of entity directly upstream from src */
+	pad = imx_media_find_upstream_pad(csi->md, src, 0);
+	if (IS_ERR(pad))
+		return PTR_ERR(pad);
+
+	sd = media_entity_to_v4l2_subdev(pad->entity);
+
+	/* To get bus type we may need to skip video mux */
+	if (skip_mux && src->function == MEDIA_ENT_F_VID_MUX) {
+		src = &sd->entity;
+		goto skip_video_mux;
+	}
+
+	/*
+	 * NOTE: this assumes an OF-graph port id is the same as a
+	 * media pad index.
+	 */
+	port = of_graph_get_port_by_id(sd->dev->of_node, pad->index);
+	if (!port)
+		return -ENODEV;
+
+	endpoint = of_get_next_child(port, NULL);
+	of_node_put(port);
+	if (!endpoint)
+		return -ENODEV;
+
+	v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), ep);
+	of_node_put(endpoint);
+
+	return 0;
+}
+
+static int imx7_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 imx7_csi *csi = v4l2_get_subdevdata(sd);
+	struct v4l2_subdev *remote_sd;
+	int ret = 0;
+
+	dev_dbg(csi->dev, "link setup %s -> %s\n", remote->entity->name,
+		local->entity->name);
+
+	mutex_lock(&csi->lock);
+
+	if (local->flags & MEDIA_PAD_FL_SINK) {
+		if (!is_media_entity_v4l2_subdev(remote->entity)) {
+			ret = -EINVAL;
+			goto unlock;
+		}
+
+		remote_sd = media_entity_to_v4l2_subdev(remote->entity);
+
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (csi->src_sd) {
+				ret = -EBUSY;
+				goto unlock;
+			}
+			csi->src_sd = remote_sd;
+		} else {
+			csi->src_sd = NULL;
+		}
+
+		goto init;
+	}
+
+	/* source pad */
+	if (flags & MEDIA_LNK_FL_ENABLED) {
+		if (csi->sink) {
+			ret = -EBUSY;
+			goto unlock;
+		}
+		csi->sink = remote->entity;
+	} else {
+		v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+		v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
+		csi->sink = NULL;
+	}
+
+init:
+	if (csi->sink || csi->src_sd)
+		imx7_csi_init(csi);
+	else
+		imx7_csi_deinit(csi);
+
+unlock:
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
+				      struct media_link *link,
+				      struct v4l2_subdev_format *source_fmt,
+				      struct v4l2_subdev_format *sink_fmt)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	struct v4l2_fwnode_endpoint upstream_ep;
+	int ret;
+
+	ret = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt);
+	if (ret)
+		return ret;
+
+	ret = imx7_csi_get_upstream_endpoint(csi, &upstream_ep, true);
+	if (ret) {
+		v4l2_err(&csi->sd, "failed to find upstream endpoint\n");
+		return ret;
+	}
+
+	mutex_lock(&csi->lock);
+
+	csi->upstream_ep = upstream_ep;
+	csi->is_csi2 = (upstream_ep.bus_type == V4L2_MBUS_CSI2);
+
+	mutex_unlock(&csi->lock);
+
+	return 0;
+}
+
+static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,
+				int buf_num)
+{
+	if (buf_num == 1)
+		imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB2);
+	else
+		imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);
+}
+
+static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
+{
+	struct imx_media_video_dev *vdev = csi->vdev;
+	struct imx_media_buffer *buf;
+	struct vb2_buffer *vb2_buf;
+	dma_addr_t phys[2];
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		buf = imx_media_capture_device_next_buf(vdev);
+		if (buf) {
+			csi->active_vb2_buf[i] = buf;
+			vb2_buf = &buf->vbuf.vb2_buf;
+			phys[i] = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
+		} else {
+			csi->active_vb2_buf[i] = NULL;
+			phys[i] = csi->underrun_buf.phys;
+		}
+
+		imx7_csi_update_buf(csi, phys[i], i);
+	}
+}
+
+static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
+					 enum vb2_buffer_state return_status)
+{
+	struct imx_media_buffer *buf;
+	int i;
+
+	/* return any remaining active frames with return_status */
+	for (i = 0; i < 2; i++) {
+		buf = csi->active_vb2_buf[i];
+		if (buf) {
+			struct vb2_buffer *vb = &buf->vbuf.vb2_buf;
+
+			vb->timestamp = ktime_get_ns();
+			vb2_buffer_done(vb, return_status);
+		}
+	}
+}
+
+static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
+{
+	struct imx_media_video_dev *vdev = csi->vdev;
+	struct imx_media_buffer *done, *next;
+	struct vb2_buffer *vb;
+	dma_addr_t phys;
+
+	done = csi->active_vb2_buf[csi->buf_num];
+	if (done) {
+		done->vbuf.field = vdev->fmt.fmt.pix.field;
+		done->vbuf.sequence = csi->frame_sequence;
+		vb = &done->vbuf.vb2_buf;
+		vb->timestamp = ktime_get_ns();
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+	csi->frame_sequence++;
+
+	/* get next queued buffer */
+	next = imx_media_capture_device_next_buf(vdev);
+	if (next) {
+		phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
+		csi->active_vb2_buf[csi->buf_num] = next;
+	} else {
+		phys = csi->underrun_buf.phys;
+		csi->active_vb2_buf[csi->buf_num] = NULL;
+	}
+
+	imx7_csi_update_buf(csi, phys, csi->buf_num);
+}
+
+static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
+{
+	struct imx7_csi *csi =  data;
+	unsigned long status;
+
+	spin_lock(&csi->irqlock);
+
+	status = imx7_csi_irq_clear(csi);
+
+	if (status & BIT_RFF_OR_INT) {
+		dev_warn(csi->dev, "Rx fifo overflow\n");
+		imx7_csi_error_recovery(csi);
+	}
+
+	if (status & BIT_HRESP_ERR_INT) {
+		dev_warn(csi->dev, "Hresponse error detected\n");
+		imx7_csi_error_recovery(csi);
+	}
+
+	if (status & BIT_ADDR_CH_ERR_INT) {
+		imx7_csi_hw_disable(csi);
+
+		imx7_csi_dma_reflash(csi);
+
+		imx7_csi_hw_enable(csi);
+	}
+
+	if ((status & BIT_DMA_TSF_DONE_FB1) &&
+	    (status & BIT_DMA_TSF_DONE_FB2)) {
+		/*
+		 * For both FB1 and FB2 interrupter bits set case,
+		 * CSI DMA is work in one of FB1 and FB2 buffer,
+		 * but software can not know the state.
+		 * Skip it to avoid base address updated
+		 * when csi work in field0 and field1 will write to
+		 * new base address.
+		 */
+	} else if (status & BIT_DMA_TSF_DONE_FB1) {
+		csi->buf_num = 0;
+	} else if (status & BIT_DMA_TSF_DONE_FB2) {
+		csi->buf_num = 1;
+	}
+
+	if ((status & BIT_DMA_TSF_DONE_FB1) ||
+	    (status & BIT_DMA_TSF_DONE_FB2)) {
+		imx7_csi_vb2_buf_done(csi);
+
+		if (csi->last_eof) {
+			complete(&csi->last_eof_completion);
+			csi->last_eof = false;
+		}
+	}
+
+
+	spin_unlock(&csi->irqlock);
+
+	return IRQ_HANDLED;
+}
+
+static int imx7_csi_dma_start(struct imx7_csi *csi)
+{
+	struct imx_media_video_dev *vdev = csi->vdev;
+	struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
+	int ret;
+
+	ret = imx_media_alloc_dma_buf(csi->md, &csi->underrun_buf,
+				      out_pix->sizeimage);
+	if (ret < 0) {
+		v4l2_warn(&csi->sd, "consider increasing the CMA area\n");
+		return ret;
+	}
+
+	csi->frame_sequence = 0;
+	csi->last_eof = false;
+	init_completion(&csi->last_eof_completion);
+
+	imx7_csi_setup_vb2_buf(csi);
+
+	return 0;
+}
+
+static void imx7_csi_dma_stop(struct imx7_csi *csi)
+{
+	unsigned long flags;
+	int ret;
+
+	/* mark next EOF interrupt as the last before stream off */
+	spin_lock_irqsave(&csi->irqlock, flags);
+	csi->last_eof = true;
+	spin_unlock_irqrestore(&csi->irqlock, flags);
+
+	/*
+	 * and then wait for interrupt handler to mark completion.
+	 */
+	ret = wait_for_completion_timeout(&csi->last_eof_completion,
+				msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
+	if (ret == 0)
+		v4l2_warn(&csi->sd, "wait last EOF timeout\n");
+
+	imx7_csi_hw_disable_irq(csi);
+
+	imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR);
+
+	imx_media_free_dma_buf(csi->md, &csi->underrun_buf);
+}
+
+static int imx7_csi_configure(struct imx7_csi *csi)
+{
+	struct imx_media_video_dev *vdev = csi->vdev;
+	struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
+	__u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code;
+	u32 cr1, cr18;
+
+	if (out_pix->field == V4L2_FIELD_INTERLACED) {
+		imx7_csi_deinterlace_enable(csi, true);
+		imx7_csi_buf_stride_set(csi, out_pix->width);
+	} else {
+		imx7_csi_deinterlace_enable(csi, false);
+		imx7_csi_buf_stride_set(csi, 0);
+	}
+
+	imx7_csi_set_imagpara(csi, out_pix->width, out_pix->height);
+
+	if (!csi->is_csi2)
+		return 0;
+
+	cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+	cr1 &= ~BIT_GCLK_MODE;
+
+	cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+	cr18 &= BIT_MIPI_DATA_FORMAT_MASK;
+	cr18 |= BIT_DATA_FROM_MIPI;
+
+	switch (out_pix->pixelformat) {
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YUYV:
+		cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
+		break;
+	case V4L2_PIX_FMT_SBGGR8:
+		cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
+		break;
+	case V4L2_PIX_FMT_SBGGR16:
+		if (in_code == MEDIA_BUS_FMT_SBGGR10_1X10)
+			cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
+		else if (in_code == MEDIA_BUS_FMT_SBGGR12_1X12)
+			cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
+		else if (in_code == MEDIA_BUS_FMT_SBGGR14_1X14)
+			cr18 |= BIT_MIPI_DATA_FORMAT_RAW14;
+		cr1 |= BIT_PIXEL_BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+	imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
+
+	return 0;
+}
+
+static int imx7_csi_enable(struct imx7_csi *csi)
+{
+	imx7_csi_sw_reset(csi);
+
+	if (csi->is_csi2) {
+		imx7_csi_dmareq_rff_enable(csi);
+		imx7_csi_hw_enable_irq(csi);
+		imx7_csi_hw_enable(csi);
+		return 0;
+	}
+
+	return 0;
+}
+
+static void imx7_csi_disable(struct imx7_csi *csi)
+{
+	imx7_csi_dmareq_rff_disable(csi);
+
+	imx7_csi_hw_disable_irq(csi);
+
+	imx7_csi_buf_stride_set(csi, 0);
+
+	imx7_csi_hw_disable(csi);
+}
+
+static int imx7_csi_streaming_start(struct imx7_csi *csi)
+{
+	int ret;
+
+	ret = imx7_csi_dma_start(csi);
+	if (ret < 0)
+		return ret;
+
+	ret = imx7_csi_configure(csi);
+	if (ret < 0)
+		goto dma_stop;
+
+	imx7_csi_enable(csi);
+
+	return 0;
+
+dma_stop:
+	imx7_csi_dma_stop(csi);
+
+	return ret;
+}
+
+static int imx7_csi_streaming_stop(struct imx7_csi *csi)
+{
+	imx7_csi_dma_stop(csi);
+
+	imx7_csi_disable(csi);
+
+	return 0;
+}
+
+static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	mutex_lock(&csi->lock);
+
+	if (!csi->src_sd || !csi->sink) {
+		ret = -EPIPE;
+		goto out_unlock;
+	}
+
+	if (csi->is_streaming == !!enable)
+		goto out_unlock;
+
+	if (enable) {
+		ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1);
+		if (ret < 0)
+			goto out_unlock;
+
+		ret = imx7_csi_streaming_start(csi);
+		if (ret < 0) {
+			v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+			goto out_unlock;
+		}
+	} else {
+		imx7_csi_streaming_stop(csi);
+
+		v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+	}
+
+	csi->is_streaming = !!enable;
+
+out_unlock:
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static struct v4l2_mbus_framefmt *imx7_csi_get_format(struct imx7_csi *csi,
+					struct v4l2_subdev_pad_config *cfg,
+					unsigned int pad,
+					enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(&csi->sd, cfg, pad);
+
+	return &csi->format_mbus[pad];
+}
+
+static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	const struct imx_media_pixfmt *in_cc;
+	struct v4l2_mbus_framefmt *in_fmt;
+	int ret = 0;
+
+	mutex_lock(&csi->lock);
+
+	in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which);
+
+	in_cc = imx_media_find_mbus_format(in_fmt->code, CS_SEL_ANY, true);
+
+	switch (code->pad) {
+	case IMX7_CSI_PAD_SINK:
+		ret = imx_media_enum_mbus_format(&code->code, code->index,
+						 CS_SEL_ANY, true);
+		break;
+	case IMX7_CSI_PAD_SRC:
+		if (code->index != 0) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+
+		code->code = in_fmt->code;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+out_unlock:
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_format *sdformat)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *fmt;
+	int ret = 0;
+
+	if (sdformat->pad >= IMX7_CSI_PADS_NUM)
+		return -EINVAL;
+
+	mutex_lock(&csi->lock);
+
+	fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+	if (!fmt) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	sdformat->format = *fmt;
+
+out_unlock:
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static void imx7_csi_try_fmt(struct imx7_csi *csi,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *sdformat,
+			     const struct imx_media_pixfmt **cc)
+{
+	const struct imx_media_pixfmt *in_cc;
+	struct v4l2_mbus_framefmt *in_fmt;
+	u32 code;
+
+	in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK,
+				     sdformat->which);
+	if (!in_fmt)
+		return;
+
+	switch (sdformat->pad) {
+	case IMX7_CSI_PAD_SRC:
+		in_cc = imx_media_find_mbus_format(in_fmt->code, CS_SEL_ANY,
+						   true);
+
+		sdformat->format.width = in_fmt->width;
+		sdformat->format.height = in_fmt->height;
+		sdformat->format.code = in_fmt->code;
+		*cc = in_cc;
+
+		sdformat->format.colorspace = in_fmt->colorspace;
+		sdformat->format.xfer_func = in_fmt->xfer_func;
+		sdformat->format.quantization = in_fmt->quantization;
+		sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
+		break;
+	case IMX7_CSI_PAD_SINK:
+		*cc = imx_media_find_mbus_format(sdformat->format.code,
+						 CS_SEL_ANY, true);
+		if (!*cc) {
+			imx_media_enum_mbus_format(&code, 0, CS_SEL_ANY, false);
+			*cc = imx_media_find_mbus_format(code, CS_SEL_ANY,
+							 false);
+			sdformat->format.code = (*cc)->codes[0];
+		}
+
+		imx_media_fill_default_mbus_fields(&sdformat->format, in_fmt,
+						   false);
+		break;
+	default:
+		break;
+	}
+}
+
+static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_format *sdformat)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	struct imx_media_video_dev *vdev = csi->vdev;
+	const struct imx_media_pixfmt *outcc;
+	struct v4l2_mbus_framefmt *outfmt;
+	struct v4l2_pix_format vdev_fmt;
+	const struct imx_media_pixfmt *cc;
+	struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_subdev_format format;
+	int ret = 0;
+
+	if (sdformat->pad >= IMX7_CSI_PADS_NUM)
+		return -EINVAL;
+
+	mutex_lock(&csi->lock);
+
+	if (csi->is_streaming) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	imx7_csi_try_fmt(csi, cfg, sdformat, &cc);
+
+	fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+	if (!fmt) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	*fmt = sdformat->format;
+
+	if (sdformat->pad == IMX7_CSI_PAD_SINK) {
+		/* propagate format to source pads */
+		format.pad = IMX7_CSI_PAD_SRC;
+		format.which = sdformat->which;
+		format.format = sdformat->format;
+		imx7_csi_try_fmt(csi, cfg, &format, &outcc);
+
+		outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC,
+					     sdformat->which);
+		*outfmt = format.format;
+
+		if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+			csi->cc[IMX7_CSI_PAD_SRC] = outcc;
+	}
+
+	if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
+		goto out_unlock;
+
+	csi->cc[sdformat->pad] = cc;
+
+	/* propagate output pad format to capture device */
+	imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt,
+				      &csi->format_mbus[IMX7_CSI_PAD_SRC],
+				      csi->cc[IMX7_CSI_PAD_SRC]);
+	mutex_unlock(&csi->lock);
+	imx_media_capture_device_set_format(vdev, &vdev_fmt);
+
+	return 0;
+
+out_unlock:
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static int imx7_csi_registered(struct v4l2_subdev *sd)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	int ret;
+	int i;
+
+	csi->md = dev_get_drvdata(sd->v4l2_dev->dev);
+
+	for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
+		csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ?
+			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+		/* set a default mbus format  */
+		ret = imx_media_init_mbus_fmt(&csi->format_mbus[i],
+					      800, 600, 0, V4L2_FIELD_NONE,
+					      &csi->cc[i]);
+		if (ret < 0)
+			return ret;
+
+		/* init default frame interval */
+		csi->frame_interval[i].numerator = 1;
+		csi->frame_interval[i].denominator = 30;
+	}
+
+	ret = media_entity_pads_init(&sd->entity, IMX7_CSI_PADS_NUM, csi->pad);
+	if (ret < 0)
+		return ret;
+
+	ret = imx_media_capture_device_register(csi->vdev);
+	if (ret < 0)
+		return ret;
+
+	ret = imx_media_add_video_device(csi->md, csi->vdev);
+	if (ret < 0) {
+		imx_media_capture_device_unregister(csi->vdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void imx7_csi_unregistered(struct v4l2_subdev *sd)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+
+	imx_media_capture_device_unregister(csi->vdev);
+}
+
+static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_pad_config *cfg)
+{
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+	struct v4l2_mbus_framefmt *mf;
+	int ret;
+	int i;
+
+	for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
+		mf = v4l2_subdev_get_try_format(sd, cfg, i);
+
+		ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
+					      &csi->cc[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations imx7_csi_entity_ops = {
+	.link_setup	= imx7_csi_link_setup,
+	.link_validate	= v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
+	.s_stream		= imx7_csi_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
+	.init_cfg =		imx7_csi_init_cfg,
+	.enum_mbus_code =	imx7_csi_enum_mbus_code,
+	.get_fmt =		imx7_csi_get_fmt,
+	.set_fmt =		imx7_csi_set_fmt,
+	.link_validate =	imx7_csi_pad_link_validate,
+};
+
+static const struct v4l2_subdev_ops imx7_csi_subdev_ops = {
+	.video =	&imx7_csi_video_ops,
+	.pad =		&imx7_csi_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops = {
+	.registered	= imx7_csi_registered,
+	.unregistered	= imx7_csi_unregistered,
+};
+
+static int imx7_csi_parse_endpoint(struct device *dev,
+				   struct v4l2_fwnode_endpoint *vep,
+				   struct v4l2_async_subdev *asd)
+{
+	return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL;
+}
+
+static int imx7_csi_parse_dt(struct imx7_csi *csi)
+{
+	struct device *dev = csi->dev;
+
+	csi->clk_disp_axi = devm_clk_get(dev, "axi");
+	if (IS_ERR(csi->clk_disp_axi)) {
+		dev_err(dev, "Could not get csi axi clock\n");
+		return -ENODEV;
+	}
+
+	csi->clk_disp_dcic = devm_clk_get(dev, "dcic");
+	if (IS_ERR(csi->clk_disp_dcic)) {
+		dev_err(dev, "Could not get disp dcic clock\n");
+		return -ENODEV;
+	}
+
+	csi->clk_csi_mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(csi->clk_csi_mclk)) {
+		dev_err(dev, "Could not get csi mclk clock\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int imx7_csi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct imx7_csi *csi;
+	struct resource *res;
+	int ret;
+
+	csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
+	if (!csi)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, &csi->sd);
+	csi->dev = dev;
+
+	ret = imx7_csi_parse_dt(csi);
+	if (ret < 0)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	csi->irq = platform_get_irq(pdev, 0);
+	if (!res || csi->irq < 0) {
+		dev_err(dev, "Missing platform resources data\n");
+		return -ENODEV;
+	}
+
+	csi->regbase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(csi->regbase)) {
+		dev_err(dev, "Failed platform resources map\n");
+		return -ENODEV;
+	}
+
+	spin_lock_init(&csi->irqlock);
+	mutex_init(&csi->lock);
+
+	/* install interrupt handler */
+	ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
+			       (void *)csi);
+	if (ret < 0) {
+		dev_err(dev, "Request CSI IRQ failed.\n");
+		return -ENODEV;
+	}
+
+	/* add media device */
+	csi->imxmd = imx_media_dev_init(dev);
+	if (IS_ERR(csi->imxmd))
+		return PTR_ERR(csi->imxmd);
+
+	ret = imx_media_of_add_csi(csi->imxmd, node);
+	if (ret < 0)
+		goto media_cleanup;
+
+	ret = imx_media_dev_notifier_register(csi->imxmd);
+	if (ret < 0)
+		goto media_cleanup;
+
+	v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops);
+	v4l2_set_subdevdata(&csi->sd, csi);
+	csi->sd.internal_ops = &imx7_csi_internal_ops;
+	csi->sd.entity.ops = &imx7_csi_entity_ops;
+	csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	csi->sd.dev = &pdev->dev;
+	csi->sd.owner = THIS_MODULE;
+	csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI;
+	snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
+
+	csi->vdev = imx_media_capture_device_init(&csi->sd, IMX7_CSI_PAD_SRC);
+	if (IS_ERR(csi->vdev))
+		return PTR_ERR(csi->vdev);
+
+	v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
+	csi->sd.ctrl_handler = &csi->ctrl_hdlr;
+
+	ret = v4l2_async_register_fwnode_subdev(&csi->sd,
+					sizeof(struct v4l2_async_subdev),
+					NULL, 0, imx7_csi_parse_endpoint);
+	if (ret)
+		goto free;
+
+	return 0;
+
+free:
+	v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+	mutex_destroy(&csi->lock);
+	imx_media_capture_device_remove(csi->vdev);
+
+media_cleanup:
+	imx_media_dev_cleanup(csi->imxmd);
+
+	return ret;
+}
+
+static int imx7_csi_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+
+	v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+	mutex_destroy(&csi->lock);
+	imx_media_capture_device_remove(csi->vdev);
+	imx_media_dev_notifier_unregister(csi->imxmd);
+	imx_media_dev_cleanup(csi->imxmd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_async_unregister_subdev(sd);
+
+	return 0;
+}
+
+static const struct of_device_id imx7_csi_of_match[] = {
+	{ .compatible = "fsl,imx7-csi" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
+
+static struct platform_driver imx7_csi_driver = {
+	.probe = imx7_csi_probe,
+	.remove = imx7_csi_remove,
+	.driver = {
+		.of_match_table = imx7_csi_of_match,
+		.name = "imx7-csi",
+	},
+};
+module_platform_driver(imx7_csi_driver);
+
+MODULE_DESCRIPTION("i.MX7 CSI subdev driver");
+MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx7-csi");
-- 
2.17.0

^ permalink raw reply related

* [PATCH v6 02/13] media: staging/imx: rearrange group id to take in account IPU
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media
In-Reply-To: <20180522145245.3143-1-rui.silva@linaro.org>

Some imx system do not have IPU, so prepare the imx media drivers to support
this kind of devices. Rename the group ids to include an _IPU_ prefix, add a new
group id to support systems with only a CSI without IPU, and also
rename the create internal links to make it clear that only systems with IPU
have internal subdevices.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
 drivers/staging/media/imx/imx-ic-common.c     |  6 ++---
 drivers/staging/media/imx/imx-ic-prp.c        | 14 +++++------
 drivers/staging/media/imx/imx-media-csi.c     |  6 ++---
 drivers/staging/media/imx/imx-media-dev.c     | 22 ++++++++++--------
 .../staging/media/imx/imx-media-internal-sd.c | 20 ++++++++--------
 drivers/staging/media/imx/imx-media-utils.c   | 12 +++++-----
 drivers/staging/media/imx/imx-media.h         | 23 ++++++++++---------
 7 files changed, 54 insertions(+), 49 deletions(-)

diff --git a/drivers/staging/media/imx/imx-ic-common.c b/drivers/staging/media/imx/imx-ic-common.c
index cfdd4900a3be..765919487a73 100644
--- a/drivers/staging/media/imx/imx-ic-common.c
+++ b/drivers/staging/media/imx/imx-ic-common.c
@@ -41,13 +41,13 @@ static int imx_ic_probe(struct platform_device *pdev)
 	pdata = priv->dev->platform_data;
 	priv->ipu_id = pdata->ipu_id;
 	switch (pdata->grp_id) {
-	case IMX_MEDIA_GRP_ID_IC_PRP:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
 		priv->task_id = IC_TASK_PRP;
 		break;
-	case IMX_MEDIA_GRP_ID_IC_PRPENC:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
 		priv->task_id = IC_TASK_ENCODER;
 		break;
-	case IMX_MEDIA_GRP_ID_IC_PRPVF:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
 		priv->task_id = IC_TASK_VIEWFINDER;
 		break;
 	default:
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index 98923fc844ce..795ca61f7cea 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -77,7 +77,7 @@ static int prp_start(struct prp_priv *priv)
 	priv->ipu = priv->md->ipu[ic_priv->ipu_id];
 
 	/* set IC to receive from CSI or VDI depending on source */
-	src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_VDIC);
+	src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
 
 	ipu_set_ic_src_mux(priv->ipu, priv->csi_id, src_is_vdic);
 
@@ -238,7 +238,7 @@ static int prp_link_setup(struct media_entity *entity,
 				goto out;
 			}
 			if (priv->sink_sd_prpenc && (remote_sd->grp_id &
-						     IMX_MEDIA_GRP_ID_VDIC)) {
+						     IMX_MEDIA_GRP_ID_IPU_VDIC)) {
 				ret = -EINVAL;
 				goto out;
 			}
@@ -259,7 +259,7 @@ static int prp_link_setup(struct media_entity *entity,
 				goto out;
 			}
 			if (priv->src_sd && (priv->src_sd->grp_id &
-					     IMX_MEDIA_GRP_ID_VDIC)) {
+					     IMX_MEDIA_GRP_ID_IPU_VDIC)) {
 				ret = -EINVAL;
 				goto out;
 			}
@@ -309,13 +309,13 @@ static int prp_link_validate(struct v4l2_subdev *sd,
 		return ret;
 
 	csi = imx_media_find_upstream_subdev(priv->md, &ic_priv->sd.entity,
-					     IMX_MEDIA_GRP_ID_CSI);
+					     IMX_MEDIA_GRP_ID_IPU_CSI);
 	if (IS_ERR(csi))
 		csi = NULL;
 
 	mutex_lock(&priv->lock);
 
-	if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_VDIC) {
+	if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
 		/*
 		 * the ->PRPENC link cannot be enabled if the source
 		 * is the VDIC
@@ -334,10 +334,10 @@ static int prp_link_validate(struct v4l2_subdev *sd,
 
 	if (csi) {
 		switch (csi->grp_id) {
-		case IMX_MEDIA_GRP_ID_CSI0:
+		case IMX_MEDIA_GRP_ID_IPU_CSI0:
 			priv->csi_id = 0;
 			break;
-		case IMX_MEDIA_GRP_ID_CSI1:
+		case IMX_MEDIA_GRP_ID_IPU_CSI1:
 			priv->csi_id = 1;
 			break;
 		default:
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 436f3b8a141b..8a86d111e935 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -981,10 +981,10 @@ static int csi_link_setup(struct media_entity *entity,
 
 		remote_sd = media_entity_to_v4l2_subdev(remote->entity);
 		switch (remote_sd->grp_id) {
-		case IMX_MEDIA_GRP_ID_VDIC:
+		case IMX_MEDIA_GRP_ID_IPU_VDIC:
 			priv->dest = IPU_CSI_DEST_VDIC;
 			break;
-		case IMX_MEDIA_GRP_ID_IC_PRP:
+		case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
 			priv->dest = IPU_CSI_DEST_IC;
 			break;
 		default:
@@ -1829,7 +1829,7 @@ static int imx_csi_probe(struct platform_device *pdev)
 	priv->sd.owner = THIS_MODULE;
 	priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 	priv->sd.grp_id = priv->csi_id ?
-		IMX_MEDIA_GRP_ID_CSI1 : IMX_MEDIA_GRP_ID_CSI0;
+		IMX_MEDIA_GRP_ID_IPU_CSI1 : IMX_MEDIA_GRP_ID_IPU_CSI0;
 	imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
 				    priv->sd.grp_id, ipu_get_num(priv->ipu));
 
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 70fcaf2d358a..9c4d70649857 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -116,7 +116,7 @@ int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
 
 	mutex_lock(&imxmd->mutex);
 
-	if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI) {
+	if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) {
 		ret = imx_media_get_ipu(imxmd, sd);
 		if (ret)
 			goto out;
@@ -140,13 +140,13 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
 
 	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
 		switch (sd->grp_id) {
-		case IMX_MEDIA_GRP_ID_VDIC:
-		case IMX_MEDIA_GRP_ID_IC_PRP:
-		case IMX_MEDIA_GRP_ID_IC_PRPENC:
-		case IMX_MEDIA_GRP_ID_IC_PRPVF:
-		case IMX_MEDIA_GRP_ID_CSI0:
-		case IMX_MEDIA_GRP_ID_CSI1:
-			ret = imx_media_create_internal_links(imxmd, sd);
+		case IMX_MEDIA_GRP_ID_IPU_VDIC:
+		case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
+		case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
+		case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
+		case IMX_MEDIA_GRP_ID_IPU_CSI0:
+		case IMX_MEDIA_GRP_ID_IPU_CSI1:
+			ret = imx_media_create_ipu_internal_links(imxmd, sd);
 			if (ret)
 				return ret;
 			/*
@@ -154,9 +154,13 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
 			 * internal entities, so create the external links
 			 * to the CSI sink pads.
 			 */
-			if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI)
+			if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI)
 				imx_media_create_csi_of_links(imxmd, sd);
 			break;
+		case IMX_MEDIA_GRP_ID_CSI:
+			imx_media_create_csi_of_links(imxmd, sd);
+
+			break;
 		default:
 			/*
 			 * if this subdev has fwnode links, create media
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index 0fdc45dbfb76..5e10d95e5529 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -30,32 +30,32 @@ static const struct internal_subdev_id {
 } isd_id[num_isd] = {
 	[isd_csi0] = {
 		.index = isd_csi0,
-		.grp_id = IMX_MEDIA_GRP_ID_CSI0,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0,
 		.name = "imx-ipuv3-csi",
 	},
 	[isd_csi1] = {
 		.index = isd_csi1,
-		.grp_id = IMX_MEDIA_GRP_ID_CSI1,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1,
 		.name = "imx-ipuv3-csi",
 	},
 	[isd_vdic] = {
 		.index = isd_vdic,
-		.grp_id = IMX_MEDIA_GRP_ID_VDIC,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC,
 		.name = "imx-ipuv3-vdic",
 	},
 	[isd_ic_prp] = {
 		.index = isd_ic_prp,
-		.grp_id = IMX_MEDIA_GRP_ID_IC_PRP,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP,
 		.name = "imx-ipuv3-ic",
 	},
 	[isd_ic_prpenc] = {
 		.index = isd_ic_prpenc,
-		.grp_id = IMX_MEDIA_GRP_ID_IC_PRPENC,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC,
 		.name = "imx-ipuv3-ic",
 	},
 	[isd_ic_prpvf] = {
 		.index = isd_ic_prpvf,
-		.grp_id = IMX_MEDIA_GRP_ID_IC_PRPVF,
+		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF,
 		.name = "imx-ipuv3-ic",
 	},
 };
@@ -229,8 +229,8 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd,
 	return ret;
 }
 
-int imx_media_create_internal_links(struct imx_media_dev *imxmd,
-				    struct v4l2_subdev *sd)
+int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
+					struct v4l2_subdev *sd)
 {
 	const struct internal_subdev *intsd;
 	const struct internal_pad *intpad;
@@ -312,8 +312,8 @@ static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
 		 * of_parse_subdev().
 		 */
 		switch (isd->id->grp_id) {
-		case IMX_MEDIA_GRP_ID_CSI0:
-		case IMX_MEDIA_GRP_ID_CSI1:
+		case IMX_MEDIA_GRP_ID_IPU_CSI0:
+		case IMX_MEDIA_GRP_ID_IPU_CSI1:
 			ret = 0;
 			break;
 		default:
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index fab98fc0d6a0..7a429e3d32cb 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -686,20 +686,20 @@ void imx_media_grp_id_to_sd_name(char *sd_name, int sz, u32 grp_id, int ipu_id)
 	int id;
 
 	switch (grp_id) {
-	case IMX_MEDIA_GRP_ID_CSI0...IMX_MEDIA_GRP_ID_CSI1:
-		id = (grp_id >> IMX_MEDIA_GRP_ID_CSI_BIT) - 1;
+	case IMX_MEDIA_GRP_ID_IPU_CSI0...IMX_MEDIA_GRP_ID_IPU_CSI1:
+		id = (grp_id >> IMX_MEDIA_GRP_ID_IPU_CSI_BIT) - 1;
 		snprintf(sd_name, sz, "ipu%d_csi%d", ipu_id + 1, id);
 		break;
-	case IMX_MEDIA_GRP_ID_VDIC:
+	case IMX_MEDIA_GRP_ID_IPU_VDIC:
 		snprintf(sd_name, sz, "ipu%d_vdic", ipu_id + 1);
 		break;
-	case IMX_MEDIA_GRP_ID_IC_PRP:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
 		snprintf(sd_name, sz, "ipu%d_ic_prp", ipu_id + 1);
 		break;
-	case IMX_MEDIA_GRP_ID_IC_PRPENC:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
 		snprintf(sd_name, sz, "ipu%d_ic_prpenc", ipu_id + 1);
 		break;
-	case IMX_MEDIA_GRP_ID_IC_PRPVF:
+	case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
 		snprintf(sd_name, sz, "ipu%d_ic_prpvf", ipu_id + 1);
 		break;
 	default:
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 8ec9738aced9..394b7486af6d 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -249,8 +249,8 @@ void imx_media_fim_free(struct imx_media_fim *fim);
 
 /* imx-media-internal-sd.c */
 int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd);
-int imx_media_create_internal_links(struct imx_media_dev *imxmd,
-				    struct v4l2_subdev *sd);
+int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
+					struct v4l2_subdev *sd);
 void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd);
 
 /* imx-media-of.c */
@@ -276,14 +276,15 @@ void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev,
 void imx_media_capture_device_error(struct imx_media_video_dev *vdev);
 
 /* subdev group ids */
-#define IMX_MEDIA_GRP_ID_CSI2      BIT(8)
-#define IMX_MEDIA_GRP_ID_CSI_BIT   9
-#define IMX_MEDIA_GRP_ID_CSI       (0x3 << IMX_MEDIA_GRP_ID_CSI_BIT)
-#define IMX_MEDIA_GRP_ID_CSI0      BIT(IMX_MEDIA_GRP_ID_CSI_BIT)
-#define IMX_MEDIA_GRP_ID_CSI1      (2 << IMX_MEDIA_GRP_ID_CSI_BIT)
-#define IMX_MEDIA_GRP_ID_VDIC      BIT(11)
-#define IMX_MEDIA_GRP_ID_IC_PRP    BIT(12)
-#define IMX_MEDIA_GRP_ID_IC_PRPENC BIT(13)
-#define IMX_MEDIA_GRP_ID_IC_PRPVF  BIT(14)
+#define IMX_MEDIA_GRP_ID_CSI2          BIT(8)
+#define IMX_MEDIA_GRP_ID_CSI           BIT(9)
+#define IMX_MEDIA_GRP_ID_IPU_CSI_BIT   10
+#define IMX_MEDIA_GRP_ID_IPU_CSI       (0x3 << IMX_MEDIA_GRP_ID_IPU_CSI_BIT)
+#define IMX_MEDIA_GRP_ID_IPU_CSI0      BIT(IMX_MEDIA_GRP_ID_IPU_CSI_BIT)
+#define IMX_MEDIA_GRP_ID_IPU_CSI1      (2 << IMX_MEDIA_GRP_ID_IPU_CSI_BIT)
+#define IMX_MEDIA_GRP_ID_IPU_VDIC      BIT(12)
+#define IMX_MEDIA_GRP_ID_IPU_IC_PRP    BIT(13)
+#define IMX_MEDIA_GRP_ID_IPU_IC_PRPENC BIT(14)
+#define IMX_MEDIA_GRP_ID_IPU_IC_PRPVF  BIT(15)
 
 #endif
-- 
2.17.0

^ permalink raw reply related

* [PATCH v6 01/13] media: staging/imx: refactor imx media device probe
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media
In-Reply-To: <20180522145245.3143-1-rui.silva@linaro.org>

Refactor and move media device initialization code to a new common module, so it
can be used by other devices, this will allow for example a near to introduce
imx7 CSI driver, to use this media device.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
 drivers/staging/media/imx/Makefile            |   1 +
 .../staging/media/imx/imx-media-dev-common.c  | 100 ++++++++++++++++++
 drivers/staging/media/imx/imx-media-dev.c     |  86 ++++-----------
 drivers/staging/media/imx/imx-media-of.c      |   6 +-
 drivers/staging/media/imx/imx-media.h         |  15 +++
 5 files changed, 139 insertions(+), 69 deletions(-)
 create mode 100644 drivers/staging/media/imx/imx-media-dev-common.c

diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index 698a4210316e..a30b3033f9a3 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o
+imx-media-objs += imx-media-dev-common.o
 imx-media-common-objs := imx-media-utils.o imx-media-fim.o
 imx-media-ic-objs := imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o
 
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
new file mode 100644
index 000000000000..98aea5f94174
--- /dev/null
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL
+/*
+ * V4L2 Media Controller Driver for Freescale common i.MX5/6/7 SOC
+ *
+ * Copyright (c) 2018 Linaro Ltd
+ * Copyright (c) 2016 Mentor Graphics Inc.
+ */
+
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include "imx-media.h"
+
+static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
+	.bound = imx_media_subdev_bound,
+	.complete = imx_media_probe_complete,
+};
+
+static const struct media_device_ops imx_media_md_ops = {
+	.link_notify = imx_media_link_notify,
+};
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev)
+{
+	struct imx_media_dev *imxmd;
+	int ret;
+
+	imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
+	if (!imxmd)
+		return ERR_PTR(-ENOMEM);
+
+	dev_set_drvdata(dev, imxmd);
+
+	strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
+	imxmd->md.ops = &imx_media_md_ops;
+	imxmd->md.dev = dev;
+
+	mutex_init(&imxmd->mutex);
+
+	imxmd->v4l2_dev.mdev = &imxmd->md;
+	strlcpy(imxmd->v4l2_dev.name, "imx-media",
+		sizeof(imxmd->v4l2_dev.name));
+
+	media_device_init(&imxmd->md);
+
+	ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
+	if (ret < 0) {
+		v4l2_err(&imxmd->v4l2_dev,
+			 "Failed to register v4l2_device: %d\n", ret);
+		goto cleanup;
+	}
+
+	dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
+
+	INIT_LIST_HEAD(&imxmd->vdev_list);
+
+	return imxmd;
+
+cleanup:
+	media_device_cleanup(&imxmd->md);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_init);
+
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
+{
+	int ret;
+
+	/* no subdevs? just bail */
+	if (imxmd->notifier.num_subdevs == 0) {
+		v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
+		return -ENODEV;
+	}
+
+	/* prepare the async subdev notifier and register it */
+	imxmd->notifier.ops = &imx_media_subdev_ops;
+	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
+					   &imxmd->notifier);
+	if (ret) {
+		v4l2_err(&imxmd->v4l2_dev,
+			 "v4l2_async_notifier_register failed with %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_notifier_register);
+
+void imx_media_dev_cleanup(struct imx_media_dev *imxmd)
+{
+	v4l2_device_unregister(&imxmd->v4l2_dev);
+	media_device_cleanup(&imxmd->md);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_cleanup);
+
+void imx_media_dev_notifier_unregister(struct imx_media_dev *imxmd)
+{
+	v4l2_async_notifier_cleanup(&imxmd->notifier);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_notifier_unregister);
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 7e7bd1c6c81b..70fcaf2d358a 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -107,9 +107,9 @@ static int imx_media_get_ipu(struct imx_media_dev *imxmd,
 }
 
 /* async subdev bound notifier */
-static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
-				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+			   struct v4l2_subdev *sd,
+			   struct v4l2_async_subdev *asd)
 {
 	struct imx_media_dev *imxmd = notifier2dev(notifier);
 	int ret = 0;
@@ -293,7 +293,7 @@ static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
 }
 
 /* async subdev complete notifier */
-static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
 {
 	struct imx_media_dev *imxmd = notifier2dev(notifier);
 	int ret;
@@ -317,11 +317,6 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
 	return media_device_register(&imxmd->md);
 }
 
-static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
-	.bound = imx_media_subdev_bound,
-	.complete = imx_media_probe_complete,
-};
-
 /*
  * adds controls to a video device from an entity subdevice.
  * Continues upstream from the entity's sink pads.
@@ -365,8 +360,8 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
 	return ret;
 }
 
-static int imx_media_link_notify(struct media_link *link, u32 flags,
-				 unsigned int notification)
+int imx_media_link_notify(struct media_link *link, u32 flags,
+			  unsigned int notification)
 {
 	struct media_entity *source = link->source->entity;
 	struct imx_media_pad_vdev *pad_vdev;
@@ -429,10 +424,6 @@ static int imx_media_link_notify(struct media_link *link, u32 flags,
 	return ret;
 }
 
-static const struct media_device_ops imx_media_md_ops = {
-	.link_notify = imx_media_link_notify,
-};
-
 static int imx_media_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -440,74 +431,36 @@ static int imx_media_probe(struct platform_device *pdev)
 	struct imx_media_dev *imxmd;
 	int ret;
 
-	imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
-	if (!imxmd)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, imxmd);
-
-	strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
-	imxmd->md.ops = &imx_media_md_ops;
-	imxmd->md.dev = dev;
-
-	mutex_init(&imxmd->mutex);
-
-	imxmd->v4l2_dev.mdev = &imxmd->md;
-	strlcpy(imxmd->v4l2_dev.name, "imx-media",
-		sizeof(imxmd->v4l2_dev.name));
-
-	media_device_init(&imxmd->md);
-
-	ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
-	if (ret < 0) {
-		v4l2_err(&imxmd->v4l2_dev,
-			 "Failed to register v4l2_device: %d\n", ret);
-		goto cleanup;
-	}
-
-	dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
-
-	INIT_LIST_HEAD(&imxmd->vdev_list);
+	imxmd = imx_media_dev_init(dev);
+	if (IS_ERR(imxmd))
+		return PTR_ERR(imxmd);
 
 	ret = imx_media_add_of_subdevs(imxmd, node);
 	if (ret) {
 		v4l2_err(&imxmd->v4l2_dev,
 			 "add_of_subdevs failed with %d\n", ret);
-		goto notifier_cleanup;
+		goto dev_cleanup;
 	}
 
 	ret = imx_media_add_internal_subdevs(imxmd);
 	if (ret) {
 		v4l2_err(&imxmd->v4l2_dev,
 			 "add_internal_subdevs failed with %d\n", ret);
-		goto notifier_cleanup;
-	}
-
-	/* no subdevs? just bail */
-	if (imxmd->notifier.num_subdevs == 0) {
-		ret = -ENODEV;
-		goto notifier_cleanup;
+		goto dev_cleanup;
 	}
 
-	/* prepare the async subdev notifier and register it */
-	imxmd->notifier.ops = &imx_media_subdev_ops;
-	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
-					   &imxmd->notifier);
-	if (ret) {
-		v4l2_err(&imxmd->v4l2_dev,
-			 "v4l2_async_notifier_register failed with %d\n", ret);
+	ret = imx_media_dev_notifier_register(imxmd);
+	if (ret < 0)
 		goto del_int;
-	}
 
 	return 0;
 
 del_int:
 	imx_media_remove_internal_subdevs(imxmd);
-notifier_cleanup:
-	v4l2_async_notifier_cleanup(&imxmd->notifier);
-	v4l2_device_unregister(&imxmd->v4l2_dev);
-cleanup:
-	media_device_cleanup(&imxmd->md);
+
+dev_cleanup:
+	imx_media_dev_cleanup(imxmd);
+
 	return ret;
 }
 
@@ -520,10 +473,9 @@ static int imx_media_remove(struct platform_device *pdev)
 
 	v4l2_async_notifier_unregister(&imxmd->notifier);
 	imx_media_remove_internal_subdevs(imxmd);
-	v4l2_async_notifier_cleanup(&imxmd->notifier);
-	v4l2_device_unregister(&imxmd->v4l2_dev);
+	imx_media_dev_notifier_unregister(imxmd);
 	media_device_unregister(&imxmd->md);
-	media_device_cleanup(&imxmd->md);
+	imx_media_dev_cleanup(imxmd);
 
 	return 0;
 }
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 1c9175433ba6..a0020cc7b3f3 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -20,7 +20,8 @@
 #include <video/imx-ipu-v3.h>
 #include "imx-media.h"
 
-static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
+			 struct device_node *csi_np)
 {
 	int ret;
 
@@ -45,6 +46,7 @@ static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
 
 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
 			     struct device_node *np)
@@ -57,7 +59,7 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
 		if (!csi_np)
 			break;
 
-		ret = of_add_csi(imxmd, csi_np);
+		ret = imx_media_of_add_csi(imxmd, csi_np);
 		of_node_put(csi_np);
 		if (ret)
 			return ret;
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 44532cd5b812..8ec9738aced9 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -224,6 +224,19 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
 			       struct fwnode_handle *fwnode,
 			       struct platform_device *pdev);
 
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+			   struct v4l2_subdev *sd,
+			   struct v4l2_async_subdev *asd);
+int imx_media_link_notify(struct media_link *link, u32 flags,
+			  unsigned int notification);
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier);
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev);
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd);
+
+void imx_media_dev_cleanup(struct imx_media_dev *imxmd);
+void imx_media_dev_notifier_unregister(struct imx_media_dev *imxmd);
+
 /* imx-media-fim.c */
 struct imx_media_fim;
 void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp);
@@ -247,6 +260,8 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd,
 			      struct v4l2_subdev *sd);
 int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
 				  struct v4l2_subdev *csi);
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
+			 struct device_node *csi_np);
 
 /* imx-media-capture.c */
 struct imx_media_video_dev *
-- 
2.17.0

^ permalink raw reply related

* [PATCH v6 00/13] media: staging/imx7: add i.MX7 media driver
From: Rui Miguel Silva @ 2018-05-22 14:52 UTC (permalink / raw)
  To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
	Rob Herring
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
	Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
	linux-media

Hi,
This series introduces the Media driver to work with the i.MX7 SoC. it uses the
already existing imx media core drivers but since the i.MX7, contrary to
i.MX5/6, do not have an IPU and because of that some changes in the imx media
core are made along this series to make it support that case.

This patches adds CSI and MIPI-CSI2 drivers for i.MX7, along with several
configurations changes for this to work as a capture subsystem. Some bugs are
also fixed along the line. And necessary documentation.

For a more detailed view of the capture paths, pads links in the i.MX7 please
take a look at the documentation in PATCH 14.

The system used to test and develop this was the Warp7 board with an OV2680
sensor, which output format is 10-bit bayer. So, only MIPI interface was
tested, a scenario with an parallel input would nice to have.

*Important note*, this code depends on Steve Longerbeam series [0]:
[PATCH v4 00/13] media: imx: Switch to subdev notifiers
which the merging status is not clear to me, but the changes in there make
senses to this series

Bellow goes an example of the output of the pads and links and the output of
v4l2-compliance testing.

The v4l-utils version used is:
v4l2-compliance SHA   : 47d43b130dc6e9e0edc900759fb37649208371e4 from Apr 4th.

The Media Driver fail some tests but this failures are coming from code out of
scope of this series (video-mux, imx-capture), and some from the sensor OV2680
but that I think not related with the sensor driver but with the testing and
core.

The csi and mipi-csi entities pass all compliance tests.

Cheers,
    Rui

[0]: https://www.mail-archive.com/linux-media@vger.kernel.org/msg131186.html

v5->v6:
Rob Herring:
 - rename power-domain node name from: pgc-power-domain to power-domain
 - change mux-control-cells to 0
 - remove bus-width from mipi bindings and dts
 - remove err... regarding clock names line
 - remove clk-settle from example
 - split mipi-csi2 and csi bindings per file
 - add OF graph description to CSI

Philipp Zabel:
 - rework group IDs and rename them with an _IPU_ prefix, this allowed to remove
   the ipu_present flag need.

v4->v5:
Sakari Ailus:
 - fix remove of the capture entries in dts bindings in the right patch

Stephen Boyd:
 - Send all series to clk list

v3->v4:
Philipp Zabel:
 - refactor initialization code from media device probe to be possible to used
   from other modules
 - Remove index of csi from all accurrencs (dts, code, documentation)
 - Remove need for capture node for imx7
 - fix pinctrl for ov2680
 - add reviewed tag to add multiplexer controls patch

Fabio Estevam:
 - remove always on from new regulator

Randy Dunlap:
 - several text editing fixes in documentation

Myself:
 - rebase on top of v4 of Steve series
 - change CSI probe to initialize imx media device
 - remove csi mux parallel endpoint from mux to avoid warning message

v2->v3:
Philipp Zabel:
 - use of_match_device in imx-media-dev instead of of_device_match
 - fix number of data lanes from 4 to 2
 - change the clock definitions and use of mipi
 - move hs-settle from endpoint

Rob Herring:
 - fix phy-supply description
 - add vendor properties
 - fix examples indentations

Stephen Boyd: patch 3/14
 - fix double sign-off
 - add fixes tag

Dong Aisheng: patch 3/14
 - fix double sign-off
 - add Acked-by tag

Shawn Guo:
patch 4/14
 - remove line breakage in parent redifiniton
 - added Acked-by tag

 - dropped CMA area increase and add more verbose information in case of
   dma allocation failure
patch 9/14
 - remove extra line between cells and reg masks

Myself:
 - rework on frame end in csi
 - add rxcount in csi driver
 - add power supplies to ov2680 node and fix gpio polarity

v1->v2:
Dan Carpenter:
 - fix return paths and codes;
 - fix clk_frequency validation and return code;
 - handle the csi remove (release resources that was missing)
 - revert the logic arround the ipu_present flag

Philipp Zabel:
 - drop patch that changed the rgb formats and address the pixel/bus format in
   mipi_csis code.

MySelf:
 - add patch that add ov2680 node to the warp7 dts, so the all data path is
   complete.
 - add linux-clk mailing list to the clock patches cc:

 media-ctl -p
Media controller API version 4.17.0

Media device information
------------------------
driver          imx-media
model           imx-media
serial
bus info
hw revision     0x0
driver version  4.17.0

Device topology
- entity 1: csi (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        pad0: Sink
                [fmt:SBGGR10_1X10/800x600 field:none]
                <- "csi_mux":2 [ENABLED]
        pad1: Source
                [fmt:SBGGR10_1X10/800x600 field:none]
                -> "csi capture":0 [ENABLED]

- entity 4: csi capture (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
        pad0: Sink
                <- "csi":1 [ENABLED]

- entity 10: csi_mux (3 pads, 2 links)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev1
        pad0: Sink
                [fmt:unknown/0x0]
        pad1: Sink
                [fmt:SBGGR10_1X10/800x600 field:none]
                <- "imx7-mipi-csis.0":1 [ENABLED]
        pad2: Source
                [fmt:SBGGR10_1X10/800x600 field:none]
                -> "csi":0 [ENABLED]

- entity 14: imx7-mipi-csis.0 (2 pads, 2 links)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev2
        pad0: Sink
                [fmt:SBGGR10_1X10/800x600 field:none]
                <- "ov2680 1-0036":0 [ENABLED]
        pad1: Source
                [fmt:SBGGR10_1X10/800x600 field:none]
                -> "csi_mux":1 [ENABLED]

- entity 17: ov2680 1-0036 (1 pad, 1 link)
             type V4L2 subdev subtype Sensor flags 0
             device node name /dev/v4l-subdev3
        pad0: Source
                [fmt:SBGGR10_1X10/800x600 field:none]
                -> "imx7-mipi-csis.0":0 [ENABLED]

compliance tests:
v4l2-compliance SHA   : 47d43b130dc6e9e0edc900759fb37649208371e4

Compliance test for device /dev/media0:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0

Required ioctls:
        test MEDIA_IOC_DEVICE_INFO: OK

Allow for multiple opens:
        test second /dev/media0 open: OK
        test MEDIA_IOC_DEVICE_INFO: OK
        test for unlimited opens: OK

Media Controller ioctls:
                Entity: 0x00000001 (Name: 'csi', Function: 0x00005002)
                Entity: 0x00000004 (Name: 'csi capture', Function: 0x00010001)
                Entity: 0x0000000a (Name: 'csi_mux', Function: 0x00005001)
                Entity: 0x0000000e (Name: 'imx7-mipi-csis.0', Function: 0x00005002)
                Entity: 0x00000011 (Name: 'ov2680 1-0036', Function: 0x00020001)
                Interface: 0x03000005 (Type: 0x00000200)
                Interface: 0x03000019 (Type: 0x00000203)
                Interface: 0x0300001b (Type: 0x00000203)
                Interface: 0x0300001d (Type: 0x00000203)
                Interface: 0x0300001f (Type: 0x00000203)
                Pad: 0x01000002
                Pad: 0x01000003
                Pad: 0x01000007
                Pad: 0x0100000b
                Pad: 0x0100000c
                Pad: 0x0100000d
                Pad: 0x0100000f
                Pad: 0x01000010
                Pad: 0x01000012
                Link: 0x02000006
                Link: 0x02000008
                Link: 0x02000013
                Link: 0x02000015
                Link: 0x02000017
                Link: 0x0200001a
                Link: 0x0200001c
                Link: 0x0200001e
                Link: 0x02000020
        test MEDIA_IOC_G_TOPOLOGY: OK
        Entities: 5 Interfaces: 5 Pads: 9 Links: 9
                Entity: 0x00000001 (Name: 'csi', Type: 0x00020000
                Entity: 0x00000004 (Name: 'csi capture', Type: 0x00010001
                Entity: 0x0000000a (Name: 'csi_mux', Type: 0x00020000
                Entity: 0x0000000e (Name: 'imx7-mipi-csis.0', Type: 0x00020000
                Entity: 0x00000011 (Name: 'ov2680 1-0036', Type: 0x00020001
                Entity Links: 0x00000001 (Name: 'csi')
                Entity Links: 0x00000004 (Name: 'csi capture')
                Entity Links: 0x0000000a (Name: 'csi_mux')
                Entity Links: 0x0000000e (Name: 'imx7-mipi-csis.0')
                Entity Links: 0x00000011 (Name: 'ov2680 1-0036')
        test MEDIA_IOC_ENUM_ENTITIES/LINKS: OK
        test MEDIA_IOC_SETUP_LINK: OK

--------------------------------------------------------------------------------

Compliance test for device /dev/video0:

Driver Info:
        Driver name      : imx-media-captu
        Card type        : imx-media-capture
        Bus info         : platform:csi
        Driver version   : 4.17.0
        Capabilities     : 0x84200001
                Video Capture
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps      : 0x04200001
                Video Capture
                Streaming
                Extended Pix Format
Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0
Interface Info:
        ID               : 0x03000005
        Type             : V4L Video
Entity Info:
        ID               : 0x00000004 (4)
        Name             : csi capture
        Function         : V4L2 I/O
        Pad 0x01000007   : Sink
          Link 0x02000008: from remote pad 0x1000003 of entity 'csi': Data, Enabled

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second /dev/video0 open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
                fail: v4l2-test-input-output.cpp(420): G_INPUT not supported for a capture device
        test VIDIOC_G/S/ENUMINPUT: FAIL
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
                info: checking v4l2_queryctrl of control 'User Controls' (0x00980001)
                info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
                info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
                info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
                info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
                info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
                info: checking v4l2_queryctrl of control 'Camera Controls' (0x009a0001)
                info: checking v4l2_queryctrl of control 'Auto Exposure' (0x009a0901)
                info: checking v4l2_queryctrl of control 'Image Processing Controls' (0x009f0001)
                info: checking v4l2_queryctrl of control 'Test Pattern' (0x009f0903)
                info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
                info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
                info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
                info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
                info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
        test VIDIOC_QUERYCTRL: OK
                info: checking control 'User Controls' (0x00980001)
                info: checking control 'Exposure' (0x00980911)
                info: checking control 'Gain, Automatic' (0x00980912)
                info: checking control 'Gain' (0x00980913)
                info: checking control 'Horizontal Flip' (0x00980914)
                info: checking control 'Vertical Flip' (0x00980915)
                info: checking control 'Camera Controls' (0x009a0001)
                info: checking control 'Auto Exposure' (0x009a0901)
                info: checking control 'Image Processing Controls' (0x009f0001)
                info: checking control 'Test Pattern' (0x009f0903)
        test VIDIOC_G/S_CTRL: OK
                info: checking extended control 'User Controls' (0x00980001)
                info: checking extended control 'Exposure' (0x00980911)
                info: checking extended control 'Gain, Automatic' (0x00980912)
                info: checking extended control 'Gain' (0x00980913)
                info: checking extended control 'Horizontal Flip' (0x00980914)
                info: checking extended control 'Vertical Flip' (0x00980915)
                info: checking extended control 'Camera Controls' (0x009a0001)
                info: checking extended control 'Auto Exposure' (0x009a0901)
                info: checking extended control 'Image Processing Controls' (0x009f0001)
                info: checking extended control 'Test Pattern' (0x009f0903)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK
                info: checking control event 'User Controls' (0x00980001)
                fail: v4l2-test-controls.cpp(796): subscribe event for control 'User Controls' failed
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 10 Private Controls: 0

Format ioctls:
                info: found 1 formats for buftype 1
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK
        test VIDIOC_TRY_FMT: OK
        test VIDIOC_S_FMT: OK
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
                info: test buftype Video Capture
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
        test VIDIOC_EXPBUF: OK

--------------------------------------------------------------------------------

Compliance test for device /dev/v4l-subdev0:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0
Interface Info:
        ID               : 0x03000019
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x00000001 (1)
        Name             : csi
        Function         : Video Interface Bridge
        Pad 0x01000002   : Sink
          Link 0x02000015: from remote pad 0x100000d of entity 'csi_mux': Data, Enabled
        Pad 0x01000003   : Source
          Link 0x02000008: to remote pad 0x1000007 of entity 'csi capture': Data, Enabled

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK

Allow for multiple opens:
        test second /dev/v4l-subdev0 open: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device ioctls (Sink Pad 0):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Sub-Device ioctls (Source Pad 1):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
        test VIDIOC_QUERYCTRL: OK
        test VIDIOC_G/S_CTRL: OK
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 0 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test VIDIOC_EXPBUF: OK (Not Supported)

--------------------------------------------------------------------------------

Compliance test for device /dev/v4l-subdev1:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0
Interface Info:
        ID               : 0x0300001b
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x0000000a (10)
        Name             : csi_mux
        Function         : Video Muxer
        Pad 0x0100000b   : Sink
        Pad 0x0100000c   : Sink
          Link 0x02000013: from remote pad 0x1000010 of entity 'imx7-mipi-csis.0': Data, Enabled
        Pad 0x0100000d   : Source
          Link 0x02000015: to remote pad 0x1000002 of entity 'csi': Data, Enabled

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK

Allow for multiple opens:
        test second /dev/v4l-subdev1 open: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device ioctls (Sink Pad 0):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
                fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
        test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
                fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
        test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Sub-Device ioctls (Sink Pad 1):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
                fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
        test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(381): s_fmt.format.code == ~0U
        test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Sub-Device ioctls (Source Pad 2):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
                fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
        test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
                fail: v4l2-test-subdevs.cpp(313): fmt.code == 0 || fmt.code == ~0U
                fail: v4l2-test-subdevs.cpp(369): checkMBusFrameFmt(node, s_fmt.format)
        test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
        test VIDIOC_QUERYCTRL: OK (Not Supported)
        test VIDIOC_G/S_CTRL: OK (Not Supported)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 0 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test VIDIOC_EXPBUF: OK (Not Supported)

--------------------------------------------------------------------------------

Compliance test for device /dev/v4l-subdev2:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0
Interface Info:
        ID               : 0x0300001d
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x0000000e (14)
        Name             : imx7-mipi-csis.0
        Function         : Video Interface Bridge
        Pad 0x0100000f   : Sink
          Link 0x02000017: from remote pad 0x1000012 of entity 'ov2680 1-0036': Data, Enabled
        Pad 0x01000010   : Source
          Link 0x02000013: to remote pad 0x100000c of entity 'csi_mux': Data, Enabled

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK

Allow for multiple opens:
        test second /dev/v4l-subdev2 open: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device ioctls (Sink Pad 0):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Sub-Device ioctls (Source Pad 1):
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
        test VIDIOC_QUERYCTRL: OK (Not Supported)
        test VIDIOC_G/S_CTRL: OK (Not Supported)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 0 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test VIDIOC_EXPBUF: OK (Not Supported)

--------------------------------------------------------------------------------

Compliance test for device /dev/v4l-subdev3:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           :
        Bus info         :
        Media version    : 4.17.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.17.0
Interface Info:
        ID               : 0x0300001f
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x00000011 (17)
        Name             : ov2680 1-0036
        Function         : Camera Sensor
        Pad 0x01000012   : Source
          Link 0x02000017: to remote pad 0x100000f of entity 'imx7-mipi-csis.0': Data, Enabled

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK

Allow for multiple opens:
        test second /dev/v4l-subdev3 open: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device ioctls (Source Pad 0):
                fail: v4l2-test-subdevs.cpp(57): node->enum_frame_interval_pad >= 0
                fail: v4l2-test-subdevs.cpp(183): ret && ret != ENOTTY
                fail: v4l2-test-subdevs.cpp(248): ret && ret != ENOTTY
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: FAIL
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK

Control ioctls:
                info: checking v4l2_queryctrl of control 'User Controls' (0x00980001)
                info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
                info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
                info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
                info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
                info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
                info: checking v4l2_queryctrl of control 'Camera Controls' (0x009a0001)
                info: checking v4l2_queryctrl of control 'Auto Exposure' (0x009a0901)
                info: checking v4l2_queryctrl of control 'Image Processing Controls' (0x009f0001)
                info: checking v4l2_queryctrl of control 'Test Pattern' (0x009f0903)
                info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
                info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
                info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
                info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
                info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
        test VIDIOC_QUERYCTRL: OK
                info: checking control 'User Controls' (0x00980001)
                info: checking control 'Exposure' (0x00980911)
                info: checking control 'Gain, Automatic' (0x00980912)
                info: checking control 'Gain' (0x00980913)
                info: checking control 'Horizontal Flip' (0x00980914)
                info: checking control 'Vertical Flip' (0x00980915)
                info: checking control 'Camera Controls' (0x009a0001)
                info: checking control 'Auto Exposure' (0x009a0901)
                info: checking control 'Image Processing Controls' (0x009f0001)
                info: checking control 'Test Pattern' (0x009f0903)
        test VIDIOC_G/S_CTRL: OK
                info: checking extended control 'User Controls' (0x00980001)
                info: checking extended control 'Exposure' (0x00980911)
                info: checking extended control 'Gain, Automatic' (0x00980912)
                info: checking extended control 'Gain' (0x00980913)
                info: checking extended control 'Horizontal Flip' (0x00980914)
                info: checking extended control 'Vertical Flip' (0x00980915)
                info: checking extended control 'Camera Controls' (0x009a0001)
                info: checking extended control 'Auto Exposure' (0x009a0901)
                info: checking extended control 'Image Processing Controls' (0x009f0001)
                info: checking extended control 'Test Pattern' (0x009f0903)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK
                info: checking control event 'User Controls' (0x00980001)
                fail: v4l2-test-controls.cpp(796): subscribe event for control 'User Controls' failed
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 10 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test VIDIOC_EXPBUF: OK (Not Supported)

Total: 267, Succeeded: 257, Failed: 10, Warnings: 0

Rui Miguel Silva (13):
  media: staging/imx: refactor imx media device probe
  media: staging/imx: rearrange group id to take in account IPU
  media: staging/imx7: add imx7 CSI subdev driver
  clk: imx7d: fix mipi dphy div parent
  clk: imx7d: reset parent for mipi csi root
  media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7
  media: dt-bindings: add bindings for i.MX7 media driver
  ARM: dts: imx7s: add mipi phy power domain
  ARM: dts: imx7s: add multiplexer controls
  ARM: dts: imx7: Add video mux, csi and mipi_csi and connections
  ARM: dts: imx7s-warp: add ov2680 sensor node
  media: imx7.rst: add documentation for i.MX7 media driver
  media: staging/imx: add i.MX7 entries to TODO file

 .../devicetree/bindings/media/imx7-csi.txt    |   44 +
 .../bindings/media/imx7-mipi-csi2.txt         |   82 +
 Documentation/media/v4l-drivers/imx7.rst      |  157 ++
 Documentation/media/v4l-drivers/index.rst     |    1 +
 arch/arm/boot/dts/imx7s-warp.dts              |   95 ++
 arch/arm/boot/dts/imx7s.dtsi                  |   43 +-
 drivers/clk/imx/clk-imx7d.c                   |    4 +-
 drivers/staging/media/imx/Kconfig             |    9 +-
 drivers/staging/media/imx/Makefile            |    4 +
 drivers/staging/media/imx/TODO                |    9 +
 drivers/staging/media/imx/imx-ic-common.c     |    6 +-
 drivers/staging/media/imx/imx-ic-prp.c        |   14 +-
 drivers/staging/media/imx/imx-media-csi.c     |    6 +-
 .../staging/media/imx/imx-media-dev-common.c  |  100 ++
 drivers/staging/media/imx/imx-media-dev.c     |  108 +-
 .../staging/media/imx/imx-media-internal-sd.c |   20 +-
 drivers/staging/media/imx/imx-media-of.c      |    6 +-
 drivers/staging/media/imx/imx-media-utils.c   |   12 +-
 drivers/staging/media/imx/imx-media.h         |   38 +-
 drivers/staging/media/imx/imx7-media-csi.c    | 1352 +++++++++++++++++
 drivers/staging/media/imx/imx7-mipi-csis.c    | 1134 ++++++++++++++
 21 files changed, 3122 insertions(+), 122 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/imx7-csi.txt
 create mode 100644 Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt
 create mode 100644 Documentation/media/v4l-drivers/imx7.rst
 create mode 100644 drivers/staging/media/imx/imx-media-dev-common.c
 create mode 100644 drivers/staging/media/imx/imx7-media-csi.c
 create mode 100644 drivers/staging/media/imx/imx7-mipi-csis.c

-- 
2.17.0

^ permalink raw reply

* Re: [PATCH 9/9] ARM: dts: silk: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:46 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-9-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)

Drop @0?
4m?

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 8/9] ARM: dts: alt: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:45 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-8-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader),256k(system),-(user)

Drop @0?

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 7/9] ARM: dts: gose: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:44 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-7-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)

Drop @0? 4m?

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 6/9] ARM: dts: wheat: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:43 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-6-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)

I think the "@0" can be dropped, as it's optional?
4m?

(Gaining more knowledge during reviewing ;-)

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 5/9] ARM: dts: porter: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:34 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-5-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader_prg),4096k(user_prg),-(flash_fs)

4m?

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 3/9] ARM: dts: stout: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:33 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-3-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:512k@0(loader),256k(uboot),256k(uboot-env),-(flash)
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 2/9] ARM: dts: lager: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:32 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-2-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)

I guess s/4096k/4m/ works, too?

> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH v3] arm64: allwinner: a64: Add Amarula A64-Relic initial support
From: Maxime Ripard @ 2018-05-22 14:30 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Michael Trimarchi, Icenowy Zheng,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20180522132228.6564-1-jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 757 bytes --]

On Tue, May 22, 2018 at 06:52:28PM +0530, Jagan Teki wrote:
> Amarula A64-Relic is Allwinner A64 based IoT device, which support
> - Allwinner A64 Cortex-A53
> - Mali-400MP2 GPU
> - AXP803 PMIC
> - 1GB DDR3 RAM
> - 8GB eMMC
> - AP6330 Wifi/BLE
> - MIPI-DSI
> - CSI: OV5640 sensor
> - USB OTG

You claim that this is doing OTG...

[..]

> +&usb_otg {
> +	dr_mode = "peripheral";
> +	status = "okay";
> +};

... and yet you're setting it as peripheral...

> +&usbphy {
> +	usb0_id_det-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
> +	usb0_vbus-supply = <&reg_drivevbus>;

While you have an ID pin and a controllable VBUS. Which one is it?

Maxime
-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply

* Re: [PATCH 4/9] ARM: dts: koelsch: Drop MTD partitioning from DT
From: Geert Uytterhoeven @ 2018-05-22 14:29 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-4-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Drop the MTD partitioning from DT, since it does not describe HW
> and to give way to a more flexible kernel command line partition
> passing.
>
> To retain the original partitioning, assure you have enabled
> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
> following to your kernel command line:
>
>   mtdparts=spi0.0:512k@0(loader),5632k(user),-(flash)
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 1/9] ARM: shmobile: defconfig: Enable MTD command line partition parsing
From: Geert Uytterhoeven @ 2018-05-22 14:29 UTC (permalink / raw)
  To: Marek Vasut
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Geert Uytterhoeven, Wolfram Sang, Linux-Renesas, Laurent Pinchart,
	Simon Horman, Linux ARM, Marek Vasut
In-Reply-To: <20180522120257.13232-1-marek.vasut+renesas@gmail.com>

On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> In preparation for removing MTD partitioning from the DTs and moving
> it over to kernel command line partition parsing, enable the support
> for kernel command line MTD partition parsing.
>
> The argument for not having MTD partitions in the DT is the same as
> for not having hard drive partitions in DT, neither describes the
> hardware itself, so it shouldn't be in the DT. Furthermore, kernel
> command line MTD partition passing allows greater flexibility in
> case someone decided to repartition the flash, which is well in the
> realm of possibility with these systems.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [RESEND PATCH 2/5] mtd: rawnand: add NVIDIA Tegra NAND Flash controller driver
From: Stefan Agner @ 2018-05-22 14:28 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: boris.brezillon, dwmw2, computersforpeace, marek.vasut, robh+dt,
	mark.rutland, thierry.reding, mturquette, sboyd, dev,
	miquel.raynal, richard, marcel, krzk, benjamin.lindqvist,
	jonathanh, pdeschrijver, pgaikwad, mirza.krak, linux-mtd,
	linux-tegra, devicetree, linux-kernel, linux-clk
In-Reply-To: <0a3c683c-15fd-d05c-4aa2-5fa109c892c6@gmail.com>

On 22.05.2018 15:34, Dmitry Osipenko wrote:
> On 22.05.2018 15:19, Stefan Agner wrote:
>> [review sent to my first patch sent off-ml, moving to ml thread]
>>
>> On 21.05.2018 16:05, Dmitry Osipenko wrote:
>>> Hello Stefan,
>>>
>>> I don't have expertise to review the actual NAND-related driver logic, so I only
>>> reviewed the basics. The driver code looks good to me, though I've couple minor
>>> comments.
>>>
>>> On 21.05.2018 03:16, Stefan Agner wrote:
>>>> Add support for the NAND flash controller found on NVIDIA
>>>> Tegra 2 SoCs. This implementation does not make use of the
>>>> command queue feature. Regular operations/data transfers are
>>>> done in PIO mode. Page read/writes with hardware ECC make
>>>> use of the DMA for data transfer.
>>>>
>>>> Signed-off-by: Lucas Stach <dev@lynxeye.de>
>>>> Signed-off-by: Stefan Agner <stefan@agner.ch>
>>>> ---

<snip>

>>>> +static int tegra_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
>>>> +				uint8_t *buf, int oob_required, int page)
>>>> +{
>>>> +	struct tegra_nand *nand = to_tegra_nand(mtd);
>>>> +	u32 value, addrs;
>>>> +
>>>> +	writel(NAND_CMD_READ0, nand->regs + CMD_1);
>>>> +	writel(NAND_CMD_READSTART, nand->regs + CMD_2);
>>>> +
>>>> +	addrs = tegra_nand_fill_address(mtd, chip, page);
>>>> +
>>>> +	value = readl(nand->regs + CFG);
>>>> +	value |= CFG_HW_ECC | CFG_ERR_COR;
>>>> +	writel(value, nand->regs + CFG);
>>>> +
>>>> +	writel(mtd->writesize - 1, nand->regs + DMA_CFG_A);
>>>> +	writel(nand->data_dma, nand->regs + DATA_PTR);
>>>> +
>>>> +	if (oob_required) {
>>>> +		writel(mtd_ooblayout_count_freebytes(mtd) - 1,
>>>> +		       nand->regs + DMA_CFG_B);
>>>> +		writel(nand->oob_dma, nand->regs + TAG_PTR);
>>>> +	} else {
>>>> +		writel(0, nand->regs + DMA_CFG_B);
>>>> +		writel(0, nand->regs + TAG_PTR);
>>>> +	}
>>>> +
>>>> +	value = DMA_CTRL_GO | DMA_CTRL_IN | DMA_CTRL_PERF_EN |
>>>> +		DMA_CTRL_REUSE | DMA_CTRL_IE_DONE | DMA_CTRL_IS_DONE |
>>>> +		DMA_CTRL_BURST_8 | DMA_CTRL_EN_A;
>>>
>>> Wouldn't be more efficient to set DMA burst to 16 words? The writesize seems
>>> always aligned to at least 64 words.
>>>
>>
>> Hm, haven't tested 16 words, 8 was the setting Lucas used.
>>
>> Are you sure this is only about write size? Not sure, but isn't the ECC
>> area also DMA'd? On Colibri we use RS with t=8, hence 144 bytes parity,
>> so this would be properly aligned non the less...
>>
> 
> I don't know, that's up to you to figure out. Is RS stands for Reed-Solomon and
> t=8 is the max number of redundant words?
> 

RS = Reed-Solomon
t=8 maximum symbol errors

Will do some testing and check whether it fails.

--
Stefan

^ permalink raw reply

* Re: [PATCH v2] ARM64: dts: sun50i: h5: Add spi flash node for OrangePi PC2
From: Maxime Ripard @ 2018-05-22 14:27 UTC (permalink / raw)
  To: Emmanuel Vadot
  Cc: wens, robh+dt, mark.rutland, catalin.marinas, will.deacon,
	linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20180521115426.92115-1-manu@freebsd.org>

[-- Attachment #1: Type: text/plain, Size: 359 bytes --]

On Mon, May 21, 2018 at 01:54:26PM +0200, Emmanuel Vadot wrote:
> The OrangePi PC2 have an mx25l1606e spi flash.
> Add a node for it.
> 
> Signed-off-by: Emmanuel Vadot <manu@freebsd.org>

Fixed the prefix and applied, thanks!
Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v2] ARM64: dts: sun50i: a64: Add spi flash node for sopine
From: Maxime Ripard @ 2018-05-22 14:27 UTC (permalink / raw)
  To: Emmanuel Vadot
  Cc: wens, robh+dt, mark.rutland, catalin.marinas, will.deacon,
	linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20180521115413.92070-1-manu@freebsd.org>

[-- Attachment #1: Type: text/plain, Size: 380 bytes --]

On Mon, May 21, 2018 at 01:54:13PM +0200, Emmanuel Vadot wrote:
> The Sopine and Pine64-LTS have a winbond w25q128 spi flash on spi0.
> Add a node for it.
> 
> Signed-off-by: Emmanuel Vadot <manu@freebsd.org>

Fixed the prefix and applied, thanks!
Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* [PATCH v8 2/2] leds: lm3601x: Introduce the lm3601x LED driver
From: Dan Murphy @ 2018-05-22 14:24 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jacek.anaszewski, andy.shevchenko
  Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
In-Reply-To: <20180522142417.19639-1-dmurphy@ti.com>

Introduce the family of LED devices that can
drive a torch, strobe or IR LED.

The LED driver can be configured with a strobe
timer to execute a strobe flash.  The IR LED
brightness is controlled via the torch brightness
register.

The data sheet for each the LM36010 and LM36011
LED drivers can be found here:
http://www.ti.com/product/LM36010
http://www.ti.com/product/LM36011

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v8 - Removed OF Kconfig dependency, change strobe to flash, updated label generation,
fixed brightness calculation, added mutex_destroy and flash_unregister - https://patchwork.kernel.org/patch/10416163/

v7 - Numerous fixes to many to list.  Highlights are moved from OF APIs to device_property
APIs, updated LED registration, timeout to reg algorithim, and fixed label generation -
https://patchwork.kernel.org/patch/10401437/
v6 - This driver has been heavily modified from v5.  There is no longer reading
of individual child nodes.  There are too many changes to list here see -
https://patchwork.kernel.org/patch/10392123/
v5 - Fixed magic numbers, change reg cache type, added of_put_node to release
the dt node ref, and I did not change the remove function to leave the LED in its
state on driver removal - https://patchwork.kernel.org/patch/10391741/
v4 - Fixed Cocci issue using ARRAY_SIZE - https://patchwork.kernel.org/patch/10389259/
v3 - removed wildcard dt compatible, fixed copyright, fixed struct doc, removed
RO registers from default, added regmap volatile for FLAGS_REG, updated regmap cache type,
fixed unlock and extra semi colon in strobe_set, removed unnecessary out label
in led register and fixed checking of the ret in brightness_set - https://patchwork.kernel.org/patch/10386243/
v2 - Fixed kbuild issue and removed unused cdev_strobe - https://patchwork.kernel.org/patch/10384585/


 drivers/leds/Kconfig        |   9 +
 drivers/leds/Makefile       |   1 +
 drivers/leds/leds-lm3601x.c | 492 ++++++++++++++++++++++++++++++++++++
 3 files changed, 502 insertions(+)
 create mode 100644 drivers/leds/leds-lm3601x.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..d95d436e6089 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -145,6 +145,15 @@ config LEDS_LM3692X
 	  This option enables support for the TI LM3692x family
 	  of white LED string drivers used for backlighting.
 
+config LEDS_LM3601X
+	tristate "LED support for LM3601x Chips"
+	depends on LEDS_CLASS && I2C
+	depends on LEDS_CLASS_FLASH
+	select REGMAP_I2C
+	help
+	  This option enables support for the TI LM3601x family
+	  of flash, torch and indicator classes.
+
 config LEDS_LOCOMO
 	tristate "LED Support for Locomo device"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..b79807fe1b67 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_LEDS_MLXREG)		+= leds-mlxreg.o
 obj-$(CONFIG_LEDS_NIC78BX)		+= leds-nic78bx.o
 obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
+obj-$(CONFIG_LEDS_LM3601X)		+= leds-lm3601x.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/leds-lm3601x.c
new file mode 100644
index 000000000000..b1f0ede704c1
--- /dev/null
+++ b/drivers/leds/leds-lm3601x.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+// Flash and torch driver for Texas Instruments LM3601X LED
+// Flash driver chip family
+// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <uapi/linux/uleds.h>
+
+#define LM3601X_LED_IR		0x0
+#define LM3601X_LED_TORCH	0x1
+
+/* Registers */
+#define LM3601X_ENABLE_REG	0x01
+#define LM3601X_CFG_REG		0x02
+#define LM3601X_LED_FLASH_REG	0x03
+#define LM3601X_LED_TORCH_REG	0x04
+#define LM3601X_FLAGS_REG	0x05
+#define LM3601X_DEV_ID_REG	0x06
+
+#define LM3601X_SW_RESET	BIT(7)
+
+/* Enable Mode bits */
+#define LM3601X_MODE_STANDBY	0x00
+#define LM3601X_MODE_IR_DRV	BIT(0)
+#define LM3601X_MODE_TORCH	BIT(1)
+#define LM3601X_MODE_STROBE	(BIT(0) | BIT(1))
+#define LM3601X_STRB_EN		BIT(2)
+#define LM3601X_STRB_EDGE_TRIG	BIT(3)
+#define LM3601X_IVFM_EN		BIT(4)
+
+#define LM36010_BOOST_LIMIT_28	BIT(5)
+#define LM36010_BOOST_FREQ_4MHZ	BIT(6)
+#define LM36010_BOOST_MODE_PASS	BIT(7)
+
+/* Flag Mask */
+#define LM3601X_FLASH_TIME_OUT	BIT(0)
+#define LM3601X_UVLO_FAULT	BIT(1)
+#define LM3601X_THERM_SHUTDOWN	BIT(2)
+#define LM3601X_THERM_CURR	BIT(3)
+#define LM36010_CURR_LIMIT	BIT(4)
+#define LM3601X_SHORT_FAULT	BIT(5)
+#define LM3601X_IVFM_TRIP	BIT(6)
+#define LM36010_OVP_FAULT	BIT(7)
+
+#define LM3601X_MAX_TORCH_I_UA	376000
+#define LM3601X_MIN_TORCH_I_UA	2400
+#define LM3601X_TORCH_REG_DIV	2965
+
+#define LM3601X_MAX_STROBE_I_UA	1500000
+#define LM3601X_MIN_STROBE_I_UA	11000
+#define LM3601X_STROBE_REG_DIV	11800
+
+#define LM3601X_TIMEOUT_MASK	0x1e
+#define LM3601X_ENABLE_MASK	(LM3601X_MODE_IR_DRV | LM3601X_MODE_TORCH)
+
+#define LM3601X_LOWER_STEP_US	40000
+#define LM3601X_UPPER_STEP_US	200000
+#define LM3601X_MIN_TIMEOUT_US	40000
+#define LM3601X_MAX_TIMEOUT_US	1600000
+#define LM3601X_TIMEOUT_XOVER_US 400000
+
+enum lm3601x_type {
+	CHIP_LM36010 = 0,
+	CHIP_LM36011,
+};
+
+/**
+ * struct lm3601x_led -
+ * @fled_cdev: flash LED class device pointer
+ * @client: Pointer to the I2C client
+ * @regmap: Devices register map
+ * @lock: Lock for reading/writing the device
+ * @led_name: LED label for the Torch or IR LED
+ * @flash_timeout: the timeout for the flash
+ * @last_flag: last known flags register value
+ * @torch_current_max: maximum current for the torch
+ * @flash_current_max: maximum current for the flash
+ * @max_flash_timeout: maximum timeout for the flash
+ * @led_mode: The mode to enable either IR or Torch
+ */
+struct lm3601x_led {
+	struct led_classdev_flash fled_cdev;
+	struct i2c_client *client;
+	struct regmap *regmap;
+	struct mutex lock;
+
+	char led_name[LED_MAX_NAME_SIZE];
+
+	unsigned int flash_timeout;
+	unsigned int last_flag;
+
+	u32 torch_current_max;
+	u32 flash_current_max;
+	u32 max_flash_timeout;
+
+	u32 led_mode;
+};
+
+static const struct reg_default lm3601x_regmap_defs[] = {
+	{ LM3601X_ENABLE_REG, 0x20 },
+	{ LM3601X_CFG_REG, 0x15 },
+	{ LM3601X_LED_FLASH_REG, 0x00 },
+	{ LM3601X_LED_TORCH_REG, 0x00 },
+};
+
+static bool lm3601x_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LM3601X_FLAGS_REG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config lm3601x_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = LM3601X_DEV_ID_REG,
+	.reg_defaults = lm3601x_regmap_defs,
+	.num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs),
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = lm3601x_volatile_reg,
+};
+
+static struct lm3601x_led *fled_cdev_to_led(
+				struct led_classdev_flash *fled_cdev)
+{
+	return container_of(fled_cdev, struct lm3601x_led, fled_cdev);
+}
+
+static int lm3601x_read_faults(struct lm3601x_led *led)
+{
+	int flags_val;
+	int ret;
+
+	ret = regmap_read(led->regmap, LM3601X_FLAGS_REG, &flags_val);
+	if (ret < 0)
+		return -EIO;
+
+	led->last_flag = 0;
+
+	if (flags_val & LM36010_OVP_FAULT)
+		led->last_flag |= LED_FAULT_OVER_VOLTAGE;
+
+	if (flags_val & (LM3601X_THERM_SHUTDOWN | LM3601X_THERM_CURR))
+		led->last_flag |= LED_FAULT_OVER_TEMPERATURE;
+
+	if (flags_val & LM3601X_SHORT_FAULT)
+		led->last_flag |= LED_FAULT_SHORT_CIRCUIT;
+
+	if (flags_val & LM36010_CURR_LIMIT)
+		led->last_flag |= LED_FAULT_OVER_CURRENT;
+
+	if (flags_val & LM3601X_UVLO_FAULT)
+		led->last_flag |= LED_FAULT_UNDER_VOLTAGE;
+
+	if (flags_val & LM3601X_IVFM_TRIP)
+		led->last_flag |= LED_FAULT_INPUT_VOLTAGE;
+
+	if (flags_val & LM3601X_THERM_SHUTDOWN)
+		led->last_flag |= LED_FAULT_LED_OVER_TEMPERATURE;
+
+	return led->last_flag;
+}
+
+static int lm3601x_brightness_set(struct led_classdev *cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev);
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+	int ret, led_mode_val;
+
+	mutex_lock(&led->lock);
+
+	ret = lm3601x_read_faults(led);
+	if (ret < 0)
+		goto out;
+
+	if (led->led_mode == LM3601X_LED_TORCH)
+		led_mode_val = LM3601X_MODE_TORCH;
+	else
+		led_mode_val = LM3601X_MODE_IR_DRV;
+
+	if (brightness == LED_OFF) {
+		ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+					led_mode_val, LED_OFF);
+		goto out;
+	}
+
+	ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+				LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,
+				led_mode_val);
+out:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static int lm3601x_flash_set(struct led_classdev_flash *fled_cdev,
+				bool state)
+{
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+	int timeout_reg_val = 0;
+	int current_timeout;
+	int ret;
+
+	mutex_lock(&led->lock);
+
+	ret = regmap_read(led->regmap, LM3601X_CFG_REG, &current_timeout);
+	if (ret < 0)
+		goto out;
+
+	if (led->flash_timeout >= LM3601X_TIMEOUT_XOVER_US)
+		timeout_reg_val = led->flash_timeout / LM3601X_UPPER_STEP_US + 0x07;
+	else
+		timeout_reg_val = led->flash_timeout / LM3601X_LOWER_STEP_US - 0x01;
+
+	if (led->flash_timeout != current_timeout)
+		ret = regmap_update_bits(led->regmap, LM3601X_CFG_REG,
+					LM3601X_TIMEOUT_MASK, timeout_reg_val);
+
+	if (state)
+		ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+					LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,
+					LM3601X_MODE_STROBE);
+	else
+		ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+					LM3601X_MODE_STROBE, LED_OFF);
+
+	ret = lm3601x_read_faults(led);
+out:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static int lm3601x_flash_brightness_set(struct led_classdev_flash *fled_cdev,
+					u32 brightness)
+{
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+	int ret;
+	u8 brightness_val;
+
+	mutex_lock(&led->lock);
+	ret = lm3601x_read_faults(led);
+	if (ret < 0)
+		goto out;
+
+	if (brightness == LED_OFF) {
+		ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+					LM3601X_MODE_STROBE, LED_OFF);
+		goto out;
+	}
+
+	brightness_val = brightness / LM3601X_STROBE_REG_DIV;
+
+	ret = regmap_write(led->regmap, LM3601X_LED_FLASH_REG, brightness_val);
+out:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static int lm3601x_flash_timeout_set(struct led_classdev_flash *fled_cdev,
+				u32 timeout)
+{
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+	int ret = 0;
+
+	mutex_lock(&led->lock);
+
+	led->flash_timeout = timeout;
+
+	mutex_unlock(&led->lock);
+
+	return ret;
+}
+
+static int lm3601x_flash_get(struct led_classdev_flash *fled_cdev,
+				bool *state)
+{
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+	int ret;
+	int flash_state;
+
+	mutex_lock(&led->lock);
+
+	ret = regmap_read(led->regmap, LM3601X_ENABLE_REG, &flash_state);
+	if (ret < 0)
+		goto out;
+
+	*state = flash_state & LM3601X_MODE_STROBE;
+
+out:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static int lm3601x_flash_fault_get(struct led_classdev_flash *fled_cdev,
+				u32 *fault)
+{
+	struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
+
+	lm3601x_read_faults(led);
+
+	*fault = led->last_flag;
+
+	return 0;
+}
+
+static const struct led_flash_ops flash_ops = {
+	.flash_brightness_set	= lm3601x_flash_brightness_set,
+	.strobe_set		= lm3601x_flash_set,
+	.strobe_get		= lm3601x_flash_get,
+	.timeout_set		= lm3601x_flash_timeout_set,
+	.fault_get		= lm3601x_flash_fault_get,
+};
+
+static int lm3601x_register_leds(struct lm3601x_led *led)
+{
+	struct led_classdev *led_cdev;
+	struct led_flash_setting *setting;
+
+	led->fled_cdev.ops = &flash_ops;
+
+	setting = &led->fled_cdev.timeout;
+	setting->min = LM3601X_MIN_TIMEOUT_US;
+	setting->max = led->max_flash_timeout;
+	setting->step = LM3601X_LOWER_STEP_US;
+	setting->val = led->max_flash_timeout;
+
+	setting = &led->fled_cdev.brightness;
+	setting->min = LM3601X_MIN_STROBE_I_UA;
+	setting->max = led->flash_current_max;
+	setting->step = LM3601X_TORCH_REG_DIV;
+	setting->val = led->flash_current_max;
+
+	led_cdev = &led->fled_cdev.led_cdev;
+	led_cdev->name = led->led_name;
+	led_cdev->brightness_set_blocking = lm3601x_brightness_set;
+	led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max,
+						LM3601X_TORCH_REG_DIV);
+	led_cdev->flags |= LED_DEV_CAP_FLASH;
+
+	return led_classdev_flash_register(&led->client->dev, &led->fled_cdev);
+}
+
+static int lm3601x_parse_node(struct lm3601x_led *led,
+			      struct device_node *node)
+{
+	struct fwnode_handle *child = NULL;
+	int ret = -ENODEV;
+	const char *name;
+
+	child = device_get_next_child_node(&led->client->dev, child);
+	if (!child) {
+		dev_err(&led->client->dev, "No LED Child node\n");
+		return ret;
+	}
+
+	ret = fwnode_property_read_u32(child, "reg", &led->led_mode);
+	if (ret) {
+		dev_err(&led->client->dev, "reg DT property missing\n");
+		goto out_err;
+	}
+
+	if (led->led_mode > LM3601X_LED_TORCH ||
+	    led->led_mode < LM3601X_LED_IR) {
+		dev_warn(&led->client->dev, "Invalid led mode requested\n");
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	ret = fwnode_property_read_string(child, "label", &name);
+	if (ret) {
+		if (led->led_mode == LM3601X_LED_TORCH)
+			name = "torch";
+		else
+			name = "infrared";
+	}
+
+	snprintf(led->led_name, sizeof(led->led_name),
+		"%s:%s", led->client->name, name);
+
+	ret = fwnode_property_read_u32(child, "led-max-microamp",
+					&led->torch_current_max);
+	if (ret < 0) {
+		dev_warn(&led->client->dev,
+			"led-max-microamp DT property missing\n");
+		goto out_err;
+	}
+
+	ret = fwnode_property_read_u32(child, "flash-max-microamp",
+				&led->flash_current_max);
+	if (ret < 0) {
+		dev_warn(&led->client->dev,
+			 "flash-max-microamp DT property missing\n");
+		goto out_err;
+	}
+
+	ret = fwnode_property_read_u32(child, "flash-max-timeout-us",
+				&led->max_flash_timeout);
+	if (ret < 0) {
+		dev_warn(&led->client->dev,
+			 "flash-max-timeout-us DT property missing\n");
+		goto out_err;
+	}
+
+out_err:
+	fwnode_handle_put(child);
+	return ret;
+}
+
+static int lm3601x_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct lm3601x_led *led;
+	int err;
+
+	led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->client = client;
+	i2c_set_clientdata(client, led);
+
+	err = lm3601x_parse_node(led, client->dev.of_node);
+	if (err < 0)
+		return -ENODEV;
+
+	led->regmap = devm_regmap_init_i2c(client, &lm3601x_regmap);
+	if (IS_ERR(led->regmap)) {
+		err = PTR_ERR(led->regmap);
+		dev_err(&client->dev,
+			"Failed to allocate register map: %d\n", err);
+		return err;
+	}
+
+	mutex_init(&led->lock);
+
+	return lm3601x_register_leds(led);
+}
+
+static int lm3601x_remove(struct i2c_client *client)
+{
+	struct lm3601x_led *led = i2c_get_clientdata(client);
+
+	led_classdev_flash_unregister(&led->fled_cdev);
+	mutex_destroy(&led->lock);
+
+	return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
+			   LM3601X_ENABLE_MASK,
+			   LM3601X_MODE_STANDBY);
+}
+
+static const struct i2c_device_id lm3601x_id[] = {
+	{ "LM36010", CHIP_LM36010 },
+	{ "LM36011", CHIP_LM36011 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm3601x_id);
+
+static const struct of_device_id of_lm3601x_leds_match[] = {
+	{ .compatible = "ti,lm36010", },
+	{ .compatible = "ti,lm36011", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, of_lm3601x_leds_match);
+
+static struct i2c_driver lm3601x_i2c_driver = {
+	.driver = {
+		.name = "lm3601x",
+		.of_match_table = of_lm3601x_leds_match,
+	},
+	.probe = lm3601x_probe,
+	.remove = lm3601x_remove,
+	.id_table = lm3601x_id,
+};
+module_i2c_driver(lm3601x_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3601X");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.17.0.582.gccdcbd54c

^ permalink raw reply related

* [PATCH v8 1/2] dt: bindings: lm3601x: Introduce the lm3601x driver
From: Dan Murphy @ 2018-05-22 14:24 UTC (permalink / raw)
  To: robh+dt, mark.rutland, jacek.anaszewski, andy.shevchenko
  Cc: devicetree, linux-kernel, linux-leds, Dan Murphy

Introduce the device tree bindings for the lm3601x
family of LED torch, flash and IR drivers.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---

v8 - No changes - https://patchwork.kernel.org/patch/10416161/

v7 - Removed led-sources in favor of reg, fixed malformatted ranges - https://patchwork.kernel.org/patch/10401435/
v6 - Removed multiple led child nodes, fixed example to display micro ranges
for corresponding child nodes and added led-sources to define the current driver -
https://patchwork.kernel.org/patch/10392121/
v5 - No changes - https://patchwork.kernel.org/patch/10391743/
v4 - Added " " around "=", changed strobe to flash on label, removed "support and
register" comment and change ir lable to ir:torch - See v2 patchworks for comments
v3 - Removed wildcard compatible - https://patchwork.kernel.org/patch/10386241/
v2 - No changes - https://patchwork.kernel.org/patch/10384587/

 .../devicetree/bindings/leds/leds-lm3601x.txt | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-lm3601x.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-lm3601x.txt b/Documentation/devicetree/bindings/leds/leds-lm3601x.txt
new file mode 100644
index 000000000000..a88b2c41e75b
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-lm3601x.txt
@@ -0,0 +1,45 @@
+* Texas Instruments - lm3601x Single-LED Flash Driver
+
+The LM3601X are ultra-small LED flash drivers that
+provide a high level of adjustability.
+
+Required properties:
+	- compatible : Can be one of the following
+		"ti,lm36010"
+		"ti,lm36011"
+	- reg : I2C slave address
+	- #address-cells : 1
+	- #size-cells : 0
+
+Required child properties:
+	- reg : 0 - Indicates a IR mode
+		1 - Indicates a Torch (white LED) mode
+
+Required properties for flash LED child nodes:
+	See Documentation/devicetree/bindings/leds/common.txt
+	- flash-max-microamp : Range from 11mA - 1.5A
+	- flash-max-timeout-us : Range from 40ms - 1600ms
+	- led-max-microamp : Range from 2.4mA - 376mA
+
+Optional child properties:
+	- label : see Documentation/devicetree/bindings/leds/common.txt
+
+Example:
+led-controller@64 {
+	compatible = "ti,lm36010";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	reg = <0x64>;
+
+	led@0 {
+		reg = <1>;
+		label = "white:torch";
+		led-max-microamp = <376000>;
+		flash-max-microamp = <1500000>;
+		flash-max-timeout-us = <1600000>;
+	};
+}
+
+For more product information please see the links below:
+http://www.ti.com/product/LM36010
+http://www.ti.com/product/LM36011
-- 
2.17.0.582.gccdcbd54c

^ permalink raw reply related

* RE: [PATCH v5 05/14] usb: typec: add API to get typec basic port power and data config
From: Jun Li @ 2018-05-22 14:19 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Mats Karrman, robh+dt@kernel.org, gregkh@linuxfoundation.org,
	linux@roeck-us.net, a.hajda@samsung.com, cw00.choi@samsung.com,
	shufan_lee@richtek.com, Peter Chen, gsomlo@gmail.com,
	devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
	dl-linux-imx
In-Reply-To: <20180521131239.GB10677@kuha.fi.intel.com>

Hi Heikki,

> -----Original Message-----
> From: Heikki Krogerus [mailto:heikki.krogerus@linux.intel.com]
> Sent: 2018年5月21日 21:13
> To: Jun Li <jun.li@nxp.com>
> Cc: Mats Karrman <mats.dev.list@gmail.com>; robh+dt@kernel.org;
> gregkh@linuxfoundation.org; linux@roeck-us.net; a.hajda@samsung.com;
> cw00.choi@samsung.com; shufan_lee@richtek.com; Peter Chen
> <peter.chen@nxp.com>; gsomlo@gmail.com; devicetree@vger.kernel.org;
> linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: Re: [PATCH v5 05/14] usb: typec: add API to get typec basic port power
> and data config
> 
> Hi Jun,
> 
> Sorry for the delay.
> 
> On Thu, May 17, 2018 at 02:41:31PM +0000, Jun Li wrote:
> > Hi
> > > -----Original Message-----
> > > From: Heikki Krogerus [mailto:heikki.krogerus@linux.intel.com]
> > > Sent: 2018??5??17?? 22:24
> > > To: Jun Li <jun.li@nxp.com>
> > > Cc: Mats Karrman <mats.dev.list@gmail.com>; robh+dt@kernel.org;
> > > gregkh@linuxfoundation.org; linux@roeck-us.net; a.hajda@samsung.com;
> > > cw00.choi@samsung.com; shufan_lee@richtek.com; Peter Chen
> > > <peter.chen@nxp.com>; gsomlo@gmail.com; devicetree@vger.kernel.org;
> > > linux-usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> > > Subject: Re: [PATCH v5 05/14] usb: typec: add API to get typec basic
> > > port power and data config
> > >
> > > On Thu, May 17, 2018 at 02:05:41PM +0000, Jun Li wrote:
> > > > Hi Heikki,
> > > >
> > > > > > I reread this patch and tried to see it more in the context of
> > > > > > the other patches and the existing code. The naming of the
> > > > > > existing string tables doesn't help in getting this right, however I have
> a proposal:
> > > > > >
> > > > > > typec_find_port_power_role() to get to TYPEC_PORT_SRC/SNK/DRP
> > > > > > typec_find_port_data_role() to get to TYPEC_PORT_DFP/UFP/DRD
> > > > > > typec_find_power_role() to get to TYPEC_SINK/SOURCE
> > > > > >
> > > > > > and sometime, if the use should arise
> > > > > >
> > > > > > typec_find_data_role() to get to TYPEC_DEVICE/HOST
> > > > > >
> > > > > > I think it is fairly comprehensible, *_port_* concerns a
> > > > > > capability and without *_port_* it is an actual state. Plus it
> > > > > > matches the names of the constants.
> > > > >
> > > > > Well, there are now four things to consider:
> > > > >
> > > > > 1) the roles (power and data) the port is capable of supporting
> > > > > 2) Try.SRC and Try.SNK, i.e. the preferred role
> > > > > 3) the current roles
> > > > > 4) the role(s) the user want's to limit the use of a port with
> > > > > DRP ports
> > > > >
> > > > > The last one I don't know if it's relevant with these functions.
> > > > > It's not information that we would get for example from firmware.
> > > > >
> > > > > I also don't think we need to use these functions with the
> > > > > current roles the port is in.
> > > > >
> > > > > If the preferred role is "sink" or "source", so just like the
> > > > > power role, we don't need separate function for it here.
> > > > >
> > > > > So isn't two functions all we need here: one for the power and
> > > > > one for data role?
> > > >
> > > > Take power as an example, can we use one function to only look up
> > > > typec_port_types[]? as capability(typec_port_type) and
> > > > state(typec_role) are different enum, and the allowed strings are
> different.
> > > >
> > > > static const char * const typec_roles[] = {
> > > > 	[TYPEC_SINK]    = "sink",
> > > > 	[TYPEC_SOURCE]  = "source",
> > > > };
> > > >
> > > > static const char * const typec_port_types[] = {
> > > > 	[TYPEC_PORT_SRC] = "source",
> > > > 	[TYPEC_PORT_SNK] = "sink",
> > > > 	[TYPEC_PORT_DRP] = "dual",
> > > > };
> > >
> > > Where out side the class code we need to convert the current role,
> > > the "state", with these functions?
> >
> > Currently, the only call site is getting the preferred power role from firmware.
> 
> My point was that if we used enum typec_port_type with the prefered role, we
> could use the helper for power role with prefered role. But never mind.

Got your point. So let's follow Mats's suggestion on this, I will update a new version.

Thanks
Li Jun
> 
> 
> Thanks,
> 
> --
> heikki

^ permalink raw reply

* Re: [PATCH RFC V2 2/6] hwmon: Add support for RPi voltage sensor
From: Guenter Roeck @ 2018-05-22 14:10 UTC (permalink / raw)
  To: Stefan Wahren, Rob Herring, Eric Anholt, Mark Rutland,
	Jonathan Corbet, Jean Delvare
  Cc: linux-hwmon, devicetree, Florian Fainelli, Scott Branden,
	linux-doc, Ray Jui, Phil Elwell, Noralf Trønnes,
	bcm-kernel-feedback-list, linux-rpi-kernel, linux-arm-kernel
In-Reply-To: <659923372.11518.1526997096662@email.1und1.de>

On 05/22/2018 06:51 AM, Stefan Wahren wrote:
> Hi Guenter,
> 
>> Guenter Roeck <linux@roeck-us.net> hat am 22. Mai 2018 um 15:41 geschrieben:
>>
>>
>> On 05/22/2018 04:21 AM, Stefan Wahren wrote:
>>> Currently there is no easy way to detect undervoltage conditions on a
>>> remote Raspberry Pi. This hwmon driver retrieves the state of the
>>> undervoltage sensor via mailbox interface. The handling based on
>>> Noralf's modifications to the downstream firmware driver. In case of
>>> an undervoltage condition only an entry is written to the kernel log.
>>>
>>> CC: "Noralf Trønnes" <noralf@tronnes.org>
>>> Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
>>> ---
>>>    Documentation/hwmon/raspberrypi-hwmon |  22 +++++
>>>    drivers/hwmon/Kconfig                 |  10 ++
>>>    drivers/hwmon/Makefile                |   1 +
>>>    drivers/hwmon/raspberrypi-hwmon.c     | 168 ++++++++++++++++++++++++++++++++++
>>>    4 files changed, 201 insertions(+)
>>>    create mode 100644 Documentation/hwmon/raspberrypi-hwmon
>>>    create mode 100644 drivers/hwmon/raspberrypi-hwmon.c
>>>
>>> diff --git a/Documentation/hwmon/raspberrypi-hwmon b/Documentation/hwmon/raspberrypi-hwmon
>>> new file mode 100644
>>> index 0000000..3c92e2c
>>> --- /dev/null
>>> +++ b/Documentation/hwmon/raspberrypi-hwmon
>>> @@ -0,0 +1,22 @@
>>> +Kernel driver raspberrypi-hwmon
>>> +===============================
>>> +
>>> +Supported boards:
>>> +  * Raspberry Pi A+ (via GPIO on SoC)
>>> +  * Raspberry Pi B+ (via GPIO on SoC)
>>> +  * Raspberry Pi 2 B (via GPIO on SoC)
>>> +  * Raspberry Pi 3 B (via GPIO on port expander)
>>> +  * Raspberry Pi 3 B+ (via PMIC)
>>> +
>>> +Author: Stefan Wahren <stefan.wahren@i2se.com>
>>> +
>>> +Description
>>> +-----------
>>> +
>>> +This driver periodically polls a mailbox property of the VC4 firmware to detect
>>> +undervoltage conditions.
>>> +
>>> +Sysfs entries
>>> +-------------
>>> +
>>> +in0_lcrit_alarm		Undervoltage alarm
>>> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
>>> index 768aed5..9a5bdb0 100644
>>> --- a/drivers/hwmon/Kconfig
>>> +++ b/drivers/hwmon/Kconfig
>>> @@ -1298,6 +1298,16 @@ config SENSORS_PWM_FAN
>>>    	  This driver can also be built as a module.  If so, the module
>>>    	  will be called pwm-fan.
>>>    
>>> +config SENSORS_RASPBERRYPI_HWMON
>>> +	tristate "Raspberry Pi voltage monitor"
>>> +	depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST
>>> +	help
>>> +	  If you say yes here you get support for voltage sensor on the
>>> +	  Raspberry Pi.
>>> +
>>> +	  This driver can also be built as a module. If so, the module
>>> +	  will be called raspberrypi-hwmon.
>>> +
>>>    config SENSORS_SHT15
>>>    	tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
>>>    	depends on GPIOLIB || COMPILE_TEST
>>> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
>>> index e7d52a3..a929770 100644
>>> --- a/drivers/hwmon/Makefile
>>> +++ b/drivers/hwmon/Makefile
>>> @@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
>>>    obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
>>>    obj-$(CONFIG_SENSORS_POWR1220)  += powr1220.o
>>>    obj-$(CONFIG_SENSORS_PWM_FAN)	+= pwm-fan.o
>>> +obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON)	+= raspberrypi-hwmon.o
>>>    obj-$(CONFIG_SENSORS_S3C)	+= s3c-hwmon.o
>>>    obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
>>>    obj-$(CONFIG_SENSORS_SCH5627)	+= sch5627.o
>>> diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c
>>> new file mode 100644
>>> index 0000000..6233e84
>>> --- /dev/null
>>> +++ b/drivers/hwmon/raspberrypi-hwmon.c
>>> @@ -0,0 +1,168 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * Raspberry Pi voltage sensor driver
>>> + *
>>> + * Based on firmware/raspberrypi.c by Noralf Trønnes
>>> + *
>>> + * Copyright (C) 2018 Stefan Wahren <stefan.wahren@i2se.com>
>>> + */
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/hwmon.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/workqueue.h>
>>> +#include <soc/bcm2835/raspberrypi-firmware.h>
>>> +
>>> +#define UNDERVOLTAGE_STICKY_BIT	BIT(16)
>>> +
>>> +struct rpi_hwmon_data {
>>> +	struct device *hwmon_dev;
>>> +	struct rpi_firmware *fw;
>>> +	u32 last_throttled;
>>> +	struct delayed_work get_values_poll_work;
>>> +};
>>> +
>>> +static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data)
>>> +{
>>> +	u32 new_uv, old_uv, value;
>>> +	int ret;
>>> +
>>> +	/* Request firmware to clear sticky bits */
>>> +	value = 0xffff;
>>> +
>>> +	ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED,
>>> +				    &value, sizeof(value));
>>> +	if (ret) {
>>> +		dev_err_once(data->hwmon_dev, "Failed to get throttled (%d)\n",
>>> +			     ret);
>>> +		return;
>>> +	}
>>> +
>>> +	new_uv = value & UNDERVOLTAGE_STICKY_BIT;
>>> +	old_uv = data->last_throttled & UNDERVOLTAGE_STICKY_BIT;
>>> +	data->last_throttled = value;
>>> +
>>> +	if (new_uv == old_uv)
>>> +		return;
>>> +
>>> +	if (new_uv)
>>> +		dev_crit(data->hwmon_dev, "Undervoltage detected!\n");
>>> +	else
>>> +		dev_info(data->hwmon_dev, "Voltage normalised\n");
>>> +
>>> +	sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm");
>>> +}
>>> +
>>> +static void get_values_poll(struct work_struct *work)
>>> +{
>>> +	struct rpi_hwmon_data *data;
>>> +
>>> +	data = container_of(work, struct rpi_hwmon_data,
>>> +			    get_values_poll_work.work);
>>> +
>>> +	rpi_firmware_get_throttled(data);
>>> +
>>> +	/*
>>> +	 * We can't run faster than the sticky shift (100ms) since we get
>>> +	 * flipping in the sticky bits that are cleared.
>>> +	 */
>>> +	schedule_delayed_work(&data->get_values_poll_work, 2 * HZ);
>>> +}
>>> +
>>> +static int rpi_read(struct device *dev, enum hwmon_sensor_types type,
>>> +		    u32 attr, int channel, long *val)
>>> +{
>>> +	struct rpi_hwmon_data *data = dev_get_drvdata(dev);
>>> +
>>> +	*val = !!(data->last_throttled & UNDERVOLTAGE_STICKY_BIT);
>>> +	return 0;
>>> +}
>>> +
>>> +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,
>>> +			      u32 attr, int channel)
>>> +{
>>> +	return 0444;
>>> +}
>>> +
>>> +static const u32 rpi_in_config[] = {
>>> +	HWMON_I_LCRIT_ALARM,
>>> +	0
>>> +};
>>> +
>>> +static const struct hwmon_channel_info rpi_in = {
>>> +	.type = hwmon_in,
>>> +	.config = rpi_in_config,
>>> +};
>>> +
>>> +static const struct hwmon_channel_info *rpi_info[] = {
>>> +	&rpi_in,
>>> +	NULL
>>> +};
>>> +
>>> +static const struct hwmon_ops rpi_hwmon_ops = {
>>> +	.is_visible = rpi_is_visible,
>>> +	.read = rpi_read,
>>> +};
>>> +
>>> +static const struct hwmon_chip_info rpi_chip_info = {
>>> +	.ops = &rpi_hwmon_ops,
>>> +	.info = rpi_info,
>>> +};
>>> +
>>> +static int rpi_hwmon_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	struct rpi_hwmon_data *data;
>>> +	int ret;
>>> +
>>> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
>>> +	if (!data)
>>> +		return -ENOMEM;
>>> +
>>> +	data->fw = platform_get_drvdata(to_platform_device(dev->parent));
>>> +	if (!data->fw)
>>> +		return -EPROBE_DEFER;
>>> +
>>
>> I am a bit at loss here (and sorry I didn't bring this up before).
>> How would this ever be possible, given that the driver is registered
>> from the firmware driver ?
> 
> Do you refer to the (wrong) return code, the assumption that the parent must be a platform driver or a possible race?
> 

The return code is one thing. My question was how the driver would ever be instantiated
with platform_get_drvdata(to_platform_device(dev->parent)) == NULL (but dev->parent != NULL),
so I referred to the race. But, sure, a second question would be how that would indicate
that the parent is not instantiated yet (which by itself seems like an odd question).

Yet another question, as you point out, is why to use platform_get_drvdata(to_platform_device(dev->parent))
instead of dev_get_drvdata(dev->parent).

Guenter

>>
>>> +	ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED,
>>> +				    &data->last_throttled,
>>> +				    sizeof(data->last_throttled));
>>> +	if (ret)
>>> +		return -ENODEV;
>>> +
>>> +	data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "rpi_volt",
>>> +							       data,
>>> +							       &rpi_chip_info,
>>> +							       NULL);
>>> +
>>> +	INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll);
>>> +	platform_set_drvdata(pdev, data);
>>> +
>>> +	if (!PTR_ERR_OR_ZERO(data->hwmon_dev))
>>> +		schedule_delayed_work(&data->get_values_poll_work, 2 * HZ);
>>> +
>>> +	return PTR_ERR_OR_ZERO(data->hwmon_dev);
>>> +}
>>> +
>>> +static int rpi_hwmon_remove(struct platform_device *pdev)
>>> +{
>>> +	struct rpi_hwmon_data *data = platform_get_drvdata(pdev);
>>> +
>>> +	cancel_delayed_work_sync(&data->get_values_poll_work);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct platform_driver rpi_hwmon_driver = {
>>> +	.probe = rpi_hwmon_probe,
>>> +	.remove = rpi_hwmon_remove,
>>> +	.driver = {
>>> +		.name = "raspberrypi-hwmon",
>>> +	},
>>> +};
>>> +module_platform_driver(rpi_hwmon_driver);
>>> +
>>> +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
>>> +MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver");
>>> +MODULE_LICENSE("GPL v2");
>>>
>>
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v4 06/12] media: dt-bindings: add bindings for i.MX7 media driver
From: Sakari Ailus @ 2018-05-22 14:08 UTC (permalink / raw)
  To: Rui Miguel Silva
  Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin, Rob Herring,
	Rui Miguel Silva, Philipp Zabel, Steve Longerbeam, Fabio Estevam,
	mchehab, Shawn Guo, linux-media
In-Reply-To: <m336yjvndy.fsf@gmail.com>

On Tue, May 22, 2018 at 02:19:21PM +0100, Rui Miguel Silva wrote:
> Hi Sakari,
> On Fri 18 May 2018 at 22:13, Sakari Ailus wrote:
> > On Fri, May 18, 2018 at 09:27:58AM +0100, Rui Miguel Silva wrote:
> > > > > +endpoint node
> > > > > +-------------
> > > > > +
> > > > > +- data-lanes    : (required) an array specifying active > >
> > > physical
> > > > > MIPI-CSI2
> > > > > +		    data input lanes and their mapping to > > logical lanes;
> > > the
> > > > > +		    array's content is unused, only its > > length is
> > > meaningful;
> > 
> > Btw. do note that you may get a warning due to this from the CSI-2 bus
> > property parsing code if the lane numbers are wrong.
> > 
> > > > > +
> > > > > +- fsl,csis-hs-settle : (optional) differential receiver > >
> > > (HS-RX)
> > > > > settle time;
> > > > > Could you calculate this, as other drivers do? It probably >
> > > changes
> > > > depending on the device runtime configuration.
> > > 
> > > The only reference to possible values to this parameter is given by
> > > table in [0], can you point me out the formula for imx7 in the
> > > documentation?
> > 
> > I don't know imx7 but the other CSI-2 drivers need no such system
> > specific
> > configuration.
> 
> Hum, I think there is at least one more (which this is compliant) that
> also use this configuration parameter. [0]

Ah, that's where it then probably comes from, if the two hardware blocks share 
some bits.

I guess it's fine to keep it if you think it's really necessary.

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply

* Re: [PATCH v2 03/14] dt-bindings: qcom_nandc: make nand-ecc-strength optional
From: Abhishek Sahu @ 2018-05-22 14:08 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
	Richard Weinberger, linux-arm-msm, linux-kernel, linux-mtd,
	Andy Gross, Archit Taneja, Rob Herring, Mark Rutland, devicetree
In-Reply-To: <20180521163254.71ade105@xps13>

On 2018-05-21 20:02, Miquel Raynal wrote:
> Hi Abhishek,
> 
> On Thu,  3 May 2018 17:50:30 +0530, Abhishek Sahu
> <absahu@codeaurora.org> wrote:
> 
>> Now, nand-ecc-strength is optional. If specified in DT, then
>> controller will use this ECC strength otherwise ECC strength will
>> be calculated according to chip requirement and available OOB size.
> 
> Same comment as before: don't start the commit log with "now,".
> 
> Thanks,
> Miquèl

  Thanks Miquel.
  I will change the commit message.

  Regards,
  Abhishek

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox