linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] media: add Toshiba TC358746 Bridge support
@ 2018-12-18 14:12 Marco Felsch
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
                   ` (3 more replies)
  0 siblings, 4 replies; 30+ messages in thread
From: Marco Felsch @ 2018-12-18 14:12 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: linux-media, devicetree, graphics

Hi,

this patch set adds the support for the Toshiba TC358746 Parallel
MIPI-CSI2 bridge device.

The last patch ("media: tc358746: update MAINTAINERS file") is optional,
due to Hans answer to Michael [1]. We can drop this patch if it isn't
needed.

I added the v4l2-compliance test in relation to [1], I used v4l2-compliance
version 1.16.0. Unfortunately the VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test
failed, but the device don't support events at all, as described in the
commit message of the 2nd patch.

The patche set was succefully rebased on top of media_tree/master and
compile tested.

[1] https://marc.info/?l=linux-kernel&m=154330540418714&w=2

Regards,
Marco

8<----------------------------------------------------------

root@samx6i:~# v4l2-compliance -s -u /dev/v4l-subdev12
v4l2-compliance SHA: not available, 32 bits

Compliance test for device /dev/v4l-subdev12:

Media Driver Info:
        Driver name      : imx-media
        Model            : imx-media
        Serial           : 
        Bus info         : 
        Media version    : 4.20.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 4.20.0
Interface Info:
        ID               : 0x030000a6
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x00000056 (86)
        Name             : tc358746 6-000e
        Function         : Video Interface Bridge
        Pad 0x01000057   : 0: Sink
          Link 0x0200008c: from remote pad 0x100005a of entity 'mt9m111 6-0048': Data, Enabled
        Pad 0x01000058   : 1: Source
          Link 0x0200008a: to remote pad 0x1000051 of entity 'imx6-mipi-csi2': Data, Enabled

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

Allow for multiple opens:
        test second /dev/v4l-subdev12 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
        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
                fail: ../../../v4l-utils-1.16.0/utils/v4l2-compliance/v4l2-test-controls.cpp(816): subscribe event for control 'Image Processing Controls' failed
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 3 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: 54, Succeeded: 53, Failed: 1, Warnings: 0

8<----------------------------------------------------------

Marco Felsch (3):
  media: dt-bindings: add bindings for Toshiba TC358746
  media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
  media: tc358746: update MAINTAINERS file

 .../bindings/media/i2c/toshiba,tc358746.txt   |   80 +
 MAINTAINERS                                   |    7 +
 drivers/media/i2c/Kconfig                     |   12 +
 drivers/media/i2c/Makefile                    |    1 +
 drivers/media/i2c/tc358746.c                  | 1847 +++++++++++++++++
 drivers/media/i2c/tc358746_regs.h             |  208 ++
 6 files changed, 2155 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
 create mode 100644 drivers/media/i2c/tc358746.c
 create mode 100644 drivers/media/i2c/tc358746_regs.h

-- 
2.19.1


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2018-12-18 14:12 [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
@ 2018-12-18 14:12 ` Marco Felsch
  2018-12-28 23:10   ` Rob Herring
                     ` (2 more replies)
  2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 30+ messages in thread
From: Marco Felsch @ 2018-12-18 14:12 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: linux-media, devicetree, graphics

Add corresponding dt-bindings for the Toshiba tc358746 device.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt

diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
new file mode 100644
index 000000000000..499733df744a
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
@@ -0,0 +1,80 @@
+* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
+
+The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
+or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
+
+Required Properties:
+
+- compatible: should be "toshiba,tc358746"
+- reg: should be <0x0e>
+- clocks: should contain a phandle link to the reference clock source
+- clock-names: the clock input is named "refclk".
+
+Optional Properties:
+
+- reset-gpios: gpio phandle GPIO connected to the reset pin
+
+Parallel Endpoint:
+
+Required Properties:
+
+- reg: should be <0>
+- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
+	     for sixteen bit wide bus.
+
+MIPI CSI-2 Endpoint:
+
+Required Properties:
+
+- reg: should be <1>
+- data-lanes: should be <1 2 3 4> for four-lane operation,
+	      or <1 2> for two-lane operation
+- clock-lanes: should be <0>
+- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
+		    expressed as a 64-bit big-endian integer. The frequency
+		    is half of the bps per lane due to DDR transmission.
+
+Optional Properties:
+
+- clock-noncontinuous: Presence of this boolean property decides whether the
+		       MIPI CSI-2 clock is continuous or non-continuous.
+
+For further information on the endpoint node properties, see
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+&i2c {
+	tc358746: tc358746@0e {
+		reg = <0x0e>;
+		compatible = "toshiba,tc358746";
+		pinctrl-names = "default";
+		clocks = <&clk_cam_ref>;
+		clock-names = "refclk";
+		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			tc358746_parallel_in: endpoint {
+				bus-width = <8>;
+				remote-endpoint = <&micron_parallel_out>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+
+			tc358746_mipi2_out: endpoint {
+				remote-endpoint = <&mipi_csi2_in>;
+				data-lanes = <1 2>;
+				clock-lanes = <0>;
+				clock-noncontinuous;
+				link-frequencies = /bits/ 64 <216000000>;
+			};
+		};
+	};
+};
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
  2018-12-18 14:12 [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
@ 2018-12-18 14:12 ` Marco Felsch
  2018-12-19  1:24   ` kbuild test robot
                     ` (2 more replies)
  2018-12-18 14:12 ` [PATCH 3/3] media: tc358746: update MAINTAINERS file Marco Felsch
  2019-01-23 12:54 ` [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
  3 siblings, 3 replies; 30+ messages in thread
From: Marco Felsch @ 2018-12-18 14:12 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: linux-media, devicetree, graphics

Adding support for the TC358746 bridge. The Bridge can receive images on
the parallel input port and send it to the host using the CSI-TX unit.
Furthermore the Bridge can receive images from the host using the CSI-RX
unit and send it to the parallel output port.

Currently the only the first case is implemented and tested. The bridge
driver needs two information from the connected sensor: hblank time and
pixel-rate. Both information are requested using the v4l2_ctrl interface.
The driver won't create a media-link if one or both information are
missing.

Missing feature:
- Provide mclk on GPIO[0]
- Sending pictures from the host to a parallel display
- v4l_event support

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/Kconfig         |   12 +
 drivers/media/i2c/Makefile        |    1 +
 drivers/media/i2c/tc358746.c      | 1847 +++++++++++++++++++++++++++++
 drivers/media/i2c/tc358746_regs.h |  208 ++++
 4 files changed, 2068 insertions(+)
 create mode 100644 drivers/media/i2c/tc358746.c
 create mode 100644 drivers/media/i2c/tc358746_regs.h

diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 4c936e129500..9995075c3eac 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -394,6 +394,18 @@ config VIDEO_TC358743_CEC
 	  When selected the tc358743 will support the optional
 	  HDMI CEC feature.
 
+config VIDEO_TC358746
+	tristate "Toshiba TC358746 decoder"
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+	select V4L2_FWNODE
+	help
+	  Support for the Toshiba TC358746 PARALLEL to MIPI CSI-2 bridge.
+	  The bridge can work in both directions but currenty only the
+	  parallel-in / csi-out path is supported.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tc358746.
+
 config VIDEO_TVP514X
 	tristate "Texas Instruments TVP514x video decoder"
 	depends on VIDEO_V4L2 && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 65fae7732de0..5cdbdf546627 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C)		+= video-i2c.o
 obj-$(CONFIG_VIDEO_ML86V7667)	+= ml86v7667.o
 obj-$(CONFIG_VIDEO_OV2659)	+= ov2659.o
 obj-$(CONFIG_VIDEO_TC358743)	+= tc358743.o
+obj-$(CONFIG_VIDEO_TC358746)	+= tc358746.o
 obj-$(CONFIG_VIDEO_IMX214)	+= imx214.o
 obj-$(CONFIG_VIDEO_IMX258)	+= imx258.o
 obj-$(CONFIG_VIDEO_IMX274)	+= imx274.o
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
new file mode 100644
index 000000000000..633b0322b85d
--- /dev/null
+++ b/drivers/media/i2c/tc358746.c
@@ -0,0 +1,1847 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * tc358746 - Parallel to CSI-2 bridge
+ *
+ * Copyright 2018 Marco Felsch <kernel@pengutronix.de>
+ *
+ * References:
+ * REF_01:
+ * - TC358746AXBG/TC358748XBG/TC358748IXBG Functional Specification Rev 1.2
+ * REF_02:
+ * - TC358746(A)748XBG_Parallel-CSI2_Tv23p.xlsx, Rev Tv23
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/property.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+
+#include "tc358746_regs.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-3)");
+
+MODULE_DESCRIPTION("Toshiba TC358746 Parallel to CSI-2 bridge driver");
+MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
+
+#define I2C_MAX_XFER_SIZE	(512 + 2)
+#define TC358746_MAX_FIFO_SIZE	512
+#define TC358746_DEF_LINK_FREQ	0
+
+#define TC358746_LINEINIT_MIN_US	110
+#define TC358746_TWAKEUP_MIN_US		1200
+#define TC358746_LPTXTIME_MIN_NS	55
+#define TC358746_TCLKZERO_MIN_NS	305
+#define TC358746_TCLKTRAIL_MIN_NS	65
+#define TC358746_TCLKPOST_MIN_NS	65
+#define TC358746_THSZERO_MIN_NS		150
+#define TC358746_THSTRAIL_MIN_NS	65
+#define TC358746_THSPREPARE_MIN_NS	45
+
+static const struct v4l2_mbus_framefmt tc358746_def_fmt = {
+	.width		= 640,
+	.height		= 480,
+	.code		= MEDIA_BUS_FMT_UYVY8_2X8,
+	.field		= V4L2_FIELD_NONE,
+	.colorspace	= V4L2_COLORSPACE_DEFAULT,
+	.ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT,
+	.quantization	= V4L2_QUANTIZATION_DEFAULT,
+	.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
+};
+
+struct tc358746_csi_param {
+	unsigned char speed_range;
+	unsigned int  unit_clk_hz;
+	unsigned char unit_clk_mul;
+	unsigned int speed_per_lane; /* bps / lane */
+	unsigned short lane_num;
+	bool is_continuous_clk;
+
+	/* CSI2-TX Parameters */
+	u32 lineinitcnt;
+	u32 lptxtimecnt;
+	u32 twakeupcnt;
+	u32 tclk_preparecnt;
+	u32 tclk_zerocnt;
+	u32 tclk_trailcnt;
+	u32 tclk_postcnt;
+	u32 ths_preparecnt;
+	u32 ths_zerocnt;
+	u32 ths_trailcnt;
+
+	unsigned int csi_hs_lp_hs_ps;
+};
+
+struct tc358746_state {
+	struct v4l2_subdev sd;
+	struct i2c_client *i2c_client;
+	struct gpio_desc *reset_gpio;
+
+	/*
+	 * Generic
+	 */
+	struct media_pad pads[2];
+	struct mutex confctl_mutex;
+	struct v4l2_mbus_framefmt fmt;
+	struct v4l2_ctrl_handler hdl;
+	bool fmt_changed;
+	bool test;
+
+	/*
+	 * Chip Clocks
+	 */
+	struct clk  *refclk;
+	/* internal pll */
+	unsigned int pllinclk_hz;
+	u16 pll_prd;
+	u16 pll_fbd;
+
+	/*
+	 * Video Buffer
+	 */
+	u16 vb_fifo; /* The FIFO size is 511x32 */
+
+	/*
+	 * CSI TX
+	 */
+	struct v4l2_ctrl	  *link_freq;
+	struct tc358746_csi_param *link_freq_settings;
+	u64			  *link_frequencies;
+	unsigned int		   link_frequencies_num;
+
+	/*
+	 * Parallel input
+	 */
+	unsigned int pclk;
+	unsigned int hblank;
+};
+
+struct tc358746_mbus_fmt {
+	u32 code;
+	u8 bus_width;
+	u8 bpp;		 /* total bpp */
+	u8 pdformat;	 /* peripheral data format */
+	u8 pdataf;	 /* parallel data format option */
+	u8 ppp;		 /* pclk per pixel */
+	bool csitx_only; /* format only in csi-tx mode supported */
+};
+
+/* TODO: Add other formats as required */
+static const struct tc358746_mbus_fmt tc358746_formats[] = {
+	{
+		.code = MEDIA_BUS_FMT_UYVY8_2X8,
+		.bus_width = 8,
+		.bpp = 16,
+		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
+		.pdataf = CONFCTL_PDATAF_MODE0,
+		.ppp = 2,
+	}, {
+		.code = MEDIA_BUS_FMT_UYVY8_1X16,
+		.bus_width = 16,
+		.bpp = 16,
+		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
+		.pdataf = CONFCTL_PDATAF_MODE1,
+		.ppp = 1,
+	}, {
+		.code = MEDIA_BUS_FMT_YUYV8_1X16,
+		.bus_width = 16,
+		.bpp = 16,
+		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
+		.pdataf = CONFCTL_PDATAF_MODE2,
+		.ppp = 1,
+	}, {
+		.code = MEDIA_BUS_FMT_UYVY10_2X10,
+		.bus_width = 10,
+		.bpp = 20,
+		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_10_BIT,
+		.pdataf = CONFCTL_PDATAF_MODE0, /* don't care */
+		.ppp = 2,
+	}, {
+		/* in datasheet listed as YUV444 */
+		.code = MEDIA_BUS_FMT_GBR888_1X24,
+		.bus_width = 24,
+		.bpp = 24,
+		.pdformat = DATAFMT_PDFMT_YCBCRFMT_444,
+		.pdataf = CONFCTL_PDATAF_MODE0, /* don't care */
+		.ppp = 2,
+		.csitx_only = true,
+	},
+};
+
+/* --------------- HELPERS ------------ */
+static void
+tc358746_dump_csi(struct device *dev,
+		  struct tc358746_csi_param *csi_setting)
+{
+	dev_dbg(dev, "Speed-Range value %u\n", csi_setting->speed_range);
+	dev_dbg(dev, "Unit Clock %u Hz\n", csi_setting->unit_clk_hz);
+	dev_dbg(dev, "Unit Clock Mul %u\n", csi_setting->unit_clk_mul);
+	dev_dbg(dev, "CSI speed/lane %u bps/lane\n",
+		csi_setting->speed_per_lane);
+	dev_dbg(dev, "CSI lanes %u\n", csi_setting->lane_num);
+	dev_dbg(dev, "CSI clock during LP %sabled\n",
+		csi_setting->is_continuous_clk ? "en" : "dis");
+
+	dev_dbg(dev, "lineinitcnt %u\n", csi_setting->lineinitcnt);
+	dev_dbg(dev, "lptxtimecnt %u\n", csi_setting->lptxtimecnt);
+	dev_dbg(dev, "tclk_preparecnt %u\n", csi_setting->tclk_preparecnt);
+	dev_dbg(dev, "tclk_zerocnt %u\n", csi_setting->tclk_zerocnt);
+	dev_dbg(dev, "tclk_trailcnt %u\n", csi_setting->tclk_trailcnt);
+	dev_dbg(dev, "ths_preparecnt %u\n", csi_setting->ths_preparecnt);
+	dev_dbg(dev, "ths_zerocnt %u\n", csi_setting->ths_zerocnt);
+	dev_dbg(dev, "twakeupcnt %u\n", csi_setting->twakeupcnt);
+	dev_dbg(dev, "tclk_postcnt %u\n", csi_setting->tclk_postcnt);
+	dev_dbg(dev, "ths_trailcnt %u\n", csi_setting->ths_trailcnt);
+	dev_dbg(dev, "csi_hs_lp_hs_ps %u (%u us)\n",
+		csi_setting->csi_hs_lp_hs_ps,
+		csi_setting->csi_hs_lp_hs_ps / 1000);
+}
+
+static void
+tc358746_dump_pll(struct device *dev, struct tc358746_state *state)
+{
+	dev_dbg(dev, "refclk %lu Hz\n", clk_get_rate(state->refclk));
+	dev_dbg(dev, "pll input clock %u Hz\n", state->pllinclk_hz);
+	dev_dbg(dev, "PLL_PRD %u\n", state->pll_prd - 1);
+	dev_dbg(dev, "PLL_FBD %u\n", state->pll_fbd - 1);
+}
+
+static inline struct tc358746_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tc358746_state, sd);
+}
+
+/* Find a data format by a pixel code */
+static int tc358746_format_supported(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++)
+		if (tc358746_formats[i].code == code)
+			return 0;
+
+	return -EINVAL;
+}
+
+static struct tc358746_csi_param *
+tc358746_g_cur_csi_settings(struct tc358746_state *state)
+{
+	int cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);
+
+	return &state->link_freq_settings[cur_freq];
+}
+
+static const struct tc358746_mbus_fmt *tc358746_get_format(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++)
+		if (tc358746_formats[i].code == code)
+			return &tc358746_formats[i];
+
+	return NULL;
+}
+
+static int
+tc358746_adjust_fifo_size(struct tc358746_state *state,
+			  const struct tc358746_mbus_fmt *format,
+			  struct tc358746_csi_param *csi_settings,
+			  int width, u16 *fifo_size)
+{
+	struct device *dev = &state->i2c_client->dev;
+	int c_hactive_ps_diff, c_lp_active_ps_diff, c_fifo_delay_ps_diff;
+	unsigned int p_hactive_ps, p_hblank_ps, p_htotal_ps;
+	unsigned int c_hactive_ps, c_lp_active_ps, c_fifo_delay_ps;
+	unsigned int csi_bps, csi_bps_period_ps;
+	unsigned int csi_hsclk, csi_hsclk_period_ps;
+	unsigned int pclk_period_ps;
+	unsigned int _fifo_size;
+
+	pclk_period_ps = 1000000000 / (state->pclk / 1000);
+	csi_bps = csi_settings->speed_per_lane * csi_settings->lane_num;
+	csi_bps_period_ps = 1000000000 / (csi_bps / 1000);
+	csi_hsclk = csi_settings->speed_per_lane >> 3;
+	csi_hsclk_period_ps = 1000000000 / (csi_hsclk / 1000);
+
+	/*
+	 * Calculation:
+	 * p_hactive_ps = pclk_period_ps * pclk_per_pixel * h_active_pixel
+	 */
+	p_hactive_ps = pclk_period_ps * format->ppp * width;
+
+	/*
+	 * Calculation:
+	 * p_hblank_ps = pclk_period_ps * h_blank_pixel
+	 */
+	p_hblank_ps = pclk_period_ps * state->hblank;
+	p_htotal_ps = p_hblank_ps + p_hactive_ps;
+
+	/*
+	 * Adjust the fifo size to adjust the csi timing. Hopefully we can find
+	 * a fifo size where the parallel input timings and the csi tx timings
+	 * fit together.
+	 */
+	for (_fifo_size = 1; _fifo_size < TC358746_MAX_FIFO_SIZE;
+	     _fifo_size++) {
+		/*
+		 * Calculation:
+		 * c_fifo_delay_ps = (fifo_size * 32) / parallel_bus_width *
+		 *		     pclk_period_ps + 4 * csi_hsclk_period_ps
+		 */
+		c_fifo_delay_ps = _fifo_size * 32 * pclk_period_ps;
+		c_fifo_delay_ps /= format->bus_width;
+		c_fifo_delay_ps += 4 * csi_hsclk_period_ps;
+
+		/*
+		 * Calculation:
+		 * c_hactive_ps = csi_bps_period_ps * image_bpp * h_active_pixel
+		 *		  + c_fifo_delay
+		 */
+		c_hactive_ps = csi_bps_period_ps * format->bpp * width;
+		c_hactive_ps += c_fifo_delay_ps;
+
+		/*
+		 * Calculation:
+		 * c_lp_active_ps = p_htotal_ps - c_hactive_ps
+		 */
+		c_lp_active_ps = p_htotal_ps - c_hactive_ps;
+
+		c_hactive_ps_diff = c_hactive_ps - p_hactive_ps;
+		c_fifo_delay_ps_diff = p_htotal_ps - c_hactive_ps;
+		c_lp_active_ps_diff =
+			c_lp_active_ps - csi_settings->csi_hs_lp_hs_ps;
+
+		if (c_hactive_ps_diff > 0 &&
+		    c_fifo_delay_ps_diff > 0 &&
+		    c_lp_active_ps_diff > 0)
+			break;
+	}
+	/*
+	 * If we can't transfer the image using this csi link frequency try to
+	 * use another link freq.
+	 */
+
+	dev_dbg(dev, "%s: found fifo-size %u\n", __func__, _fifo_size);
+	*fifo_size = _fifo_size;
+	return _fifo_size == TC358746_MAX_FIFO_SIZE ? -EINVAL : 0;
+}
+
+static int
+tc358746_adjust_timings(struct tc358746_state *state,
+			const struct tc358746_mbus_fmt *format,
+			int *width, u16 *fifo_size)
+{
+
+	int cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);
+	int freq = cur_freq;
+	struct tc358746_csi_param *csi_lane_setting;
+	int err;
+	int _width;
+
+	/*
+	 * Adjust timing:
+	 * 1) Try to use the desired width and the current csi-link-frequency
+	 * 2) If this doesn't fit try other csi-link-frequencies
+	 * 3) If this doesn't fit too, reducing the desired width and test
+	 *    it again width the current csi-link-frequency
+	 * 4) Goto step 2 if it doesn't fit at all
+	 */
+	for (_width = *width; _width > 0; _width -= 10) {
+		csi_lane_setting = &state->link_freq_settings[cur_freq];
+		err = tc358746_adjust_fifo_size(state, format, csi_lane_setting,
+						_width, fifo_size);
+		if (!err)
+			goto out;
+
+		for (freq = 0; freq < state->link_frequencies_num; freq++) {
+			if (freq == cur_freq)
+				continue;
+
+			csi_lane_setting = &state->link_freq_settings[freq];
+			err = tc358746_adjust_fifo_size(state, format,
+							csi_lane_setting,
+							_width, fifo_size);
+			if (!err)
+				goto out;
+		}
+	}
+
+out:
+	*width = _width;
+	return freq;
+}
+
+static int
+tc358746_calculate_csi_txtimings(struct tc358746_state *state,
+				 struct tc358746_csi_param *csi_setting)
+{
+	struct device *dev = &state->i2c_client->dev;
+	unsigned int spl;
+	unsigned int spl_p_ps, hsclk_p_ps, hfclk_p_ns;
+	unsigned int hfclk, hsclk; /* SYSCLK */
+	unsigned int tmp;
+	unsigned int lptxtime_ps, tclk_post_ps, tclk_trail_ps, tclk_zero_ps,
+		     ths_trail_ps, ths_zero_ps;
+
+	spl = csi_setting->speed_per_lane;
+	hsclk = spl >> 3; /* spl in bit-per-second, hsclk in byte-per-sercond */
+	hfclk = hsclk >> 1; /* HFCLK = SYSCLK / 2 */
+
+	if (hsclk > 125000000U) {
+		dev_err(dev, "unsupported HS byte clock %d, must <= 125 MHz\n",
+			hsclk);
+		return -EINVAL;
+	}
+
+	hfclk_p_ns = DIV_ROUND_CLOSEST(1000000000, hfclk);
+	hsclk_p_ps = 1000000000 / (hsclk / 1000);
+	spl_p_ps   = 1000000000 / (spl / 1000);
+
+	/*
+	 * Calculation:
+	 * hfclk_p_ns * lineinitcnt > 100us
+	 * lineinitcnt > 100 * 10^-6s / hfclk_p_ns * 10^-9
+	 *
+	 */
+	csi_setting->lineinitcnt = DIV_ROUND_UP(TC358746_LINEINIT_MIN_US * 1000,
+					  hfclk_p_ns);
+
+	/*
+	 * Calculation:
+	 * (lptxtimecnt + 1) * hsclk_p_ps > 50ns
+	 * 38ns < (tclk_preparecnt + 1) * hsclk_p_ps < 95ns
+	 */
+	csi_setting->lptxtimecnt = csi_setting->tclk_preparecnt =
+		DIV_ROUND_UP(TC358746_LPTXTIME_MIN_NS * 1000, hsclk_p_ps) - 1;
+
+	/*
+	 * Limit:
+	 * (tclk_zero + tclk_prepar) period > 300ns.
+	 * Since we have no upper limit and for simplicity:
+	 * tclk_zero > 300ns.
+	 *
+	 * Calculation:
+	 * tclk_zero = ([2,3] + tclk_zerocnt) * hsclk_p_ps + ([2,3] * spl_p_ps)
+	 *
+	 * Note: REF_02 uses
+	 * tclk_zero = (2.5 + tclk_zerocnt) * hsclk_p_ps + (3.5 * spl_p_ps)
+	 */
+	tmp = TC358746_TCLKZERO_MIN_NS * 1000 - 3 * spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->tclk_zerocnt = tmp - 2;
+
+	/*
+	 * Limit:
+	 * 40ns + 4 * spl_p_ps < (ths_preparecnt + 1) * hsclk_p_ps
+	 *		       < 85ns + 6 * spl_p_ps
+	 */
+	tmp = TC358746_THSPREPARE_MIN_NS * 1000 + 4 * spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->ths_preparecnt = tmp - 1;
+
+	/*
+	 * Limit:
+	 * (ths_zero + ths_prepare) period > 145ns + 10 * spl_p_ps.
+	 * Since we have no upper limit and for simplicity:
+	 * ths_zero period > 145ns + 10 * spl_p_ps.
+	 *
+	 * Calculation:
+	 * ths_zero = ([6,8] + ths_zerocnt) * hsclk_p_ps + [3,4] * hsclk_p_ps +
+	 *	      [13,14] * spl_p_ps
+	 *
+	 * Note: REF_02 uses
+	 * ths_zero = (7 + ths_zerocnt) * hsclk_p_ps + 4 * hsclk_p_ps +
+	 *	      11 * spl_p_ps
+	 */
+	tmp = TC358746_THSZERO_MIN_NS * 1000 - spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->ths_zerocnt = tmp < 11 ? 0 : tmp - 11;
+
+	/*
+	 * Limit:
+	 * hsclk_p_ps * (lptxtimecnt + 1) * (twakeupcnt + 1) > 1ms
+	 *
+	 * Since we have no upper limit use 1.2ms as lower limit to
+	 * surley meet the spec limit.
+	 */
+	tmp = hsclk_p_ps / 1000; /* tmp = hsclk_p_ns */
+	csi_setting->twakeupcnt =
+		DIV_ROUND_UP(TC358746_TWAKEUP_MIN_US * 1000,
+			     tmp * (csi_setting->lptxtimecnt + 1)) - 1;
+
+	/*
+	 * Limit:
+	 * 60ns + 4 * spl_p_ps < thstrail < 105ns + 12 * spl_p_ps
+	 *
+	 * Calculation:
+	 * thstrail = (1 + ths_trailcnt) * hsclk_p_ps + [3,4] * hsclk_p_ps -
+	 *	      [13,14] * spl_p_ps
+	 *
+	 * [2] set formula to:
+	 * thstrail = (1 + ths_trailcnt) * hsclk_p_ps + 4 * hsclk_p_ps -
+	 *	      11 * spl_p_ps
+	 */
+	tmp = TC358746_THSTRAIL_MIN_NS * 1000 + 15 * spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->ths_trailcnt = tmp - 5;
+
+	/*
+	 * Limit:
+	 * 60ns < tclk_trail < 105ns + 12 * spl_p_ps
+	 *
+	 * Limit used by REF_02:
+	 * 60ns < tclk_trail < 105ns + 12 * spl_p_ps - 30
+	 *
+	 * Calculation:
+	 * tclk_trail = ([1,2] + tclk_trailcnt) * hsclk_p_ps +
+	 *		(2 + [1,2]) * hsclk_p_ps - [2,3] * spl_p_ps
+	 *
+	 * Calculation used by REF_02:
+	 * tclk_trail = (1 + tclk_trailcnt) * hsclk_p_ps +
+	 *		4 * hsclk_p_ps - 3 * spl_p_ps
+	 */
+	tmp = TC358746_TCLKTRAIL_MIN_NS * 1000 + 3 * spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->tclk_trailcnt = tmp < 5 ? 0 : tmp - 5;
+
+	/*
+	 * Limit:
+	 * tclk_post > 60ns + 52 * spl_p_ps
+	 *
+	 * Limit used by REF_02:
+	 * tclk_post > 60ns + 52 * spl_p_ps
+	 *
+	 * Calculation:
+	 * tclk_post = ([1,2] + (tclk_postcnt + 1)) * hsclk_p_ps + hsclk_p_ps
+	 *
+	 * Note REF_02 uses:
+	 * tclk_post = (2.5 + tclk_postcnt) * hsclk_p_ps + hsclk_p_ps +
+	 *		2.5 * spl_p_ps
+	 * To meet the REF_02 validation limits following equation is used:
+	 * tclk_post = (2 + tclk_postcnt) * hsclk_p_ps + hsclk_p_ps +
+	 *		3 * spl_p_ps
+	 */
+	tmp = TC358746_TCLKPOST_MIN_NS * 1000 + 49 * spl_p_ps;
+	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
+	csi_setting->tclk_postcnt = tmp - 3;
+
+	/*
+	 * Last calculate the csi hs->lp->hs transistion time in ns. Note REF_02
+	 * mixed units in the equation for the continuous case. I don't know if
+	 * this was the intention. The driver drops the last 'multiply all by
+	 * two' to get nearly the same results.
+	 */
+	lptxtime_ps = (csi_setting->lptxtimecnt + 1) * hsclk_p_ps;
+	tclk_post_ps =
+		(4 + csi_setting->tclk_postcnt) * hsclk_p_ps + 3 * spl_p_ps;
+	tclk_trail_ps =
+		(5 + csi_setting->tclk_trailcnt) * hsclk_p_ps - 3 * spl_p_ps;
+	tclk_zero_ps =
+		(2 + csi_setting->tclk_zerocnt) * hsclk_p_ps + 3 * spl_p_ps;
+	ths_trail_ps =
+		(5 + csi_setting->ths_trailcnt) * hsclk_p_ps - 11 * spl_p_ps;
+	ths_zero_ps =
+		(7 + csi_setting->ths_zerocnt) * hsclk_p_ps + 4 * hsclk_p_ps +
+		11 * spl_p_ps;
+
+	if (csi_setting->is_continuous_clk) {
+		tmp = 2 * lptxtime_ps;
+		tmp += 25 * hsclk_p_ps;
+		tmp += ths_trail_ps;
+		tmp += ths_zero_ps;
+	} else {
+		tmp = 4 * lptxtime_ps;
+		tmp += ths_trail_ps + tclk_post_ps + tclk_trail_ps +
+			tclk_zero_ps + ths_zero_ps;
+		tmp += (13 + csi_setting->lptxtimecnt * 8) * hsclk_p_ps;
+		tmp += 22 * hsclk_p_ps;
+		tmp *= 3;
+		tmp = DIV_ROUND_CLOSEST(tmp, 2);
+	}
+	csi_setting->csi_hs_lp_hs_ps = tmp;
+
+	return 0;
+}
+
+/* --------------- i2c helper ------------ */
+
+static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct i2c_client *client = state->i2c_client;
+	int err;
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 data[I2C_MAX_XFER_SIZE];
+
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 2,
+			.buf = buf,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = n,
+			.buf = data,
+		},
+	};
+
+	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (err != ARRAY_SIZE(msgs)) {
+		v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
+			 __func__, reg, client->addr);
+	}
+
+	switch (n) {
+	case 1:
+		values[0] = data[0];
+		break;
+	case 2:
+		values[0] = data[1];
+		values[1] = data[0];
+		break;
+	case 4:
+		values[0] = data[1];
+		values[1] = data[0];
+		values[2] = data[3];
+		values[3] = data[2];
+		break;
+	default:
+		v4l2_info(sd, "unsupported I2C read %d bytes from address 0x%04x\n",
+			  n, reg);
+	}
+
+	if (debug < 3)
+		return;
+
+	switch (n) {
+	case 1:
+		v4l2_info(sd, "I2C read 0x%04x = 0x%02x",
+			  reg, data[0]);
+		break;
+	case 2:
+		v4l2_info(sd, "I2C read 0x%04x = 0x%02x%02x",
+			  reg, data[0], data[1]);
+		break;
+	case 4:
+		v4l2_info(sd, "I2C read 0x%04x = 0x%02x%02x%02x%02x",
+			  reg, data[2], data[3], data[0], data[1]);
+		break;
+	default:
+		v4l2_info(sd, "I2C unsupported read %d bytes from address 0x%04x\n",
+			  n, reg);
+	}
+}
+
+static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct i2c_client *client = state->i2c_client;
+	int err;
+	struct i2c_msg msg;
+	u8 data[I2C_MAX_XFER_SIZE];
+
+	if ((2 + n) > I2C_MAX_XFER_SIZE) {
+		n = I2C_MAX_XFER_SIZE - 2;
+		v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n",
+			  reg, 2 + n);
+	}
+
+	msg.addr = client->addr;
+	msg.buf = data;
+	msg.len = 2 + n;
+	msg.flags = 0;
+
+	data[0] = reg >> 8;
+	data[1] = reg & 0xff;
+
+	switch (n) {
+	case 1:
+		data[2 + 0] = values[0];
+		break;
+	case 2:
+		data[2 + 0] = values[1];
+		data[2 + 1] = values[0];
+		break;
+	case 4:
+		data[2 + 0] = values[1];
+		data[2 + 1] = values[0];
+		data[2 + 2] = values[3];
+		data[2 + 3] = values[2];
+		break;
+	default:
+		v4l2_info(sd, "unsupported I2C write %d bytes from address 0x%04x\n",
+			  n, reg);
+	}
+
+	err = i2c_transfer(client->adapter, &msg, 1);
+	if (err != 1) {
+		v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
+			 __func__, reg, client->addr);
+		return;
+	}
+
+	if (debug < 3)
+		return;
+
+	switch (n) {
+	case 1:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x", reg, data[2 + 0]);
+		break;
+	case 2:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", reg, data[2 + 0],
+			  data[2 + 1]);
+		break;
+	case 4:
+		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", reg,
+			  data[2 + 2], data[2 + 3], data[2 + 0], data[2 + 1]);
+		break;
+	default:
+		v4l2_info(sd, "I2C unsupported write %d bytes from address 0x%04x\n",
+			  n, reg);
+	}
+}
+
+static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+{
+	__le32 val = 0;
+
+	i2c_rd(sd, reg, (u8 __force *)&val, n);
+
+	return le32_to_cpu(val);
+}
+
+static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
+{
+	__le32 raw = cpu_to_le32(val);
+
+	i2c_wr(sd, reg, (u8 __force *)&raw, n);
+}
+
+static u16 __maybe_unused i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+{
+	return i2c_rdreg(sd, reg, 1);
+}
+
+static u16 __maybe_unused i2c_rd16(struct v4l2_subdev *sd, u16 reg)
+{
+	return i2c_rdreg(sd, reg, 2);
+}
+
+static u32 __maybe_unused i2c_rd32(struct v4l2_subdev *sd, u16 reg)
+{
+	return i2c_rdreg(sd, reg, 4);
+}
+
+static void __maybe_unused i2c_wr8(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	i2c_wrreg(sd, reg, val, 1);
+}
+
+static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	i2c_wrreg(sd, reg, val, 2);
+}
+
+static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u32 mask, u16 val)
+{
+	u16 m = (u16) mask;
+
+	i2c_wrreg(sd, reg, (i2c_rd16(sd, reg) & m) | val, 2);
+}
+
+static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
+{
+	i2c_wrreg(sd, reg, val, 4);
+}
+
+/* --------------- init --------------- */
+
+static void
+tc358746_wr_csi_control(struct v4l2_subdev *sd, int val)
+{
+	struct tc358746_state *state = to_state(sd);
+	u32 _val;
+
+	val &= CSI_CONFW_DATA_MASK;
+	_val = CSI_CONFW_MODE_SET_MASK | CSI_CONFW_ADDRESS_CSI_CONTROL_MASK |
+		val;
+
+	dev_dbg(&state->i2c_client->dev, "CSI_CONFW 0x%04x\n", _val);
+	i2c_wr32(sd, CSI_CONFW, _val);
+}
+
+static inline void tc358746_sleep_mode(struct v4l2_subdev *sd, int enable)
+{
+	i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
+			enable ? SYSCTL_SLEEP_MASK : 0);
+}
+
+static inline void tc358746_sreset(struct v4l2_subdev *sd)
+{
+	i2c_wr16(sd, SYSCTL, SYSCTL_SRESET_MASK);
+	udelay(10);
+	i2c_wr16(sd, SYSCTL, 0);
+}
+
+static inline void tc358746_enable_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct tc358746_state *state = to_state(sd);
+
+	dev_dbg(&state->i2c_client->dev, "%sable\n", enable ? "en" : "dis");
+
+	mutex_lock(&state->confctl_mutex);
+	if (!enable) {
+		i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_FRMSTOP_MASK,
+				PP_MISC_FRMSTOP_MASK);
+		i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK, 0);
+		i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_RSTPTR_MASK,
+				PP_MISC_RSTPTR_MASK);
+
+		i2c_wr32(sd, CSIRESET, (CSIRESET_RESET_CNF_MASK |
+					CSIRESET_RESET_MODULE_MASK));
+		i2c_wr16(sd, DBG_ACT_LINE_CNT, 0);
+	} else {
+		i2c_wr16(sd, PP_MISC, 0);
+		i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK,
+				CONFCTL_PPEN_MASK);
+	}
+	mutex_unlock(&state->confctl_mutex);
+}
+
+static void tc358746_set_pll(struct v4l2_subdev *sd)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct tc358746_csi_param *csi_setting =
+		tc358746_g_cur_csi_settings(state);
+	struct device *dev = &state->i2c_client->dev;
+	u16 pllctl0 = i2c_rd16(sd, PLLCTL0);
+	u16 pllctl1 = i2c_rd16(sd, PLLCTL1);
+	u16 pll_frs = csi_setting->speed_range;
+	u16 pllctl0_new;
+
+	/*
+	 * Calculation:
+	 * speed_per_lane = (pllinclk_hz * (fbd + 1)) / 2^frs
+	 *
+	 * Calculation used by REF_02:
+	 * speed_per_lane = (pllinclk_hz * fbd) / 2^frs
+	 */
+	state->pll_fbd = csi_setting->speed_per_lane / state->pllinclk_hz;
+	state->pll_fbd <<= pll_frs;
+
+	pllctl0_new = PLLCTL0_PLL_PRD_SET(state->pll_prd) |
+		      PLLCTL0_PLL_FBD_SET(state->pll_fbd);
+
+	/*
+	 * Only rewrite when needed (new value or disabled), since rewriting
+	 * triggers another format change event.
+	 */
+	if ((pllctl0 != pllctl0_new) ||
+	    ((pllctl1 & PLLCTL1_PLL_EN_MASK) == 0)) {
+		u16 pllctl1_mask = (u16) ~(PLLCTL1_PLL_FRS_MASK |
+					   PLLCTL1_RESETB_MASK  |
+					   PLLCTL1_PLL_EN_MASK);
+		u16 pllctl1_val = PLLCTL1_PLL_FRS_SET(pll_frs) |
+				  PLLCTL1_RESETB_MASK | PLLCTL1_PLL_EN_MASK;
+
+		dev_dbg(dev, "updating PLL clock\n");
+		i2c_wr16(sd, PLLCTL0, pllctl0_new);
+		i2c_wr16_and_or(sd, PLLCTL1, pllctl1_mask, pllctl1_val);
+		udelay(1000);
+		i2c_wr16_and_or(sd, PLLCTL1, ~PLLCTL1_CKEN_MASK,
+				PLLCTL1_CKEN_MASK);
+	}
+
+	tc358746_dump_pll(dev, state);
+}
+
+static void tc358746_set_csi_color_space(struct v4l2_subdev *sd)
+{
+	struct tc358746_state *state = to_state(sd);
+	const struct tc358746_mbus_fmt *tc358746_fmt =
+		tc358746_get_format(state->fmt.code);
+
+	/* currently no self defined csi user data type id's are supported */
+	mutex_lock(&state->confctl_mutex);
+	i2c_wr16_and_or(sd, DATAFMT,
+			~(DATAFMT_PDFMT_MASK | DATAFMT_UDT_EN_MASK),
+			DATAFMT_PDFMT_SET(tc358746_fmt->pdformat));
+	i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PDATAF_MASK,
+			CONFCTL_PDATAF_SET(tc358746_fmt->pdataf));
+	mutex_unlock(&state->confctl_mutex);
+}
+
+static void tc38764_debug_pattern_80(struct v4l2_subdev *sd)
+{
+	int i;
+
+	i2c_wr16(sd, DBG_ACT_LINE_CNT, 0x8000);
+	i2c_wr16(sd, DBG_LINE_WIDTH, 0x0396);
+	i2c_wr16(sd, DBG_VERT_BLANK_LINE_CNT, 0x0000);
+
+	for (i = 0; i < 80; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0xff7f);
+	i2c_wr16(sd, DBG_VIDEO_DATA, 0xff00);
+	for (i = 0; i < 40; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0xffff);
+	i2c_wr16(sd, DBG_VIDEO_DATA, 0xc0ff);
+	for (i = 0; i < 40; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0xc000);
+	for (i = 0; i < 80; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0x7f00);
+	for (i = 0; i < 80; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0x7fff);
+	i2c_wr16(sd, DBG_VIDEO_DATA, 0x0000);
+	for (i = 0; i < 40; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0x00ff);
+	i2c_wr16(sd, DBG_VIDEO_DATA, 0x00ff);
+	for (i = 0; i < 40; i++)
+		i2c_wr16(sd, DBG_VIDEO_DATA, 0x0000);
+	i2c_wr16(sd, DBG_VIDEO_DATA, 0x007f);
+
+	i2c_wr16(sd, DBG_ACT_LINE_CNT, 0xC1DF);
+}
+
+static void tc358746_enable_csi_lanes(struct v4l2_subdev *sd, int enable)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct tc358746_csi_param *csi_setting =
+		tc358746_g_cur_csi_settings(state);
+	unsigned int lanes = csi_setting->lane_num;
+	u32 val = 0;
+
+	if (lanes < 1 || !enable)
+		i2c_wr32(sd, CLW_CNTRL, CLW_CNTRL_CLW_LANEDISABLE_MASK);
+	if (lanes < 1 || !enable)
+		i2c_wr32(sd, D0W_CNTRL, D0W_CNTRL_D0W_LANEDISABLE_MASK);
+	if (lanes < 2 || !enable)
+		i2c_wr32(sd, D1W_CNTRL, D1W_CNTRL_D1W_LANEDISABLE_MASK);
+	if (lanes < 3 || !enable)
+		i2c_wr32(sd, D2W_CNTRL, D2W_CNTRL_D2W_LANEDISABLE_MASK);
+	if (lanes < 4 || !enable)
+		i2c_wr32(sd, D3W_CNTRL, D2W_CNTRL_D3W_LANEDISABLE_MASK);
+
+	if (lanes > 0 && enable)
+		val |= HSTXVREGEN_CLM_HSTXVREGEN_MASK |
+			HSTXVREGEN_D0M_HSTXVREGEN_MASK;
+	if (lanes > 1 && enable)
+		val |= HSTXVREGEN_D1M_HSTXVREGEN_MASK;
+	if (lanes > 2 && enable)
+		val |= HSTXVREGEN_D2M_HSTXVREGEN_MASK;
+	if (lanes > 3 && enable)
+		val |= HSTXVREGEN_D3M_HSTXVREGEN_MASK;
+
+	i2c_wr32(sd, HSTXVREGEN, val);
+}
+
+static void tc358746_set_csi(struct v4l2_subdev *sd)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct tc358746_csi_param *csi_setting =
+		tc358746_g_cur_csi_settings(state);
+	bool en_continuous_clk = csi_setting->is_continuous_clk;
+	u32 val;
+
+	val = TCLK_HEADERCNT_TCLK_ZEROCNT_SET(csi_setting->tclk_zerocnt) |
+	      TCLK_HEADERCNT_TCLK_PREPARECNT_SET(csi_setting->tclk_preparecnt);
+	i2c_wr32(sd, TCLK_HEADERCNT, val);
+	val = THS_HEADERCNT_THS_ZEROCNT_SET(csi_setting->ths_zerocnt) |
+	      THS_HEADERCNT_THS_PREPARECNT_SET(csi_setting->ths_preparecnt);
+	i2c_wr32(sd, THS_HEADERCNT, val);
+	i2c_wr32(sd, TWAKEUP, csi_setting->twakeupcnt);
+	i2c_wr32(sd, TCLK_POSTCNT, csi_setting->tclk_postcnt);
+	i2c_wr32(sd, THS_TRAILCNT, csi_setting->ths_trailcnt);
+	i2c_wr32(sd, LINEINITCNT, csi_setting->lineinitcnt);
+	i2c_wr32(sd, LPTXTIMECNT, csi_setting->lptxtimecnt);
+	i2c_wr32(sd, TCLK_TRAILCNT, csi_setting->tclk_trailcnt);
+	i2c_wr32(sd, TXOPTIONCNTRL,
+		 en_continuous_clk ? TXOPTIONCNTRL_CONTCLKMODE_MASK : 0);
+
+	if (state->test)
+		tc38764_debug_pattern_80(sd);
+
+	tc358746_dump_csi(&state->i2c_client->dev, csi_setting);
+}
+
+static void tc358746_enable_csi_module(struct v4l2_subdev *sd, int enable)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct tc358746_csi_param *csi_setting =
+		tc358746_g_cur_csi_settings(state);
+	unsigned int lanes = csi_setting->lane_num;
+	u32 val;
+
+	if (!enable)
+		return;
+
+	i2c_wr32(sd, STARTCNTRL, STARTCNTRL_START_MASK);
+	i2c_wr32(sd, CSI_START, CSI_START_STRT_MASK);
+
+	val = CSI_CONTROL_NOL_1_MASK;
+	if (lanes == 2)
+		val = CSI_CONTROL_NOL_2_MASK;
+	else if (lanes == 3)
+		val = CSI_CONTROL_NOL_3_MASK;
+	else if (lanes == 4)
+		val = CSI_CONTROL_NOL_4_MASK;
+
+	val |= CSI_CONTROL_CSI_MODE_MASK | CSI_CONTROL_TXHSMD_MASK;
+	tc358746_wr_csi_control(sd, val);
+}
+
+static void tc358746_set_buffers(struct v4l2_subdev *sd)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct device *dev = &state->i2c_client->dev;
+	const struct tc358746_mbus_fmt *tc358746_mbusfmt =
+		tc358746_get_format(state->fmt.code);
+	unsigned int byte_per_line =
+		(state->fmt.width * tc358746_mbusfmt->bpp) / 8;
+
+	i2c_wr16(sd, FIFOCTL, state->vb_fifo);
+	i2c_wr16(sd, WORDCNT, byte_per_line);
+	dev_dbg(dev, "FIFOCTL 0x%02x: WORDCNT 0x%02x\n",
+		state->vb_fifo, byte_per_line);
+}
+
+/* --------------- CORE OPS --------------- */
+
+static int tc358746_log_status(struct v4l2_subdev *sd)
+{
+	struct tc358746_state *state = to_state(sd);
+	uint16_t sysctl = i2c_rd16(sd, SYSCTL);
+
+	v4l2_info(sd, "-----Chip status-----\n");
+	v4l2_info(sd, "Chip ID: 0x%02lx\n",
+		  (i2c_rd16(sd, CHIPID) & CHIPID_CHIPID_MASK) >> 8);
+	v4l2_info(sd, "Chip revision: 0x%02lx\n",
+		  i2c_rd16(sd, CHIPID) & CHIPID_REVID_MASK);
+	v4l2_info(sd, "Sleep mode: %s\n", sysctl & SYSCTL_SLEEP_MASK ?
+		  "on" : "off");
+
+	v4l2_info(sd, "-----CSI-TX status-----\n");
+	v4l2_info(sd, "Waiting for particular sync signal: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_WSYNC_MASK) ?
+			"yes" : "no");
+	v4l2_info(sd, "Transmit mode: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_TXACT_MASK) ?
+			"yes" : "no");
+	v4l2_info(sd, "Stopped: %s\n",
+			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_HLT_MASK) ?
+			"yes" : "no");
+	v4l2_info(sd, "Color space: %s\n",
+			state->fmt.code == MEDIA_BUS_FMT_UYVY8_2X8 ?
+			"YCbCr 422 8-bit" : "Unsupported");
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static void tc358746_print_register_map(struct v4l2_subdev *sd)
+{
+	v4l2_info(sd, "0x0000-0x0050: Global Register\n");
+	v4l2_info(sd, "0x0056-0x0070: Rx Control Registers\n");
+	v4l2_info(sd, "0x0080-0x00F8: Rx Status Registers\n");
+	v4l2_info(sd, "0x0100-0x0150: Tx D-PHY Register\n");
+	v4l2_info(sd, "0x0204-0x0238: Tx PPI Register\n");
+	v4l2_info(sd, "0x040c-0x0518: Tx Control Register\n");
+}
+
+static int tc358746_get_reg_size(u16 address)
+{
+	if (address <= 0x00ff)
+		return 2;
+	else if ((address >= 0x0100) && (address <= 0x05FF))
+		return 4;
+	else
+		return 1;
+}
+
+static int tc358746_g_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	if (reg->reg > 0xffff) {
+		tc358746_print_register_map(sd);
+		return -EINVAL;
+	}
+
+	reg->size = tc358746_get_reg_size(reg->reg);
+
+	reg->val = i2c_rdreg(sd, reg->reg, reg->size);
+
+	return 0;
+}
+
+static int tc358746_s_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	if (reg->reg > 0xffff) {
+		tc358746_print_register_map(sd);
+		return -EINVAL;
+	}
+
+	i2c_wrreg(sd, (u16)reg->reg, reg->val,
+			tc358746_get_reg_size(reg->reg));
+
+	return 0;
+}
+#endif
+
+/* --------------- video ops --------------- */
+
+static int tc358746_g_mbus_config(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_config *cfg)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct tc358746_csi_param *csi_setting =
+		tc358746_g_cur_csi_settings(state);
+
+	cfg->type = V4L2_MBUS_CSI2_DPHY;
+	cfg->flags = csi_setting->is_continuous_clk ?
+			V4L2_MBUS_CSI2_CONTINUOUS_CLOCK :
+			V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
+
+	switch (csi_setting->lane_num) {
+	case 1:
+		cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
+		break;
+	case 2:
+		cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
+		break;
+	case 3:
+		cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
+		break;
+	case 4:
+		cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tc358746_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct tc358746_state *state = to_state(sd);
+
+	/*
+	 * REF_01:
+	 * Softreset don't reset configuration registers content but is needed
+	 * during power-on to trigger a csi LP-11 state change and during
+	 * power-off to disable the csi-module.
+	 */
+	tc358746_sreset(sd);
+
+	if (state->fmt_changed) {
+		tc358746_set_buffers(sd);
+		tc358746_set_csi(sd);
+		tc358746_set_csi_color_space(sd);
+
+		/* as recommend in REF_01 */
+		tc358746_sleep_mode(sd, 1);
+		tc358746_set_pll(sd);
+		tc358746_sleep_mode(sd, 0);
+
+		state->fmt_changed = false;
+	}
+
+	tc358746_enable_csi_lanes(sd, on);
+	tc358746_enable_csi_module(sd, on);
+	tc358746_sleep_mode(sd, !on);
+
+	return 0;
+}
+
+static int tc358746_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	tc358746_enable_stream(sd, enable);
+
+	return 0;
+}
+
+/* --------------- pad ops --------------- */
+
+static int tc358746_enum_mbus_code(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(tc358746_formats))
+		return -EINVAL;
+
+	code->code = tc358746_formats[code->index].code;
+
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__tc358746_get_pad_format(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  unsigned int pad, u32 which)
+{
+	struct tc358746_state *state = to_state(sd);
+
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(sd, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &state->fmt;
+	default:
+		return NULL;
+	}
+}
+
+static int tc358746_get_fmt(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_format *format)
+{
+	struct tc358746_state *state = to_state(sd);
+
+	if (format->pad != 0 && format->pad != 1)
+		return -EINVAL;
+
+	format->format.code = state->fmt.code;
+	format->format.width = state->fmt.width;
+	format->format.height = state->fmt.height;
+	format->format.field = state->fmt.field;
+
+	return 0;
+}
+
+static int tc358746_set_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_format *format)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct device *dev = &state->i2c_client->dev;
+	struct media_pad *pad = &state->pads[format->pad];
+	struct media_pad *remote_sensor_pad =
+		media_entity_remote_pad(&state->pads[0]);
+	struct v4l2_subdev *sensor_sd;
+	struct v4l2_mbus_framefmt *mbusformat;
+	const struct tc358746_mbus_fmt *tc358746_mbusformat;
+	struct v4l2_ctrl *ctrl;
+	unsigned int pclk, hblank;
+	int new_freq, cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);
+	u16 vb_fifo;
+
+	if (pad->flags == MEDIA_PAD_FL_SOURCE)
+		return tc358746_get_fmt(sd, cfg, format);
+
+	mbusformat = __tc358746_get_pad_format(sd, cfg, format->pad,
+					       format->which);
+	if (!mbusformat)
+		return -EINVAL;
+
+	tc358746_mbusformat = tc358746_get_format(format->format.code);
+	if (!tc358746_mbusformat) {
+		format->format.code = tc358746_def_fmt.code;
+		tc358746_mbusformat = tc358746_get_format(format->format.code);
+	}
+
+	/*
+	 * Some sensors change their hblank and pclk value on different formats,
+	 * so we need to request it again.
+	 */
+	sensor_sd = media_entity_to_v4l2_subdev(remote_sensor_pad->entity);
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	pclk = v4l2_ctrl_g_ctrl_int64(ctrl);
+	if (pclk != state->pclk) {
+		dev_dbg(dev, "Update pclk from %u to %u\n", state->pclk, pclk);
+		state->pclk = pclk;
+	}
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_HBLANK);
+	hblank = v4l2_ctrl_g_ctrl(ctrl);
+	if (hblank != state->hblank) {
+		dev_dbg(dev, "Update hblank from %u to %u\n", state->hblank,
+			hblank);
+		state->hblank = hblank;
+	}
+
+	/*
+	 * Normaly the HW has no size limitations but we have to check if the
+	 * csi timings are valid for this size. The timings can be adjust by the
+	 * fifo size. If this doesn't work we have to do this check again with a
+	 * other csi link frequency if it is possible.
+	 */
+	new_freq = tc358746_adjust_timings(state, tc358746_mbusformat,
+					   &format->format.width, &vb_fifo);
+
+	/* Currently only a few YUV based formats are supported */
+	if (tc358746_format_supported(format->format.code))
+		format->format.code = MEDIA_BUS_FMT_UYVY8_2X8;
+
+	/* Currently only non interleaved images are supported */
+	format->format.field = V4L2_FIELD_NONE;
+
+	*mbusformat = format->format;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		state->fmt_changed = true;
+		state->vb_fifo = vb_fifo;
+		if (new_freq != cur_freq)
+			v4l2_ctrl_s_ctrl(state->link_freq, new_freq);
+	}
+
+	return 0;
+}
+
+static int
+tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link,
+		       struct v4l2_subdev_format *source_fmt,
+		       struct v4l2_subdev_format *sink_fmt)
+{
+	struct tc358746_state *state = to_state(sd);
+	struct device *dev = &state->i2c_client->dev;
+	const struct tc358746_mbus_fmt *tc358746_mbusformat;
+	struct v4l2_subdev *sensor_sd;
+	struct v4l2_ctrl *ctrl;
+	unsigned int pclk, pclk_old = state->pclk;
+	unsigned int hblank, hblank_old = state->hblank;
+	int new_freq;
+	u16 vb_fifo;
+
+	/*
+	 * Only validate if the timings are changed, after the link was already
+	 * initialized. This can be happen if the parallel sensor frame interval
+	 * is changed. Format checks are perfomed by the common code.
+	 */
+
+	tc358746_mbusformat = tc358746_get_format(sink_fmt->format.code);
+	if (!tc358746_mbusformat)
+		return -EINVAL; /* Format was changed too and is invalid */
+
+	sensor_sd = media_entity_to_v4l2_subdev(link->source->entity);
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	pclk = v4l2_ctrl_g_ctrl_int64(ctrl);
+	if (pclk != state->pclk) {
+		dev_dbg(dev, "%s pixel rate is changed\n", sensor_sd->name);
+		state->pclk = pclk;
+	}
+
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_HBLANK);
+	hblank = v4l2_ctrl_g_ctrl(ctrl);
+	if (hblank != state->hblank) {
+		dev_dbg(dev,
+			"%s hblank interval is changed\n", sensor_sd->name);
+		state->hblank = hblank;
+	}
+
+	new_freq = tc358746_adjust_timings(state, tc358746_mbusformat,
+					   &source_fmt->format.width, &vb_fifo);
+
+	if (new_freq != v4l2_ctrl_g_ctrl(state->link_freq)) {
+		/*
+		 * This can lead into undefined behaviour, so we don't support
+		 * dynamic changes due to a to late re-configuration.
+		 */
+		dev_err(dev,
+			"%s format can't be applied re-run the whole s_fmt\n",
+			sensor_sd->name);
+		state->pclk = pclk_old;
+		state->hblank = hblank_old;
+
+		return -EINVAL;
+	}
+
+	state->fmt_changed = true;
+	state->vb_fifo = vb_fifo;
+
+	return 0;
+}
+
+static int tc358764_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct tc358746_state *state = container_of(ctrl->handler,
+					       struct tc358746_state, hdl);
+	struct device *dev = &state->i2c_client->dev;
+
+	switch (ctrl->id) {
+	case V4L2_CID_LINK_FREQ:
+		dev_info(dev, "Update link-frequency %llu -> %llu\n",
+			 state->link_frequencies[ctrl->cur.val],
+			 state->link_frequencies[ctrl->val]);
+
+		return 0;
+	case V4L2_CID_TEST_PATTERN:
+		state->test = ctrl->val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tc358746_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 v4l2_subdev *ps_sd = media_entity_to_v4l2_subdev(remote->entity);
+	struct tc358746_state *state = to_state(sd);
+	struct v4l2_ctrl *ctrl;
+
+	/* no special requirements on source pads */
+	if (local->flags & MEDIA_PAD_FL_SOURCE)
+		return 0;
+
+	dev_dbg(sd->dev, "link setup '%s':%d->'%s':%d[%d]",
+		remote->entity->name, remote->index, local->entity->name,
+		local->index, flags & MEDIA_LNK_FL_ENABLED);
+
+	/*
+	 * The remote parallel sensor must support pixel rate and hblank query
+	 */
+	ctrl = v4l2_ctrl_find(ps_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	if (!ctrl) {
+		dev_err(sd->dev, "Subdev %s must support V4L2_CID_PIXEL_RATE\n",
+			ps_sd->name);
+		return -EINVAL;
+	}
+	state->pclk = v4l2_ctrl_g_ctrl_int64(ctrl);
+
+	ctrl = v4l2_ctrl_find(ps_sd->ctrl_handler, V4L2_CID_HBLANK);
+	if (!ctrl) {
+		dev_err(sd->dev, "Subdev %s must support V4L2_CID_HBLANK\n",
+			ps_sd->name);
+		return -EINVAL;
+	}
+	state->hblank = v4l2_ctrl_g_ctrl(ctrl);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_ctrl_ops tc358764_ctrl_ops = {
+	.s_ctrl = tc358764_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tc358746_core_ops = {
+	.log_status = tc358746_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = tc358746_g_register,
+	.s_register = tc358746_s_register,
+#endif
+	.s_power = tc358746_s_power,
+};
+
+static const struct v4l2_subdev_video_ops tc358746_video_ops = {
+	.g_mbus_config = tc358746_g_mbus_config,
+	.s_stream = tc358746_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops tc358746_pad_ops = {
+	.enum_mbus_code = tc358746_enum_mbus_code,
+	.set_fmt = tc358746_set_fmt,
+	.get_fmt = tc358746_get_fmt,
+	.link_validate = tc358746_link_validate,
+};
+
+static const struct v4l2_subdev_ops tc358746_ops = {
+	.core = &tc358746_core_ops,
+	.video = &tc358746_video_ops,
+	.pad = &tc358746_pad_ops,
+};
+
+static const struct media_entity_operations tc358746_entity_ops = {
+	.link_setup = &tc358746_link_setup,
+	.link_validate = &v4l2_subdev_link_validate,
+};
+
+/* --------------- PROBE / REMOVE --------------- */
+
+static int tc358746_set_lane_settings(struct tc358746_state *state,
+				      struct v4l2_fwnode_endpoint *fw)
+{
+	struct device *dev = &state->i2c_client->dev;
+	int i;
+
+	for (i = 0; i < fw->nr_of_link_frequencies; i++) {
+		struct tc358746_csi_param *s =
+			&state->link_freq_settings[i];
+		u32 bps_pr_lane;
+
+		state->link_frequencies[i] = fw->link_frequencies[i];
+
+		/*
+		 * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
+		 * bps_pr_lane = 2 * link_freq, because MIPI data lane is double
+		 * data rate.
+		 */
+		bps_pr_lane = 2 * fw->link_frequencies[i];
+		if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
+			dev_err(dev, "unsupported bps per lane: %u bps\n",
+				bps_pr_lane);
+			return -EINVAL;
+		}
+
+		if (bps_pr_lane > 500000000)
+			s->speed_range = 0;
+		else if (bps_pr_lane > 250000000)
+			s->speed_range = 1;
+		else if (bps_pr_lane > 125000000)
+			s->speed_range = 2;
+		else
+			s->speed_range = 3;
+
+		s->unit_clk_hz = state->pllinclk_hz >> s->speed_range;
+		s->unit_clk_mul = bps_pr_lane / s->unit_clk_hz;
+		s->speed_per_lane = bps_pr_lane;
+		s->lane_num = fw->bus.mipi_csi2.num_data_lanes;
+		s->is_continuous_clk = fw->bus.mipi_csi2.flags &
+			V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+		if (s->speed_per_lane != 432000000U)
+			dev_warn(dev, "untested bps per lane: %u bps\n",
+				 s->speed_per_lane);
+
+		dev_dbg(dev, "%s: lane setting %d\n", __func__, i);
+		dev_dbg(dev, "unit_clk %uHz: unit_clk_mul %u: speed_range %u: speed_per_lane(bps/lane) %u: csi_lange_numbers %u\n",
+			s->unit_clk_hz, s->unit_clk_mul, s->speed_range,
+			s->speed_per_lane, s->lane_num);
+	}
+
+	state->link_frequencies_num = fw->nr_of_link_frequencies;
+
+	return 0;
+}
+
+static void tc358746_gpio_reset(struct tc358746_state *state)
+{
+	usleep_range(5000, 10000);
+	gpiod_set_value(state->reset_gpio, 1);
+	usleep_range(1000, 2000);
+	gpiod_set_value(state->reset_gpio, 0);
+	msleep(20);
+}
+
+static int tc358746_apply_fw(struct tc358746_state *state)
+{
+	struct tc358746_csi_param *csi_setting;
+	int err, i;
+
+	for (i = 0; i < state->link_frequencies_num; i++) {
+		csi_setting = &state->link_freq_settings[i];
+
+		err = tc358746_calculate_csi_txtimings(state, csi_setting);
+		if (err) {
+			dev_err(&state->i2c_client->dev,
+				"Failed to calc csi-tx tminings\n");
+			return err;
+		}
+	}
+
+	/*
+	 * Set it to the hw default value. The correct value will be set during
+	 * set_fmt(), since it depends on the pclk and and the resulution.
+	 */
+	state->vb_fifo = 1;
+
+	err = clk_prepare_enable(state->refclk);
+	if (err) {
+		dev_err(&state->i2c_client->dev, "Failed to enable clock\n");
+		return err;
+	}
+
+	if (state->reset_gpio)
+		tc358746_gpio_reset(state);
+
+	return 0;
+}
+
+static int tc358746_probe_fw(struct tc358746_state *state)
+{
+	struct device *dev = &state->i2c_client->dev;
+	struct v4l2_fwnode_endpoint endpoint = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY,
+	};
+	struct fwnode_handle *fw_node;
+	unsigned int refclk, pllinclk;
+	unsigned char pll_prediv;
+	int ret = -EINVAL;
+
+	/* Parse all clocks */
+	state->refclk = devm_clk_get(dev, "refclk");
+	if (IS_ERR(state->refclk)) {
+		if (PTR_ERR(state->refclk) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get refclk: %ld\n",
+				PTR_ERR(state->refclk));
+		return PTR_ERR(state->refclk);
+	}
+
+	refclk = clk_get_rate(state->refclk);
+	if (refclk < 6000000 || refclk > 40000000) {
+		dev_err(dev, "refclk must between 6MHz and 40MHz\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The PLL input clock is obtained by dividing refclk by pll_prd.
+	 * It must be between 4 MHz and 40 MHz, lower frequency is better.
+	 */
+	pll_prediv = DIV_ROUND_CLOSEST(refclk, 4000000);
+	if (pll_prediv < 1 || pll_prediv > 16) {
+		dev_err(dev, "invalid pll pre-divider value: %d\n", pll_prediv);
+		return -EINVAL;
+	}
+	state->pll_prd = pll_prediv;
+
+	pllinclk = DIV_ROUND_CLOSEST(refclk, pll_prediv);
+	if (pllinclk < 4000000 || pllinclk > 40000000) {
+		dev_err(dev, "invalid pll input clock: %d Hz\n", pllinclk);
+		return -EINVAL;
+	}
+	state->pllinclk_hz = pllinclk;
+
+	/* Now parse the fw-node */
+	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fw_node) {
+		struct fwnode_endpoint fw_ep;
+
+		ret = fwnode_graph_parse_endpoint(fw_node, &fw_ep);
+		if (ret)
+			return -EINVAL;
+
+		/* get downstream endpoint */
+		if (fw_ep.port == 1)
+			break;
+	}
+
+	if (!fw_node) {
+		dev_err(dev, "missing endpoint node\n");
+		return -EINVAL;
+	}
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(fw_node, &endpoint);
+	if (ret) {
+		dev_err(dev, "failed to parse endpoint %d\n", ret);
+		return ret;
+	}
+
+	if (endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
+	    endpoint.nr_of_link_frequencies == 0) {
+		dev_err(dev, "missing CSI-2 properties in endpoint\n");
+		ret = -EINVAL;
+		goto free_ep;
+	}
+
+	if (endpoint.bus.mipi_csi2.num_data_lanes > 4) {
+		dev_err(dev, "invalid number of lanes\n");
+		ret = -EINVAL;
+		goto free_ep;
+	}
+
+	state->link_freq_settings =
+		devm_kcalloc(dev, endpoint.nr_of_link_frequencies,
+			     sizeof(*state->link_freq_settings), GFP_KERNEL);
+	if (!state->link_freq_settings) {
+		ret = -ENOMEM;
+		goto free_ep;
+	}
+
+	state->link_frequencies =
+		devm_kcalloc(dev, endpoint.nr_of_link_frequencies,
+			     sizeof(*state->link_frequencies), GFP_KERNEL);
+	if (!state->link_frequencies) {
+		ret = -ENOMEM;
+		goto free_ep;
+	}
+
+	ret = tc358746_set_lane_settings(state, &endpoint);
+	if (ret)
+		goto free_ep;
+
+	state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						    GPIOD_OUT_LOW);
+	if (IS_ERR(state->reset_gpio)) {
+		dev_err(dev, "failed to get reset gpio\n");
+		return PTR_ERR(state->reset_gpio);
+	}
+
+	ret = 0;
+
+free_ep:
+	v4l2_fwnode_endpoint_free(&endpoint);
+	return ret;
+}
+
+static int tc358746_parse_endpoint(struct device *dev,
+				   struct v4l2_fwnode_endpoint *vep,
+				   struct v4l2_async_subdev *asd)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+
+	if (!fwnode_device_is_available(asd->match.fwnode)) {
+		v4l2_err(sd, "remote is not available\n");
+		return -ENOTCONN;
+	}
+
+	if (vep->bus_type != V4L2_MBUS_PARALLEL) {
+		v4l2_err(sd, "invalid bus type, must be PARALLEL\n");
+		return -ENOTCONN;
+	}
+
+	return 0;
+};
+
+static int tc358746_async_register(struct v4l2_subdev *sd)
+{
+	unsigned int port = 0;
+
+	return v4l2_async_register_fwnode_subdev(
+		sd, sizeof(struct v4l2_async_subdev), &port, 1,
+		tc358746_parse_endpoint);
+
+}
+
+static const char * const tc358764_test_pattern_menu[] = {
+	"Disabled",
+	"colorbar 80px",
+};
+
+static int tc358746_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct tc358746_state *state;
+	struct v4l2_subdev *sd;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	state->i2c_client = client;
+
+	/* platform data */
+	err = tc358746_probe_fw(state);
+	if (err)
+		return err;
+
+	err = tc358746_apply_fw(state);
+	if (err)
+		return err;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &tc358746_ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	/* i2c access */
+	if (((i2c_rd16(sd, CHIPID) & CHIPID_CHIPID_MASK) >> 8) != 0x44) {
+		v4l2_info(sd, "not a TC358746 on address 0x%x\n",
+			  client->addr << 1);
+		return -ENODEV;
+	}
+
+	/* control handlers */
+	v4l2_ctrl_handler_init(&state->hdl, 1);
+
+	v4l2_ctrl_new_std_menu_items(&state->hdl,
+			&tc358764_ctrl_ops, V4L2_CID_TEST_PATTERN,
+			ARRAY_SIZE(tc358764_test_pattern_menu) - 1, 0, 0,
+			tc358764_test_pattern_menu);
+
+	state->link_freq =
+		v4l2_ctrl_new_int_menu(&state->hdl, &tc358764_ctrl_ops,
+				       V4L2_CID_LINK_FREQ,
+				       state->link_frequencies_num - 1,
+				       TC358746_DEF_LINK_FREQ,
+				       state->link_frequencies);
+
+
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		err = state->hdl.error;
+		goto err_hdl;
+	}
+
+	state->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+	state->pads[0].flags = MEDIA_PAD_FL_SINK;
+	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	sd->entity.ops = &tc358746_entity_ops;
+	err = media_entity_pads_init(&sd->entity, 2, state->pads);
+	if (err < 0)
+		goto err_hdl;
+
+	mutex_init(&state->confctl_mutex);
+
+	state->fmt = tc358746_def_fmt;
+
+	/* apply default settings */
+	tc358746_sreset(sd);
+	tc358746_set_buffers(sd);
+	tc358746_set_csi(sd);
+	tc358746_set_csi_color_space(sd);
+	tc358746_sleep_mode(sd, 1);
+	tc358746_set_pll(sd);
+	tc358746_enable_stream(sd, 0);
+
+	err = tc358746_async_register(sd);
+	if (err < 0)
+		goto err_hdl;
+
+	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+		  client->addr << 1, client->adapter->name);
+
+	return 0;
+
+err_hdl:
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&state->hdl);
+	return err;
+}
+
+static int tc358746_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tc358746_state *state = to_state(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	v4l2_device_unregister_subdev(sd);
+	mutex_destroy(&state->confctl_mutex);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&state->hdl);
+
+	return 0;
+}
+
+static const struct i2c_device_id tc358746_id[] = {
+	{"tc358746", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tc358746_id);
+
+static const struct of_device_id __maybe_unused tc358746_of_match[] = {
+	{ .compatible = "toshiba,tc358746" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tc358746_of_match);
+
+static struct i2c_driver tc358746_driver = {
+	.driver = {
+		.name = "tc358746",
+		.of_match_table = of_match_ptr(tc358746_of_match),
+	},
+	.probe = tc358746_probe,
+	.remove = tc358746_remove,
+	.id_table = tc358746_id,
+};
+
+module_i2c_driver(tc358746_driver);
diff --git a/drivers/media/i2c/tc358746_regs.h b/drivers/media/i2c/tc358746_regs.h
new file mode 100644
index 000000000000..9232d00d0e92
--- /dev/null
+++ b/drivers/media/i2c/tc358746_regs.h
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tc358746 - Toshiba Parallel to CSI-2 bridge - register names and bit masks
+ *
+ * Convention:
+ * <REGISTER>
+ * <REGISTER>_<BITFIELD>_MASK
+ * <REGISTER>_<BITFIELD>_<VALUE>
+ * <REGISTER>_<BITFIELD>_SET(val = <REGISTER>_<BITFIELD>_<VALUE>)
+ *
+ * References:
+ * REF_01:
+ * - TC358746AXBG/TC358748XBG/TC358748IXBG Functional Specification Rev 1.2
+ */
+
+#ifndef __TC358746_REGS_H
+#define __TC358746_REGS_H
+
+#define CHIPID			0x0000
+#define CHIPID_CHIPID_MASK		GENMASK(15, 8)
+#define CHIPID_REVID_MASK		GENMASK(7, 0)
+
+#define SYSCTL			0x0002
+#define SYSCTL_SLEEP_MASK		BIT(1)
+#define SYSCTL_SRESET_MASK		BIT(0)
+
+#define CONFCTL                 0x0004
+#define CONFCTL_TRIEN_MASK		BIT(15)
+#define CONFCTL_INTE2N_MASK		BIT(13)
+#define CONFCTL_BT656EN_MASK		BIT(12)
+#define CONFCTL_PDATAF_MASK		GENMASK(9, 8)
+#define CONFCTL_PDATAF_SET(val)		(((val << 8) & CONFCTL_PDATAF_MASK))
+#define CONFCTL_PDATAF_MODE0		0
+#define CONFCTL_PDATAF_MODE1		1
+#define CONFCTL_PDATAF_MODE2		2
+#define CONFCTL_PPEN_MASK		BIT(6)
+#define CONFCTL_VVALIDP_MASK		BIT(5)
+#define CONFCTL_HVALIDP_MASK		BIT(4)
+#define CONFCTL_PCLKP_MASK		BIT(3)
+#define CONFCTL_AUTO_MASK		BIT(2)
+#define CONFCTL_DATALANE_MASK		GENMASK(1, 0)
+#define CONFCTL_DATALANE_1		0
+#define CONFCTL_DATALANE_2		1
+#define CONFCTL_DATALANE_3		2
+#define CONFCTL_DATALANE_4		3
+
+#define FIFOCTL			0x0006
+#define DATAFMT			0x0008
+#define DATAFMT_PDFMT_RAW8		0
+#define DATAFMT_PDFMT_RAW10		1
+#define DATAFMT_PDFMT_RAW12		2
+#define DATAFMT_PDFMT_RGB888		3
+#define DATAFMT_PDFMT_RGB666		4
+#define DATAFMT_PDFMT_RGB565		5
+#define DATAFMT_PDFMT_YCBCRFMT_422_8_BIT 6
+#define DATAFMT_PDFMT_RAW14		8
+#define DATAFMT_PDFMT_YCBCRFMT_422_10_BIT 9
+#define DATAFMT_PDFMT_YCBCRFMT_444	10
+#define DATAFMT_PDFMT_MASK		GENMASK(7, 4)
+#define DATAFMT_PDFMT_SET(val)		(((val) << 4) & DATAFMT_PDFMT_MASK)
+#define DATAFMT_UDT_EN_MASK		BIT(0)
+
+#define MCLKCTL			0x000c
+#define MCLKCTL_MCLK_HIGH_MASK		GENMASK(15, 8)
+#define MCLKCTL_MCLK_HIGH_SET(val)	((((val) - 1) << 8) & MCLKCTL_MCLK_HIGH_MASK)
+#define MCLKCTL_MCLK_LOW_MASK		GENMASK(7, 0)
+#define MCLKCTL_MCLK_LOW_SET(val)	(((val) - 1) & MCLKCTL_MCLK_LOW_MASK)
+
+#define PLLCTL0			0x0016
+#define PLLCTL0_PLL_PRD_MASK		GENMASK(15, 12)
+#define PLLCTL0_PLL_PRD_SET(prd)	((((prd) - 1) << 12) & PLLCTL0_PLL_PRD_MASK)
+#define PLLCTL0_PLL_FBD_MASK		GENMASK(8, 0)
+#define PLLCTL0_PLL_FBD_SET(fbd)        (((fbd) - 1) & PLLCTL0_PLL_FBD_MASK)
+
+#define PLLCTL1                 0x0018
+#define PLLCTL1_PLL_FRS_MASK            GENMASK(11, 10)
+#define PLLCTL1_PLL_FRS_SET(frs)        (((frs) << 10) & PLLCTL1_PLL_FRS_MASK)
+#define PLLCTL1_PLL_LBWS_MASK		GENMASK(9, 8)
+#define PLLCTL1_LFBREN_MASK		BIT(6)
+#define PLLCTL1_BYPCKEN_MASK		BIT(5)
+#define PLLCTL1_CKEN_MASK		BIT(4)
+#define PLLCTL1_RESETB_MASK		BIT(1)
+#define PLLCTL1_PLL_EN_MASK		BIT(0)
+
+#define CLKCTL			0x0020
+#define CLKCTL_MCLKDIV_MASK		GENMASK(3, 2)
+#define CLKCTL_MCLKDIV_SET(val)		((val << 2) & CLKCTL_MCLKDIV_MASK)
+#define CLKCTL_MCLKDIV_8		0
+#define CLKCTL_MCLKDIV_4		1
+#define CLKCTL_MCLKDIV_2		2
+
+#define WORDCNT			0x0022
+#define PP_MISC                 0x0032
+#define PP_MISC_FRMSTOP_MASK		BIT(15)
+#define PP_MISC_RSTPTR_MASK		BIT(14)
+
+#define CSI2TX_DATA_TYPE	0x0050
+#define MIPI_PHY_STATUS		0x0062
+#define CSI2_ERROR_STATUS       0x0064
+#define CSI2_ERR_EN             0x0066
+#define CSI2_IDID_ERROR         0x006c
+#define DBG_ACT_LINE_CNT        0x00e0
+#define DBG_LINE_WIDTH		0x00e2
+#define DBG_VERT_BLANK_LINE_CNT	0x00e4
+#define DBG_VIDEO_DATA          0x00e8
+#define FIFOSTATUS              0x00F8
+
+#define CLW_CNTRL               0x0140
+#define CLW_CNTRL_CLW_LANEDISABLE_MASK	BIT(0)
+
+#define D0W_CNTRL               0x0144
+#define D0W_CNTRL_D0W_LANEDISABLE_MASK	BIT(0)
+
+#define D1W_CNTRL		0x0148
+#define D1W_CNTRL_D1W_LANEDISABLE_MASK	BIT(0)
+
+#define D2W_CNTRL		0x014C
+#define D2W_CNTRL_D2W_LANEDISABLE_MASK	BIT(0)
+
+#define D3W_CNTRL		0x0150
+#define D2W_CNTRL_D3W_LANEDISABLE_MASK	BIT(0)
+
+#define STARTCNTRL              0x0204
+#define STARTCNTRL_START_MASK		BIT(0)
+
+#define LINEINITCNT		0x0210
+#define LPTXTIMECNT		0x0214
+#define TCLK_HEADERCNT		0x0218
+#define	TCLK_HEADERCNT_TCLK_ZEROCNT_MASK	GENMASK(15, 8)
+#define TCLK_HEADERCNT_TCLK_PREPARECNT_MASK	GENMASK(6, 0)
+#define	TCLK_HEADERCNT_TCLK_ZEROCNT_SET(val)	((val << 8) & TCLK_HEADERCNT_TCLK_ZEROCNT_MASK)
+#define	TCLK_HEADERCNT_TCLK_PREPARECNT_SET(val)	(val & TCLK_HEADERCNT_TCLK_PREPARECNT_MASK)
+
+#define TCLK_TRAILCNT		0x021C
+#define THS_HEADERCNT		0x0220
+#define	THS_HEADERCNT_THS_ZEROCNT_MASK		GENMASK(14, 8)
+#define	THS_HEADERCNT_THS_PREPARECNT_MASK	GENMASK(6, 0)
+#define	THS_HEADERCNT_THS_ZEROCNT_SET(val)	((val << 8) & THS_HEADERCNT_THS_ZEROCNT_MASK)
+#define	THS_HEADERCNT_THS_PREPARECNT_SET(val)	(val & THS_HEADERCNT_THS_PREPARECNT_MASK)
+
+#define TWAKEUP			0x0224
+#define TCLK_POSTCNT		0x0228
+#define THS_TRAILCNT		0x022C
+#define HSTXVREGCNT		0x0230
+#define HSTXVREGEN              0x0234
+#define HSTXVREGEN_D3M_HSTXVREGEN_MASK	BIT(4)
+#define HSTXVREGEN_D2M_HSTXVREGEN_MASK  BIT(3)
+#define HSTXVREGEN_D1M_HSTXVREGEN_MASK  BIT(2)
+#define HSTXVREGEN_D0M_HSTXVREGEN_MASK  BIT(1)
+#define HSTXVREGEN_CLM_HSTXVREGEN_MASK  BIT(0)
+
+#define TXOPTIONCNTRL           0x0238
+#define TXOPTIONCNTRL_CONTCLKMODE_MASK	BIT(0)
+
+#define CSI_CONTROL             0x040C
+#define CSI_CONTROL_CSI_MODE_MASK       BIT(15)
+#define CSI_CONTROL_HTXTOEN_MASK        BIT(10)
+#define CSI_CONTROL_TXHSMD_MASK         BIT(7)
+#define CSI_CONTROL_NOL_MASK            GENMASK(2, 1)
+#define CSI_CONTROL_NOL_1_MASK          0
+#define CSI_CONTROL_NOL_2_MASK          BIT(1)
+#define CSI_CONTROL_NOL_3_MASK          BIT(2)
+#define CSI_CONTROL_NOL_4_MASK          (BIT(1) | BIT(2))
+#define CSI_CONTROL_EOTDIS_MASK         BIT(0)
+
+#define CSI_STATUS              0x0410
+#define CSI_STATUS_S_WSYNC_MASK		BIT(10)
+#define CSI_STATUS_S_TXACT_MASK		BIT(9)
+#define CSI_STATUS_S_HLT_MASK		BIT(0)
+
+#define CSI_INT			0x0414
+#define CSI_INT_INTHLT_MASK		BIT(3)
+#define CSI_INT_INTER_MASK		BIT(2)
+
+#define CSI_INT_ENA             0x0418
+#define CSI_INT_ENA_IENHLT_MASK		BIT(3)
+#define CSI_INT_ENA_IENER_MASK		BIT(2)
+
+#define CSI_ERR                 0x044C
+#define CSI_ERR_INER_MASK               BIT(9)
+#define CSI_ERR_WCER_MASK		BIT(8)
+#define CSI_ERR_QUNK_MASK		BIT(4)
+#define CSI_ERR_TXBRK_MASK		BIT(1)
+
+#define CSI_ERR_INTENA          0x0450
+#define CSI_ERR_HALT            0x0454
+#define CSI_CONFW               0x0500
+#define CSI_CONFW_MODE_MASK			GENMASK(31, 29)
+#define CSI_CONFW_MODE_SET_MASK			(BIT(31) | BIT(29))
+#define CSI_CONFW_MODE_CLEAR_MASK		(BIT(31) | BIT(30))
+#define CSI_CONFW_ADDRESS_MASK			GENMASK(28, 24)
+#define CSI_CONFW_ADDRESS_CSI_CONTROL_MASK	(BIT(24) | BIT(25))
+#define CSI_CONFW_ADDRESS_CSI_INT_ENA_MASK	(BIT(25) | BIT(26))
+#define CSI_CONFW_ADDRESS_CSI_ERR_INTENA_MASK	(BIT(28) | BIT(26))
+#define CSI_CONFW_ADDRESS_CSI_ERR_HALT_MASK	(BIT(28) | BIT(26) | BIT(24))
+#define CSI_CONFW_DATA_MASK			GENMASK(15, 0)
+
+#define CSIRESET                0x0504
+#define CSIRESET_RESET_CNF_MASK		BIT(1)
+#define CSIRESET_RESET_MODULE_MASK	BIT(0)
+
+#define CSI_INT_CLR             0x050C
+#define CSI_INT_CLR_ICRER_MASK		BIT(2)
+
+#define CSI_START               0x0518
+#define CSI_START_STRT_MASK		BIT(0)
+
+#endif
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 3/3] media: tc358746: update MAINTAINERS file
  2018-12-18 14:12 [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
  2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
@ 2018-12-18 14:12 ` Marco Felsch
  2019-02-18 11:46   ` Sakari Ailus
  2019-01-23 12:54 ` [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
  3 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2018-12-18 14:12 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: linux-media, devicetree, graphics

Add me as partial maintainer, others are welcome too.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 546f8d936589..f97dedbe545c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15230,6 +15230,13 @@ S:	Maintained
 F:	drivers/media/i2c/tc358743*
 F:	include/media/i2c/tc358743.h
 
+TOSHIBA TC358746 DRIVER
+M:	Marco Felsch <kernel@pengutronix.de>
+L:	linux-media@vger.kernel.org
+S:	Odd Fixes
+F:	drivers/media/i2c/tc358746*
+F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
+
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
 L:	platform-driver-x86@vger.kernel.org
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
  2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
@ 2018-12-19  1:24   ` kbuild test robot
  2018-12-20 19:37   ` kbuild test robot
  2019-02-18 11:25   ` Sakari Ailus
  2 siblings, 0 replies; 30+ messages in thread
From: kbuild test robot @ 2018-12-19  1:24 UTC (permalink / raw)
  To: Marco Felsch
  Cc: kbuild-all, hans.verkuil, sakari.ailus, mchehab, robh+dt,
	mark.rutland, linux-media, devicetree, graphics

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

Hi Marco,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[cannot apply to v4.20-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Marco-Felsch/media-add-Toshiba-TC358746-Bridge-support/20181219-041919
base:   git://linuxtv.org/media_tree.git master
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=8.1.0 make.cross ARCH=ia64 

All warnings (new ones prefixed by >>):

   drivers/media/i2c/tc358746.c: In function 'tc358746_sleep_mode':
>> drivers/media/i2c/tc358746.c:790:30: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551613' to '4294967293' [-Woverflow]
     i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
   drivers/media/i2c/tc358746.c: In function 'tc358746_enable_stream':
   drivers/media/i2c/tc358746.c:809:32: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709518847' to '4294934527' [-Woverflow]
      i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_FRMSTOP_MASK,
   drivers/media/i2c/tc358746.c:811:32: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551551' to '4294967231' [-Woverflow]
      i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK, 0);
   drivers/media/i2c/tc358746.c:812:32: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709535231' to '4294950911' [-Woverflow]
      i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_RSTPTR_MASK,
   drivers/media/i2c/tc358746.c:820:32: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551551' to '4294967231' [-Woverflow]
      i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK,
   drivers/media/i2c/tc358746.c: In function 'tc358746_set_pll':
   drivers/media/i2c/tc358746.c:866:32: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551599' to '4294967279' [-Woverflow]
      i2c_wr16_and_or(sd, PLLCTL1, ~PLLCTL1_CKEN_MASK,
   drivers/media/i2c/tc358746.c: In function 'tc358746_set_csi_color_space':
   drivers/media/i2c/tc358746.c:882:4: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551374' to '4294967054' [-Woverflow]
       ~(DATAFMT_PDFMT_MASK | DATAFMT_UDT_EN_MASK),
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/tc358746.c:884:31: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709550847' to '4294966527' [-Woverflow]
     i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PDATAF_MASK,

vim +790 drivers/media/i2c/tc358746.c

   787	
   788	static inline void tc358746_sleep_mode(struct v4l2_subdev *sd, int enable)
   789	{
 > 790		i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
   791				enable ? SYSCTL_SLEEP_MASK : 0);
   792	}
   793	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52418 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
  2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
  2018-12-19  1:24   ` kbuild test robot
@ 2018-12-20 19:37   ` kbuild test robot
  2019-02-18 11:25   ` Sakari Ailus
  2 siblings, 0 replies; 30+ messages in thread
From: kbuild test robot @ 2018-12-20 19:37 UTC (permalink / raw)
  To: Marco Felsch
  Cc: kbuild-all, hans.verkuil, sakari.ailus, mchehab, robh+dt,
	mark.rutland, linux-media, devicetree, graphics

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

Hi Marco,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on next-20181220]
[cannot apply to v4.20-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Marco-Felsch/media-add-Toshiba-TC358746-Bridge-support/20181219-041919
base:   git://linuxtv.org/media_tree.git master
config: sparc64-allyesconfig (attached as .config)
compiler: sparc64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=sparc64 

All warnings (new ones prefixed by >>):

   drivers/media//i2c/tc358746.c: In function 'tc358746_sleep_mode':
>> drivers/media//i2c/tc358746.c:790:30: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
                                 ^
   drivers/media//i2c/tc358746.c: In function 'tc358746_enable_stream':
   drivers/media//i2c/tc358746.c:809:32: warning: large integer implicitly truncated to unsigned type [-Woverflow]
      i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_FRMSTOP_MASK,
                                   ^
   drivers/media//i2c/tc358746.c:811:32: warning: large integer implicitly truncated to unsigned type [-Woverflow]
      i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK, 0);
                                   ^
   drivers/media//i2c/tc358746.c:812:32: warning: large integer implicitly truncated to unsigned type [-Woverflow]
      i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_RSTPTR_MASK,
                                   ^
   drivers/media//i2c/tc358746.c:820:32: warning: large integer implicitly truncated to unsigned type [-Woverflow]
      i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK,
                                   ^
   drivers/media//i2c/tc358746.c: In function 'tc358746_set_pll':
   drivers/media//i2c/tc358746.c:866:32: warning: large integer implicitly truncated to unsigned type [-Woverflow]
      i2c_wr16_and_or(sd, PLLCTL1, ~PLLCTL1_CKEN_MASK,
                                   ^
   drivers/media//i2c/tc358746.c: In function 'tc358746_set_csi_color_space':
   drivers/media//i2c/tc358746.c:882:4: warning: large integer implicitly truncated to unsigned type [-Woverflow]
       ~(DATAFMT_PDFMT_MASK | DATAFMT_UDT_EN_MASK),
       ^
   drivers/media//i2c/tc358746.c:884:31: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PDATAF_MASK,
                                  ^

vim +790 drivers/media//i2c/tc358746.c

   787	
   788	static inline void tc358746_sleep_mode(struct v4l2_subdev *sd, int enable)
   789	{
 > 790		i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
   791				enable ? SYSCTL_SLEEP_MASK : 0);
   792	}
   793	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 56038 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
@ 2018-12-28 23:10   ` Rob Herring
  2019-02-13 17:57   ` Jacopo Mondi
  2019-02-18 10:03   ` Sakari Ailus
  2 siblings, 0 replies; 30+ messages in thread
From: Rob Herring @ 2018-12-28 23:10 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

On Tue, 18 Dec 2018 15:12:38 +0100, Marco Felsch wrote:
> Add corresponding dt-bindings for the Toshiba tc358746 device.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 0/3] media: add Toshiba TC358746 Bridge support
  2018-12-18 14:12 [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
                   ` (2 preceding siblings ...)
  2018-12-18 14:12 ` [PATCH 3/3] media: tc358746: update MAINTAINERS file Marco Felsch
@ 2019-01-23 12:54 ` Marco Felsch
  2019-02-12 16:10   ` Marco Felsch
  3 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-01-23 12:54 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: devicetree, graphics, linux-media

Hi,

Just a ping.

The kbuilder reports some warning which I will fix in a v2 but I still
waiting for feedback from you.

Regards,
Marco

On 18-12-18 15:12, Marco Felsch wrote:
> Hi,
> 
> this patch set adds the support for the Toshiba TC358746 Parallel
> MIPI-CSI2 bridge device.
> 
> The last patch ("media: tc358746: update MAINTAINERS file") is optional,
> due to Hans answer to Michael [1]. We can drop this patch if it isn't
> needed.
> 
> I added the v4l2-compliance test in relation to [1], I used v4l2-compliance
> version 1.16.0. Unfortunately the VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test
> failed, but the device don't support events at all, as described in the
> commit message of the 2nd patch.
> 
> The patche set was succefully rebased on top of media_tree/master and
> compile tested.
> 
> [1] https://marc.info/?l=linux-kernel&m=154330540418714&w=2
> 
> Regards,
> Marco
> 
> 8<----------------------------------------------------------
> 
> root@samx6i:~# v4l2-compliance -s -u /dev/v4l-subdev12
> v4l2-compliance SHA: not available, 32 bits
> 
> Compliance test for device /dev/v4l-subdev12:
> 
> Media Driver Info:
>         Driver name      : imx-media
>         Model            : imx-media
>         Serial           : 
>         Bus info         : 
>         Media version    : 4.20.0
>         Hardware revision: 0x00000000 (0)
>         Driver version   : 4.20.0
> Interface Info:
>         ID               : 0x030000a6
>         Type             : V4L Sub-Device
> Entity Info:
>         ID               : 0x00000056 (86)
>         Name             : tc358746 6-000e
>         Function         : Video Interface Bridge
>         Pad 0x01000057   : 0: Sink
>           Link 0x0200008c: from remote pad 0x100005a of entity 'mt9m111 6-0048': Data, Enabled
>         Pad 0x01000058   : 1: Source
>           Link 0x0200008a: to remote pad 0x1000051 of entity 'imx6-mipi-csi2': Data, Enabled
> 
> Required ioctls:
>         test MC information (see 'Media Driver Info' above): OK
> 
> Allow for multiple opens:
>         test second /dev/v4l-subdev12 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
>         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
>                 fail: ../../../v4l-utils-1.16.0/utils/v4l2-compliance/v4l2-test-controls.cpp(816): subscribe event for control 'Image Processing Controls' failed
>         test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
>         test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>         Standard Controls: 3 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: 54, Succeeded: 53, Failed: 1, Warnings: 0
> 
> 8<----------------------------------------------------------
> 
> Marco Felsch (3):
>   media: dt-bindings: add bindings for Toshiba TC358746
>   media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
>   media: tc358746: update MAINTAINERS file
> 
>  .../bindings/media/i2c/toshiba,tc358746.txt   |   80 +
>  MAINTAINERS                                   |    7 +
>  drivers/media/i2c/Kconfig                     |   12 +
>  drivers/media/i2c/Makefile                    |    1 +
>  drivers/media/i2c/tc358746.c                  | 1847 +++++++++++++++++
>  drivers/media/i2c/tc358746_regs.h             |  208 ++
>  6 files changed, 2155 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
>  create mode 100644 drivers/media/i2c/tc358746.c
>  create mode 100644 drivers/media/i2c/tc358746_regs.h
> 
> -- 
> 2.19.1
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 0/3] media: add Toshiba TC358746 Bridge support
  2019-01-23 12:54 ` [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
@ 2019-02-12 16:10   ` Marco Felsch
  0 siblings, 0 replies; 30+ messages in thread
From: Marco Felsch @ 2019-02-12 16:10 UTC (permalink / raw)
  To: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland
  Cc: devicetree, graphics, linux-media

Hi,

gentle ping..

On 19-01-23 13:54, Marco Felsch wrote:
> Hi,
> 
> Just a ping.
> 
> The kbuilder reports some warning which I will fix in a v2 but I still
> waiting for feedback from you.
> 
> Regards,
> Marco
> 
> On 18-12-18 15:12, Marco Felsch wrote:
> > Hi,
> > 
> > this patch set adds the support for the Toshiba TC358746 Parallel
> > MIPI-CSI2 bridge device.
> > 
> > The last patch ("media: tc358746: update MAINTAINERS file") is optional,
> > due to Hans answer to Michael [1]. We can drop this patch if it isn't
> > needed.
> > 
> > I added the v4l2-compliance test in relation to [1], I used v4l2-compliance
> > version 1.16.0. Unfortunately the VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test
> > failed, but the device don't support events at all, as described in the
> > commit message of the 2nd patch.
> > 
> > The patche set was succefully rebased on top of media_tree/master and
> > compile tested.
> > 
> > [1] https://marc.info/?l=linux-kernel&m=154330540418714&w=2
> > 
> > Regards,
> > Marco
> > 
> > 8<----------------------------------------------------------
> > 
> > root@samx6i:~# v4l2-compliance -s -u /dev/v4l-subdev12
> > v4l2-compliance SHA: not available, 32 bits
> > 
> > Compliance test for device /dev/v4l-subdev12:
> > 
> > Media Driver Info:
> >         Driver name      : imx-media
> >         Model            : imx-media
> >         Serial           : 
> >         Bus info         : 
> >         Media version    : 4.20.0
> >         Hardware revision: 0x00000000 (0)
> >         Driver version   : 4.20.0
> > Interface Info:
> >         ID               : 0x030000a6
> >         Type             : V4L Sub-Device
> > Entity Info:
> >         ID               : 0x00000056 (86)
> >         Name             : tc358746 6-000e
> >         Function         : Video Interface Bridge
> >         Pad 0x01000057   : 0: Sink
> >           Link 0x0200008c: from remote pad 0x100005a of entity 'mt9m111 6-0048': Data, Enabled
> >         Pad 0x01000058   : 1: Source
> >           Link 0x0200008a: to remote pad 0x1000051 of entity 'imx6-mipi-csi2': Data, Enabled
> > 
> > Required ioctls:
> >         test MC information (see 'Media Driver Info' above): OK
> > 
> > Allow for multiple opens:
> >         test second /dev/v4l-subdev12 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
> >         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
> >                 fail: ../../../v4l-utils-1.16.0/utils/v4l2-compliance/v4l2-test-controls.cpp(816): subscribe event for control 'Image Processing Controls' failed
> >         test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> >         test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> >         Standard Controls: 3 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: 54, Succeeded: 53, Failed: 1, Warnings: 0
> > 
> > 8<----------------------------------------------------------
> > 
> > Marco Felsch (3):
> >   media: dt-bindings: add bindings for Toshiba TC358746
> >   media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
> >   media: tc358746: update MAINTAINERS file
> > 
> >  .../bindings/media/i2c/toshiba,tc358746.txt   |   80 +
> >  MAINTAINERS                                   |    7 +
> >  drivers/media/i2c/Kconfig                     |   12 +
> >  drivers/media/i2c/Makefile                    |    1 +
> >  drivers/media/i2c/tc358746.c                  | 1847 +++++++++++++++++
> >  drivers/media/i2c/tc358746_regs.h             |  208 ++
> >  6 files changed, 2155 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> >  create mode 100644 drivers/media/i2c/tc358746.c
> >  create mode 100644 drivers/media/i2c/tc358746_regs.h
> > 
> > -- 
> > 2.19.1
> > 
> > 
> > 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
  2018-12-28 23:10   ` Rob Herring
@ 2019-02-13 17:57   ` Jacopo Mondi
  2019-03-01 10:26     ` Marco Felsch
  2019-02-18 10:03   ` Sakari Ailus
  2 siblings, 1 reply; 30+ messages in thread
From: Jacopo Mondi @ 2019-02-13 17:57 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

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

Hi Marco,
    thanks for the patch.

I have some comments, which I hope might get the ball rolling...

On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> Add corresponding dt-bindings for the Toshiba tc358746 device.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> new file mode 100644
> index 000000000000..499733df744a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> @@ -0,0 +1,80 @@
> +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> +
> +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX

nit:
s/is a bridge that/is a bridge device that/
or drop is a bridge completely?

> +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.

From the thin public available datasheet, it seems to support SPI as
programming interface, but only when doing Parallel->CSI-2. I would
mention that.

> +
> +Required Properties:
> +
> +- compatible: should be "toshiba,tc358746"
> +- reg: should be <0x0e>

nit: s/should/shall

> +- clocks: should contain a phandle link to the reference clock source

just "phandle to the reference clock source" ?

> +- clock-names: the clock input is named "refclk".

According to the clock bindings this is optional, and since you have
a single clock I would drop it.

> +
> +Optional Properties:
> +
> +- reset-gpios: gpio phandle GPIO connected to the reset pin

would you drop one of the two "gpio" here. Like ": phandle to the GPIO
connected to the reset input pin"

> +
> +Parallel Endpoint:

Here I got confused. The chip supports 2 inputs (parallel and CSI-2)
and two outputs (parallel and CSI-2 again). You mention endpoints
propery only here, but it seems from the example you want two ports,
with one endpoint child-node each.

Even if the driver does not support CSI-2->Parallel at the moment,
bindings should be future-proof, so I would reserve the first two
ports for the inputs, and the last two for the output, or, considering
that the two input-output combinations are mutually exclusive, provide
one "input" port with two optional endpoints, and one "output" port with
two optional endpoints.

In both cases only one input and one output at the time could be
described in DT. Up to you, maybe others have different ideas as
well...

> +
> +Required Properties:
> +
> +- reg: should be <0>
> +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> +	     for sixteen bit wide bus.

The chip seems to support up to 24 bits of data bus width

> +
> +MIPI CSI-2 Endpoint:
> +
> +Required Properties:
> +
> +- reg: should be <1>
> +- data-lanes: should be <1 2 3 4> for four-lane operation,
> +	      or <1 2> for two-lane operation
> +- clock-lanes: should be <0>

Can this be changed? If the chip does not allow lane re-ordering you
could drop this.

> +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> +		    expressed as a 64-bit big-endian integer. The frequency
> +		    is half of the bps per lane due to DDR transmission.

Does the chip supports a limited set of bus frequencies, or are this
"hints" ? I admit this property actually puzzles me, so I might got it
wrong..

Thanks
   j

> +
> +Optional Properties:
> +
> +- clock-noncontinuous: Presence of this boolean property decides whether the
> +		       MIPI CSI-2 clock is continuous or non-continuous.
> +
> +For further information on the endpoint node properties, see
> +Documentation/devicetree/bindings/media/video-interfaces.txt.
> +
> +Example:
> +
> +&i2c {
> +	tc358746: tc358746@0e {
> +		reg = <0x0e>;
> +		compatible = "toshiba,tc358746";
> +		pinctrl-names = "default";
> +		clocks = <&clk_cam_ref>;
> +		clock-names = "refclk";
> +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port@0 {
> +			reg = <0>;
> +
> +			tc358746_parallel_in: endpoint {
> +				bus-width = <8>;
> +				remote-endpoint = <&micron_parallel_out>;
> +			};
> +		};
> +
> +		port@1 {
> +			reg = <1>;
> +
> +			tc358746_mipi2_out: endpoint {
> +				remote-endpoint = <&mipi_csi2_in>;
> +				data-lanes = <1 2>;
> +				clock-lanes = <0>;
> +				clock-noncontinuous;
> +				link-frequencies = /bits/ 64 <216000000>;
> +			};
> +		};
> +	};
> +};
> --
> 2.19.1
>

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
  2018-12-28 23:10   ` Rob Herring
  2019-02-13 17:57   ` Jacopo Mondi
@ 2019-02-18 10:03   ` Sakari Ailus
  2019-03-01 10:52     ` Marco Felsch
  2 siblings, 1 reply; 30+ messages in thread
From: Sakari Ailus @ 2019-02-18 10:03 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Marco,

My apologies for reviewing this so late. You've received good comments
already. I have a few more.

On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> Add corresponding dt-bindings for the Toshiba tc358746 device.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> new file mode 100644
> index 000000000000..499733df744a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> @@ -0,0 +1,80 @@
> +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> +
> +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.

This is interesting. The driver somehow needs to figure out the direction
of the data flow if it does not originate from DT. I guess it shouldn't as
it's not the property of an individual device, albeit in practice in all
hardware I've seen the direction of the pipeline is determinable and this
is visible in the kAPI as well. So I'm suggesting no changes due to this in
bindings, likely we'll need to address it somehow elsewhere going forward.

> +
> +Required Properties:
> +
> +- compatible: should be "toshiba,tc358746"
> +- reg: should be <0x0e>
> +- clocks: should contain a phandle link to the reference clock source
> +- clock-names: the clock input is named "refclk".
> +
> +Optional Properties:
> +
> +- reset-gpios: gpio phandle GPIO connected to the reset pin
> +
> +Parallel Endpoint:
> +
> +Required Properties:

It'd be nice if the relation between these sections would be somehow
apparent. E.g. using different underlining, such as in
Documentation/devicetree/bindings/media/ti,omap3isp.txt .

> +
> +- reg: should be <0>
> +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> +	     for sixteen bit wide bus.
> +
> +MIPI CSI-2 Endpoint:
> +
> +Required Properties:
> +
> +- reg: should be <1>
> +- data-lanes: should be <1 2 3 4> for four-lane operation,
> +	      or <1 2> for two-lane operation
> +- clock-lanes: should be <0>
> +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> +		    expressed as a 64-bit big-endian integer. The frequency
> +		    is half of the bps per lane due to DDR transmission.
> +
> +Optional Properties:
> +
> +- clock-noncontinuous: Presence of this boolean property decides whether the
> +		       MIPI CSI-2 clock is continuous or non-continuous.
> +
> +For further information on the endpoint node properties, see
> +Documentation/devicetree/bindings/media/video-interfaces.txt.
> +
> +Example:
> +
> +&i2c {
> +	tc358746: tc358746@0e {

The node name should be a generic name of the type of the device, not the
name of the specific device as such. A similar Cadence device uses
"csi-bridge".

> +		reg = <0x0e>;
> +		compatible = "toshiba,tc358746";
> +		pinctrl-names = "default";
> +		clocks = <&clk_cam_ref>;
> +		clock-names = "refclk";
> +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port@0 {
> +			reg = <0>;
> +
> +			tc358746_parallel_in: endpoint {
> +				bus-width = <8>;
> +				remote-endpoint = <&micron_parallel_out>;
> +			};
> +		};
> +
> +		port@1 {
> +			reg = <1>;
> +
> +			tc358746_mipi2_out: endpoint {
> +				remote-endpoint = <&mipi_csi2_in>;
> +				data-lanes = <1 2>;
> +				clock-lanes = <0>;
> +				clock-noncontinuous;
> +				link-frequencies = /bits/ 64 <216000000>;
> +			};
> +		};
> +	};
> +};

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver
  2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
  2018-12-19  1:24   ` kbuild test robot
  2018-12-20 19:37   ` kbuild test robot
@ 2019-02-18 11:25   ` Sakari Ailus
  2 siblings, 0 replies; 30+ messages in thread
From: Sakari Ailus @ 2019-02-18 11:25 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Marco,

On Tue, Dec 18, 2018 at 03:12:39PM +0100, Marco Felsch wrote:
> Adding support for the TC358746 bridge. The Bridge can receive images on
> the parallel input port and send it to the host using the CSI-TX unit.
> Furthermore the Bridge can receive images from the host using the CSI-RX
> unit and send it to the parallel output port.
> 
> Currently the only the first case is implemented and tested. The bridge
> driver needs two information from the connected sensor: hblank time and
> pixel-rate. Both information are requested using the v4l2_ctrl interface.
> The driver won't create a media-link if one or both information are
> missing.
> 
> Missing feature:
> - Provide mclk on GPIO[0]
> - Sending pictures from the host to a parallel display
> - v4l_event support
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  drivers/media/i2c/Kconfig         |   12 +
>  drivers/media/i2c/Makefile        |    1 +
>  drivers/media/i2c/tc358746.c      | 1847 +++++++++++++++++++++++++++++
>  drivers/media/i2c/tc358746_regs.h |  208 ++++
>  4 files changed, 2068 insertions(+)
>  create mode 100644 drivers/media/i2c/tc358746.c
>  create mode 100644 drivers/media/i2c/tc358746_regs.h
> 
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 4c936e129500..9995075c3eac 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -394,6 +394,18 @@ config VIDEO_TC358743_CEC
>  	  When selected the tc358743 will support the optional
>  	  HDMI CEC feature.
>  
> +config VIDEO_TC358746
> +	tristate "Toshiba TC358746 decoder"

How about calling it e.g. parallel-CSI2 bridge instead of a decoder?

> +	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
> +	select V4L2_FWNODE
> +	help
> +	  Support for the Toshiba TC358746 PARALLEL to MIPI CSI-2 bridge.
> +	  The bridge can work in both directions but currenty only the
> +	  parallel-in / csi-out path is supported.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called tc358746.
> +
>  config VIDEO_TVP514X
>  	tristate "Texas Instruments TVP514x video decoder"
>  	depends on VIDEO_V4L2 && I2C
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index 65fae7732de0..5cdbdf546627 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C)		+= video-i2c.o
>  obj-$(CONFIG_VIDEO_ML86V7667)	+= ml86v7667.o
>  obj-$(CONFIG_VIDEO_OV2659)	+= ov2659.o
>  obj-$(CONFIG_VIDEO_TC358743)	+= tc358743.o
> +obj-$(CONFIG_VIDEO_TC358746)	+= tc358746.o
>  obj-$(CONFIG_VIDEO_IMX214)	+= imx214.o
>  obj-$(CONFIG_VIDEO_IMX258)	+= imx258.o
>  obj-$(CONFIG_VIDEO_IMX274)	+= imx274.o
> diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
> new file mode 100644
> index 000000000000..633b0322b85d
> --- /dev/null
> +++ b/drivers/media/i2c/tc358746.c
> @@ -0,0 +1,1847 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * tc358746 - Parallel to CSI-2 bridge
> + *
> + * Copyright 2018 Marco Felsch <kernel@pengutronix.de>
> + *
> + * References:
> + * REF_01:
> + * - TC358746AXBG/TC358748XBG/TC358748IXBG Functional Specification Rev 1.2
> + * REF_02:
> + * - TC358746(A)748XBG_Parallel-CSI2_Tv23p.xlsx, Rev Tv23
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/interrupt.h>
> +#include <linux/timer.h>
> +#include <linux/property.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-fwnode.h>

Alphabetical order, please.

> +
> +#include "tc358746_regs.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "debug level (0-3)");
> +
> +MODULE_DESCRIPTION("Toshiba TC358746 Parallel to CSI-2 bridge driver");
> +MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>");
> +MODULE_LICENSE("GPL");

"GPL v2"?

> +
> +#define I2C_MAX_XFER_SIZE	(512 + 2)
> +#define TC358746_MAX_FIFO_SIZE	512
> +#define TC358746_DEF_LINK_FREQ	0
> +
> +#define TC358746_LINEINIT_MIN_US	110
> +#define TC358746_TWAKEUP_MIN_US		1200
> +#define TC358746_LPTXTIME_MIN_NS	55
> +#define TC358746_TCLKZERO_MIN_NS	305
> +#define TC358746_TCLKTRAIL_MIN_NS	65
> +#define TC358746_TCLKPOST_MIN_NS	65
> +#define TC358746_THSZERO_MIN_NS		150
> +#define TC358746_THSTRAIL_MIN_NS	65
> +#define TC358746_THSPREPARE_MIN_NS	45
> +
> +static const struct v4l2_mbus_framefmt tc358746_def_fmt = {
> +	.width		= 640,
> +	.height		= 480,
> +	.code		= MEDIA_BUS_FMT_UYVY8_2X8,
> +	.field		= V4L2_FIELD_NONE,
> +	.colorspace	= V4L2_COLORSPACE_DEFAULT,
> +	.ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT,
> +	.quantization	= V4L2_QUANTIZATION_DEFAULT,
> +	.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
> +};
> +
> +struct tc358746_csi_param {
> +	unsigned char speed_range;
> +	unsigned int  unit_clk_hz;
> +	unsigned char unit_clk_mul;
> +	unsigned int speed_per_lane; /* bps / lane */
> +	unsigned short lane_num;
> +	bool is_continuous_clk;
> +
> +	/* CSI2-TX Parameters */
> +	u32 lineinitcnt;
> +	u32 lptxtimecnt;
> +	u32 twakeupcnt;
> +	u32 tclk_preparecnt;
> +	u32 tclk_zerocnt;
> +	u32 tclk_trailcnt;
> +	u32 tclk_postcnt;
> +	u32 ths_preparecnt;
> +	u32 ths_zerocnt;
> +	u32 ths_trailcnt;
> +
> +	unsigned int csi_hs_lp_hs_ps;
> +};
> +
> +struct tc358746_state {
> +	struct v4l2_subdev sd;
> +	struct i2c_client *i2c_client;
> +	struct gpio_desc *reset_gpio;
> +
> +	/*
> +	 * Generic
> +	 */
> +	struct media_pad pads[2];
> +	struct mutex confctl_mutex;
> +	struct v4l2_mbus_framefmt fmt;
> +	struct v4l2_ctrl_handler hdl;
> +	bool fmt_changed;
> +	bool test;
> +
> +	/*
> +	 * Chip Clocks
> +	 */
> +	struct clk  *refclk;
> +	/* internal pll */
> +	unsigned int pllinclk_hz;
> +	u16 pll_prd;
> +	u16 pll_fbd;
> +
> +	/*
> +	 * Video Buffer
> +	 */
> +	u16 vb_fifo; /* The FIFO size is 511x32 */
> +
> +	/*
> +	 * CSI TX
> +	 */
> +	struct v4l2_ctrl	  *link_freq;
> +	struct tc358746_csi_param *link_freq_settings;
> +	u64			  *link_frequencies;
> +	unsigned int		   link_frequencies_num;
> +
> +	/*
> +	 * Parallel input
> +	 */
> +	unsigned int pclk;
> +	unsigned int hblank;
> +};
> +
> +struct tc358746_mbus_fmt {
> +	u32 code;
> +	u8 bus_width;
> +	u8 bpp;		 /* total bpp */
> +	u8 pdformat;	 /* peripheral data format */
> +	u8 pdataf;	 /* parallel data format option */
> +	u8 ppp;		 /* pclk per pixel */
> +	bool csitx_only; /* format only in csi-tx mode supported */
> +};
> +
> +/* TODO: Add other formats as required */
> +static const struct tc358746_mbus_fmt tc358746_formats[] = {
> +	{
> +		.code = MEDIA_BUS_FMT_UYVY8_2X8,
> +		.bus_width = 8,
> +		.bpp = 16,
> +		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
> +		.pdataf = CONFCTL_PDATAF_MODE0,
> +		.ppp = 2,
> +	}, {
> +		.code = MEDIA_BUS_FMT_UYVY8_1X16,
> +		.bus_width = 16,
> +		.bpp = 16,
> +		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
> +		.pdataf = CONFCTL_PDATAF_MODE1,
> +		.ppp = 1,
> +	}, {
> +		.code = MEDIA_BUS_FMT_YUYV8_1X16,
> +		.bus_width = 16,
> +		.bpp = 16,
> +		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_8_BIT,
> +		.pdataf = CONFCTL_PDATAF_MODE2,
> +		.ppp = 1,
> +	}, {
> +		.code = MEDIA_BUS_FMT_UYVY10_2X10,
> +		.bus_width = 10,
> +		.bpp = 20,
> +		.pdformat = DATAFMT_PDFMT_YCBCRFMT_422_10_BIT,
> +		.pdataf = CONFCTL_PDATAF_MODE0, /* don't care */
> +		.ppp = 2,
> +	}, {
> +		/* in datasheet listed as YUV444 */
> +		.code = MEDIA_BUS_FMT_GBR888_1X24,
> +		.bus_width = 24,
> +		.bpp = 24,
> +		.pdformat = DATAFMT_PDFMT_YCBCRFMT_444,
> +		.pdataf = CONFCTL_PDATAF_MODE0, /* don't care */
> +		.ppp = 2,
> +		.csitx_only = true,
> +	},
> +};
> +
> +/* --------------- HELPERS ------------ */
> +static void
> +tc358746_dump_csi(struct device *dev,
> +		  struct tc358746_csi_param *csi_setting)
> +{
> +	dev_dbg(dev, "Speed-Range value %u\n", csi_setting->speed_range);
> +	dev_dbg(dev, "Unit Clock %u Hz\n", csi_setting->unit_clk_hz);
> +	dev_dbg(dev, "Unit Clock Mul %u\n", csi_setting->unit_clk_mul);
> +	dev_dbg(dev, "CSI speed/lane %u bps/lane\n",
> +		csi_setting->speed_per_lane);
> +	dev_dbg(dev, "CSI lanes %u\n", csi_setting->lane_num);
> +	dev_dbg(dev, "CSI clock during LP %sabled\n",
> +		csi_setting->is_continuous_clk ? "en" : "dis");
> +
> +	dev_dbg(dev, "lineinitcnt %u\n", csi_setting->lineinitcnt);
> +	dev_dbg(dev, "lptxtimecnt %u\n", csi_setting->lptxtimecnt);
> +	dev_dbg(dev, "tclk_preparecnt %u\n", csi_setting->tclk_preparecnt);
> +	dev_dbg(dev, "tclk_zerocnt %u\n", csi_setting->tclk_zerocnt);
> +	dev_dbg(dev, "tclk_trailcnt %u\n", csi_setting->tclk_trailcnt);
> +	dev_dbg(dev, "ths_preparecnt %u\n", csi_setting->ths_preparecnt);
> +	dev_dbg(dev, "ths_zerocnt %u\n", csi_setting->ths_zerocnt);
> +	dev_dbg(dev, "twakeupcnt %u\n", csi_setting->twakeupcnt);
> +	dev_dbg(dev, "tclk_postcnt %u\n", csi_setting->tclk_postcnt);
> +	dev_dbg(dev, "ths_trailcnt %u\n", csi_setting->ths_trailcnt);
> +	dev_dbg(dev, "csi_hs_lp_hs_ps %u (%u us)\n",
> +		csi_setting->csi_hs_lp_hs_ps,
> +		csi_setting->csi_hs_lp_hs_ps / 1000);
> +}
> +
> +static void
> +tc358746_dump_pll(struct device *dev, struct tc358746_state *state)
> +{
> +	dev_dbg(dev, "refclk %lu Hz\n", clk_get_rate(state->refclk));
> +	dev_dbg(dev, "pll input clock %u Hz\n", state->pllinclk_hz);
> +	dev_dbg(dev, "PLL_PRD %u\n", state->pll_prd - 1);
> +	dev_dbg(dev, "PLL_FBD %u\n", state->pll_fbd - 1);
> +}
> +
> +static inline struct tc358746_state *to_state(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct tc358746_state, sd);
> +}
> +
> +/* Find a data format by a pixel code */
> +static int tc358746_format_supported(u32 code)
> +{
> +	int i;

unsigned int?

> +
> +	for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++)
> +		if (tc358746_formats[i].code == code)
> +			return 0;
> +
> +	return -EINVAL;
> +}
> +
> +static struct tc358746_csi_param *
> +tc358746_g_cur_csi_settings(struct tc358746_state *state)
> +{
> +	int cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);

