* [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 = <µn_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
* 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 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 = <µn_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 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 = <µn_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-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 = <µn_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 = <µn_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-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 = <µn_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 = <µn_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 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 = <µn_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-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 = <µn_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 = <µn_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 = <µn_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 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 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 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 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 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
* 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
* [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
* 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 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
* [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 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 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 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 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
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).