If you'd be holding the mutex already, you could access the value directly.

> +
> +	return &state->link_freq_settings[cur_freq];
> +}
> +
> +static const struct tc358746_mbus_fmt *tc358746_get_format(u32 code)
> +{
> +	int i;

unsigned int.

> +
> +	for (i = 0; i < ARRAY_SIZE(tc358746_formats); i++)
> +		if (tc358746_formats[i].code == code)
> +			return &tc358746_formats[i];
> +
> +	return NULL;
> +}
> +
> +static int
> +tc358746_adjust_fifo_size(struct tc358746_state *state,
> +			  const struct tc358746_mbus_fmt *format,
> +			  struct tc358746_csi_param *csi_settings,
> +			  int width, u16 *fifo_size)

width should be unsigned.

> +{
> +	struct device *dev = &state->i2c_client->dev;
> +	int c_hactive_ps_diff, c_lp_active_ps_diff, c_fifo_delay_ps_diff;
> +	unsigned int p_hactive_ps, p_hblank_ps, p_htotal_ps;
> +	unsigned int c_hactive_ps, c_lp_active_ps, c_fifo_delay_ps;
> +	unsigned int csi_bps, csi_bps_period_ps;
> +	unsigned int csi_hsclk, csi_hsclk_period_ps;
> +	unsigned int pclk_period_ps;
> +	unsigned int _fifo_size;
> +
> +	pclk_period_ps = 1000000000 / (state->pclk / 1000);
> +	csi_bps = csi_settings->speed_per_lane * csi_settings->lane_num;
> +	csi_bps_period_ps = 1000000000 / (csi_bps / 1000);
> +	csi_hsclk = csi_settings->speed_per_lane >> 3;
> +	csi_hsclk_period_ps = 1000000000 / (csi_hsclk / 1000);
> +
> +	/*
> +	 * Calculation:
> +	 * p_hactive_ps = pclk_period_ps * pclk_per_pixel * h_active_pixel
> +	 */
> +	p_hactive_ps = pclk_period_ps * format->ppp * width;
> +
> +	/*
> +	 * Calculation:
> +	 * p_hblank_ps = pclk_period_ps * h_blank_pixel
> +	 */
> +	p_hblank_ps = pclk_period_ps * state->hblank;
> +	p_htotal_ps = p_hblank_ps + p_hactive_ps;
> +
> +	/*
> +	 * Adjust the fifo size to adjust the csi timing. Hopefully we can find
> +	 * a fifo size where the parallel input timings and the csi tx timings
> +	 * fit together.
> +	 */
> +	for (_fifo_size = 1; _fifo_size < TC358746_MAX_FIFO_SIZE;
> +	     _fifo_size++) {
> +		/*
> +		 * Calculation:
> +		 * c_fifo_delay_ps = (fifo_size * 32) / parallel_bus_width *
> +		 *		     pclk_period_ps + 4 * csi_hsclk_period_ps
> +		 */
> +		c_fifo_delay_ps = _fifo_size * 32 * pclk_period_ps;
> +		c_fifo_delay_ps /= format->bus_width;
> +		c_fifo_delay_ps += 4 * csi_hsclk_period_ps;
> +
> +		/*
> +		 * Calculation:
> +		 * c_hactive_ps = csi_bps_period_ps * image_bpp * h_active_pixel
> +		 *		  + c_fifo_delay
> +		 */
> +		c_hactive_ps = csi_bps_period_ps * format->bpp * width;
> +		c_hactive_ps += c_fifo_delay_ps;
> +
> +		/*
> +		 * Calculation:
> +		 * c_lp_active_ps = p_htotal_ps - c_hactive_ps
> +		 */
> +		c_lp_active_ps = p_htotal_ps - c_hactive_ps;
> +
> +		c_hactive_ps_diff = c_hactive_ps - p_hactive_ps;
> +		c_fifo_delay_ps_diff = p_htotal_ps - c_hactive_ps;
> +		c_lp_active_ps_diff =
> +			c_lp_active_ps - csi_settings->csi_hs_lp_hs_ps;
> +
> +		if (c_hactive_ps_diff > 0 &&
> +		    c_fifo_delay_ps_diff > 0 &&
> +		    c_lp_active_ps_diff > 0)
> +			break;
> +	}
> +	/*
> +	 * If we can't transfer the image using this csi link frequency try to
> +	 * use another link freq.
> +	 */
> +
> +	dev_dbg(dev, "%s: found fifo-size %u\n", __func__, _fifo_size);
> +	*fifo_size = _fifo_size;
> +	return _fifo_size == TC358746_MAX_FIFO_SIZE ? -EINVAL : 0;
> +}
> +
> +static int
> +tc358746_adjust_timings(struct tc358746_state *state,
> +			const struct tc358746_mbus_fmt *format,
> +			int *width, u16 *fifo_size)
> +{
> +
> +	int cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);
> +	int freq = cur_freq;

unsigned int?

> +	struct tc358746_csi_param *csi_lane_setting;
> +	int err;
> +	int _width;
> +
> +	/*
> +	 * Adjust timing:
> +	 * 1) Try to use the desired width and the current csi-link-frequency
> +	 * 2) If this doesn't fit try other csi-link-frequencies
> +	 * 3) If this doesn't fit too, reducing the desired width and test
> +	 *    it again width the current csi-link-frequency
> +	 * 4) Goto step 2 if it doesn't fit at all
> +	 */
> +	for (_width = *width; _width > 0; _width -= 10) {
> +		csi_lane_setting = &state->link_freq_settings[cur_freq];
> +		err = tc358746_adjust_fifo_size(state, format, csi_lane_setting,
> +						_width, fifo_size);
> +		if (!err)
> +			goto out;
> +
> +		for (freq = 0; freq < state->link_frequencies_num; freq++) {
> +			if (freq == cur_freq)
> +				continue;
> +
> +			csi_lane_setting = &state->link_freq_settings[freq];
> +			err = tc358746_adjust_fifo_size(state, format,
> +							csi_lane_setting,
> +							_width, fifo_size);
> +			if (!err)
> +				goto out;
> +		}
> +	}
> +
> +out:
> +	*width = _width;
> +	return freq;
> +}
> +
> +static int
> +tc358746_calculate_csi_txtimings(struct tc358746_state *state,
> +				 struct tc358746_csi_param *csi_setting)
> +{
> +	struct device *dev = &state->i2c_client->dev;
> +	unsigned int spl;
> +	unsigned int spl_p_ps, hsclk_p_ps, hfclk_p_ns;
> +	unsigned int hfclk, hsclk; /* SYSCLK */
> +	unsigned int tmp;
> +	unsigned int lptxtime_ps, tclk_post_ps, tclk_trail_ps, tclk_zero_ps,
> +		     ths_trail_ps, ths_zero_ps;
> +
> +	spl = csi_setting->speed_per_lane;
> +	hsclk = spl >> 3; /* spl in bit-per-second, hsclk in byte-per-sercond */
> +	hfclk = hsclk >> 1; /* HFCLK = SYSCLK / 2 */
> +
> +	if (hsclk > 125000000U) {
> +		dev_err(dev, "unsupported HS byte clock %d, must <= 125 MHz\n",
> +			hsclk);
> +		return -EINVAL;
> +	}
> +
> +	hfclk_p_ns = DIV_ROUND_CLOSEST(1000000000, hfclk);
> +	hsclk_p_ps = 1000000000 / (hsclk / 1000);
> +	spl_p_ps   = 1000000000 / (spl / 1000);
> +
> +	/*
> +	 * Calculation:
> +	 * hfclk_p_ns * lineinitcnt > 100us
> +	 * lineinitcnt > 100 * 10^-6s / hfclk_p_ns * 10^-9
> +	 *
> +	 */
> +	csi_setting->lineinitcnt = DIV_ROUND_UP(TC358746_LINEINIT_MIN_US * 1000,
> +					  hfclk_p_ns);
> +
> +	/*
> +	 * Calculation:
> +	 * (lptxtimecnt + 1) * hsclk_p_ps > 50ns
> +	 * 38ns < (tclk_preparecnt + 1) * hsclk_p_ps < 95ns
> +	 */
> +	csi_setting->lptxtimecnt = csi_setting->tclk_preparecnt =
> +		DIV_ROUND_UP(TC358746_LPTXTIME_MIN_NS * 1000, hsclk_p_ps) - 1;
> +
> +	/*
> +	 * Limit:
> +	 * (tclk_zero + tclk_prepar) period > 300ns.
> +	 * Since we have no upper limit and for simplicity:
> +	 * tclk_zero > 300ns.
> +	 *
> +	 * Calculation:
> +	 * tclk_zero = ([2,3] + tclk_zerocnt) * hsclk_p_ps + ([2,3] * spl_p_ps)
> +	 *
> +	 * Note: REF_02 uses
> +	 * tclk_zero = (2.5 + tclk_zerocnt) * hsclk_p_ps + (3.5 * spl_p_ps)
> +	 */
> +	tmp = TC358746_TCLKZERO_MIN_NS * 1000 - 3 * spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->tclk_zerocnt = tmp - 2;
> +
> +	/*
> +	 * Limit:
> +	 * 40ns + 4 * spl_p_ps < (ths_preparecnt + 1) * hsclk_p_ps
> +	 *		       < 85ns + 6 * spl_p_ps
> +	 */
> +	tmp = TC358746_THSPREPARE_MIN_NS * 1000 + 4 * spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->ths_preparecnt = tmp - 1;
> +
> +	/*
> +	 * Limit:
> +	 * (ths_zero + ths_prepare) period > 145ns + 10 * spl_p_ps.
> +	 * Since we have no upper limit and for simplicity:
> +	 * ths_zero period > 145ns + 10 * spl_p_ps.
> +	 *
> +	 * Calculation:
> +	 * ths_zero = ([6,8] + ths_zerocnt) * hsclk_p_ps + [3,4] * hsclk_p_ps +
> +	 *	      [13,14] * spl_p_ps
> +	 *
> +	 * Note: REF_02 uses
> +	 * ths_zero = (7 + ths_zerocnt) * hsclk_p_ps + 4 * hsclk_p_ps +
> +	 *	      11 * spl_p_ps
> +	 */
> +	tmp = TC358746_THSZERO_MIN_NS * 1000 - spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->ths_zerocnt = tmp < 11 ? 0 : tmp - 11;
> +
> +	/*
> +	 * Limit:
> +	 * hsclk_p_ps * (lptxtimecnt + 1) * (twakeupcnt + 1) > 1ms
> +	 *
> +	 * Since we have no upper limit use 1.2ms as lower limit to
> +	 * surley meet the spec limit.
> +	 */
> +	tmp = hsclk_p_ps / 1000; /* tmp = hsclk_p_ns */
> +	csi_setting->twakeupcnt =
> +		DIV_ROUND_UP(TC358746_TWAKEUP_MIN_US * 1000,
> +			     tmp * (csi_setting->lptxtimecnt + 1)) - 1;
> +
> +	/*
> +	 * Limit:
> +	 * 60ns + 4 * spl_p_ps < thstrail < 105ns + 12 * spl_p_ps
> +	 *
> +	 * Calculation:
> +	 * thstrail = (1 + ths_trailcnt) * hsclk_p_ps + [3,4] * hsclk_p_ps -
> +	 *	      [13,14] * spl_p_ps
> +	 *
> +	 * [2] set formula to:
> +	 * thstrail = (1 + ths_trailcnt) * hsclk_p_ps + 4 * hsclk_p_ps -
> +	 *	      11 * spl_p_ps
> +	 */
> +	tmp = TC358746_THSTRAIL_MIN_NS * 1000 + 15 * spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->ths_trailcnt = tmp - 5;
> +
> +	/*
> +	 * Limit:
> +	 * 60ns < tclk_trail < 105ns + 12 * spl_p_ps
> +	 *
> +	 * Limit used by REF_02:
> +	 * 60ns < tclk_trail < 105ns + 12 * spl_p_ps - 30
> +	 *
> +	 * Calculation:
> +	 * tclk_trail = ([1,2] + tclk_trailcnt) * hsclk_p_ps +
> +	 *		(2 + [1,2]) * hsclk_p_ps - [2,3] * spl_p_ps
> +	 *
> +	 * Calculation used by REF_02:
> +	 * tclk_trail = (1 + tclk_trailcnt) * hsclk_p_ps +
> +	 *		4 * hsclk_p_ps - 3 * spl_p_ps
> +	 */
> +	tmp = TC358746_TCLKTRAIL_MIN_NS * 1000 + 3 * spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->tclk_trailcnt = tmp < 5 ? 0 : tmp - 5;
> +
> +	/*
> +	 * Limit:
> +	 * tclk_post > 60ns + 52 * spl_p_ps
> +	 *
> +	 * Limit used by REF_02:
> +	 * tclk_post > 60ns + 52 * spl_p_ps
> +	 *
> +	 * Calculation:
> +	 * tclk_post = ([1,2] + (tclk_postcnt + 1)) * hsclk_p_ps + hsclk_p_ps
> +	 *
> +	 * Note REF_02 uses:
> +	 * tclk_post = (2.5 + tclk_postcnt) * hsclk_p_ps + hsclk_p_ps +
> +	 *		2.5 * spl_p_ps
> +	 * To meet the REF_02 validation limits following equation is used:
> +	 * tclk_post = (2 + tclk_postcnt) * hsclk_p_ps + hsclk_p_ps +
> +	 *		3 * spl_p_ps
> +	 */
> +	tmp = TC358746_TCLKPOST_MIN_NS * 1000 + 49 * spl_p_ps;
> +	tmp = DIV_ROUND_UP(tmp, hsclk_p_ps);
> +	csi_setting->tclk_postcnt = tmp - 3;
> +
> +	/*
> +	 * Last calculate the csi hs->lp->hs transistion time in ns. Note REF_02
> +	 * mixed units in the equation for the continuous case. I don't know if
> +	 * this was the intention. The driver drops the last 'multiply all by
> +	 * two' to get nearly the same results.
> +	 */
> +	lptxtime_ps = (csi_setting->lptxtimecnt + 1) * hsclk_p_ps;
> +	tclk_post_ps =
> +		(4 + csi_setting->tclk_postcnt) * hsclk_p_ps + 3 * spl_p_ps;
> +	tclk_trail_ps =
> +		(5 + csi_setting->tclk_trailcnt) * hsclk_p_ps - 3 * spl_p_ps;
> +	tclk_zero_ps =
> +		(2 + csi_setting->tclk_zerocnt) * hsclk_p_ps + 3 * spl_p_ps;
> +	ths_trail_ps =
> +		(5 + csi_setting->ths_trailcnt) * hsclk_p_ps - 11 * spl_p_ps;
> +	ths_zero_ps =
> +		(7 + csi_setting->ths_zerocnt) * hsclk_p_ps + 4 * hsclk_p_ps +
> +		11 * spl_p_ps;
> +
> +	if (csi_setting->is_continuous_clk) {
> +		tmp = 2 * lptxtime_ps;
> +		tmp += 25 * hsclk_p_ps;
> +		tmp += ths_trail_ps;
> +		tmp += ths_zero_ps;
> +	} else {
> +		tmp = 4 * lptxtime_ps;
> +		tmp += ths_trail_ps + tclk_post_ps + tclk_trail_ps +
> +			tclk_zero_ps + ths_zero_ps;
> +		tmp += (13 + csi_setting->lptxtimecnt * 8) * hsclk_p_ps;
> +		tmp += 22 * hsclk_p_ps;
> +		tmp *= 3;
> +		tmp = DIV_ROUND_CLOSEST(tmp, 2);
> +	}
> +	csi_setting->csi_hs_lp_hs_ps = tmp;
> +
> +	return 0;
> +}
> +
> +/* --------------- i2c helper ------------ */
> +
> +static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct i2c_client *client = state->i2c_client;
> +	int err;
> +	u8 buf[2] = { reg >> 8, reg & 0xff };
> +	u8 data[I2C_MAX_XFER_SIZE];
> +
> +	struct i2c_msg msgs[] = {
> +		{
> +			.addr = client->addr,
> +			.flags = 0,
> +			.len = 2,
> +			.buf = buf,
> +		},
> +		{
> +			.addr = client->addr,
> +			.flags = I2C_M_RD,
> +			.len = n,
> +			.buf = data,
> +		},
> +	};
> +
> +	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> +	if (err != ARRAY_SIZE(msgs)) {
> +		v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
> +			 __func__, reg, client->addr);
> +	}
> +
> +	switch (n) {
> +	case 1:
> +		values[0] = data[0];
> +		break;
> +	case 2:
> +		values[0] = data[1];
> +		values[1] = data[0];
> +		break;
> +	case 4:
> +		values[0] = data[1];
> +		values[1] = data[0];
> +		values[2] = data[3];
> +		values[3] = data[2];
> +		break;
> +	default:
> +		v4l2_info(sd, "unsupported I2C read %d bytes from address 0x%04x\n",
> +			  n, reg);
> +	}
> +
> +	if (debug < 3)
> +		return;
> +
> +	switch (n) {
> +	case 1:
> +		v4l2_info(sd, "I2C read 0x%04x = 0x%02x",
> +			  reg, data[0]);
> +		break;
> +	case 2:
> +		v4l2_info(sd, "I2C read 0x%04x = 0x%02x%02x",
> +			  reg, data[0], data[1]);
> +		break;
> +	case 4:
> +		v4l2_info(sd, "I2C read 0x%04x = 0x%02x%02x%02x%02x",
> +			  reg, data[2], data[3], data[0], data[1]);
> +		break;
> +	default:
> +		v4l2_info(sd, "I2C unsupported read %d bytes from address 0x%04x\n",
> +			  n, reg);
> +	}
> +}
> +
> +static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct i2c_client *client = state->i2c_client;
> +	int err;
> +	struct i2c_msg msg;
> +	u8 data[I2C_MAX_XFER_SIZE];
> +
> +	if ((2 + n) > I2C_MAX_XFER_SIZE) {
> +		n = I2C_MAX_XFER_SIZE - 2;
> +		v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n",
> +			  reg, 2 + n);
> +	}
> +
> +	msg.addr = client->addr;
> +	msg.buf = data;
> +	msg.len = 2 + n;
> +	msg.flags = 0;
> +
> +	data[0] = reg >> 8;
> +	data[1] = reg & 0xff;
> +
> +	switch (n) {
> +	case 1:
> +		data[2 + 0] = values[0];
> +		break;
> +	case 2:
> +		data[2 + 0] = values[1];
> +		data[2 + 1] = values[0];
> +		break;
> +	case 4:
> +		data[2 + 0] = values[1];
> +		data[2 + 1] = values[0];
> +		data[2 + 2] = values[3];
> +		data[2 + 3] = values[2];
> +		break;
> +	default:
> +		v4l2_info(sd, "unsupported I2C write %d bytes from address 0x%04x\n",
> +			  n, reg);
> +	}
> +
> +	err = i2c_transfer(client->adapter, &msg, 1);
> +	if (err != 1) {
> +		v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
> +			 __func__, reg, client->addr);
> +		return;
> +	}
> +
> +	if (debug < 3)
> +		return;
> +
> +	switch (n) {
> +	case 1:
> +		v4l2_info(sd, "I2C write 0x%04x = 0x%02x", reg, data[2 + 0]);
> +		break;
> +	case 2:
> +		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", reg, data[2 + 0],
> +			  data[2 + 1]);
> +		break;
> +	case 4:
> +		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", reg,
> +			  data[2 + 2], data[2 + 3], data[2 + 0], data[2 + 1]);
> +		break;
> +	default:
> +		v4l2_info(sd, "I2C unsupported write %d bytes from address 0x%04x\n",
> +			  n, reg);
> +	}
> +}
> +
> +static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
> +{
> +	__le32 val = 0;
> +
> +	i2c_rd(sd, reg, (u8 __force *)&val, n);
> +
> +	return le32_to_cpu(val);
> +}
> +
> +static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
> +{
> +	__le32 raw = cpu_to_le32(val);
> +
> +	i2c_wr(sd, reg, (u8 __force *)&raw, n);
> +}
> +
> +static u16 __maybe_unused i2c_rd8(struct v4l2_subdev *sd, u16 reg)
> +{
> +	return i2c_rdreg(sd, reg, 1);
> +}
> +
> +static u16 __maybe_unused i2c_rd16(struct v4l2_subdev *sd, u16 reg)
> +{
> +	return i2c_rdreg(sd, reg, 2);
> +}
> +
> +static u32 __maybe_unused i2c_rd32(struct v4l2_subdev *sd, u16 reg)
> +{
> +	return i2c_rdreg(sd, reg, 4);
> +}
> +
> +static void __maybe_unused i2c_wr8(struct v4l2_subdev *sd, u16 reg, u16 val)
> +{
> +	i2c_wrreg(sd, reg, val, 1);
> +}
> +
> +static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
> +{
> +	i2c_wrreg(sd, reg, val, 2);
> +}
> +
> +static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u32 mask, u16 val)
> +{
> +	u16 m = (u16) mask;
> +
> +	i2c_wrreg(sd, reg, (i2c_rd16(sd, reg) & m) | val, 2);
> +}
> +
> +static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
> +{
> +	i2c_wrreg(sd, reg, val, 4);
> +}
> +
> +/* --------------- init --------------- */
> +
> +static void
> +tc358746_wr_csi_control(struct v4l2_subdev *sd, int val)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	u32 _val;
> +
> +	val &= CSI_CONFW_DATA_MASK;
> +	_val = CSI_CONFW_MODE_SET_MASK | CSI_CONFW_ADDRESS_CSI_CONTROL_MASK |
> +		val;
> +
> +	dev_dbg(&state->i2c_client->dev, "CSI_CONFW 0x%04x\n", _val);
> +	i2c_wr32(sd, CSI_CONFW, _val);
> +}
> +
> +static inline void tc358746_sleep_mode(struct v4l2_subdev *sd, int enable)
> +{
> +	i2c_wr16_and_or(sd, SYSCTL, ~SYSCTL_SLEEP_MASK,
> +			enable ? SYSCTL_SLEEP_MASK : 0);
> +}
> +
> +static inline void tc358746_sreset(struct v4l2_subdev *sd)
> +{
> +	i2c_wr16(sd, SYSCTL, SYSCTL_SRESET_MASK);
> +	udelay(10);
> +	i2c_wr16(sd, SYSCTL, 0);
> +}
> +
> +static inline void tc358746_enable_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +
> +	dev_dbg(&state->i2c_client->dev, "%sable\n", enable ? "en" : "dis");
> +
> +	mutex_lock(&state->confctl_mutex);
> +	if (!enable) {
> +		i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_FRMSTOP_MASK,
> +				PP_MISC_FRMSTOP_MASK);
> +		i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK, 0);
> +		i2c_wr16_and_or(sd, PP_MISC, ~PP_MISC_RSTPTR_MASK,
> +				PP_MISC_RSTPTR_MASK);
> +
> +		i2c_wr32(sd, CSIRESET, (CSIRESET_RESET_CNF_MASK |
> +					CSIRESET_RESET_MODULE_MASK));
> +		i2c_wr16(sd, DBG_ACT_LINE_CNT, 0);
> +	} else {
> +		i2c_wr16(sd, PP_MISC, 0);
> +		i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PPEN_MASK,
> +				CONFCTL_PPEN_MASK);
> +	}
> +	mutex_unlock(&state->confctl_mutex);
> +}
> +
> +static void tc358746_set_pll(struct v4l2_subdev *sd)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct tc358746_csi_param *csi_setting =
> +		tc358746_g_cur_csi_settings(state);
> +	struct device *dev = &state->i2c_client->dev;
> +	u16 pllctl0 = i2c_rd16(sd, PLLCTL0);
> +	u16 pllctl1 = i2c_rd16(sd, PLLCTL1);
> +	u16 pll_frs = csi_setting->speed_range;
> +	u16 pllctl0_new;
> +
> +	/*
> +	 * Calculation:
> +	 * speed_per_lane = (pllinclk_hz * (fbd + 1)) / 2^frs
> +	 *
> +	 * Calculation used by REF_02:
> +	 * speed_per_lane = (pllinclk_hz * fbd) / 2^frs
> +	 */
> +	state->pll_fbd = csi_setting->speed_per_lane / state->pllinclk_hz;
> +	state->pll_fbd <<= pll_frs;
> +
> +	pllctl0_new = PLLCTL0_PLL_PRD_SET(state->pll_prd) |
> +		      PLLCTL0_PLL_FBD_SET(state->pll_fbd);
> +
> +	/*
> +	 * Only rewrite when needed (new value or disabled), since rewriting
> +	 * triggers another format change event.
> +	 */
> +	if ((pllctl0 != pllctl0_new) ||
> +	    ((pllctl1 & PLLCTL1_PLL_EN_MASK) == 0)) {
> +		u16 pllctl1_mask = (u16) ~(PLLCTL1_PLL_FRS_MASK |
> +					   PLLCTL1_RESETB_MASK  |
> +					   PLLCTL1_PLL_EN_MASK);
> +		u16 pllctl1_val = PLLCTL1_PLL_FRS_SET(pll_frs) |
> +				  PLLCTL1_RESETB_MASK | PLLCTL1_PLL_EN_MASK;
> +
> +		dev_dbg(dev, "updating PLL clock\n");
> +		i2c_wr16(sd, PLLCTL0, pllctl0_new);
> +		i2c_wr16_and_or(sd, PLLCTL1, pllctl1_mask, pllctl1_val);
> +		udelay(1000);
> +		i2c_wr16_and_or(sd, PLLCTL1, ~PLLCTL1_CKEN_MASK,
> +				PLLCTL1_CKEN_MASK);
> +	}
> +
> +	tc358746_dump_pll(dev, state);
> +}
> +
> +static void tc358746_set_csi_color_space(struct v4l2_subdev *sd)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	const struct tc358746_mbus_fmt *tc358746_fmt =
> +		tc358746_get_format(state->fmt.code);
> +
> +	/* currently no self defined csi user data type id's are supported */
> +	mutex_lock(&state->confctl_mutex);
> +	i2c_wr16_and_or(sd, DATAFMT,
> +			~(DATAFMT_PDFMT_MASK | DATAFMT_UDT_EN_MASK),
> +			DATAFMT_PDFMT_SET(tc358746_fmt->pdformat));
> +	i2c_wr16_and_or(sd, CONFCTL, ~CONFCTL_PDATAF_MASK,
> +			CONFCTL_PDATAF_SET(tc358746_fmt->pdataf));
> +	mutex_unlock(&state->confctl_mutex);
> +}
> +
> +static void tc38764_debug_pattern_80(struct v4l2_subdev *sd)
> +{
> +	int i;

unsigned int

> +
> +	i2c_wr16(sd, DBG_ACT_LINE_CNT, 0x8000);
> +	i2c_wr16(sd, DBG_LINE_WIDTH, 0x0396);
> +	i2c_wr16(sd, DBG_VERT_BLANK_LINE_CNT, 0x0000);
> +
> +	for (i = 0; i < 80; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0xff7f);
> +	i2c_wr16(sd, DBG_VIDEO_DATA, 0xff00);
> +	for (i = 0; i < 40; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0xffff);
> +	i2c_wr16(sd, DBG_VIDEO_DATA, 0xc0ff);
> +	for (i = 0; i < 40; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0xc000);
> +	for (i = 0; i < 80; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0x7f00);
> +	for (i = 0; i < 80; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0x7fff);
> +	i2c_wr16(sd, DBG_VIDEO_DATA, 0x0000);
> +	for (i = 0; i < 40; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0x00ff);
> +	i2c_wr16(sd, DBG_VIDEO_DATA, 0x00ff);
> +	for (i = 0; i < 40; i++)
> +		i2c_wr16(sd, DBG_VIDEO_DATA, 0x0000);
> +	i2c_wr16(sd, DBG_VIDEO_DATA, 0x007f);
> +
> +	i2c_wr16(sd, DBG_ACT_LINE_CNT, 0xC1DF);
> +}
> +
> +static void tc358746_enable_csi_lanes(struct v4l2_subdev *sd, int enable)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct tc358746_csi_param *csi_setting =
> +		tc358746_g_cur_csi_settings(state);
> +	unsigned int lanes = csi_setting->lane_num;
> +	u32 val = 0;
> +
> +	if (lanes < 1 || !enable)
> +		i2c_wr32(sd, CLW_CNTRL, CLW_CNTRL_CLW_LANEDISABLE_MASK);
> +	if (lanes < 1 || !enable)
> +		i2c_wr32(sd, D0W_CNTRL, D0W_CNTRL_D0W_LANEDISABLE_MASK);
> +	if (lanes < 2 || !enable)
> +		i2c_wr32(sd, D1W_CNTRL, D1W_CNTRL_D1W_LANEDISABLE_MASK);
> +	if (lanes < 3 || !enable)
> +		i2c_wr32(sd, D2W_CNTRL, D2W_CNTRL_D2W_LANEDISABLE_MASK);
> +	if (lanes < 4 || !enable)
> +		i2c_wr32(sd, D3W_CNTRL, D2W_CNTRL_D3W_LANEDISABLE_MASK);
> +
> +	if (lanes > 0 && enable)
> +		val |= HSTXVREGEN_CLM_HSTXVREGEN_MASK |
> +			HSTXVREGEN_D0M_HSTXVREGEN_MASK;
> +	if (lanes > 1 && enable)
> +		val |= HSTXVREGEN_D1M_HSTXVREGEN_MASK;
> +	if (lanes > 2 && enable)
> +		val |= HSTXVREGEN_D2M_HSTXVREGEN_MASK;
> +	if (lanes > 3 && enable)
> +		val |= HSTXVREGEN_D3M_HSTXVREGEN_MASK;
> +
> +	i2c_wr32(sd, HSTXVREGEN, val);
> +}
> +
> +static void tc358746_set_csi(struct v4l2_subdev *sd)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct tc358746_csi_param *csi_setting =
> +		tc358746_g_cur_csi_settings(state);
> +	bool en_continuous_clk = csi_setting->is_continuous_clk;
> +	u32 val;
> +
> +	val = TCLK_HEADERCNT_TCLK_ZEROCNT_SET(csi_setting->tclk_zerocnt) |
> +	      TCLK_HEADERCNT_TCLK_PREPARECNT_SET(csi_setting->tclk_preparecnt);
> +	i2c_wr32(sd, TCLK_HEADERCNT, val);
> +	val = THS_HEADERCNT_THS_ZEROCNT_SET(csi_setting->ths_zerocnt) |
> +	      THS_HEADERCNT_THS_PREPARECNT_SET(csi_setting->ths_preparecnt);
> +	i2c_wr32(sd, THS_HEADERCNT, val);
> +	i2c_wr32(sd, TWAKEUP, csi_setting->twakeupcnt);
> +	i2c_wr32(sd, TCLK_POSTCNT, csi_setting->tclk_postcnt);
> +	i2c_wr32(sd, THS_TRAILCNT, csi_setting->ths_trailcnt);
> +	i2c_wr32(sd, LINEINITCNT, csi_setting->lineinitcnt);
> +	i2c_wr32(sd, LPTXTIMECNT, csi_setting->lptxtimecnt);
> +	i2c_wr32(sd, TCLK_TRAILCNT, csi_setting->tclk_trailcnt);
> +	i2c_wr32(sd, TXOPTIONCNTRL,
> +		 en_continuous_clk ? TXOPTIONCNTRL_CONTCLKMODE_MASK : 0);
> +
> +	if (state->test)
> +		tc38764_debug_pattern_80(sd);
> +
> +	tc358746_dump_csi(&state->i2c_client->dev, csi_setting);
> +}
> +
> +static void tc358746_enable_csi_module(struct v4l2_subdev *sd, int enable)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct tc358746_csi_param *csi_setting =
> +		tc358746_g_cur_csi_settings(state);
> +	unsigned int lanes = csi_setting->lane_num;
> +	u32 val;
> +
> +	if (!enable)
> +		return;
> +
> +	i2c_wr32(sd, STARTCNTRL, STARTCNTRL_START_MASK);
> +	i2c_wr32(sd, CSI_START, CSI_START_STRT_MASK);
> +
> +	val = CSI_CONTROL_NOL_1_MASK;
> +	if (lanes == 2)
> +		val = CSI_CONTROL_NOL_2_MASK;
> +	else if (lanes == 3)
> +		val = CSI_CONTROL_NOL_3_MASK;
> +	else if (lanes == 4)
> +		val = CSI_CONTROL_NOL_4_MASK;
> +
> +	val |= CSI_CONTROL_CSI_MODE_MASK | CSI_CONTROL_TXHSMD_MASK;
> +	tc358746_wr_csi_control(sd, val);
> +}
> +
> +static void tc358746_set_buffers(struct v4l2_subdev *sd)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct device *dev = &state->i2c_client->dev;
> +	const struct tc358746_mbus_fmt *tc358746_mbusfmt =
> +		tc358746_get_format(state->fmt.code);
> +	unsigned int byte_per_line =
> +		(state->fmt.width * tc358746_mbusfmt->bpp) / 8;
> +
> +	i2c_wr16(sd, FIFOCTL, state->vb_fifo);
> +	i2c_wr16(sd, WORDCNT, byte_per_line);
> +	dev_dbg(dev, "FIFOCTL 0x%02x: WORDCNT 0x%02x\n",
> +		state->vb_fifo, byte_per_line);
> +}
> +
> +/* --------------- CORE OPS --------------- */
> +
> +static int tc358746_log_status(struct v4l2_subdev *sd)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	uint16_t sysctl = i2c_rd16(sd, SYSCTL);
> +
> +	v4l2_info(sd, "-----Chip status-----\n");
> +	v4l2_info(sd, "Chip ID: 0x%02lx\n",
> +		  (i2c_rd16(sd, CHIPID) & CHIPID_CHIPID_MASK) >> 8);
> +	v4l2_info(sd, "Chip revision: 0x%02lx\n",
> +		  i2c_rd16(sd, CHIPID) & CHIPID_REVID_MASK);
> +	v4l2_info(sd, "Sleep mode: %s\n", sysctl & SYSCTL_SLEEP_MASK ?
> +		  "on" : "off");
> +
> +	v4l2_info(sd, "-----CSI-TX status-----\n");
> +	v4l2_info(sd, "Waiting for particular sync signal: %s\n",
> +			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_WSYNC_MASK) ?
> +			"yes" : "no");
> +	v4l2_info(sd, "Transmit mode: %s\n",
> +			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_TXACT_MASK) ?
> +			"yes" : "no");
> +	v4l2_info(sd, "Stopped: %s\n",
> +			(i2c_rd16(sd, CSI_STATUS) & CSI_STATUS_S_HLT_MASK) ?
> +			"yes" : "no");
> +	v4l2_info(sd, "Color space: %s\n",
> +			state->fmt.code == MEDIA_BUS_FMT_UYVY8_2X8 ?
> +			"YCbCr 422 8-bit" : "Unsupported");
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_VIDEO_ADV_DEBUG
> +static void tc358746_print_register_map(struct v4l2_subdev *sd)
> +{
> +	v4l2_info(sd, "0x0000-0x0050: Global Register\n");
> +	v4l2_info(sd, "0x0056-0x0070: Rx Control Registers\n");
> +	v4l2_info(sd, "0x0080-0x00F8: Rx Status Registers\n");
> +	v4l2_info(sd, "0x0100-0x0150: Tx D-PHY Register\n");
> +	v4l2_info(sd, "0x0204-0x0238: Tx PPI Register\n");
> +	v4l2_info(sd, "0x040c-0x0518: Tx Control Register\n");
> +}
> +
> +static int tc358746_get_reg_size(u16 address)
> +{
> +	if (address <= 0x00ff)
> +		return 2;
> +	else if ((address >= 0x0100) && (address <= 0x05FF))
> +		return 4;
> +	else
> +		return 1;
> +}
> +
> +static int tc358746_g_register(struct v4l2_subdev *sd,
> +			       struct v4l2_dbg_register *reg)
> +{
> +	if (reg->reg > 0xffff) {
> +		tc358746_print_register_map(sd);
> +		return -EINVAL;
> +	}
> +
> +	reg->size = tc358746_get_reg_size(reg->reg);
> +
> +	reg->val = i2c_rdreg(sd, reg->reg, reg->size);
> +
> +	return 0;
> +}
> +
> +static int tc358746_s_register(struct v4l2_subdev *sd,
> +			       const struct v4l2_dbg_register *reg)
> +{
> +	if (reg->reg > 0xffff) {
> +		tc358746_print_register_map(sd);
> +		return -EINVAL;
> +	}
> +
> +	i2c_wrreg(sd, (u16)reg->reg, reg->val,
> +			tc358746_get_reg_size(reg->reg));
> +
> +	return 0;
> +}
> +#endif
> +
> +/* --------------- video ops --------------- */
> +
> +static int tc358746_g_mbus_config(struct v4l2_subdev *sd,
> +			     struct v4l2_mbus_config *cfg)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct tc358746_csi_param *csi_setting =
> +		tc358746_g_cur_csi_settings(state);
> +
> +	cfg->type = V4L2_MBUS_CSI2_DPHY;
> +	cfg->flags = csi_setting->is_continuous_clk ?
> +			V4L2_MBUS_CSI2_CONTINUOUS_CLOCK :
> +			V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;

The other device can get this from its firmware data, just as this one.

> +
> +	switch (csi_setting->lane_num) {
> +	case 1:
> +		cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
> +		break;
> +	case 2:
> +		cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
> +		break;
> +	case 3:
> +		cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
> +		break;
> +	case 4:
> +		cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
> +		break;

If you don't have a need to change these dynamically right now, please drop
g_mbus_config(). We'll soon have a better solution (using frame descriptors
Niklas has been working on).

> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tc358746_s_power(struct v4l2_subdev *sd, int on)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +
> +	/*
> +	 * REF_01:
> +	 * Softreset don't reset configuration registers content but is needed
> +	 * during power-on to trigger a csi LP-11 state change and during
> +	 * power-off to disable the csi-module.
> +	 */
> +	tc358746_sreset(sd);
> +
> +	if (state->fmt_changed) {
> +		tc358746_set_buffers(sd);
> +		tc358746_set_csi(sd);
> +		tc358746_set_csi_color_space(sd);
> +
> +		/* as recommend in REF_01 */
> +		tc358746_sleep_mode(sd, 1);
> +		tc358746_set_pll(sd);
> +		tc358746_sleep_mode(sd, 0);
> +
> +		state->fmt_changed = false;
> +	}
> +
> +	tc358746_enable_csi_lanes(sd, on);
> +	tc358746_enable_csi_module(sd, on);
> +	tc358746_sleep_mode(sd, !on);
> +
> +	return 0;
> +}
> +
> +static int tc358746_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	tc358746_enable_stream(sd, enable);

Could you call tc358746_enable_stream() instead of tc358746_s_stream() and
drop tc358746_s_stream()? Maybe the function return type and arguments
need to be changed?

> +
> +	return 0;
> +}
> +
> +/* --------------- pad ops --------------- */
> +
> +static int tc358746_enum_mbus_code(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_pad_config *cfg,
> +				   struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->index >= ARRAY_SIZE(tc358746_formats))
> +		return -EINVAL;
> +
> +	code->code = tc358746_formats[code->index].code;
> +
> +	return 0;
> +}
> +
> +static struct v4l2_mbus_framefmt *
> +__tc358746_get_pad_format(struct v4l2_subdev *sd,
> +			  struct v4l2_subdev_pad_config *cfg,
> +			  unsigned int pad, u32 which)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_format(sd, cfg, pad);
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &state->fmt;
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int tc358746_get_fmt(struct v4l2_subdev *sd,
> +		struct v4l2_subdev_pad_config *cfg,
> +		struct v4l2_subdev_format *format)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +
> +	if (format->pad != 0 && format->pad != 1)
> +		return -EINVAL;
> +
> +	format->format.code = state->fmt.code;
> +	format->format.width = state->fmt.width;
> +	format->format.height = state->fmt.height;
> +	format->format.field = state->fmt.field;
> +
> +	return 0;
> +}
> +
> +static int tc358746_set_fmt(struct v4l2_subdev *sd,
> +			    struct v4l2_subdev_pad_config *cfg,
> +			    struct v4l2_subdev_format *format)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct device *dev = &state->i2c_client->dev;
> +	struct media_pad *pad = &state->pads[format->pad];
> +	struct media_pad *remote_sensor_pad =
> +		media_entity_remote_pad(&state->pads[0]);
> +	struct v4l2_subdev *sensor_sd;
> +	struct v4l2_mbus_framefmt *mbusformat;
> +	const struct tc358746_mbus_fmt *tc358746_mbusformat;
> +	struct v4l2_ctrl *ctrl;
> +	unsigned int pclk, hblank;
> +	int new_freq, cur_freq = v4l2_ctrl_g_ctrl(state->link_freq);
> +	u16 vb_fifo;
> +
> +	if (pad->flags == MEDIA_PAD_FL_SOURCE)
> +		return tc358746_get_fmt(sd, cfg, format);
> +
> +	mbusformat = __tc358746_get_pad_format(sd, cfg, format->pad,
> +					       format->which);
> +	if (!mbusformat)
> +		return -EINVAL;
> +
> +	tc358746_mbusformat = tc358746_get_format(format->format.code);
> +	if (!tc358746_mbusformat) {
> +		format->format.code = tc358746_def_fmt.code;
> +		tc358746_mbusformat = tc358746_get_format(format->format.code);
> +	}
> +
> +	/*
> +	 * Some sensors change their hblank and pclk value on different formats,
> +	 * so we need to request it again.
> +	 */
> +	sensor_sd = media_entity_to_v4l2_subdev(remote_sensor_pad->entity);
> +	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);

ctrl may be NULL.

> +	pclk = v4l2_ctrl_g_ctrl_int64(ctrl);
> +	if (pclk != state->pclk) {
> +		dev_dbg(dev, "Update pclk from %u to %u\n", state->pclk, pclk);
> +		state->pclk = pclk;
> +	}
> +	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_HBLANK);

Ditto. There are other such cases below, too, in the link validation
functio.

> +	hblank = v4l2_ctrl_g_ctrl(ctrl);
> +	if (hblank != state->hblank) {
> +		dev_dbg(dev, "Update hblank from %u to %u\n", state->hblank,
> +			hblank);
> +		state->hblank = hblank;
> +	}
> +
> +	/*
> +	 * Normaly the HW has no size limitations but we have to check if the
> +	 * csi timings are valid for this size. The timings can be adjust by the
> +	 * fifo size. If this doesn't work we have to do this check again with a
> +	 * other csi link frequency if it is possible.
> +	 */
> +	new_freq = tc358746_adjust_timings(state, tc358746_mbusformat,
> +					   &format->format.width, &vb_fifo);
> +
> +	/* Currently only a few YUV based formats are supported */
> +	if (tc358746_format_supported(format->format.code))
> +		format->format.code = MEDIA_BUS_FMT_UYVY8_2X8;
> +
> +	/* Currently only non interleaved images are supported */
> +	format->format.field = V4L2_FIELD_NONE;
> +
> +	*mbusformat = format->format;
> +
> +	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		state->fmt_changed = true;
> +		state->vb_fifo = vb_fifo;
> +		if (new_freq != cur_freq)
> +			v4l2_ctrl_s_ctrl(state->link_freq, new_freq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link,
> +		       struct v4l2_subdev_format *source_fmt,
> +		       struct v4l2_subdev_format *sink_fmt)
> +{
> +	struct tc358746_state *state = to_state(sd);
> +	struct device *dev = &state->i2c_client->dev;
> +	const struct tc358746_mbus_fmt *tc358746_mbusformat;
> +	struct v4l2_subdev *sensor_sd;
> +	struct v4l2_ctrl *ctrl;
> +	unsigned int pclk, pclk_old = state->pclk;
> +	unsigned int hblank, hblank_old = state->hblank;
> +	int new_freq;
> +	u16 vb_fifo;
> +
> +	/*
> +	 * Only validate if the timings are changed, after the link was already
> +	 * initialized. This can be happen if the parallel sensor frame interval
> +	 * is changed. Format checks are perfomed by the common code.
> +	 */
> +
> +	tc358746_mbusformat = tc358746_get_format(sink_fmt->format.code);
> +	if (!tc358746_mbusformat)
> +		return -EINVAL; /* Format was changed too and is invalid */
> +
> +	sensor_sd = media_entity_to_v4l2_subdev(link->source->entity);
> +	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
> +	pclk = v4l2_ctrl_g_ctrl_int64(ctrl);
> +	if (pclk != state->pclk) {
> +		dev_dbg(dev, "%s pixel rate is changed\n", sensor_sd->name);
> +		state->pclk = pclk;
> +	}
> +
> +	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_HBLANK);
> +	hblank = v4l2_ctrl_g_ctrl(ctrl);
> +	if (hblank != state->hblank) {
> +		dev_dbg(dev,
> +			"%s hblank interval is changed\n", sensor_sd->name);
> +		state->hblank = hblank;
> +	}
> +
> +	new_freq = tc358746_adjust_timings(state, tc358746_mbusformat,
> +					   &source_fmt->format.width, &vb_fifo);
> +
> +	if (new_freq != v4l2_ctrl_g_ctrl(state->link_freq)) {
> +		/*
> +		 * This can lead into undefined behaviour, so we don't support
> +		 * dynamic changes due to a to late re-configuration.
> +		 */
> +		dev_err(dev,
> +			"%s format can't be applied re-run the whole s_fmt\n",
> +			sensor_sd->name);
> +		state->pclk = pclk_old;
> +		state->hblank = hblank_old;
> +
> +		return -EINVAL;
> +	}
> +
> +	state->fmt_changed = true;
> +	state->vb_fifo = vb_fifo;
> +
> +	return 0;
> +}
> +
> +static int tc358764_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct tc358746_state *state = container_of(ctrl->handler,
> +					       struct tc358746_state, hdl);
> +	struct device *dev = &state->i2c_client->dev;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_LINK_FREQ:
> +		dev_info(dev, "Update link-frequency %llu -> %llu\n",
> +			 state->link_frequencies[ctrl->cur.val],
> +			 state->link_frequencies[ctrl->val]);
> +
> +		return 0;
> +	case V4L2_CID_TEST_PATTERN:
> +		state->test = ctrl->val;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int tc358746_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 v4l2_subdev *ps_sd = media_entity_to_v4l2_subdev(remote->entity);
> +	struct tc358746_state *state = to_state(sd);
> +	struct v4l2_ctrl *ctrl;
> +
> +	/* no special requirements on source pads */
> +	if (local->flags & MEDIA_PAD_FL_SOURCE)
> +		return 0;
> +
> +	dev_dbg(sd->dev, "link setup '%s':%d->'%s':%d[%d]",
> +		remote->entity->name, remote->index, local->entity->name,
> +		local->index, flags & MEDIA_LNK_FL_ENABLED);
> +
> +	/*
> +	 * The remote parallel sensor must support pixel rate and hblank query
> +	 */
> +	ctrl = v4l2_ctrl_find(ps_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
> +	if (!ctrl) {
> +		dev_err(sd->dev, "Subdev %s must support V4L2_CID_PIXEL_RATE\n",
> +			ps_sd->name);
> +		return -EINVAL;
> +	}
> +	state->pclk = v4l2_ctrl_g_ctrl_int64(ctrl);

The values could well change after enabling a link. You're also using the
controls later on. How about storing the pointer to the control instead?

> +
> +	ctrl = v4l2_ctrl_find(ps_sd->ctrl_handler, V4L2_CID_HBLANK);
> +	if (!ctrl) {
> +		dev_err(sd->dev, "Subdev %s must support V4L2_CID_HBLANK\n",
> +			ps_sd->name);
> +		return -EINVAL;
> +	}
> +	state->hblank = v4l2_ctrl_g_ctrl(ctrl);
> +
> +	return 0;
> +}
> +
> +/* -------------------------------------------------------------------------- */
> +
> +static const struct v4l2_ctrl_ops tc358764_ctrl_ops = {
> +	.s_ctrl = tc358764_s_ctrl,
> +};
> +
> +static const struct v4l2_subdev_core_ops tc358746_core_ops = {
> +	.log_status = tc358746_log_status,
> +#ifdef CONFIG_VIDEO_ADV_DEBUG
> +	.g_register = tc358746_g_register,
> +	.s_register = tc358746_s_register,
> +#endif
> +	.s_power = tc358746_s_power,
> +};
> +
> +static const struct v4l2_subdev_video_ops tc358746_video_ops = {
> +	.g_mbus_config = tc358746_g_mbus_config,
> +	.s_stream = tc358746_s_stream,
> +};
> +
> +static const struct v4l2_subdev_pad_ops tc358746_pad_ops = {
> +	.enum_mbus_code = tc358746_enum_mbus_code,
> +	.set_fmt = tc358746_set_fmt,
> +	.get_fmt = tc358746_get_fmt,
> +	.link_validate = tc358746_link_validate,
> +};
> +
> +static const struct v4l2_subdev_ops tc358746_ops = {
> +	.core = &tc358746_core_ops,
> +	.video = &tc358746_video_ops,
> +	.pad = &tc358746_pad_ops,
> +};
> +
> +static const struct media_entity_operations tc358746_entity_ops = {
> +	.link_setup = &tc358746_link_setup,
> +	.link_validate = &v4l2_subdev_link_validate,
> +};
> +
> +/* --------------- PROBE / REMOVE --------------- */
> +
> +static int tc358746_set_lane_settings(struct tc358746_state *state,
> +				      struct v4l2_fwnode_endpoint *fw)
> +{
> +	struct device *dev = &state->i2c_client->dev;
> +	int i;
> +
> +	for (i = 0; i < fw->nr_of_link_frequencies; i++) {
> +		struct tc358746_csi_param *s =
> +			&state->link_freq_settings[i];
> +		u32 bps_pr_lane;
> +
> +		state->link_frequencies[i] = fw->link_frequencies[i];
> +
> +		/*
> +		 * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
> +		 * bps_pr_lane = 2 * link_freq, because MIPI data lane is double
> +		 * data rate.
> +		 */
> +		bps_pr_lane = 2 * fw->link_frequencies[i];
> +		if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
> +			dev_err(dev, "unsupported bps per lane: %u bps\n",
> +				bps_pr_lane);
> +			return -EINVAL;
> +		}
> +
> +		if (bps_pr_lane > 500000000)
> +			s->speed_range = 0;
> +		else if (bps_pr_lane > 250000000)
> +			s->speed_range = 1;
> +		else if (bps_pr_lane > 125000000)
> +			s->speed_range = 2;
> +		else
> +			s->speed_range = 3;
> +
> +		s->unit_clk_hz = state->pllinclk_hz >> s->speed_range;
> +		s->unit_clk_mul = bps_pr_lane / s->unit_clk_hz;
> +		s->speed_per_lane = bps_pr_lane;
> +		s->lane_num = fw->bus.mipi_csi2.num_data_lanes;
> +		s->is_continuous_clk = fw->bus.mipi_csi2.flags &
> +			V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
> +
> +		if (s->speed_per_lane != 432000000U)
> +			dev_warn(dev, "untested bps per lane: %u bps\n",
> +				 s->speed_per_lane);
> +
> +		dev_dbg(dev, "%s: lane setting %d\n", __func__, i);
> +		dev_dbg(dev, "unit_clk %uHz: unit_clk_mul %u: speed_range %u: speed_per_lane(bps/lane) %u: csi_lange_numbers %u\n",
> +			s->unit_clk_hz, s->unit_clk_mul, s->speed_range,
> +			s->speed_per_lane, s->lane_num);
> +	}
> +
> +	state->link_frequencies_num = fw->nr_of_link_frequencies;
> +
> +	return 0;
> +}
> +
> +static void tc358746_gpio_reset(struct tc358746_state *state)
> +{
> +	usleep_range(5000, 10000);
> +	gpiod_set_value(state->reset_gpio, 1);
> +	usleep_range(1000, 2000);
> +	gpiod_set_value(state->reset_gpio, 0);
> +	msleep(20);
> +}
> +
> +static int tc358746_apply_fw(struct tc358746_state *state)
> +{
> +	struct tc358746_csi_param *csi_setting;
> +	int err, i;
> +
> +	for (i = 0; i < state->link_frequencies_num; i++) {
> +		csi_setting = &state->link_freq_settings[i];
> +
> +		err = tc358746_calculate_csi_txtimings(state, csi_setting);
> +		if (err) {
> +			dev_err(&state->i2c_client->dev,
> +				"Failed to calc csi-tx tminings\n");
> +			return err;
> +		}
> +	}
> +
> +	/*
> +	 * Set it to the hw default value. The correct value will be set during
> +	 * set_fmt(), since it depends on the pclk and and the resulution.
> +	 */
> +	state->vb_fifo = 1;
> +
> +	err = clk_prepare_enable(state->refclk);
> +	if (err) {
> +		dev_err(&state->i2c_client->dev, "Failed to enable clock\n");
> +		return err;
> +	}
> +
> +	if (state->reset_gpio)
> +		tc358746_gpio_reset(state);
> +
> +	return 0;
> +}
> +
> +static int tc358746_probe_fw(struct tc358746_state *state)
> +{
> +	struct device *dev = &state->i2c_client->dev;
> +	struct v4l2_fwnode_endpoint endpoint = {
> +		.bus_type = V4L2_MBUS_CSI2_DPHY,
> +	};
> +	struct fwnode_handle *fw_node;
> +	unsigned int refclk, pllinclk;
> +	unsigned char pll_prediv;
> +	int ret = -EINVAL;
> +
> +	/* Parse all clocks */
> +	state->refclk = devm_clk_get(dev, "refclk");
> +	if (IS_ERR(state->refclk)) {
> +		if (PTR_ERR(state->refclk) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get refclk: %ld\n",
> +				PTR_ERR(state->refclk));
> +		return PTR_ERR(state->refclk);
> +	}
> +
> +	refclk = clk_get_rate(state->refclk);
> +	if (refclk < 6000000 || refclk > 40000000) {
> +		dev_err(dev, "refclk must between 6MHz and 40MHz\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * The PLL input clock is obtained by dividing refclk by pll_prd.
> +	 * It must be between 4 MHz and 40 MHz, lower frequency is better.
> +	 */
> +	pll_prediv = DIV_ROUND_CLOSEST(refclk, 4000000);
> +	if (pll_prediv < 1 || pll_prediv > 16) {
> +		dev_err(dev, "invalid pll pre-divider value: %d\n", pll_prediv);
> +		return -EINVAL;
> +	}
> +	state->pll_prd = pll_prediv;
> +
> +	pllinclk = DIV_ROUND_CLOSEST(refclk, pll_prediv);
> +	if (pllinclk < 4000000 || pllinclk > 40000000) {
> +		dev_err(dev, "invalid pll input clock: %d Hz\n", pllinclk);
> +		return -EINVAL;
> +	}
> +	state->pllinclk_hz = pllinclk;
> +
> +	/* Now parse the fw-node */
> +	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fw_node) {
> +		struct fwnode_endpoint fw_ep;
> +
> +		ret = fwnode_graph_parse_endpoint(fw_node, &fw_ep);
> +		if (ret)
> +			return -EINVAL;
> +
> +		/* get downstream endpoint */
> +		if (fw_ep.port == 1)
> +			break;
> +	}
> +
> +	if (!fw_node) {
> +		dev_err(dev, "missing endpoint node\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = v4l2_fwnode_endpoint_alloc_parse(fw_node, &endpoint);
> +	if (ret) {
> +		dev_err(dev, "failed to parse endpoint %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
> +	    endpoint.nr_of_link_frequencies == 0) {
> +		dev_err(dev, "missing CSI-2 properties in endpoint\n");
> +		ret = -EINVAL;
> +		goto free_ep;
> +	}
> +
> +	if (endpoint.bus.mipi_csi2.num_data_lanes > 4) {
> +		dev_err(dev, "invalid number of lanes\n");
> +		ret = -EINVAL;
> +		goto free_ep;
> +	}
> +
> +	state->link_freq_settings =
> +		devm_kcalloc(dev, endpoint.nr_of_link_frequencies,
> +			     sizeof(*state->link_freq_settings), GFP_KERNEL);
> +	if (!state->link_freq_settings) {
> +		ret = -ENOMEM;
> +		goto free_ep;
> +	}
> +
> +	state->link_frequencies =
> +		devm_kcalloc(dev, endpoint.nr_of_link_frequencies,
> +			     sizeof(*state->link_frequencies), GFP_KERNEL);
> +	if (!state->link_frequencies) {
> +		ret = -ENOMEM;
> +		goto free_ep;
> +	}
> +
> +	ret = tc358746_set_lane_settings(state, &endpoint);
> +	if (ret)
> +		goto free_ep;
> +
> +	state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
> +						    GPIOD_OUT_LOW);
> +	if (IS_ERR(state->reset_gpio)) {
> +		dev_err(dev, "failed to get reset gpio\n");
> +		return PTR_ERR(state->reset_gpio);

Shouldn't the endpoint be freed here, too?

> +	}
> +
> +	ret = 0;
> +
> +free_ep:
> +	v4l2_fwnode_endpoint_free(&endpoint);
> +	return ret;
> +}
> +
> +static int tc358746_parse_endpoint(struct device *dev,
> +				   struct v4l2_fwnode_endpoint *vep,
> +				   struct v4l2_async_subdev *asd)
> +{
> +	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> +
> +	if (!fwnode_device_is_available(asd->match.fwnode)) {
> +		v4l2_err(sd, "remote is not available\n");
> +		return -ENOTCONN;
> +	}
> +
> +	if (vep->bus_type != V4L2_MBUS_PARALLEL) {
> +		v4l2_err(sd, "invalid bus type, must be PARALLEL\n");
> +		return -ENOTCONN;
> +	}
> +
> +	return 0;
> +};
> +
> +static int tc358746_async_register(struct v4l2_subdev *sd)
> +{
> +	unsigned int port = 0;
> +
> +	return v4l2_async_register_fwnode_subdev(
> +		sd, sizeof(struct v4l2_async_subdev), &port, 1,
> +		tc358746_parse_endpoint);
> +
> +}
> +
> +static const char * const tc358764_test_pattern_menu[] = {
> +	"Disabled",
> +	"colorbar 80px",

One or more bars? How about "80 Pixel Color Bars"?

> +};
> +
> +static int tc358746_probe(struct i2c_client *client,
> +			  const struct i2c_device_id *id)
> +{
> +	struct tc358746_state *state;
> +	struct v4l2_subdev *sd;
> +	int err;
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> +		return -EIO;
> +
> +	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	state->i2c_client = client;
> +
> +	/* platform data */
> +	err = tc358746_probe_fw(state);
> +	if (err)
> +		return err;
> +
> +	err = tc358746_apply_fw(state);
> +	if (err)
> +		return err;
> +
> +	sd = &state->sd;
> +	v4l2_i2c_subdev_init(sd, client, &tc358746_ops);
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +	/* i2c access */
> +	if (((i2c_rd16(sd, CHIPID) & CHIPID_CHIPID_MASK) >> 8) != 0x44) {
> +		v4l2_info(sd, "not a TC358746 on address 0x%x\n",
> +			  client->addr << 1);

clk_disable_unprepare(state->refclk);

Perhaps a new label?

> +		return -ENODEV;
> +	}
> +
> +	/* control handlers */
> +	v4l2_ctrl_handler_init(&state->hdl, 1);
> +
> +	v4l2_ctrl_new_std_menu_items(&state->hdl,
> +			&tc358764_ctrl_ops, V4L2_CID_TEST_PATTERN,
> +			ARRAY_SIZE(tc358764_test_pattern_menu) - 1, 0, 0,
> +			tc358764_test_pattern_menu);
> +
> +	state->link_freq =
> +		v4l2_ctrl_new_int_menu(&state->hdl, &tc358764_ctrl_ops,
> +				       V4L2_CID_LINK_FREQ,
> +				       state->link_frequencies_num - 1,
> +				       TC358746_DEF_LINK_FREQ,
> +				       state->link_frequencies);
> +
> +
> +	sd->ctrl_handler = &state->hdl;
> +	if (state->hdl.error) {
> +		err = state->hdl.error;
> +		goto err_hdl;
> +	}
> +
> +	state->pads[1].flags = MEDIA_PAD_FL_SOURCE;
> +	state->pads[0].flags = MEDIA_PAD_FL_SINK;
> +	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> +	sd->entity.ops = &tc358746_entity_ops;
> +	err = media_entity_pads_init(&sd->entity, 2, state->pads);
> +	if (err < 0)
> +		goto err_hdl;
> +
> +	mutex_init(&state->confctl_mutex);
> +
> +	state->fmt = tc358746_def_fmt;
> +
> +	/* apply default settings */
> +	tc358746_sreset(sd);
> +	tc358746_set_buffers(sd);
> +	tc358746_set_csi(sd);
> +	tc358746_set_csi_color_space(sd);
> +	tc358746_sleep_mode(sd, 1);
> +	tc358746_set_pll(sd);
> +	tc358746_enable_stream(sd, 0);
> +
> +	err = tc358746_async_register(sd);
> +	if (err < 0)
> +		goto err_hdl;
> +
> +	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
> +		  client->addr << 1, client->adapter->name);

Please try to use either v4l2_*() or dev_*() macros to print debug
messages, but not both.

> +
> +	return 0;
> +
> +err_hdl:

mutex_destroy(&state->confctl_mutex);

You'll probably need one more label for that at least.

> +	media_entity_cleanup(&sd->entity);
> +	v4l2_ctrl_handler_free(&state->hdl);

An extra newline would be nice before return, as you have elsewhere.

> +	return err;
> +}
> +
> +static int tc358746_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct tc358746_state *state = to_state(sd);
> +
> +	v4l2_async_unregister_subdev(sd);
> +	v4l2_device_unregister_subdev(sd);
> +	mutex_destroy(&state->confctl_mutex);
> +	media_entity_cleanup(&sd->entity);
> +	v4l2_ctrl_handler_free(&state->hdl);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id tc358746_id[] = {
> +	{"tc358746", 0},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, tc358746_id);
> +
> +static const struct of_device_id __maybe_unused tc358746_of_match[] = {
> +	{ .compatible = "toshiba,tc358746" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, tc358746_of_match);
> +
> +static struct i2c_driver tc358746_driver = {
> +	.driver = {
> +		.name = "tc358746",
> +		.of_match_table = of_match_ptr(tc358746_of_match),
> +	},
> +	.probe = tc358746_probe,
> +	.remove = tc358746_remove,
> +	.id_table = tc358746_id,

If you have no need for I²C IDs, then you could switch to probe_new and
ignore the i2c ID table.

> +};
> +
> +module_i2c_driver(tc358746_driver);
> diff --git a/drivers/media/i2c/tc358746_regs.h b/drivers/media/i2c/tc358746_regs.h
> new file mode 100644
> index 000000000000..9232d00d0e92
> --- /dev/null
> +++ b/drivers/media/i2c/tc358746_regs.h
> @@ -0,0 +1,208 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * tc358746 - Toshiba Parallel to CSI-2 bridge - register names and bit masks
> + *
> + * Convention:
> + * <REGISTER>
> + * <REGISTER>_<BITFIELD>_MASK
> + * <REGISTER>_<BITFIELD>_<VALUE>
> + * <REGISTER>_<BITFIELD>_SET(val = <REGISTER>_<BITFIELD>_<VALUE>)
> + *
> + * References:
> + * REF_01:
> + * - TC358746AXBG/TC358748XBG/TC358748IXBG Functional Specification Rev 1.2
> + */
> +
> +#ifndef __TC358746_REGS_H
> +#define __TC358746_REGS_H
> +
> +#define CHIPID			0x0000
> +#define CHIPID_CHIPID_MASK		GENMASK(15, 8)
> +#define CHIPID_REVID_MASK		GENMASK(7, 0)
> +
> +#define SYSCTL			0x0002
> +#define SYSCTL_SLEEP_MASK		BIT(1)
> +#define SYSCTL_SRESET_MASK		BIT(0)
> +
> +#define CONFCTL                 0x0004
> +#define CONFCTL_TRIEN_MASK		BIT(15)
> +#define CONFCTL_INTE2N_MASK		BIT(13)
> +#define CONFCTL_BT656EN_MASK		BIT(12)
> +#define CONFCTL_PDATAF_MASK		GENMASK(9, 8)
> +#define CONFCTL_PDATAF_SET(val)		(((val << 8) & CONFCTL_PDATAF_MASK))
> +#define CONFCTL_PDATAF_MODE0		0
> +#define CONFCTL_PDATAF_MODE1		1
> +#define CONFCTL_PDATAF_MODE2		2
> +#define CONFCTL_PPEN_MASK		BIT(6)
> +#define CONFCTL_VVALIDP_MASK		BIT(5)
> +#define CONFCTL_HVALIDP_MASK		BIT(4)
> +#define CONFCTL_PCLKP_MASK		BIT(3)
> +#define CONFCTL_AUTO_MASK		BIT(2)
> +#define CONFCTL_DATALANE_MASK		GENMASK(1, 0)
> +#define CONFCTL_DATALANE_1		0
> +#define CONFCTL_DATALANE_2		1
> +#define CONFCTL_DATALANE_3		2
> +#define CONFCTL_DATALANE_4		3
> +
> +#define FIFOCTL			0x0006
> +#define DATAFMT			0x0008
> +#define DATAFMT_PDFMT_RAW8		0
> +#define DATAFMT_PDFMT_RAW10		1
> +#define DATAFMT_PDFMT_RAW12		2
> +#define DATAFMT_PDFMT_RGB888		3
> +#define DATAFMT_PDFMT_RGB666		4
> +#define DATAFMT_PDFMT_RGB565		5
> +#define DATAFMT_PDFMT_YCBCRFMT_422_8_BIT 6
> +#define DATAFMT_PDFMT_RAW14		8
> +#define DATAFMT_PDFMT_YCBCRFMT_422_10_BIT 9
> +#define DATAFMT_PDFMT_YCBCRFMT_444	10
> +#define DATAFMT_PDFMT_MASK		GENMASK(7, 4)
> +#define DATAFMT_PDFMT_SET(val)		(((val) << 4) & DATAFMT_PDFMT_MASK)
> +#define DATAFMT_UDT_EN_MASK		BIT(0)
> +
> +#define MCLKCTL			0x000c
> +#define MCLKCTL_MCLK_HIGH_MASK		GENMASK(15, 8)
> +#define MCLKCTL_MCLK_HIGH_SET(val)	((((val) - 1) << 8) & MCLKCTL_MCLK_HIGH_MASK)
> +#define MCLKCTL_MCLK_LOW_MASK		GENMASK(7, 0)
> +#define MCLKCTL_MCLK_LOW_SET(val)	(((val) - 1) & MCLKCTL_MCLK_LOW_MASK)
> +
> +#define PLLCTL0			0x0016
> +#define PLLCTL0_PLL_PRD_MASK		GENMASK(15, 12)
> +#define PLLCTL0_PLL_PRD_SET(prd)	((((prd) - 1) << 12) & PLLCTL0_PLL_PRD_MASK)
> +#define PLLCTL0_PLL_FBD_MASK		GENMASK(8, 0)
> +#define PLLCTL0_PLL_FBD_SET(fbd)        (((fbd) - 1) & PLLCTL0_PLL_FBD_MASK)
> +
> +#define PLLCTL1                 0x0018
> +#define PLLCTL1_PLL_FRS_MASK            GENMASK(11, 10)
> +#define PLLCTL1_PLL_FRS_SET(frs)        (((frs) << 10) & PLLCTL1_PLL_FRS_MASK)
> +#define PLLCTL1_PLL_LBWS_MASK		GENMASK(9, 8)
> +#define PLLCTL1_LFBREN_MASK		BIT(6)
> +#define PLLCTL1_BYPCKEN_MASK		BIT(5)
> +#define PLLCTL1_CKEN_MASK		BIT(4)
> +#define PLLCTL1_RESETB_MASK		BIT(1)
> +#define PLLCTL1_PLL_EN_MASK		BIT(0)
> +
> +#define CLKCTL			0x0020
> +#define CLKCTL_MCLKDIV_MASK		GENMASK(3, 2)
> +#define CLKCTL_MCLKDIV_SET(val)		((val << 2) & CLKCTL_MCLKDIV_MASK)
> +#define CLKCTL_MCLKDIV_8		0
> +#define CLKCTL_MCLKDIV_4		1
> +#define CLKCTL_MCLKDIV_2		2
> +
> +#define WORDCNT			0x0022
> +#define PP_MISC                 0x0032
> +#define PP_MISC_FRMSTOP_MASK		BIT(15)
> +#define PP_MISC_RSTPTR_MASK		BIT(14)
> +
> +#define CSI2TX_DATA_TYPE	0x0050
> +#define MIPI_PHY_STATUS		0x0062
> +#define CSI2_ERROR_STATUS       0x0064
> +#define CSI2_ERR_EN             0x0066
> +#define CSI2_IDID_ERROR         0x006c
> +#define DBG_ACT_LINE_CNT        0x00e0
> +#define DBG_LINE_WIDTH		0x00e2
> +#define DBG_VERT_BLANK_LINE_CNT	0x00e4
> +#define DBG_VIDEO_DATA          0x00e8
> +#define FIFOSTATUS              0x00F8
> +
> +#define CLW_CNTRL               0x0140
> +#define CLW_CNTRL_CLW_LANEDISABLE_MASK	BIT(0)
> +
> +#define D0W_CNTRL               0x0144
> +#define D0W_CNTRL_D0W_LANEDISABLE_MASK	BIT(0)
> +
> +#define D1W_CNTRL		0x0148
> +#define D1W_CNTRL_D1W_LANEDISABLE_MASK	BIT(0)
> +
> +#define D2W_CNTRL		0x014C
> +#define D2W_CNTRL_D2W_LANEDISABLE_MASK	BIT(0)
> +
> +#define D3W_CNTRL		0x0150
> +#define D2W_CNTRL_D3W_LANEDISABLE_MASK	BIT(0)
> +
> +#define STARTCNTRL              0x0204
> +#define STARTCNTRL_START_MASK		BIT(0)
> +
> +#define LINEINITCNT		0x0210
> +#define LPTXTIMECNT		0x0214
> +#define TCLK_HEADERCNT		0x0218
> +#define	TCLK_HEADERCNT_TCLK_ZEROCNT_MASK	GENMASK(15, 8)
> +#define TCLK_HEADERCNT_TCLK_PREPARECNT_MASK	GENMASK(6, 0)
> +#define	TCLK_HEADERCNT_TCLK_ZEROCNT_SET(val)	((val << 8) & TCLK_HEADERCNT_TCLK_ZEROCNT_MASK)
> +#define	TCLK_HEADERCNT_TCLK_PREPARECNT_SET(val)	(val & TCLK_HEADERCNT_TCLK_PREPARECNT_MASK)
> +
> +#define TCLK_TRAILCNT		0x021C
> +#define THS_HEADERCNT		0x0220
> +#define	THS_HEADERCNT_THS_ZEROCNT_MASK		GENMASK(14, 8)
> +#define	THS_HEADERCNT_THS_PREPARECNT_MASK	GENMASK(6, 0)
> +#define	THS_HEADERCNT_THS_ZEROCNT_SET(val)	((val << 8) & THS_HEADERCNT_THS_ZEROCNT_MASK)
> +#define	THS_HEADERCNT_THS_PREPARECNT_SET(val)	(val & THS_HEADERCNT_THS_PREPARECNT_MASK)
> +
> +#define TWAKEUP			0x0224
> +#define TCLK_POSTCNT		0x0228
> +#define THS_TRAILCNT		0x022C
> +#define HSTXVREGCNT		0x0230
> +#define HSTXVREGEN              0x0234
> +#define HSTXVREGEN_D3M_HSTXVREGEN_MASK	BIT(4)
> +#define HSTXVREGEN_D2M_HSTXVREGEN_MASK  BIT(3)
> +#define HSTXVREGEN_D1M_HSTXVREGEN_MASK  BIT(2)
> +#define HSTXVREGEN_D0M_HSTXVREGEN_MASK  BIT(1)
> +#define HSTXVREGEN_CLM_HSTXVREGEN_MASK  BIT(0)
> +
> +#define TXOPTIONCNTRL           0x0238
> +#define TXOPTIONCNTRL_CONTCLKMODE_MASK	BIT(0)
> +
> +#define CSI_CONTROL             0x040C
> +#define CSI_CONTROL_CSI_MODE_MASK       BIT(15)
> +#define CSI_CONTROL_HTXTOEN_MASK        BIT(10)
> +#define CSI_CONTROL_TXHSMD_MASK         BIT(7)
> +#define CSI_CONTROL_NOL_MASK            GENMASK(2, 1)
> +#define CSI_CONTROL_NOL_1_MASK          0
> +#define CSI_CONTROL_NOL_2_MASK          BIT(1)
> +#define CSI_CONTROL_NOL_3_MASK          BIT(2)
> +#define CSI_CONTROL_NOL_4_MASK          (BIT(1) | BIT(2))
> +#define CSI_CONTROL_EOTDIS_MASK         BIT(0)
> +
> +#define CSI_STATUS              0x0410
> +#define CSI_STATUS_S_WSYNC_MASK		BIT(10)
> +#define CSI_STATUS_S_TXACT_MASK		BIT(9)
> +#define CSI_STATUS_S_HLT_MASK		BIT(0)
> +
> +#define CSI_INT			0x0414
> +#define CSI_INT_INTHLT_MASK		BIT(3)
> +#define CSI_INT_INTER_MASK		BIT(2)
> +
> +#define CSI_INT_ENA             0x0418
> +#define CSI_INT_ENA_IENHLT_MASK		BIT(3)
> +#define CSI_INT_ENA_IENER_MASK		BIT(2)
> +
> +#define CSI_ERR                 0x044C
> +#define CSI_ERR_INER_MASK               BIT(9)
> +#define CSI_ERR_WCER_MASK		BIT(8)
> +#define CSI_ERR_QUNK_MASK		BIT(4)
> +#define CSI_ERR_TXBRK_MASK		BIT(1)
> +
> +#define CSI_ERR_INTENA          0x0450
> +#define CSI_ERR_HALT            0x0454
> +#define CSI_CONFW               0x0500
> +#define CSI_CONFW_MODE_MASK			GENMASK(31, 29)
> +#define CSI_CONFW_MODE_SET_MASK			(BIT(31) | BIT(29))
> +#define CSI_CONFW_MODE_CLEAR_MASK		(BIT(31) | BIT(30))
> +#define CSI_CONFW_ADDRESS_MASK			GENMASK(28, 24)
> +#define CSI_CONFW_ADDRESS_CSI_CONTROL_MASK	(BIT(24) | BIT(25))
> +#define CSI_CONFW_ADDRESS_CSI_INT_ENA_MASK	(BIT(25) | BIT(26))
> +#define CSI_CONFW_ADDRESS_CSI_ERR_INTENA_MASK	(BIT(28) | BIT(26))
> +#define CSI_CONFW_ADDRESS_CSI_ERR_HALT_MASK	(BIT(28) | BIT(26) | BIT(24))
> +#define CSI_CONFW_DATA_MASK			GENMASK(15, 0)
> +
> +#define CSIRESET                0x0504
> +#define CSIRESET_RESET_CNF_MASK		BIT(1)
> +#define CSIRESET_RESET_MODULE_MASK	BIT(0)
> +
> +#define CSI_INT_CLR             0x050C
> +#define CSI_INT_CLR_ICRER_MASK		BIT(2)
> +
> +#define CSI_START               0x0518
> +#define CSI_START_STRT_MASK		BIT(0)
> +
> +#endif

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] media: tc358746: update MAINTAINERS file
  2018-12-18 14:12 ` [PATCH 3/3] media: tc358746: update MAINTAINERS file Marco Felsch
@ 2019-02-18 11:46   ` Sakari Ailus
  2019-03-04 17:31     ` Marco Felsch
  0 siblings, 1 reply; 30+ messages in thread
From: Sakari Ailus @ 2019-02-18 11:46 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Marco,

On Tue, Dec 18, 2018 at 03:12:40PM +0100, Marco Felsch wrote:
> Add me as partial maintainer, others are welcome too.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 546f8d936589..f97dedbe545c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15230,6 +15230,13 @@ S:	Maintained
>  F:	drivers/media/i2c/tc358743*
>  F:	include/media/i2c/tc358743.h
>  
> +TOSHIBA TC358746 DRIVER
> +M:	Marco Felsch <kernel@pengutronix.de>
> +L:	linux-media@vger.kernel.org
> +S:	Odd Fixes
> +F:	drivers/media/i2c/tc358746*
> +F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> +
>  TOSHIBA WMI HOTKEYS DRIVER
>  M:	Azael Avalos <coproscefalo@gmail.com>
>  L:	platform-driver-x86@vger.kernel.org

This should go together with the DT bindings, in the same patch.

I'd expect a new driver to be listed as "Maintained". "Odd Fixes" suggests
no-one is particularly looking after it, and it's not nice if a new driver
starts off like that. :-I

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-02-13 17:57   ` Jacopo Mondi
@ 2019-03-01 10:26     ` Marco Felsch
  2019-03-04  9:38       ` Jacopo Mondi
  0 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-03-01 10:26 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

On 19-02-13 18:57, Jacopo Mondi wrote:
> Hi Marco,
>     thanks for the patch.
> 
> I have some comments, which I hope might get the ball rolling...

Hi Jacopo,

thanks for your review and sorry for the late response. My schedule was
a bit filled.

> 
> On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > Add corresponding dt-bindings for the Toshiba tc358746 device.
> >
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> >  1 file changed, 80 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> >
> > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > new file mode 100644
> > index 000000000000..499733df744a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > @@ -0,0 +1,80 @@
> > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > +
> > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> 
> nit:
> s/is a bridge that/is a bridge device that/
> or drop is a bridge completely?

You're right, I will drop this statement.

> 
> > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> 
> From the thin public available datasheet, it seems to support SPI as
> programming interface, but only when doing Parallel->CSI-2. I would
> mention that.

You're right, the SPI interface is only supported in that mode.

Should I add something like:
It is programmable trough I2C and SPI. The SPI interface is only
supported in parallel-in -> csi-out mode.
 
> > +
> > +Required Properties:
> > +
> > +- compatible: should be "toshiba,tc358746"
> > +- reg: should be <0x0e>
> 
> nit: s/should/shall

Okay.

> > +- clocks: should contain a phandle link to the reference clock source
> 
> just "phandle to the reference clock source" ?

Okay.

> > +- clock-names: the clock input is named "refclk".
> 
> According to the clock bindings this is optional, and since you have
> a single clock I would drop it.

Yes it's optional, but the device can also act as clock provider (not
now, patches in my personal queue for rework). So I won't drop it since
I never linked the generic clock-bindings.

> > +
> > +Optional Properties:
> > +
> > +- reset-gpios: gpio phandle GPIO connected to the reset pin
> 
> would you drop one of the two "gpio" here. Like ": phandle to the GPIO
> connected to the reset input pin"

Okay.

> > +
> > +Parallel Endpoint:
> 
> Here I got confused. The chip supports 2 inputs (parallel and CSI-2)
> and two outputs (parallel and CSI-2 again). You mention endpoints
> propery only here, but it seems from the example you want two ports,
> with one endpoint child-node each.

Nope, the device has one CSI and one Parallel interface. These
interfaces can be configured as receiver or as transmitter (according to
the selected mode). I got you but I remember also the discussion with
Mauro, Hans, Sakari about the TVP5150 ports. The result of that
discussion was "don't introduce 'virtual' ports". If I got you right
your Idea will introduce virtual ports too:

/* Parallel */
port@0{
	port@0 { ... }; /* input case */
	port@1 { ... }; /* output case */
};

/* CSI */
port@1{
	port@0 { ... }; /* input case */
	port@1 { ... }; /* output case */
};

> Even if the driver does not support CSI-2->Parallel at the moment,
> bindings should be future-proof, so I would reserve the first two
> ports for the inputs, and the last two for the output, or, considering
> that the two input-output combinations are mutually exclusive, provide
> one "input" port with two optional endpoints, and one "output" port with
> two optional endpoints.

I wouldn't map the combinations to the device tree since it is the
hw-abstraction and the signals still routed to the same pads. The only
difference in the CSI-2->Parallel case is the timing calculation which
is out of scope for the dt.

> In both cases only one input and one output at the time could be
> described in DT. Up to you, maybe others have different ideas as
> well...
> 
> > +
> > +Required Properties:
> > +
> > +- reg: should be <0>
> > +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> > +	     for sixteen bit wide bus.
> 
> The chip seems to support up to 24 bits of data bus width

You're right, I will change that.

> > +
> > +MIPI CSI-2 Endpoint:
> > +
> > +Required Properties:
> > +
> > +- reg: should be <1>
> > +- data-lanes: should be <1 2 3 4> for four-lane operation,
> > +	      or <1 2> for two-lane operation
> > +- clock-lanes: should be <0>
> 
> Can this be changed? If the chip does not allow lane re-ordering you
> could drop this.

Nope it can't. Only the data-lanes can be disabled seperatly so I added
the data-lanes property to determine that number and for the sake of
completeness I added the clock-lanes property.

> 
> > +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> > +		    expressed as a 64-bit big-endian integer. The frequency
> > +		    is half of the bps per lane due to DDR transmission.
> 
> Does the chip supports a limited set of bus frequencies, or are this
> "hints" ? I admit this property actually puzzles me, so I might got it
> wrong..

That's not that easy to answer. The user can add different link-freq.
the driver can choose. This is relevant for the Parallel-in --> CSI-out.
If the external pclk is to slow (due to dyn. fps change) and the link-freq.
is to fast the internally pixel buffer throws underrun interrupts. The
user notice that by green pixel artifacts. If the user adds more
possible link-freq. the driver will switch to that one wich full fill
the timings to avoid a fifo underrun.

> 
> Thanks
>    j

Regards,
Marco

> > +
> > +Optional Properties:
> > +
> > +- clock-noncontinuous: Presence of this boolean property decides whether the
> > +		       MIPI CSI-2 clock is continuous or non-continuous.
> > +
> > +For further information on the endpoint node properties, see
> > +Documentation/devicetree/bindings/media/video-interfaces.txt.
> > +
> > +Example:
> > +
> > +&i2c {
> > +	tc358746: tc358746@0e {
> > +		reg = <0x0e>;
> > +		compatible = "toshiba,tc358746";
> > +		pinctrl-names = "default";
> > +		clocks = <&clk_cam_ref>;
> > +		clock-names = "refclk";
> > +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> > +
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		port@0 {
> > +			reg = <0>;
> > +
> > +			tc358746_parallel_in: endpoint {
> > +				bus-width = <8>;
> > +				remote-endpoint = <&micron_parallel_out>;
> > +			};
> > +		};
> > +
> > +		port@1 {
> > +			reg = <1>;
> > +
> > +			tc358746_mipi2_out: endpoint {
> > +				remote-endpoint = <&mipi_csi2_in>;
> > +				data-lanes = <1 2>;
> > +				clock-lanes = <0>;
> > +				clock-noncontinuous;
> > +				link-frequencies = /bits/ 64 <216000000>;
> > +			};
> > +		};
> > +	};
> > +};
> > --
> > 2.19.1
> >



-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-02-18 10:03   ` Sakari Ailus
@ 2019-03-01 10:52     ` Marco Felsch
  2019-03-01 11:07       ` Ian Arkver
  2019-03-04 12:10       ` Sakari Ailus
  0 siblings, 2 replies; 30+ messages in thread
From: Marco Felsch @ 2019-03-01 10:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Sakari,

On 19-02-18 12:03, Sakari Ailus wrote:
> Hi Marco,
> 
> My apologies for reviewing this so late. You've received good comments
> already. I have a few more.

Thanks for your review for the other patches as well =) Sorry for my
delayed response.

> On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> >  1 file changed, 80 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > new file mode 100644
> > index 000000000000..499733df744a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > @@ -0,0 +1,80 @@
> > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > +
> > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> 
> This is interesting. The driver somehow needs to figure out the direction
> of the data flow if it does not originate from DT. I guess it shouldn't as
> it's not the property of an individual device, albeit in practice in all
> hardware I've seen the direction of the pipeline is determinable and this
> is visible in the kAPI as well. So I'm suggesting no changes due to this in
> bindings, likely we'll need to address it somehow elsewhere going forward.

What did you mean with "... and this is visible in the kAPI as well"?
I'm relative new in the linux-media world but I never saw a device which
supports two directions. Our customer which uses that chip use it
only in parallel-in/csi-out mode. To be flexible the switching should be
done by a subdev-ioctl but it is also reasonable to define a default value
within the DT.

> > +
> > +Required Properties:
> > +
> > +- compatible: should be "toshiba,tc358746"
> > +- reg: should be <0x0e>
> > +- clocks: should contain a phandle link to the reference clock source
> > +- clock-names: the clock input is named "refclk".
> > +
> > +Optional Properties:
> > +
> > +- reset-gpios: gpio phandle GPIO connected to the reset pin
> > +
> > +Parallel Endpoint:
> > +
> > +Required Properties:
> 
> It'd be nice if the relation between these sections would be somehow
> apparent. E.g. using different underlining, such as in
> Documentation/devicetree/bindings/media/ti,omap3isp.txt .

Thats a really good example thanks.

> 
> > +
> > +- reg: should be <0>
> > +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> > +	     for sixteen bit wide bus.
> > +
> > +MIPI CSI-2 Endpoint:
> > +
> > +Required Properties:
> > +
> > +- reg: should be <1>
> > +- data-lanes: should be <1 2 3 4> for four-lane operation,
> > +	      or <1 2> for two-lane operation
> > +- clock-lanes: should be <0>
> > +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> > +		    expressed as a 64-bit big-endian integer. The frequency
> > +		    is half of the bps per lane due to DDR transmission.
> > +
> > +Optional Properties:
> > +
> > +- clock-noncontinuous: Presence of this boolean property decides whether the
> > +		       MIPI CSI-2 clock is continuous or non-continuous.
> > +
> > +For further information on the endpoint node properties, see
> > +Documentation/devicetree/bindings/media/video-interfaces.txt.
> > +
> > +Example:
> > +
> > +&i2c {
> > +	tc358746: tc358746@0e {
> 
> The node name should be a generic name of the type of the device, not the
> name of the specific device as such. A similar Cadence device uses
> "csi-bridge".

Okay, I will change that.

> 
> > +		reg = <0x0e>;
> > +		compatible = "toshiba,tc358746";
> > +		pinctrl-names = "default";
> > +		clocks = <&clk_cam_ref>;
> > +		clock-names = "refclk";
> > +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> > +
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		port@0 {
> > +			reg = <0>;
> > +
> > +			tc358746_parallel_in: endpoint {
> > +				bus-width = <8>;
> > +				remote-endpoint = <&micron_parallel_out>;
> > +			};
> > +		};
> > +
> > +		port@1 {
> > +			reg = <1>;
> > +
> > +			tc358746_mipi2_out: endpoint {
> > +				remote-endpoint = <&mipi_csi2_in>;
> > +				data-lanes = <1 2>;
> > +				clock-lanes = <0>;
> > +				clock-noncontinuous;
> > +				link-frequencies = /bits/ 64 <216000000>;
> > +			};
> > +		};
> > +	};
> > +};
> 
> -- 
> Kind regards,
> 
> Sakari Ailus
> sakari.ailus@linux.intel.com
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 10:52     ` Marco Felsch
@ 2019-03-01 11:07       ` Ian Arkver
  2019-03-01 13:01         ` Marco Felsch
  2019-03-04 12:10       ` Sakari Ailus
  1 sibling, 1 reply; 30+ messages in thread
From: Ian Arkver @ 2019-03-01 11:07 UTC (permalink / raw)
  To: Marco Felsch, Sakari Ailus
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi,

On 01/03/2019 10:52, Marco Felsch wrote:
> Hi Sakari,
> 
> On 19-02-18 12:03, Sakari Ailus wrote:
>> Hi Marco,
>>
>> My apologies for reviewing this so late. You've received good comments
>> already. I have a few more.
> 
> Thanks for your review for the other patches as well =) Sorry for my
> delayed response.
> 
>> On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
>>> Add corresponding dt-bindings for the Toshiba tc358746 device.
>>>
>>> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
>>> ---
>>>   .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
>>>   1 file changed, 80 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
>>> new file mode 100644
>>> index 000000000000..499733df744a
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
>>> @@ -0,0 +1,80 @@
>>> +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
>>> +
>>> +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
>>> +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
>>
>> This is interesting. The driver somehow needs to figure out the direction
>> of the data flow if it does not originate from DT. I guess it shouldn't as
>> it's not the property of an individual device, albeit in practice in all
>> hardware I've seen the direction of the pipeline is determinable and this
>> is visible in the kAPI as well. So I'm suggesting no changes due to this in
>> bindings, likely we'll need to address it somehow elsewhere going forward.
> 
> What did you mean with "... and this is visible in the kAPI as well"?
> I'm relative new in the linux-media world but I never saw a device which
> supports two directions. Our customer which uses that chip use it
> only in parallel-in/csi-out mode. To be flexible the switching should be
> done by a subdev-ioctl but it is also reasonable to define a default value
> within the DT.

The mode is set by a pin strap at reset time (MSEL). It's not 
programmable by i2c. As far as I can see, looking at the registers, it's 
also not readable by i2c, so there's no easy way for a driver which 
supports both modes to see what the pinstrap is set to.

I'm not sure if the driver could tell from the direction of the 
endpoints it's linked to which mode to use, but if not it'll need to be 
told somehow and a DT property seems reasonable to me. Given that the 
same pins are used in each direction I think the direction is most 
likely to be hard wired and board specific.

Regards,
Ian.

>>> +
>>> +Required Properties:
>>> +
>>> +- compatible: should be "toshiba,tc358746"
>>> +- reg: should be <0x0e>
>>> +- clocks: should contain a phandle link to the reference clock source
>>> +- clock-names: the clock input is named "refclk".
>>> +
>>> +Optional Properties:
>>> +
>>> +- reset-gpios: gpio phandle GPIO connected to the reset pin
>>> +
>>> +Parallel Endpoint:
>>> +
>>> +Required Properties:
>>
>> It'd be nice if the relation between these sections would be somehow
>> apparent. E.g. using different underlining, such as in
>> Documentation/devicetree/bindings/media/ti,omap3isp.txt .
> 
> Thats a really good example thanks.
> 
>>
>>> +
>>> +- reg: should be <0>
>>> +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
>>> +	     for sixteen bit wide bus.
>>> +
>>> +MIPI CSI-2 Endpoint:
>>> +
>>> +Required Properties:
>>> +
>>> +- reg: should be <1>
>>> +- data-lanes: should be <1 2 3 4> for four-lane operation,
>>> +	      or <1 2> for two-lane operation
>>> +- clock-lanes: should be <0>
>>> +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
>>> +		    expressed as a 64-bit big-endian integer. The frequency
>>> +		    is half of the bps per lane due to DDR transmission.
>>> +
>>> +Optional Properties:
>>> +
>>> +- clock-noncontinuous: Presence of this boolean property decides whether the
>>> +		       MIPI CSI-2 clock is continuous or non-continuous.
>>> +
>>> +For further information on the endpoint node properties, see
>>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>>> +
>>> +Example:
>>> +
>>> +&i2c {
>>> +	tc358746: tc358746@0e {
>>
>> The node name should be a generic name of the type of the device, not the
>> name of the specific device as such. A similar Cadence device uses
>> "csi-bridge".
> 
> Okay, I will change that.
> 
>>
>>> +		reg = <0x0e>;
>>> +		compatible = "toshiba,tc358746";
>>> +		pinctrl-names = "default";
>>> +		clocks = <&clk_cam_ref>;
>>> +		clock-names = "refclk";
>>> +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
>>> +
>>> +		#address-cells = <1>;
>>> +		#size-cells = <0>;
>>> +
>>> +		port@0 {
>>> +			reg = <0>;
>>> +
>>> +			tc358746_parallel_in: endpoint {
>>> +				bus-width = <8>;
>>> +				remote-endpoint = <&micron_parallel_out>;
>>> +			};
>>> +		};
>>> +
>>> +		port@1 {
>>> +			reg = <1>;
>>> +
>>> +			tc358746_mipi2_out: endpoint {
>>> +				remote-endpoint = <&mipi_csi2_in>;
>>> +				data-lanes = <1 2>;
>>> +				clock-lanes = <0>;
>>> +				clock-noncontinuous;
>>> +				link-frequencies = /bits/ 64 <216000000>;
>>> +			};
>>> +		};
>>> +	};
>>> +};
>>
>> -- 
>> Kind regards,
>>
>> Sakari Ailus
>> sakari.ailus@linux.intel.com
>>
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 11:07       ` Ian Arkver
@ 2019-03-01 13:01         ` Marco Felsch
  2019-03-04  9:41           ` Jacopo Mondi
  2019-03-04 12:36           ` Sakari Ailus
  0 siblings, 2 replies; 30+ messages in thread
From: Marco Felsch @ 2019-03-01 13:01 UTC (permalink / raw)
  To: Ian Arkver
  Cc: Sakari Ailus, hans.verkuil, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

Hi Ian,

On 19-03-01 11:07, Ian Arkver wrote:
> Hi,
> 
> On 01/03/2019 10:52, Marco Felsch wrote:
> > Hi Sakari,
> > 
> > On 19-02-18 12:03, Sakari Ailus wrote:
> > > Hi Marco,
> > > 
> > > My apologies for reviewing this so late. You've received good comments
> > > already. I have a few more.
> > 
> > Thanks for your review for the other patches as well =) Sorry for my
> > delayed response.
> > 
> > > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > > 
> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > ---
> > > >   .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > > >   1 file changed, 80 insertions(+)
> > > >   create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > new file mode 100644
> > > > index 000000000000..499733df744a
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > @@ -0,0 +1,80 @@
> > > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > > +
> > > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > > 
> > > This is interesting. The driver somehow needs to figure out the direction
> > > of the data flow if it does not originate from DT. I guess it shouldn't as
> > > it's not the property of an individual device, albeit in practice in all
> > > hardware I've seen the direction of the pipeline is determinable and this
> > > is visible in the kAPI as well. So I'm suggesting no changes due to this in
> > > bindings, likely we'll need to address it somehow elsewhere going forward.
> > 
> > What did you mean with "... and this is visible in the kAPI as well"?
> > I'm relative new in the linux-media world but I never saw a device which
> > supports two directions. Our customer which uses that chip use it
> > only in parallel-in/csi-out mode. To be flexible the switching should be
> > done by a subdev-ioctl but it is also reasonable to define a default value
> > within the DT.
> 
> The mode is set by a pin strap at reset time (MSEL). It's not programmable
> by i2c. As far as I can see, looking at the registers, it's also not
> readable by i2c, so there's no easy way for a driver which supports both
> modes to see what the pinstrap is set to.
> 
> I'm not sure if the driver could tell from the direction of the endpoints
> it's linked to which mode to use, but if not it'll need to be told somehow
> and a DT property seems reasonable to me. Given that the same pins are used
> in each direction I think the direction is most likely to be hard wired and
> board specific.

You're absolutly right. Sorry didn't catched this, since it's a bit out of my
mind.. There 'can be' cases where the MSEL is connected to a GPIO but in
that case the device needs a hard reset to resample the pin. Also a
parallel-bus mux must be in front of the device. So I think that
'danymic switching' case is currently out of scope. I'm with you to
define the mode by a DT property is absolutly okay, the property should
something like:

(more device specific)
tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */

or

(more generic)
tc358746,default-dir = <PARALLEL_TO_CSI2>
tc358746,default-dir = <CSI2_TO_PARALLEL>

So we can add the 'maybe' dynamic switching later on.

Regards,
Marco

> 
> Regards,
> Ian.
> 
> > > > +
> > > > +Required Properties:
> > > > +
> > > > +- compatible: should be "toshiba,tc358746"
> > > > +- reg: should be <0x0e>
> > > > +- clocks: should contain a phandle link to the reference clock source
> > > > +- clock-names: the clock input is named "refclk".
> > > > +
> > > > +Optional Properties:
> > > > +
> > > > +- reset-gpios: gpio phandle GPIO connected to the reset pin
> > > > +
> > > > +Parallel Endpoint:
> > > > +
> > > > +Required Properties:
> > > 
> > > It'd be nice if the relation between these sections would be somehow
> > > apparent. E.g. using different underlining, such as in
> > > Documentation/devicetree/bindings/media/ti,omap3isp.txt .
> > 
> > Thats a really good example thanks.
> > 
> > > 
> > > > +
> > > > +- reg: should be <0>
> > > > +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> > > > +	     for sixteen bit wide bus.
> > > > +
> > > > +MIPI CSI-2 Endpoint:
> > > > +
> > > > +Required Properties:
> > > > +
> > > > +- reg: should be <1>
> > > > +- data-lanes: should be <1 2 3 4> for four-lane operation,
> > > > +	      or <1 2> for two-lane operation
> > > > +- clock-lanes: should be <0>
> > > > +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> > > > +		    expressed as a 64-bit big-endian integer. The frequency
> > > > +		    is half of the bps per lane due to DDR transmission.
> > > > +
> > > > +Optional Properties:
> > > > +
> > > > +- clock-noncontinuous: Presence of this boolean property decides whether the
> > > > +		       MIPI CSI-2 clock is continuous or non-continuous.
> > > > +
> > > > +For further information on the endpoint node properties, see
> > > > +Documentation/devicetree/bindings/media/video-interfaces.txt.
> > > > +
> > > > +Example:
> > > > +
> > > > +&i2c {
> > > > +	tc358746: tc358746@0e {
> > > 
> > > The node name should be a generic name of the type of the device, not the
> > > name of the specific device as such. A similar Cadence device uses
> > > "csi-bridge".
> > 
> > Okay, I will change that.
> > 
> > > 
> > > > +		reg = <0x0e>;
> > > > +		compatible = "toshiba,tc358746";
> > > > +		pinctrl-names = "default";
> > > > +		clocks = <&clk_cam_ref>;
> > > > +		clock-names = "refclk";
> > > > +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> > > > +
> > > > +		#address-cells = <1>;
> > > > +		#size-cells = <0>;
> > > > +
> > > > +		port@0 {
> > > > +			reg = <0>;
> > > > +
> > > > +			tc358746_parallel_in: endpoint {
> > > > +				bus-width = <8>;
> > > > +				remote-endpoint = <&micron_parallel_out>;
> > > > +			};
> > > > +		};
> > > > +
> > > > +		port@1 {
> > > > +			reg = <1>;
> > > > +
> > > > +			tc358746_mipi2_out: endpoint {
> > > > +				remote-endpoint = <&mipi_csi2_in>;
> > > > +				data-lanes = <1 2>;
> > > > +				clock-lanes = <0>;
> > > > +				clock-noncontinuous;
> > > > +				link-frequencies = /bits/ 64 <216000000>;
> > > > +			};
> > > > +		};
> > > > +	};
> > > > +};
> > > 
> > > -- 
> > > Kind regards,
> > > 
> > > Sakari Ailus
> > > sakari.ailus@linux.intel.com
> > > 
> > 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 10:26     ` Marco Felsch
@ 2019-03-04  9:38       ` Jacopo Mondi
  2019-03-04 16:43         ` Marco Felsch
  0 siblings, 1 reply; 30+ messages in thread
From: Jacopo Mondi @ 2019-03-04  9:38 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

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

Hi Marco,

On Fri, Mar 01, 2019 at 11:26:48AM +0100, Marco Felsch wrote:
> On 19-02-13 18:57, Jacopo Mondi wrote:
> > Hi Marco,
> >     thanks for the patch.
> >
> > I have some comments, which I hope might get the ball rolling...
>
> Hi Jacopo,
>
> thanks for your review and sorry for the late response. My schedule was
> a bit filled.
>

No worries at all

> >
> > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > >
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > >  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > >  1 file changed, 80 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > new file mode 100644
> > > index 000000000000..499733df744a
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > @@ -0,0 +1,80 @@
> > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > +
> > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> >
> > nit:
> > s/is a bridge that/is a bridge device that/
> > or drop is a bridge completely?
>
> You're right, I will drop this statement.
>
> >
> > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> >
> > From the thin public available datasheet, it seems to support SPI as
> > programming interface, but only when doing Parallel->CSI-2. I would
> > mention that.
>
> You're right, the SPI interface is only supported in that mode.
>
> Should I add something like:
> It is programmable trough I2C and SPI. The SPI interface is only
> supported in parallel-in -> csi-out mode.
>

I would:
"It is programmable through I2C and SPI, with the SPI interface only
available in parallel to CSI-2 conversion mode"

matter of tastes, really up to you :)

> > > +
> > > +Required Properties:
> > > +
> > > +- compatible: should be "toshiba,tc358746"
> > > +- reg: should be <0x0e>
> >
> > nit: s/should/shall
>
> Okay.
>
> > > +- clocks: should contain a phandle link to the reference clock source
> >
> > just "phandle to the reference clock source" ?
>
> Okay.
>
> > > +- clock-names: the clock input is named "refclk".
> >
> > According to the clock bindings this is optional, and since you have
> > a single clock I would drop it.
>
> Yes it's optional, but the device can also act as clock provider (not
> now, patches in my personal queue for rework). So I won't drop it since
> I never linked the generic clock-bindings.
>

As I read the clock bindings documentation, I don't think 'clock-names'
is related to clock provider functionalities, but it is only for
consumers.

Optional properties:
clock-names:	List of clock input name strings sorted in the same
		order as the clocks property.  Consumers drivers
		will use clock-names to match clock input names
		with clocks specifiers.

If you're going to support clock provider functionalities, you're
likely going to do that thought a clock-output-names property.

Maybe I don't get what you mean here, and that's anyway minor as it's not
wrong to have that property there, it's maybe just redundant.

> > > +
> > > +Optional Properties:
> > > +
> > > +- reset-gpios: gpio phandle GPIO connected to the reset pin
> >
> > would you drop one of the two "gpio" here. Like ": phandle to the GPIO
> > connected to the reset input pin"
>
> Okay.
>
> > > +
> > > +Parallel Endpoint:
> >
> > Here I got confused. The chip supports 2 inputs (parallel and CSI-2)
> > and two outputs (parallel and CSI-2 again). You mention endpoints
> > propery only here, but it seems from the example you want two ports,
> > with one endpoint child-node each.
>
> Nope, the device has one CSI and one Parallel interface. These
> interfaces can be configured as receiver or as transmitter (according to
> the selected mode). I got you but I remember also the discussion with
> Mauro, Hans, Sakari about the TVP5150 ports. The result of that
> discussion was "don't introduce 'virtual' ports". If I got you right
> your Idea will introduce virtual ports too:
>
> /* Parallel */
> port@0{
> 	port@0 { ... }; /* input case */
> 	port@1 { ... }; /* output case */
> };
>
> /* CSI */
> port@1{
> 	port@0 { ... }; /* input case */
> 	port@1 { ... }; /* output case */
> };
>

Not really, that was more something like
        port@0{
                parallel-input-endpoint
                ....
        }
        port@1{
                mipi-input-endpoint
                ....
        }
        port@2{
                parallel-output-endpoint
                ....
        }
        port@3{
                mipi-output-endpoint
                ....
        }

As you explained below here, that's a bad idea.

> > Even if the driver does not support CSI-2->Parallel at the moment,
> > bindings should be future-proof, so I would reserve the first two
> > ports for the inputs, and the last two for the output, or, considering
> > that the two input-output combinations are mutually exclusive, provide
> > one "input" port with two optional endpoints, and one "output" port with
> > two optional endpoints.
>
> I wouldn't map the combinations to the device tree since it is the
> hw-abstraction and the signals still routed to the same pads. The only
> difference in the CSI-2->Parallel case is the timing calculation which
> is out of scope for the dt.
>

I see, thanks for explaining. The hardware connections are certainly
the same, so yes, two ports for input and two ports for output is a
bad idea.

Though, you should better describe here you that you want two ports,
one input and one output one, with one optional endpoint describing a
parallel or CSI-2 connection

Do you think something like the following might apply?
Feel free to re-word and use what you think is appropriate:

"The device node must contain two ports children nodes, grouped in a 'ports'
node. The first port describes the input connection, the second one describes
the output one. Each port shall contain one endpoint subnode that connects
to a remote device and specifies the bus type of the input and output
ports. Only one endpoint per port shall be present.

Endpoint properties:
- Parallel endpoints:
  - Required properties:
    - bus-width:
  - Optional properties:
    -

- MIPI CSI-2 endpoints:
  - Required properties:
    - data-lanes:
  - Optional properties:
    -

 " ^ Here you might need to specify properties whose value depends if
 the endpoint is input or output, like link-frequencies above that
 afaict applies only to output CSI-2 endpoints, not input ones"

Example:

        ....
        tc358746: tc358746@0e {
                ....

                ports {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        port@0 {
                                reg = <0>;

                                tc358746_parallel_in: endpoint {
                                        bus-width = <8>;
                                        remote-endpoint = <&micron_parallel_out>;
                                };
                        };

                        port@1 {
                                reg = <1>;

                                tc358746_mipi2_out: endpoint {
                                        data-lanes = <1 2>;
                                        remote-endpoint = <&mipi_csi2_in>;
                                };
                        };
                };
         };

What I'm not sure about is if you would need to number the endpoints.
I don't think so as only one at the time could be there, but
video-interfaces.txt seems to suggest so:

If a port can be configured to work with more than one remote device on the same
bus, an 'endpoint' child node must be provided for each of them.  If more than
one port is present in a device node or there is more than one endpoint at a
port, or port node needs to be associated with a selected hardware interface,
a common scheme using '#address-cells', '#size-cells' and 'reg' properties is
used.


> > In both cases only one input and one output at the time could be
> > described in DT. Up to you, maybe others have different ideas as
> > well...
> >
> > > +
> > > +Required Properties:
> > > +
> > > +- reg: should be <0>
> > > +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> > > +	     for sixteen bit wide bus.
> >
> > The chip seems to support up to 24 bits of data bus width
>
> You're right, I will change that.
>
> > > +
> > > +MIPI CSI-2 Endpoint:
> > > +
> > > +Required Properties:
> > > +
> > > +- reg: should be <1>
> > > +- data-lanes: should be <1 2 3 4> for four-lane operation,
> > > +	      or <1 2> for two-lane operation
> > > +- clock-lanes: should be <0>
> >
> > Can this be changed? If the chip does not allow lane re-ordering you
> > could drop this.
>
> Nope it can't. Only the data-lanes can be disabled seperatly so I added
> the data-lanes property to determine that number and for the sake of
> completeness I added the clock-lanes property.

I see, still a required property with a fixed value is not that
necessary.

>
> >
> > > +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> > > +		    expressed as a 64-bit big-endian integer. The frequency
> > > +		    is half of the bps per lane due to DDR transmission.
> >
> > Does the chip supports a limited set of bus frequencies, or are this
> > "hints" ? I admit this property actually puzzles me, so I might got it
> > wrong..
>
> That's not that easy to answer. The user can add different link-freq.
> the driver can choose. This is relevant for the Parallel-in --> CSI-out.
> If the external pclk is to slow (due to dyn. fps change) and the link-freq.
> is to fast the internally pixel buffer throws underrun interrupts. The
> user notice that by green pixel artifacts. If the user adds more
> possible link-freq. the driver will switch to that one wich full fill
> the timings to avoid a fifo underrun.
>

Ah, so the user is expected to specify a set of frequencies the
driver should pick from to handle slower pixel rates, I see. I cannot
tell how this should handle. If nobody else complains, I think it's
fine then :)

Thanks
  j

> >
> > Thanks
> >    j
>
> Regards,
> Marco
>
> > > +
> > > +Optional Properties:
> > > +
> > > +- clock-noncontinuous: Presence of this boolean property decides whether the
> > > +		       MIPI CSI-2 clock is continuous or non-continuous.
> > > +
> > > +For further information on the endpoint node properties, see
> > > +Documentation/devicetree/bindings/media/video-interfaces.txt.
> > > +
> > > +Example:
> > > +
> > > +&i2c {
> > > +	tc358746: tc358746@0e {
> > > +		reg = <0x0e>;
> > > +		compatible = "toshiba,tc358746";
> > > +		pinctrl-names = "default";
> > > +		clocks = <&clk_cam_ref>;
> > > +		clock-names = "refclk";
> > > +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> > > +
> > > +		#address-cells = <1>;
> > > +		#size-cells = <0>;
> > > +
> > > +		port@0 {
> > > +			reg = <0>;
> > > +
> > > +			tc358746_parallel_in: endpoint {
> > > +				bus-width = <8>;
> > > +				remote-endpoint = <&micron_parallel_out>;
> > > +			};
> > > +		};
> > > +
> > > +		port@1 {
> > > +			reg = <1>;
> > > +
> > > +			tc358746_mipi2_out: endpoint {
> > > +				remote-endpoint = <&mipi_csi2_in>;
> > > +				data-lanes = <1 2>;
> > > +				clock-lanes = <0>;
> > > +				clock-noncontinuous;
> > > +				link-frequencies = /bits/ 64 <216000000>;
> > > +			};
> > > +		};
> > > +	};
> > > +};
> > > --
> > > 2.19.1
> > >
>
>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 13:01         ` Marco Felsch
@ 2019-03-04  9:41           ` Jacopo Mondi
  2019-03-04 12:36           ` Sakari Ailus
  1 sibling, 0 replies; 30+ messages in thread
From: Jacopo Mondi @ 2019-03-04  9:41 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Ian Arkver, Sakari Ailus, hans.verkuil, mchehab, robh+dt,
	mark.rutland, linux-media, devicetree, graphics

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

Hi Marco, Ian,

On Fri, Mar 01, 2019 at 02:01:18PM +0100, Marco Felsch wrote:
> Hi Ian,
>
> On 19-03-01 11:07, Ian Arkver wrote:
> > Hi,
> >
> > On 01/03/2019 10:52, Marco Felsch wrote:
> > > Hi Sakari,
> > >
> > > On 19-02-18 12:03, Sakari Ailus wrote:
> > > > Hi Marco,
> > > >
> > > > My apologies for reviewing this so late. You've received good comments
> > > > already. I have a few more.
> > >
> > > Thanks for your review for the other patches as well =) Sorry for my
> > > delayed response.
> > >
> > > > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > > >
> > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > > ---
> > > > >   .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > > > >   1 file changed, 80 insertions(+)
> > > > >   create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > >
> > > > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > new file mode 100644
> > > > > index 000000000000..499733df744a
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > @@ -0,0 +1,80 @@
> > > > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > > > +
> > > > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > > > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > > >
> > > > This is interesting. The driver somehow needs to figure out the direction
> > > > of the data flow if it does not originate from DT. I guess it shouldn't as
> > > > it's not the property of an individual device, albeit in practice in all
> > > > hardware I've seen the direction of the pipeline is determinable and this
> > > > is visible in the kAPI as well. So I'm suggesting no changes due to this in
> > > > bindings, likely we'll need to address it somehow elsewhere going forward.
> > >
> > > What did you mean with "... and this is visible in the kAPI as well"?
> > > I'm relative new in the linux-media world but I never saw a device which
> > > supports two directions. Our customer which uses that chip use it
> > > only in parallel-in/csi-out mode. To be flexible the switching should be
> > > done by a subdev-ioctl but it is also reasonable to define a default value
> > > within the DT.
> >
> > The mode is set by a pin strap at reset time (MSEL). It's not programmable
> > by i2c. As far as I can see, looking at the registers, it's also not
> > readable by i2c, so there's no easy way for a driver which supports both
> > modes to see what the pinstrap is set to.
> >
> > I'm not sure if the driver could tell from the direction of the endpoints
> > it's linked to which mode to use, but if not it'll need to be told somehow
> > and a DT property seems reasonable to me. Given that the same pins are used
> > in each direction I think the direction is most likely to be hard wired and
> > board specific.
>
> You're absolutly right. Sorry didn't catched this, since it's a bit out of my
> mind.. There 'can be' cases where the MSEL is connected to a GPIO but in
> that case the device needs a hard reset to resample the pin. Also a
> parallel-bus mux must be in front of the device. So I think that
> 'danymic switching' case is currently out of scope. I'm with you to
> define the mode by a DT property is absolutly okay, the property should
> something like:
>
> (more device specific)
> tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
>
> or
>
> (more generic)
> tc358746,default-dir = <PARALLEL_TO_CSI2>
> tc358746,default-dir = <CSI2_TO_PARALLEL>
>
> So we can add the 'maybe' dynamic switching later on.
>

I think if you model the bindings with one endpoint per input/output port,
you can just parse the endpoints, using the bus hints that are now
available, and deduct the bus types and thus the conversion directions
without introducing any custom property.

Thanks
   j


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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 10:52     ` Marco Felsch
  2019-03-01 11:07       ` Ian Arkver
@ 2019-03-04 12:10       ` Sakari Ailus
  1 sibling, 0 replies; 30+ messages in thread
From: Sakari Ailus @ 2019-03-04 12:10 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Macro,

On Fri, Mar 01, 2019 at 11:52:35AM +0100, Marco Felsch wrote:
> Hi Sakari,
> 
> On 19-02-18 12:03, Sakari Ailus wrote:
> > Hi Marco,
> > 
> > My apologies for reviewing this so late. You've received good comments
> > already. I have a few more.
> 
> Thanks for your review for the other patches as well =) Sorry for my
> delayed response.
> 
> > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > >  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > >  1 file changed, 80 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > 
> > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > new file mode 100644
> > > index 000000000000..499733df744a
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > @@ -0,0 +1,80 @@
> > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > +
> > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > 
> > This is interesting. The driver somehow needs to figure out the direction
> > of the data flow if it does not originate from DT. I guess it shouldn't as
> > it's not the property of an individual device, albeit in practice in all
> > hardware I've seen the direction of the pipeline is determinable and this
> > is visible in the kAPI as well. So I'm suggesting no changes due to this in
> > bindings, likely we'll need to address it somehow elsewhere going forward.
> 
> What did you mean with "... and this is visible in the kAPI as well"?
> I'm relative new in the linux-media world but I never saw a device which
> supports two directions. Our customer which uses that chip use it
> only in parallel-in/csi-out mode. To be flexible the switching should be
> done by a subdev-ioctl but it is also reasonable to define a default value
> within the DT.

What I meant that the V4L2 sub-device API does not provide any information
on the direction. It is implicit --- MC does, but it does it based on the
links created by the driver.

I agree a DT property would be a good way to tell this, especially now that
there's a related hardware configuration (but which the software cannot
obtain directly).

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-01 13:01         ` Marco Felsch
  2019-03-04  9:41           ` Jacopo Mondi
@ 2019-03-04 12:36           ` Sakari Ailus
  2019-03-04 16:55             ` Marco Felsch
  1 sibling, 1 reply; 30+ messages in thread
From: Sakari Ailus @ 2019-03-04 12:36 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Ian Arkver, hans.verkuil, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

Hi Marco,

On Fri, Mar 01, 2019 at 02:01:18PM +0100, Marco Felsch wrote:
> Hi Ian,
> 
> On 19-03-01 11:07, Ian Arkver wrote:
> > Hi,
> > 
> > On 01/03/2019 10:52, Marco Felsch wrote:
> > > Hi Sakari,
> > > 
> > > On 19-02-18 12:03, Sakari Ailus wrote:
> > > > Hi Marco,
> > > > 
> > > > My apologies for reviewing this so late. You've received good comments
> > > > already. I have a few more.
> > > 
> > > Thanks for your review for the other patches as well =) Sorry for my
> > > delayed response.
> > > 
> > > > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > > > 
> > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > > ---
> > > > >   .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > > > >   1 file changed, 80 insertions(+)
> > > > >   create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > new file mode 100644
> > > > > index 000000000000..499733df744a
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > @@ -0,0 +1,80 @@
> > > > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > > > +
> > > > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > > > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > > > 
> > > > This is interesting. The driver somehow needs to figure out the direction
> > > > of the data flow if it does not originate from DT. I guess it shouldn't as
> > > > it's not the property of an individual device, albeit in practice in all
> > > > hardware I've seen the direction of the pipeline is determinable and this
> > > > is visible in the kAPI as well. So I'm suggesting no changes due to this in
> > > > bindings, likely we'll need to address it somehow elsewhere going forward.
> > > 
> > > What did you mean with "... and this is visible in the kAPI as well"?
> > > I'm relative new in the linux-media world but I never saw a device which
> > > supports two directions. Our customer which uses that chip use it
> > > only in parallel-in/csi-out mode. To be flexible the switching should be
> > > done by a subdev-ioctl but it is also reasonable to define a default value
> > > within the DT.
> > 
> > The mode is set by a pin strap at reset time (MSEL). It's not programmable
> > by i2c. As far as I can see, looking at the registers, it's also not
> > readable by i2c, so there's no easy way for a driver which supports both
> > modes to see what the pinstrap is set to.
> > 
> > I'm not sure if the driver could tell from the direction of the endpoints
> > it's linked to which mode to use, but if not it'll need to be told somehow
> > and a DT property seems reasonable to me. Given that the same pins are used
> > in each direction I think the direction is most likely to be hard wired and
> > board specific.
> 
> You're absolutly right. Sorry didn't catched this, since it's a bit out of my
> mind.. There 'can be' cases where the MSEL is connected to a GPIO but in
> that case the device needs a hard reset to resample the pin. Also a
> parallel-bus mux must be in front of the device. So I think that
> 'danymic switching' case is currently out of scope. I'm with you to
> define the mode by a DT property is absolutly okay, the property should
> something like:
> 
> (more device specific)
> tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> 
> or
> 
> (more generic)
> tc358746,default-dir = <PARALLEL_TO_CSI2>
> tc358746,default-dir = <CSI2_TO_PARALLEL>

The prefix for Toshiba is "toshiba". What would you think of
"toshiba,csi2-direction" with values of either "rx" or "tx"? Or
"toshiba,csi2-mode" with either "master" or "slave", which would be a
little bit more generic, but could be slightly more probable to get wrong
as well.

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-04  9:38       ` Jacopo Mondi
@ 2019-03-04 16:43         ` Marco Felsch
  0 siblings, 0 replies; 30+ messages in thread
From: Marco Felsch @ 2019-03-04 16:43 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: hans.verkuil, sakari.ailus, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

Hi Jacopo,

On 19-03-04 10:38, Jacopo Mondi wrote:
> Hi Marco,
> 
> On Fri, Mar 01, 2019 at 11:26:48AM +0100, Marco Felsch wrote:
> > On 19-02-13 18:57, Jacopo Mondi wrote:
> > > Hi Marco,
> > >     thanks for the patch.
> > >
> > > I have some comments, which I hope might get the ball rolling...
> >
> > Hi Jacopo,
> >
> > thanks for your review and sorry for the late response. My schedule was
> > a bit filled.
> >
> 
> No worries at all
> 
> > >
> > > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > >
> > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > ---
> > > >  .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > > >  1 file changed, 80 insertions(+)
> > > >  create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > new file mode 100644
> > > > index 000000000000..499733df744a
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > @@ -0,0 +1,80 @@
> > > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > > +
> > > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > >
> > > nit:
> > > s/is a bridge that/is a bridge device that/
> > > or drop is a bridge completely?
> >
> > You're right, I will drop this statement.
> >
> > >
> > > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > >
> > > From the thin public available datasheet, it seems to support SPI as
> > > programming interface, but only when doing Parallel->CSI-2. I would
> > > mention that.
> >
> > You're right, the SPI interface is only supported in that mode.
> >
> > Should I add something like:
> > It is programmable trough I2C and SPI. The SPI interface is only
> > supported in parallel-in -> csi-out mode.
> >
> 
> I would:
> "It is programmable through I2C and SPI, with the SPI interface only
> available in parallel to CSI-2 conversion mode"
> 
> matter of tastes, really up to you :)
> 
> > > > +
> > > > +Required Properties:
> > > > +
> > > > +- compatible: should be "toshiba,tc358746"
> > > > +- reg: should be <0x0e>
> > >
> > > nit: s/should/shall
> >
> > Okay.
> >
> > > > +- clocks: should contain a phandle link to the reference clock source
> > >
> > > just "phandle to the reference clock source" ?
> >
> > Okay.
> >
> > > > +- clock-names: the clock input is named "refclk".
> > >
> > > According to the clock bindings this is optional, and since you have
> > > a single clock I would drop it.
> >
> > Yes it's optional, but the device can also act as clock provider (not
> > now, patches in my personal queue for rework). So I won't drop it since
> > I never linked the generic clock-bindings.
> >
> 
> As I read the clock bindings documentation, I don't think 'clock-names'
> is related to clock provider functionalities, but it is only for
> consumers.
> 
> Optional properties:
> clock-names:	List of clock input name strings sorted in the same
> 		order as the clocks property.  Consumers drivers
> 		will use clock-names to match clock input names
> 		with clocks specifiers.
> 
> If you're going to support clock provider functionalities, you're
> likely going to do that thought a clock-output-names property.

You're absolutely right I mixed this, sry. Now after getting back into
the patch set I know why I added the clock-names property. It's because
I request the clk by a 'devm_clk_get(dev, "refclk")' call. I will change
this to drop the clock-names property.

> Maybe I don't get what you mean here, and that's anyway minor as it's not
> wrong to have that property there, it's maybe just redundant.
> 
> > > > +
> > > > +Optional Properties:
> > > > +
> > > > +- reset-gpios: gpio phandle GPIO connected to the reset pin
> > >
> > > would you drop one of the two "gpio" here. Like ": phandle to the GPIO
> > > connected to the reset input pin"
> >
> > Okay.
> >
> > > > +
> > > > +Parallel Endpoint:
> > >
> > > Here I got confused. The chip supports 2 inputs (parallel and CSI-2)
> > > and two outputs (parallel and CSI-2 again). You mention endpoints
> > > propery only here, but it seems from the example you want two ports,
> > > with one endpoint child-node each.
> >
> > Nope, the device has one CSI and one Parallel interface. These
> > interfaces can be configured as receiver or as transmitter (according to
> > the selected mode). I got you but I remember also the discussion with
> > Mauro, Hans, Sakari about the TVP5150 ports. The result of that
> > discussion was "don't introduce 'virtual' ports". If I got you right
> > your Idea will introduce virtual ports too:
> >
> > /* Parallel */
> > port@0{
> > 	port@0 { ... }; /* input case */
> > 	port@1 { ... }; /* output case */
> > };
> >
> > /* CSI */
> > port@1{
> > 	port@0 { ... }; /* input case */
> > 	port@1 { ... }; /* output case */
> > };
> >
> 
> Not really, that was more something like
>         port@0{
>                 parallel-input-endpoint
>                 ....
>         }
>         port@1{
>                 mipi-input-endpoint
>                 ....
>         }
>         port@2{
>                 parallel-output-endpoint
>                 ....
>         }
>         port@3{
>                 mipi-output-endpoint
>                 ....
>         }
> 
> As you explained below here, that's a bad idea.
> 
> > > Even if the driver does not support CSI-2->Parallel at the moment,
> > > bindings should be future-proof, so I would reserve the first two
> > > ports for the inputs, and the last two for the output, or, considering
> > > that the two input-output combinations are mutually exclusive, provide
> > > one "input" port with two optional endpoints, and one "output" port with
> > > two optional endpoints.
> >
> > I wouldn't map the combinations to the device tree since it is the
> > hw-abstraction and the signals still routed to the same pads. The only
> > difference in the CSI-2->Parallel case is the timing calculation which
> > is out of scope for the dt.
> >
> 
> I see, thanks for explaining. The hardware connections are certainly
> the same, so yes, two ports for input and two ports for output is a
> bad idea.
> 
> Though, you should better describe here you that you want two ports,
> one input and one output one, with one optional endpoint describing a
> parallel or CSI-2 connection
> 
> Do you think something like the following might apply?
> Feel free to re-word and use what you think is appropriate:
> 
> "The device node must contain two ports children nodes, grouped in a 'ports'
> node. The first port describes the input connection, the second one describes
> the output one. Each port shall contain one endpoint subnode that connects
> to a remote device and specifies the bus type of the input and output
> ports. Only one endpoint per port shall be present.

That sounds good to me, I will take it as it is and add some more notes
from Sakari's feedback.

> 
> Endpoint properties:
> - Parallel endpoints:
>   - Required properties:
>     - bus-width:
>   - Optional properties:
>     -
> 
> - MIPI CSI-2 endpoints:
>   - Required properties:
>     - data-lanes:
>   - Optional properties:
>     -
> 
>  " ^ Here you might need to specify properties whose value depends if
>  the endpoint is input or output, like link-frequencies above that
>  afaict applies only to output CSI-2 endpoints, not input ones"

Sorry if I wasn't that clear in my explanation but I think the
link-frequencies property applies to both cases e.g. if the panel
refresh rate is to fast and the link-frequency to slow. But I can't
verify that since my customer board uses only the parallel-in -> csi-out
case.

> 
> Example:
> 
>         ....
>         tc358746: tc358746@0e {
>                 ....
> 
>                 ports {
>                         #address-cells = <1>;
>                         #size-cells = <0>;
> 
>                         port@0 {
>                                 reg = <0>;
> 
>                                 tc358746_parallel_in: endpoint {
>                                         bus-width = <8>;
>                                         remote-endpoint = <&micron_parallel_out>;
>                                 };
>                         };
> 
>                         port@1 {
>                                 reg = <1>;
> 
>                                 tc358746_mipi2_out: endpoint {
>                                         data-lanes = <1 2>;
>                                         remote-endpoint = <&mipi_csi2_in>;
>                                 };
>                         };
>                 };
>          };
> 
> What I'm not sure about is if you would need to number the endpoints.
> I don't think so as only one at the time could be there, but
> video-interfaces.txt seems to suggest so:
> 
> If a port can be configured to work with more than one remote device on the same
> bus, an 'endpoint' child node must be provided for each of them.  If more than
> one port is present in a device node or there is more than one endpoint at a
> port, or port node needs to be associated with a selected hardware interface,
> a common scheme using '#address-cells', '#size-cells' and 'reg' properties is
> used.

No I don't think so too since only one endpoint at a time is supported.

> > > In both cases only one input and one output at the time could be
> > > described in DT. Up to you, maybe others have different ideas as
> > > well...
> > >
> > > > +
> > > > +Required Properties:
> > > > +
> > > > +- reg: should be <0>
> > > > +- bus-width: the data bus width e.g. <8> for eight bit bus, or <16>
> > > > +	     for sixteen bit wide bus.
> > >
> > > The chip seems to support up to 24 bits of data bus width
> >
> > You're right, I will change that.
> >
> > > > +
> > > > +MIPI CSI-2 Endpoint:
> > > > +
> > > > +Required Properties:
> > > > +
> > > > +- reg: should be <1>
> > > > +- data-lanes: should be <1 2 3 4> for four-lane operation,
> > > > +	      or <1 2> for two-lane operation
> > > > +- clock-lanes: should be <0>
> > >
> > > Can this be changed? If the chip does not allow lane re-ordering you
> > > could drop this.
> >
> > Nope it can't. Only the data-lanes can be disabled seperatly so I added
> > the data-lanes property to determine that number and for the sake of
> > completeness I added the clock-lanes property.
> 
> I see, still a required property with a fixed value is not that
> necessary.
> 
> >
> > >
> > > > +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is
> > > > +		    expressed as a 64-bit big-endian integer. The frequency
> > > > +		    is half of the bps per lane due to DDR transmission.
> > >
> > > Does the chip supports a limited set of bus frequencies, or are this
> > > "hints" ? I admit this property actually puzzles me, so I might got it
> > > wrong..
> >
> > That's not that easy to answer. The user can add different link-freq.
> > the driver can choose. This is relevant for the Parallel-in --> CSI-out.
> > If the external pclk is to slow (due to dyn. fps change) and the link-freq.
> > is to fast the internally pixel buffer throws underrun interrupts. The
> > user notice that by green pixel artifacts. If the user adds more
> > possible link-freq. the driver will switch to that one wich full fill
> > the timings to avoid a fifo underrun.
> >
> 
> Ah, so the user is expected to specify a set of frequencies the
> driver should pick from to handle slower pixel rates, I see. I cannot
> tell how this should handle. If nobody else complains, I think it's
> fine then :)

Thanks for the feedback :)

Regards,
Marco

> Thanks
>   j
> 
> > >
> > > Thanks
> > >    j
> >
> > Regards,
> > Marco
> >
> > > > +
> > > > +Optional Properties:
> > > > +
> > > > +- clock-noncontinuous: Presence of this boolean property decides whether the
> > > > +		       MIPI CSI-2 clock is continuous or non-continuous.
> > > > +
> > > > +For further information on the endpoint node properties, see
> > > > +Documentation/devicetree/bindings/media/video-interfaces.txt.
> > > > +
> > > > +Example:
> > > > +
> > > > +&i2c {
> > > > +	tc358746: tc358746@0e {
> > > > +		reg = <0x0e>;
> > > > +		compatible = "toshiba,tc358746";
> > > > +		pinctrl-names = "default";
> > > > +		clocks = <&clk_cam_ref>;
> > > > +		clock-names = "refclk";
> > > > +		reset-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
> > > > +
> > > > +		#address-cells = <1>;
> > > > +		#size-cells = <0>;
> > > > +
> > > > +		port@0 {
> > > > +			reg = <0>;
> > > > +
> > > > +			tc358746_parallel_in: endpoint {
> > > > +				bus-width = <8>;
> > > > +				remote-endpoint = <&micron_parallel_out>;
> > > > +			};
> > > > +		};
> > > > +
> > > > +		port@1 {
> > > > +			reg = <1>;
> > > > +
> > > > +			tc358746_mipi2_out: endpoint {
> > > > +				remote-endpoint = <&mipi_csi2_in>;
> > > > +				data-lanes = <1 2>;
> > > > +				clock-lanes = <0>;
> > > > +				clock-noncontinuous;
> > > > +				link-frequencies = /bits/ 64 <216000000>;
> > > > +			};
> > > > +		};
> > > > +	};
> > > > +};
> > > > --
> > > > 2.19.1
> > > >
> >
> >
> >
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-04 12:36           ` Sakari Ailus
@ 2019-03-04 16:55             ` Marco Felsch
  2019-03-04 18:17               ` Sakari Ailus
  0 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-03-04 16:55 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Ian Arkver, hans.verkuil, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

Hi Sakari,

On 19-03-04 14:36, Sakari Ailus wrote:
> Hi Marco,
> 
> On Fri, Mar 01, 2019 at 02:01:18PM +0100, Marco Felsch wrote:
> > Hi Ian,
> > 
> > On 19-03-01 11:07, Ian Arkver wrote:
> > > Hi,
> > > 
> > > On 01/03/2019 10:52, Marco Felsch wrote:
> > > > Hi Sakari,
> > > > 
> > > > On 19-02-18 12:03, Sakari Ailus wrote:
> > > > > Hi Marco,
> > > > > 
> > > > > My apologies for reviewing this so late. You've received good comments
> > > > > already. I have a few more.
> > > > 
> > > > Thanks for your review for the other patches as well =) Sorry for my
> > > > delayed response.
> > > > 
> > > > > On Tue, Dec 18, 2018 at 03:12:38PM +0100, Marco Felsch wrote:
> > > > > > Add corresponding dt-bindings for the Toshiba tc358746 device.
> > > > > > 
> > > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > > > > ---
> > > > > >   .../bindings/media/i2c/toshiba,tc358746.txt   | 80 +++++++++++++++++++
> > > > > >   1 file changed, 80 insertions(+)
> > > > > >   create mode 100644 Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > > 
> > > > > > diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > > new file mode 100644
> > > > > > index 000000000000..499733df744a
> > > > > > --- /dev/null
> > > > > > +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > > > > @@ -0,0 +1,80 @@
> > > > > > +* Toshiba TC358746 Parallel to MIPI CSI2-TX or MIPI CSI2-RX to Parallel Bridge
> > > > > > +
> > > > > > +The Toshiba TC358746 is a bridge that converts a Parallel-in stream to MIPI CSI-2 TX
> > > > > > +or a MIPI CSI-2 RX stream into a Parallel-out. It is programmable through I2C.
> > > > > 
> > > > > This is interesting. The driver somehow needs to figure out the direction
> > > > > of the data flow if it does not originate from DT. I guess it shouldn't as
> > > > > it's not the property of an individual device, albeit in practice in all
> > > > > hardware I've seen the direction of the pipeline is determinable and this
> > > > > is visible in the kAPI as well. So I'm suggesting no changes due to this in
> > > > > bindings, likely we'll need to address it somehow elsewhere going forward.
> > > > 
> > > > What did you mean with "... and this is visible in the kAPI as well"?
> > > > I'm relative new in the linux-media world but I never saw a device which
> > > > supports two directions. Our customer which uses that chip use it
> > > > only in parallel-in/csi-out mode. To be flexible the switching should be
> > > > done by a subdev-ioctl but it is also reasonable to define a default value
> > > > within the DT.
> > > 
> > > The mode is set by a pin strap at reset time (MSEL). It's not programmable
> > > by i2c. As far as I can see, looking at the registers, it's also not
> > > readable by i2c, so there's no easy way for a driver which supports both
> > > modes to see what the pinstrap is set to.
> > > 
> > > I'm not sure if the driver could tell from the direction of the endpoints
> > > it's linked to which mode to use, but if not it'll need to be told somehow
> > > and a DT property seems reasonable to me. Given that the same pins are used
> > > in each direction I think the direction is most likely to be hard wired and
> > > board specific.
> > 
> > You're absolutly right. Sorry didn't catched this, since it's a bit out of my
> > mind.. There 'can be' cases where the MSEL is connected to a GPIO but in
> > that case the device needs a hard reset to resample the pin. Also a
> > parallel-bus mux must be in front of the device. So I think that
> > 'danymic switching' case is currently out of scope. I'm with you to
> > define the mode by a DT property is absolutly okay, the property should
> > something like:
> > 
> > (more device specific)
> > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > 
> > or
> > 
> > (more generic)
> > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > tc358746,default-dir = <CSI2_TO_PARALLEL>
> 
> The prefix for Toshiba is "toshiba". What would you think of
> "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> "toshiba,csi2-mode" with either "master" or "slave", which would be a
> little bit more generic, but could be slightly more probable to get wrong
> as well.

You're right mixed the prefix with the device.. If we need to introduce
a property I would prefer the "toshiba,csi2-direction" one. I said if
because as Jacopo mentioned we can avoid the property by define port@0
as input and port@1 as output. I tink that's the best solution, since we
can avoid device specific bindings and it's common to use the last port
as output (e.g. video-mux).

Regards,
Marco

> -- 
> Regards,
> 
> Sakari Ailus
> sakari.ailus@linux.intel.com
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] media: tc358746: update MAINTAINERS file
  2019-02-18 11:46   ` Sakari Ailus
@ 2019-03-04 17:31     ` Marco Felsch
  2019-03-04 18:18       ` Sakari Ailus
  0 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-03-04 17:31 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

Hi Sakari,

On 19-02-18 13:46, Sakari Ailus wrote:
> Hi Marco,
> 
> On Tue, Dec 18, 2018 at 03:12:40PM +0100, Marco Felsch wrote:
> > Add me as partial maintainer, others are welcome too.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  MAINTAINERS | 7 +++++++
> >  1 file changed, 7 insertions(+)
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 546f8d936589..f97dedbe545c 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -15230,6 +15230,13 @@ S:	Maintained
> >  F:	drivers/media/i2c/tc358743*
> >  F:	include/media/i2c/tc358743.h
> >  
> > +TOSHIBA TC358746 DRIVER
> > +M:	Marco Felsch <kernel@pengutronix.de>
> > +L:	linux-media@vger.kernel.org
> > +S:	Odd Fixes
> > +F:	drivers/media/i2c/tc358746*
> > +F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > +
> >  TOSHIBA WMI HOTKEYS DRIVER
> >  M:	Azael Avalos <coproscefalo@gmail.com>
> >  L:	platform-driver-x86@vger.kernel.org
> 
> This should go together with the DT bindings, in the same patch.
> 
> I'd expect a new driver to be listed as "Maintained". "Odd Fixes" suggests
> no-one is particularly looking after it, and it's not nice if a new driver
> starts off like that. :-I

Okay, I will squash it in the v2 and set the status to "Maintained".

Regards,
Marco
 
> -- 
> Kind regards,
> 
> Sakari Ailus
> sakari.ailus@linux.intel.com
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-04 16:55             ` Marco Felsch
@ 2019-03-04 18:17               ` Sakari Ailus
  2019-03-05  8:49                 ` Jacopo Mondi
  0 siblings, 1 reply; 30+ messages in thread
From: Sakari Ailus @ 2019-03-04 18:17 UTC (permalink / raw)
  To: Marco Felsch
  Cc: Ian Arkver, hans.verkuil, mchehab, robh+dt, mark.rutland,
	linux-media, devicetree, graphics

Hi Marco,

On Mon, Mar 04, 2019 at 05:55:28PM +0100, Marco Felsch wrote:
> > > (more device specific)
> > > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > > 
> > > or
> > > 
> > > (more generic)
> > > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > > tc358746,default-dir = <CSI2_TO_PARALLEL>
> > 
> > The prefix for Toshiba is "toshiba". What would you think of
> > "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> > "toshiba,csi2-mode" with either "master" or "slave", which would be a
> > little bit more generic, but could be slightly more probable to get wrong
> > as well.
> 
> You're right mixed the prefix with the device.. If we need to introduce
> a property I would prefer the "toshiba,csi2-direction" one. I said if
> because as Jacopo mentioned we can avoid the property by define port@0
> as input and port@1 as output. I tink that's the best solution, since we
> can avoid device specific bindings and it's common to use the last port
> as output (e.g. video-mux).

The ports represent hardware and I think I would avoid reordering them. I
wonder what would the DT folks prefer.

The device specific property is to the point at least: it describes an
orthogonal part of the device configuration. That's why I'd pick that if I
were to choose. But I'll let Rob to comment on this.

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] media: tc358746: update MAINTAINERS file
  2019-03-04 17:31     ` Marco Felsch
@ 2019-03-04 18:18       ` Sakari Ailus
  0 siblings, 0 replies; 30+ messages in thread
From: Sakari Ailus @ 2019-03-04 18:18 UTC (permalink / raw)
  To: Marco Felsch
  Cc: hans.verkuil, mchehab, robh+dt, mark.rutland, linux-media,
	devicetree, graphics

On Mon, Mar 04, 2019 at 06:31:51PM +0100, Marco Felsch wrote:
> Hi Sakari,
> 
> On 19-02-18 13:46, Sakari Ailus wrote:
> > Hi Marco,
> > 
> > On Tue, Dec 18, 2018 at 03:12:40PM +0100, Marco Felsch wrote:
> > > Add me as partial maintainer, others are welcome too.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > >  MAINTAINERS | 7 +++++++
> > >  1 file changed, 7 insertions(+)
> > > 
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 546f8d936589..f97dedbe545c 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -15230,6 +15230,13 @@ S:	Maintained
> > >  F:	drivers/media/i2c/tc358743*
> > >  F:	include/media/i2c/tc358743.h
> > >  
> > > +TOSHIBA TC358746 DRIVER
> > > +M:	Marco Felsch <kernel@pengutronix.de>
> > > +L:	linux-media@vger.kernel.org
> > > +S:	Odd Fixes
> > > +F:	drivers/media/i2c/tc358746*
> > > +F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358746.txt
> > > +
> > >  TOSHIBA WMI HOTKEYS DRIVER
> > >  M:	Azael Avalos <coproscefalo@gmail.com>
> > >  L:	platform-driver-x86@vger.kernel.org
> > 
> > This should go together with the DT bindings, in the same patch.
> > 
> > I'd expect a new driver to be listed as "Maintained". "Odd Fixes" suggests
> > no-one is particularly looking after it, and it's not nice if a new driver
> > starts off like that. :-I
> 
> Okay, I will squash it in the v2 and set the status to "Maintained".

Thanks!

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-04 18:17               ` Sakari Ailus
@ 2019-03-05  8:49                 ` Jacopo Mondi
  2019-03-05 18:14                   ` Marco Felsch
  0 siblings, 1 reply; 30+ messages in thread
From: Jacopo Mondi @ 2019-03-05  8:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Marco Felsch, Ian Arkver, hans.verkuil, mchehab, robh+dt,
	mark.rutland, linux-media, devicetree, graphics

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

Hi Sakari, Marco,

On Mon, Mar 04, 2019 at 08:17:48PM +0200, Sakari Ailus wrote:
> Hi Marco,
>
> On Mon, Mar 04, 2019 at 05:55:28PM +0100, Marco Felsch wrote:
> > > > (more device specific)
> > > > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > > > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > > >
> > > > or
> > > >
> > > > (more generic)
> > > > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > > > tc358746,default-dir = <CSI2_TO_PARALLEL>
> > >
> > > The prefix for Toshiba is "toshiba". What would you think of
> > > "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> > > "toshiba,csi2-mode" with either "master" or "slave", which would be a
> > > little bit more generic, but could be slightly more probable to get wrong
> > > as well.
> >
> > You're right mixed the prefix with the device.. If we need to introduce
> > a property I would prefer the "toshiba,csi2-direction" one. I said if
> > because as Jacopo mentioned we can avoid the property by define port@0
> > as input and port@1 as output. I tink that's the best solution, since we
> > can avoid device specific bindings and it's common to use the last port
> > as output (e.g. video-mux).
>
> The ports represent hardware and I think I would avoid reordering them. I
> wonder what would the DT folks prefer.
>

I might have missed why you mention re-ordering? :)

> The device specific property is to the point at least: it describes an
> orthogonal part of the device configuration. That's why I'd pick that if I
> were to choose. But I'll let Rob to comment on this.

That's true indeed. Let's wait for inputs from DT people, I'm fine
with both approaches.

Thanks
   j

>
> --
> Regards,
>
> Sakari Ailus
> sakari.ailus@linux.intel.com

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-05  8:49                 ` Jacopo Mondi
@ 2019-03-05 18:14                   ` Marco Felsch
  2019-04-16 10:45                     ` Marco Felsch
  0 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-03-05 18:14 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, Ian Arkver, hans.verkuil, mchehab, robh+dt,
	mark.rutland, linux-media, devicetree, graphics

Hi Rob,

I think you didn't followed the discussion in detail so I will ask you
personal. In short the tc358746 can act as parallel-in -> csi-out or as
csi->in -> parallel-out device. The phyiscal pins are always the same
only the internal timings are different. So we have two ports with two
endpoints.

Now the question is how we determine the mode. We have two approaches:
1)
  port@0 -> input port
  port@1 -> output port

  pro:
  + no extra vendor specific binding is needed to determine the mode

  con:
  - input/output endpoint can be parallel or mipi-csi2.

2)
  port@0 -> parallel port
  port@1 -> mipi-csi2 port

  pro:
  + input/output endpoint are fixed to parallel or mipi

  con:
  - vendor specific binding is needed to determine the mode

Thanks for your comments :)

Regards,
Marco

On 19-03-05 09:49, Jacopo Mondi wrote:
> Hi Sakari, Marco,
> 
> On Mon, Mar 04, 2019 at 08:17:48PM +0200, Sakari Ailus wrote:
> > Hi Marco,
> >
> > On Mon, Mar 04, 2019 at 05:55:28PM +0100, Marco Felsch wrote:
> > > > > (more device specific)
> > > > > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > > > > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > > > >
> > > > > or
> > > > >
> > > > > (more generic)
> > > > > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > > > > tc358746,default-dir = <CSI2_TO_PARALLEL>
> > > >
> > > > The prefix for Toshiba is "toshiba". What would you think of
> > > > "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> > > > "toshiba,csi2-mode" with either "master" or "slave", which would be a
> > > > little bit more generic, but could be slightly more probable to get wrong
> > > > as well.
> > >
> > > You're right mixed the prefix with the device.. If we need to introduce
> > > a property I would prefer the "toshiba,csi2-direction" one. I said if
> > > because as Jacopo mentioned we can avoid the property by define port@0
> > > as input and port@1 as output. I tink that's the best solution, since we
> > > can avoid device specific bindings and it's common to use the last port
> > > as output (e.g. video-mux).
> >
> > The ports represent hardware and I think I would avoid reordering them. I
> > wonder what would the DT folks prefer.
> >
> 
> I might have missed why you mention re-ordering? :)
> 
> > The device specific property is to the point at least: it describes an
> > orthogonal part of the device configuration. That's why I'd pick that if I
> > were to choose. But I'll let Rob to comment on this.
> 
> That's true indeed. Let's wait for inputs from DT people, I'm fine
> with both approaches.
> 
> Thanks
>    j
> 
> >
> > --
> > Regards,
> >
> > Sakari Ailus
> > sakari.ailus@linux.intel.com



-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-03-05 18:14                   ` Marco Felsch
@ 2019-04-16 10:45                     ` Marco Felsch
  2019-04-29 16:44                       ` Marco Felsch
  0 siblings, 1 reply; 30+ messages in thread
From: Marco Felsch @ 2019-04-16 10:45 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mark.rutland, devicetree, Ian Arkver, robh+dt, hans.verkuil,
	Sakari Ailus, mchehab, graphics, linux-media

Hi Rob,

gentle ping.

Regards,
  Marco

On 19-03-05 19:14, Marco Felsch wrote:
> Hi Rob,
> 
> I think you didn't followed the discussion in detail so I will ask you
> personal. In short the tc358746 can act as parallel-in -> csi-out or as
> csi->in -> parallel-out device. The phyiscal pins are always the same
> only the internal timings are different. So we have two ports with two
> endpoints.
> 
> Now the question is how we determine the mode. We have two approaches:
> 1)
>   port@0 -> input port
>   port@1 -> output port
> 
>   pro:
>   + no extra vendor specific binding is needed to determine the mode
> 
>   con:
>   - input/output endpoint can be parallel or mipi-csi2.
> 
> 2)
>   port@0 -> parallel port
>   port@1 -> mipi-csi2 port
> 
>   pro:
>   + input/output endpoint are fixed to parallel or mipi
> 
>   con:
>   - vendor specific binding is needed to determine the mode
> 
> Thanks for your comments :)
> 
> Regards,
> Marco
> 
> On 19-03-05 09:49, Jacopo Mondi wrote:
> > Hi Sakari, Marco,
> > 
> > On Mon, Mar 04, 2019 at 08:17:48PM +0200, Sakari Ailus wrote:
> > > Hi Marco,
> > >
> > > On Mon, Mar 04, 2019 at 05:55:28PM +0100, Marco Felsch wrote:
> > > > > > (more device specific)
> > > > > > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > > > > > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > > > > >
> > > > > > or
> > > > > >
> > > > > > (more generic)
> > > > > > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > > > > > tc358746,default-dir = <CSI2_TO_PARALLEL>
> > > > >
> > > > > The prefix for Toshiba is "toshiba". What would you think of
> > > > > "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> > > > > "toshiba,csi2-mode" with either "master" or "slave", which would be a
> > > > > little bit more generic, but could be slightly more probable to get wrong
> > > > > as well.
> > > >
> > > > You're right mixed the prefix with the device.. If we need to introduce
> > > > a property I would prefer the "toshiba,csi2-direction" one. I said if
> > > > because as Jacopo mentioned we can avoid the property by define port@0
> > > > as input and port@1 as output. I tink that's the best solution, since we
> > > > can avoid device specific bindings and it's common to use the last port
> > > > as output (e.g. video-mux).
> > >
> > > The ports represent hardware and I think I would avoid reordering them. I
> > > wonder what would the DT folks prefer.
> > >
> > 
> > I might have missed why you mention re-ordering? :)
> > 
> > > The device specific property is to the point at least: it describes an
> > > orthogonal part of the device configuration. That's why I'd pick that if I
> > > were to choose. But I'll let Rob to comment on this.
> > 
> > That's true indeed. Let's wait for inputs from DT people, I'm fine
> > with both approaches.
> > 
> > Thanks
> >    j
> > 
> > >
> > > --
> > > Regards,
> > >
> > > Sakari Ailus
> > > sakari.ailus@linux.intel.com
> 
> 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746
  2019-04-16 10:45                     ` Marco Felsch
@ 2019-04-29 16:44                       ` Marco Felsch
  0 siblings, 0 replies; 30+ messages in thread
From: Marco Felsch @ 2019-04-29 16:44 UTC (permalink / raw)
  To: robh+dt
  Cc: mark.rutland, devicetree, Ian Arkver, hans.verkuil, Sakari Ailus,
	mchehab, graphics, linux-media, Jacopo Mondi

Hi Rob,

sorry instead of adding you to To you was on Cc.
Do you have any preferences about the below discussion?

Regards,
  Marco

On 19-04-16 12:45, Marco Felsch wrote:
> Hi Rob,
> 
> gentle ping.
> 
> Regards,
>   Marco
> 
> On 19-03-05 19:14, Marco Felsch wrote:
> > Hi Rob,
> > 
> > I think you didn't followed the discussion in detail so I will ask you
> > personal. In short the tc358746 can act as parallel-in -> csi-out or as
> > csi->in -> parallel-out device. The phyiscal pins are always the same
> > only the internal timings are different. So we have two ports with two
> > endpoints.
> > 
> > Now the question is how we determine the mode. We have two approaches:
> > 1)
> >   port@0 -> input port
> >   port@1 -> output port
> > 
> >   pro:
> >   + no extra vendor specific binding is needed to determine the mode
> > 
> >   con:
> >   - input/output endpoint can be parallel or mipi-csi2.
> > 
> > 2)
> >   port@0 -> parallel port
> >   port@1 -> mipi-csi2 port
> > 
> >   pro:
> >   + input/output endpoint are fixed to parallel or mipi
> > 
> >   con:
> >   - vendor specific binding is needed to determine the mode
> > 
> > Thanks for your comments :)
> > 
> > Regards,
> > Marco
> > 
> > On 19-03-05 09:49, Jacopo Mondi wrote:
> > > Hi Sakari, Marco,
> > > 
> > > On Mon, Mar 04, 2019 at 08:17:48PM +0200, Sakari Ailus wrote:
> > > > Hi Marco,
> > > >
> > > > On Mon, Mar 04, 2019 at 05:55:28PM +0100, Marco Felsch wrote:
> > > > > > > (more device specific)
> > > > > > > tc358746,default-mode = <CSI-Tx> /* Parallel-in -> CSI-out */
> > > > > > > tc358746,default-mode = <CSI-Rx> /* CSI-in -> Parallel-out */
> > > > > > >
> > > > > > > or
> > > > > > >
> > > > > > > (more generic)
> > > > > > > tc358746,default-dir = <PARALLEL_TO_CSI2>
> > > > > > > tc358746,default-dir = <CSI2_TO_PARALLEL>
> > > > > >
> > > > > > The prefix for Toshiba is "toshiba". What would you think of
> > > > > > "toshiba,csi2-direction" with values of either "rx" or "tx"? Or
> > > > > > "toshiba,csi2-mode" with either "master" or "slave", which would be a
> > > > > > little bit more generic, but could be slightly more probable to get wrong
> > > > > > as well.
> > > > >
> > > > > You're right mixed the prefix with the device.. If we need to introduce
> > > > > a property I would prefer the "toshiba,csi2-direction" one. I said if
> > > > > because as Jacopo mentioned we can avoid the property by define port@0
> > > > > as input and port@1 as output. I tink that's the best solution, since we
> > > > > can avoid device specific bindings and it's common to use the last port
> > > > > as output (e.g. video-mux).
> > > >
> > > > The ports represent hardware and I think I would avoid reordering them. I
> > > > wonder what would the DT folks prefer.
> > > >
> > > 
> > > I might have missed why you mention re-ordering? :)
> > > 
> > > > The device specific property is to the point at least: it describes an
> > > > orthogonal part of the device configuration. That's why I'd pick that if I
> > > > were to choose. But I'll let Rob to comment on this.
> > > 
> > > That's true indeed. Let's wait for inputs from DT people, I'm fine
> > > with both approaches.
> > > 
> > > Thanks
> > >    j
> > > 
> > > >
> > > > --
> > > > Regards,
> > > >
> > > > Sakari Ailus
> > > > sakari.ailus@linux.intel.com
> > 
> > 
> > 
> > -- 
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> > 
> > 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2019-04-29 16:44 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-18 14:12 [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
2018-12-18 14:12 ` [PATCH 1/3] media: dt-bindings: add bindings for Toshiba TC358746 Marco Felsch
2018-12-28 23:10   ` Rob Herring
2019-02-13 17:57   ` Jacopo Mondi
2019-03-01 10:26     ` Marco Felsch
2019-03-04  9:38       ` Jacopo Mondi
2019-03-04 16:43         ` Marco Felsch
2019-02-18 10:03   ` Sakari Ailus
2019-03-01 10:52     ` Marco Felsch
2019-03-01 11:07       ` Ian Arkver
2019-03-01 13:01         ` Marco Felsch
2019-03-04  9:41           ` Jacopo Mondi
2019-03-04 12:36           ` Sakari Ailus
2019-03-04 16:55             ` Marco Felsch
2019-03-04 18:17               ` Sakari Ailus
2019-03-05  8:49                 ` Jacopo Mondi
2019-03-05 18:14                   ` Marco Felsch
2019-04-16 10:45                     ` Marco Felsch
2019-04-29 16:44                       ` Marco Felsch
2019-03-04 12:10       ` Sakari Ailus
2018-12-18 14:12 ` [PATCH 2/3] media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver Marco Felsch
2018-12-19  1:24   ` kbuild test robot
2018-12-20 19:37   ` kbuild test robot
2019-02-18 11:25   ` Sakari Ailus
2018-12-18 14:12 ` [PATCH 3/3] media: tc358746: update MAINTAINERS file Marco Felsch
2019-02-18 11:46   ` Sakari Ailus
2019-03-04 17:31     ` Marco Felsch
2019-03-04 18:18       ` Sakari Ailus
2019-01-23 12:54 ` [PATCH 0/3] media: add Toshiba TC358746 Bridge support Marco Felsch
2019-02-12 16:10   ` Marco Felsch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).