* [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des
@ 2023-12-08 14:33 Julien Massot
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Julien Massot @ 2023-12-08 14:33 UTC (permalink / raw)
To: devicetree, linux-media; +Cc: kernel, Julien Massot
Change in v2:
- move dt-binding changes from 3/4 to 1/4
Hi,
These patches add support for Maxim MAX96714F deserializer and
MAX96717F serializer.
MAX96714F has one GMSL2 input port and one CSI2 4 lanes output port,
MAX96717F has one CSI2 input port and one GMSL2 output port.
The drivers support the tunnel mode where all the
CSI2 traffic coming from an imager is replicated through the deserializer
output port.
Both MAX96714F and MAX96717F are limited to a 3Gbps forward link rate
leaving a maximum of 2.6Gbps for the video payload.
Julien Massot (4):
dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer
dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer
media: i2c: add MAX96714 driver
media: i2c: add MAX96717 driver
.../bindings/media/i2c/maxim,max96714f.yaml | 163 +++
.../bindings/media/i2c/maxim,max96717f.yaml | 144 +++
MAINTAINERS | 12 +
drivers/media/i2c/Kconfig | 26 +
drivers/media/i2c/Makefile | 2 +
drivers/media/i2c/max96714.c | 945 ++++++++++++++++
drivers/media/i2c/max96717.c | 1003 +++++++++++++++++
7 files changed, 2295 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
create mode 100644 drivers/media/i2c/max96714.c
create mode 100644 drivers/media/i2c/max96717.c
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer
2023-12-08 14:33 [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des Julien Massot
@ 2023-12-08 14:33 ` Julien Massot
2023-12-08 15:29 ` Rob Herring
2023-12-08 17:16 ` Krzysztof Kozlowski
2023-12-08 14:33 ` [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer Julien Massot
` (2 subsequent siblings)
3 siblings, 2 replies; 16+ messages in thread
From: Julien Massot @ 2023-12-08 14:33 UTC (permalink / raw)
To: devicetree, linux-media; +Cc: kernel, Julien Massot
Add DT bindings for Maxim MAX96714F GMSL2 Deserializer.
Signed-off-by: Julien Massot <julien.massot@collabora.com>
---
.../bindings/media/i2c/maxim,max96714f.yaml | 163 ++++++++++++++++++
1 file changed, 163 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
new file mode 100644
index 000000000000..8a2a06e7e279
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
@@ -0,0 +1,163 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2023 Collabora Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/maxim,max96714f.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GMSL2 to CSI-2 Deserializer
+
+maintainers:
+ - Julien Massot <julien.massot@collabora.com>
+
+description: |
+ The MAX96714F deserializer converts GMSL2 serial inputs into MIPI
+ CSI-2 D-PHY or C-PHY formatted output. The device allows the GMSL2 link to
+ simultaneously transmit bidirectional control-channel data while forward
+ video transmissions are in progress. The MAX96714F can connect to one
+ remotely located serializer using industry-standard coax or STP
+ interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
+ the MAX96714F can select individual video stream, while the tunnel mode forward all
+ the MIPI data received by the serializer.
+
+ The GMSL2 serial link operates at a fixed rate of 3Gbps in the
+ forward direction and 187.5Mbps in the reverse direction.
+
+properties:
+ compatible:
+ const: maxim,max96714f
+
+ reg:
+ description: I2C device address
+ maxItems: 1
+
+ enable-gpios: true
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ unevaluatedProperties: false
+ description: GMSL Input
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+ description:
+ Endpoint for GMSL2-Link port.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: CSI-2 Output
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes: true
+ bus-type:
+ enum:
+ - 4 # MEDIA_BUS_TYPE_CSI2_DPHY
+
+ required:
+ - data-lanes
+ - bus-type
+
+ required:
+ - port@1
+
+ i2c-gate:
+ $ref: /schemas/i2c/i2c-controller.yaml
+ unevaluatedProperties: false
+ description: |
+ The MAX96714 will pass through and forward the I2C requests from the
+ incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate
+ subnode to configure a serializer.
+
+ port0-poc-supply:
+ description: Regulator providing Power over Coax for a particular port
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
+
+ main_i2c2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gmsl-deserializer@28 {
+ compatible = "maxim,max96714f";
+ reg = <0x28>;
+ enable-gpios = <&main_gpio0 37 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ max96714_gmsl_in: endpoint {
+ remote-endpoint = <&max96917f_gmsl_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96714_csi_out: endpoint {
+ bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <400000000>;
+ remote-endpoint = <&csi_in>;
+ };
+ };
+ };
+
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gmsl-serializer@40 {
+ compatible = "maxim,max96717f";
+ reg = <0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ max96717f_csi_in: endpoint {
+ data-lanes = <1 2>;
+ lane-polarities = <1 0 1>;
+ remote-endpoint = <&vd5661_csi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96917f_gmsl_out: endpoint {
+ remote-endpoint = <&max96714_gmsl_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer
2023-12-08 14:33 [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des Julien Massot
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
@ 2023-12-08 14:33 ` Julien Massot
2023-12-08 15:29 ` Rob Herring
2023-12-08 17:17 ` Krzysztof Kozlowski
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
2023-12-08 14:33 ` [PATCH v2 4/4] media: i2c: add MAX96717 driver Julien Massot
3 siblings, 2 replies; 16+ messages in thread
From: Julien Massot @ 2023-12-08 14:33 UTC (permalink / raw)
To: devicetree, linux-media; +Cc: kernel, Julien Massot
Add DT bindings for Maxim MAX96717F GMSL2 Serializer.
Signed-off-by: Julien Massot <julien.massot@collabora.com>
---
.../bindings/media/i2c/maxim,max96717f.yaml | 144 ++++++++++++++++++
1 file changed, 144 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
new file mode 100644
index 000000000000..ae649c3041a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2023 Collabora Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/maxim,max96717f.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GMSL2 to CSI-2 Serializer
+
+maintainers:
+ - Julien Massot <julien.massot@collabora.com>
+
+description: |
+ The MAX96717F serializer converts MIPI CSI-2 D-PHY or C-PHY formatted input
+ into GMSL2 serial outputs. The device allows the GMSL2 link to
+ simultaneously transmit bidirectional control-channel data while forward
+ video transmissions are in progress. The MAX96717F can connect to one
+ remotely located deserializer using industry-standard coax or STP
+ interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
+ the MAX96717F can select the MIPI datatype, while the tunnel mode forward all the MIPI
+ data received by the serializer.
+ The MAX96717F supports Reference Over Reverse (channel),
+ to generate a clock output for the sensor from the GMSL reverse channel.
+
+ The GMSL2 serial link operates at a fixed rate of 3Gbps in the
+ forward direction and 187.5Mbps in the reverse direction.
+
+properties:
+ compatible:
+ const: maxim,max96717f
+
+ '#gpio-cells':
+ const: 2
+ description:
+ First cell is the GPIO pin number, second cell is the flags. The GPIO pin
+ number must be in range of [0, 10].
+
+ gpio-controller: true
+
+ '#clock-cells':
+ const: 0
+
+ reg:
+ description: I2C device address
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: CSI-2 Input port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ required:
+ - data-lanes
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ unevaluatedProperties: false
+ description: GMSL Output port
+
+ required:
+ - port@1
+
+ i2c-gate:
+ $ref: /schemas/i2c/i2c-controller.yaml
+ unevaluatedProperties: false
+ description: |
+ The MAX96717F will pass through and forward the I2C requests from the
+ incoming GMSL2 link. Therefore it supports an i2c-gate
+ subnode to configure a sensor.
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ serializer: serializer@40 {
+ compatible = "maxim,max96717f";
+ reg = <0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ max96717f_csi_in: endpoint {
+ data-lanes = <1 2>;
+ lane-polarities = <1 0 1>;
+ remote-endpoint = <&vd5661_csi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96917f_gmsl_out: endpoint {
+ remote-endpoint = <&max96714_gmsl_in>;
+ };
+ };
+ };
+
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ vd5661@10 {
+ compatible = "st,st-vgxy61";
+ reg = <0x10>;
+ reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ clocks = <&serializer>;
+ VCORE-supply = <&v1v2>;
+ VDDIO-supply = <&v1v8>;
+ VANA-supply = <&v2v8>;
+ port {
+ vd5661_csi: endpoint {
+ data-lanes = <1 2>;
+ remote-endpoint = <&max96717f_csi_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 3/4] media: i2c: add MAX96714 driver
2023-12-08 14:33 [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des Julien Massot
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
2023-12-08 14:33 ` [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer Julien Massot
@ 2023-12-08 14:33 ` Julien Massot
2023-12-08 17:18 ` Krzysztof Kozlowski
` (2 more replies)
2023-12-08 14:33 ` [PATCH v2 4/4] media: i2c: add MAX96717 driver Julien Massot
3 siblings, 3 replies; 16+ messages in thread
From: Julien Massot @ 2023-12-08 14:33 UTC (permalink / raw)
To: devicetree, linux-media; +Cc: kernel, Julien Massot
This driver handle the MAX96714 deserializer in tunnel mode.
The CSI output will replicate all the CSI traffic capture by
the remote serializer.
Signed-off-by: Julien Massot <julien.massot@collabora.com>
---
MAINTAINERS | 6 +
drivers/media/i2c/Kconfig | 13 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/max96714.c | 945 +++++++++++++++++++++++++++++++++++
4 files changed, 965 insertions(+)
create mode 100644 drivers/media/i2c/max96714.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 10a981abd6ec..1010e7db32f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13016,6 +13016,12 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/staging/media/max96712/max96712.c
+MAX96714 GMSL2 DESERIALIZER DRIVER
+M: Julien Massot <julien.massot@collabora.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/i2c/max96714.c
+
MAX9860 MONO AUDIO VOICE CODEC DRIVER
M: Peter Rosin <peda@axentia.se>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 59ee0ca2c978..6e2819a9ba96 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1498,6 +1498,19 @@ config VIDEO_DS90UB960
Device driver for the Texas Instruments DS90UB960
FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer.
+config VIDEO_MAX96714
+ tristate "Maxim MAX96714 GMSL2 deserializer"
+ depends on OF && I2C && VIDEO_DEV
+ select I2C_MUX
+ select MEDIA_CONTROLLER
+ select GPIOLIB
+ select REGMAP_I2C
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Device driver for the Maxim MAX96714
+ GMSL2 Deserializer.
+
endmenu
endif # VIDEO_DEV
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index f5010f80a21f..c6e23d3fdc22 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
+obj-$(CONFIG_VIDEO_MAX96714) += max96714.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
diff --git a/drivers/media/i2c/max96714.c b/drivers/media/i2c/max96714.c
new file mode 100644
index 000000000000..a65f18991a2a
--- /dev/null
+++ b/drivers/media/i2c/max96714.c
@@ -0,0 +1,945 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Maxim GMSL2 Deserializer Driver
+ *
+ * Copyright (C) 2023 Collabora Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/fwnode.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX96714F_DEVICE_ID 0xca
+#define MAX96714_NPORTS 2
+#define MAX96714_PAD_SINK 0
+#define MAX96714_PAD_SOURCE 1
+
+/* DEV */
+#define MAX96714_REG13 0x0d
+#define MAX96714_DEV_REV 0x0e
+#define MAX96714_DEV_REV_MASK GENMASK(3, 0)
+#define MAX96714_LINK_LOCK 0x13
+#define MAX96714_LINK_LOCK_BIT BIT(3)
+
+/* VID_RX */
+#define MAX96714_VIDEO_RX8 0x11a
+#define MAX96714_VID_LOCK BIT(6)
+
+/* BACKTOP */
+#define MAX96714_BACKTOP25 0x320
+#define CSI_DPLL_FREQ_MASK GENMASK(4, 0)
+
+/* MIPI_PHY */
+#define MAX96714_MIPI_STDBY_N 0x332
+#define MAX96714_MIPI_STDBY_MASK GENMASK(5, 4)
+#define MAX96714_MIPI_LANE_MAP 0x333
+#define MAX96714_MIPI_POLARITY 0x335
+#define MAX96714_MIPI_POLARITY_MASK GENMASK(5, 0)
+
+/* MIPI_TX */
+#define MAX96714_MIPI_LANE_CNT 0x44a
+#define MAX96714_CSI2_LANE_CNT_MASK GENMASK(7, 6)
+#define MAX96714_MIPI_TX52 0x474
+#define MAX96714_TUN_EN BIT(0)
+
+#define MHZ(v) ((u32)((v) * 1000000U))
+
+struct max96714_rxport {
+ struct {
+ struct v4l2_subdev *sd;
+ u16 pad;
+ struct fwnode_handle *ep_fwnode;
+ } source;
+ struct regulator *poc;
+};
+
+struct max96714_txport {
+ struct v4l2_fwnode_endpoint vep;
+};
+
+struct max96714_priv {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *gpiod_pwdn;
+ struct max96714_rxport rxport;
+ struct i2c_mux_core *mux;
+ u64 enabled_source_streams;
+ struct v4l2_subdev sd;
+ struct media_pad pads[MAX96714_NPORTS];
+ struct v4l2_fwnode_endpoint vep;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_async_notifier notifier;
+ s64 tx_link_freq;
+};
+
+static struct regmap_config max96714_regmap_config = {
+ .name = "max96714",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xFFFF,
+};
+
+static inline struct max96714_priv *sd_to_max96714(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct max96714_priv, sd);
+}
+
+static int max96714_read(struct max96714_priv *priv, u16 reg, u8 *val)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int v;
+ int ret;
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret) {
+ dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+ }
+
+ *val = v;
+
+ return ret;
+}
+
+static int max96714_write(struct max96714_priv *priv, u16 reg, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret)
+ dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int max96714_update_bits(struct max96714_priv *priv, u16 reg, u8 mask,
+ u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_update_bits(priv->regmap, reg, mask, val);
+ if (ret)
+ dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int max96714_enable_tx_port(struct max96714_priv *priv)
+{
+ return max96714_update_bits(priv, MAX96714_MIPI_STDBY_N,
+ MAX96714_MIPI_STDBY_MASK,
+ MAX96714_MIPI_STDBY_MASK);
+}
+
+static void max96714_disable_tx_port(struct max96714_priv *priv)
+{
+ max96714_update_bits(priv, MAX96714_MIPI_STDBY_N,
+ MAX96714_MIPI_STDBY_MASK, 0);
+}
+
+static bool max96714_tx_port_enabled(struct max96714_priv *priv)
+{
+ u8 val;
+
+ max96714_read(priv, MAX96714_MIPI_STDBY_N, &val);
+
+ return val & MAX96714_MIPI_STDBY_MASK;
+}
+
+static int max96714_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 source_pad, u64 streams_mask)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ u64 sink_streams;
+ int ret;
+
+ if (!priv->enabled_source_streams)
+ max96714_enable_tx_port(priv);
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96714_PAD_SOURCE,
+ MAX96714_PAD_SINK,
+ &streams_mask);
+
+ ret = v4l2_subdev_enable_streams(priv->rxport.source.sd,
+ priv->rxport.source.pad,
+ sink_streams);
+ if (ret)
+ return ret;
+
+ priv->enabled_source_streams |= streams_mask;
+
+
+ return ret;
+}
+
+static int max96714_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 source_pad, u64 streams_mask)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ u64 sink_streams;
+ int ret;
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96714_PAD_SOURCE,
+ MAX96714_PAD_SINK,
+ &streams_mask);
+
+ ret = v4l2_subdev_disable_streams(priv->rxport.source.sd,
+ priv->rxport.source.pad,
+ sink_streams);
+ if (ret)
+ return ret;
+
+ priv->enabled_source_streams &= ~streams_mask;
+
+ if (!priv->enabled_source_streams)
+ max96714_disable_tx_port(priv);
+
+ return 0;
+}
+
+static int max96714_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret;
+ u64 streams_mask = BIT(0);
+
+ if (enable)
+ ret = v4l2_subdev_enable_streams(subdev, MAX96714_PAD_SOURCE,
+ streams_mask);
+ else
+ ret = v4l2_subdev_disable_streams(subdev, MAX96714_PAD_SOURCE,
+ streams_mask);
+ return ret;
+}
+
+static int max96714_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ struct v4l2_mbus_framefmt *fmt;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ priv->enabled_source_streams)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (format->pad == MAX96714_PAD_SOURCE)
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ return 0;
+}
+
+static int _max96714_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ int ret;
+
+ static const struct v4l2_mbus_framefmt format = {
+ .width = 1280,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .field = V4L2_FIELD_NONE,
+ };
+
+ /*
+ * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
+ * frame desc is made dynamically allocated.
+ */
+ if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+ return -EINVAL;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int max96714_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
+ return -EBUSY;
+
+ return _max96714_set_routing(sd, state, which, routing);
+}
+
+static int max96714_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = MAX96714_PAD_SINK,
+ .sink_stream = 0,
+ .source_pad = MAX96714_PAD_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ }
+ };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _max96714_set_routing(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE,
+ &routing);
+}
+
+static const struct v4l2_subdev_pad_ops max96714_pad_ops = {
+ .enable_streams = max96714_enable_streams,
+ .disable_streams = max96714_disable_streams,
+
+ .set_routing = max96714_set_routing,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = max96714_set_fmt,
+
+ .init_cfg = max96714_init_cfg,
+};
+
+static bool max96714_link_locked(struct max96714_priv *priv)
+{
+ u8 val;
+
+ max96714_read(priv, MAX96714_LINK_LOCK, &val);
+
+ return val & MAX96714_LINK_LOCK_BIT;
+}
+
+static void max96714_link_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Link locked:%d\n", max96714_link_locked(priv));
+}
+
+static bool max96714_pipe_locked(struct max96714_priv *priv)
+{
+ u8 val;
+
+ max96714_read(priv, MAX96714_VIDEO_RX8, &val);
+
+ return val & MAX96714_VID_LOCK;
+}
+
+static void max96714_pipe_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Pipe vidlock:%d\n", max96714_pipe_locked(priv));
+}
+
+static void max96714_csi_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u8 freq;
+
+ max96714_read(priv, MAX96714_BACKTOP25, &freq);
+ freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
+
+ dev_info(dev, "CSI controller DPLL freq:%u00MHz CSIPHY enabled:%d\n",
+ freq, max96714_tx_port_enabled(priv));
+}
+
+static int max96714_log_status(struct v4l2_subdev *sd)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Deserializer: max96714\n");
+
+ max96714_link_status(priv);
+ max96714_pipe_status(priv);
+ max96714_csi_status(priv);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops max96714_subdev_core_ops = {
+ .log_status = max96714_log_status,
+};
+
+static const struct v4l2_subdev_video_ops max96714_video_ops = {
+ .s_stream = max96714_s_stream,
+};
+
+static const struct v4l2_subdev_ops max96714_subdev_ops = {
+ .video = &max96714_video_ops,
+ .core = &max96714_subdev_core_ops,
+ .pad = &max96714_pad_ops,
+};
+
+static const struct media_entity_operations max96714_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int max96714_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct max96714_priv *priv = sd_to_max96714(notifier->sd);
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(&subdev->entity,
+ priv->rxport.source.ep_fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n", subdev->name);
+ return ret;
+ }
+
+ priv->rxport.source.sd = subdev;
+ priv->rxport.source.pad = ret;
+
+ ret = media_create_pad_link(&priv->rxport.source.sd->entity,
+ priv->rxport.source.pad, &priv->sd.entity,
+ MAX96714_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:%u\n",
+ priv->rxport.source.sd->name, priv->rxport.source.pad,
+ priv->sd.name, MAX96714_PAD_SINK);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations max96714_notify_ops = {
+ .bound = max96714_notify_bound,
+};
+
+static int max96714_v4l2_notifier_register(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct max96714_rxport *rxport = &priv->rxport;
+ struct v4l2_async_connection *asd;
+ int ret;
+
+ v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
+
+ asd = v4l2_async_nf_add_fwnode(&priv->notifier,
+ rxport->source.ep_fwnode,
+ struct v4l2_async_connection);
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev: %pe", asd);
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ priv->notifier.ops = &max96714_notify_ops;
+
+ ret = v4l2_async_nf_register(&priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void max96714_v4l2_notifier_unregister(struct max96714_priv *priv)
+{
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+}
+
+static int max96714_create_subdev(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96714_subdev_ops);
+
+ v4l2_ctrl_handler_init(&priv->ctrl_handler, 1);
+ priv->sd.ctrl_handler = &priv->ctrl_handler;
+
+ priv->tx_link_freq = priv->vep.link_frequencies[0];
+ if (priv->tx_link_freq < 0)
+ return priv->tx_link_freq;
+
+ v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, &priv->tx_link_freq);
+ if (priv->ctrl_handler.error) {
+ ret = priv->ctrl_handler.error;
+ goto err_free_ctrl;
+ }
+
+ priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &max96714_entity_ops;
+
+ priv->pads[MAX96714_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ priv->pads[MAX96714_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&priv->sd.entity,
+ MAX96714_NPORTS,
+ priv->pads);
+ if (ret)
+ goto err_free_ctrl;
+
+ priv->sd.state_lock = priv->sd.ctrl_handler->lock;
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = max96714_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret);
+ goto err_subdev_cleanup;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret);
+ goto err_unreg_notif;
+ }
+
+ return 0;
+
+err_unreg_notif:
+ max96714_v4l2_notifier_unregister(priv);
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&priv->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&priv->sd.entity);
+err_free_ctrl:
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+
+ return ret;
+
+};
+
+static void max96714_destroy_subdev(struct max96714_priv *priv)
+{
+ max96714_v4l2_notifier_unregister(priv);
+ v4l2_async_unregister_subdev(&priv->sd);
+
+ v4l2_subdev_cleanup(&priv->sd);
+
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+}
+
+static int max96714_i2c_mux_select(struct i2c_mux_core *mux, u32 chan)
+{
+ return 0;
+}
+
+static int max96714_i2c_mux_init(struct max96714_priv *priv)
+{
+ priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
+ 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
+ max96714_i2c_mux_select, NULL);
+ if (!priv->mux)
+ return -ENOMEM;
+
+ return i2c_mux_add_adapter(priv->mux, 0, 0, 0);
+}
+
+static void max96714_init_tx_port(struct max96714_priv *priv)
+{
+ struct v4l2_mbus_config_mipi_csi2 *mipi;
+ unsigned long lanes_used = 0;
+ u8 val, lane;
+
+ max96714_disable_tx_port(priv);
+
+ mipi = &priv->vep.bus.mipi_csi2;
+ val = *priv->vep.link_frequencies * 2 / MHZ(100);
+
+ max96714_update_bits(priv, MAX96714_BACKTOP25,
+ CSI_DPLL_FREQ_MASK, val);
+
+ val = FIELD_PREP(MAX96714_CSI2_LANE_CNT_MASK, mipi->num_data_lanes - 1);
+ max96714_update_bits(priv, MAX96714_MIPI_LANE_CNT,
+ MAX96714_CSI2_LANE_CNT_MASK, val);
+
+ /* lanes polarity */
+ val = 0;
+ for (lane = 0; lane < mipi->num_data_lanes + 1; lane++) {
+ if (!mipi->lane_polarities[lane])
+ continue;
+ if (lane == 0)
+ /* clock lane */
+ val |= BIT(5);
+ else if (lane < 3)
+ /* Lane D0 and D1 */
+ val |= BIT(lane - 1);
+ else
+ /* D2 and D3 */
+ val |= BIT(lane);
+ }
+
+ max96714_update_bits(priv, MAX96714_MIPI_POLARITY,
+ MAX96714_MIPI_POLARITY_MASK, val);
+
+ /* lanes mapping */
+ val = 0;
+ for (lane = 0; lane < mipi->num_data_lanes; lane++) {
+ val |= (mipi->data_lanes[lane] - 1) << (lane*2);
+ lanes_used |= BIT(mipi->data_lanes[lane] - 1);
+ }
+
+ /* Unused lanes need to be mapped as well to not have
+ * the same lanes mapped twice.
+ */
+ for (; lane < 4; lane++) {
+ unsigned int idx = find_first_zero_bit(&lanes_used, 4);
+
+ val |= idx << (lane * 2);
+ lanes_used |= BIT(idx);
+ }
+
+ max96714_write(priv, MAX96714_MIPI_LANE_MAP, val);
+}
+
+static int max96714_rxport_enable_poc(struct max96714_priv *priv)
+{
+ struct max96714_rxport *rxport = &priv->rxport;
+
+ if (!rxport->poc)
+ return 0;
+
+ return regulator_enable(rxport->poc);
+}
+
+static void max96714_rxport_disable_poc(struct max96714_priv *priv)
+{
+ struct max96714_rxport *rxport = &priv->rxport;
+
+ if (rxport->poc)
+ regulator_disable(rxport->poc);
+}
+
+static int max96714_parse_dt_txport(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct fwnode_handle *ep_fwnode;
+ u32 num_data_lanes;
+ s64 dpll_freq;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96714_PAD_SOURCE, 0, 0);
+ if (!ep_fwnode)
+ return -EINVAL;
+
+ priv->vep.bus_type = V4L2_MBUS_UNKNOWN;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &priv->vep);
+ fwnode_handle_put(ep_fwnode);
+ if (ret) {
+ dev_err(dev, "tx: failed to parse endpoint data\n");
+ return -EINVAL;
+ }
+
+ if (priv->vep.bus_type != V4L2_MBUS_CSI2_DPHY) {
+ dev_err(&priv->client->dev, "Unsupported bus-type %u\n",
+ priv->vep.bus_type);
+ return -EINVAL;
+ }
+
+ if (priv->vep.nr_of_link_frequencies != 1) {
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ /* DPLL freq is twice the link frequency */
+ dpll_freq = priv->vep.link_frequencies[0] * 2;
+
+ /* 100Mbps step, Min 100Mbps, Max 2500Mbps */
+ if (dpll_freq % MHZ(100) || dpll_freq < MHZ(100) ||
+ dpll_freq > MHZ(2500)) {
+ dev_err(dev, "tx: invalid link frequency\n");
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ num_data_lanes = priv->vep.bus.mipi_csi2.num_data_lanes;
+ if (num_data_lanes < 1 || num_data_lanes > 4) {
+ dev_err(dev,
+ "tx: invalid number of data lanes should be 1 to 4\n");
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ return 0;
+
+err_free_vep:
+ v4l2_fwnode_endpoint_free(&priv->vep);
+
+ return ret;
+};
+
+static int max96714_parse_dt_rxport(struct max96714_priv *priv)
+{
+ static const char *poc_name = "port0-poc";
+ struct max96714_rxport *rxport = &priv->rxport;
+ struct device *dev = &priv->client->dev;
+ struct fwnode_handle *ep_fwnode;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96714_PAD_SINK,
+ 0, 0);
+ if (!ep_fwnode)
+ return -ENOENT;
+
+ rxport->source.ep_fwnode = fwnode_graph_get_remote_endpoint(ep_fwnode);
+ fwnode_handle_put(ep_fwnode);
+
+ if (!rxport->source.ep_fwnode) {
+ dev_err(dev, "rx: no remote endpoint\n");
+ return -EINVAL;
+ }
+
+ rxport->poc = devm_regulator_get_optional(dev, poc_name);
+ if (IS_ERR(rxport->poc)) {
+ ret = PTR_ERR(rxport->poc);
+ if (ret == -ENODEV) {
+ rxport->poc = NULL;
+ } else {
+ dev_err(dev, "rx: failed to get POC supply: %d\n", ret);
+ goto err_put_source_ep_fwnode;
+ }
+ }
+
+ return 0;
+
+err_put_source_ep_fwnode:
+ fwnode_handle_put(rxport->source.ep_fwnode);
+ return ret;
+}
+
+static int max96714_parse_dt(struct max96714_priv *priv)
+{
+ int ret;
+
+ ret = max96714_parse_dt_rxport(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_parse_dt_txport(priv);
+ if (ret)
+ goto err_put_fwnode;
+
+ return 0;
+
+err_put_fwnode:
+ fwnode_handle_put(priv->rxport.source.ep_fwnode);
+
+ return ret;
+}
+
+static int max96714_enable_core_hw(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u8 val;
+ int ret;
+
+ if (priv->gpiod_pwdn) {
+ /* wait min 2 ms for reset to complete */
+ gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
+ fsleep(2000);
+ gpiod_set_value_cansleep(priv->gpiod_pwdn, 1);
+ /* wait min 2 ms for power up to finish */
+ fsleep(2000);
+ }
+
+ ret = max96714_read(priv, MAX96714_REG13, &val);
+ if (ret) {
+ dev_err_probe(dev, ret, "Cannot read first register, abort\n");
+ goto err_pd_gpio;
+ }
+
+ if (val != MAX96714F_DEVICE_ID) {
+ dev_err(dev, "Unsupported device id expected %x got %x\n",
+ MAX96714F_DEVICE_ID, val);
+ ret = -EOPNOTSUPP;
+ goto err_pd_gpio;
+ }
+
+ ret = max96714_read(priv, MAX96714_DEV_REV, &val);
+ if (ret)
+ goto err_pd_gpio;
+
+ dev_dbg(dev, "Found %x (rev %lx)\n", MAX96714F_DEVICE_ID,
+ val & MAX96714_DEV_REV_MASK);
+
+ ret = max96714_read(priv, MAX96714_MIPI_TX52, &val);
+ if (ret)
+ goto err_pd_gpio;
+
+ if (!(val & MAX96714_TUN_EN)) {
+ dev_err(dev, "Only supporting tunnel mode");
+ ret = -EOPNOTSUPP;
+ goto err_pd_gpio;
+ }
+
+ return 0;
+
+err_pd_gpio:
+ gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
+ return ret;
+}
+
+static void max96714_disable_core_hw(struct max96714_priv *priv)
+{
+ gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
+}
+
+static int max96714_get_hw_resources(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ priv->regmap = devm_regmap_init_i2c(priv->client,
+ &max96714_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->gpiod_pwdn = devm_gpiod_get_optional(&priv->client->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_pwdn))
+ return dev_err_probe(dev, PTR_ERR(priv->gpiod_pwdn),
+ "Cannot get enable GPIO\n");
+ gpiod_set_consumer_name(priv->gpiod_pwdn, "maxgmsl2-pwdn");
+
+ return 0;
+}
+
+static int max96714_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct max96714_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ priv->regmap = devm_regmap_init_i2c(priv->client,
+ &max96714_regmap_config);
+
+ ret = max96714_get_hw_resources(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_enable_core_hw(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_parse_dt(priv);
+ if (ret)
+ goto err_disable_core_hw;
+
+ max96714_init_tx_port(priv);
+
+ ret = max96714_rxport_enable_poc(priv);
+ if (ret)
+ goto err_free_ports;
+
+ ret = max96714_i2c_mux_init(priv);
+ if (ret)
+ goto err_disable_poc;
+
+ ret = max96714_create_subdev(priv);
+ if (ret)
+ goto err_del_mux;
+
+ return 0;
+
+err_del_mux:
+ i2c_mux_del_adapters(priv->mux);
+err_disable_poc:
+ max96714_rxport_disable_poc(priv);
+err_free_ports:
+ fwnode_handle_put(priv->rxport.source.ep_fwnode);
+ v4l2_fwnode_endpoint_free(&priv->vep);
+err_disable_core_hw:
+ max96714_disable_core_hw(priv);
+
+ return ret;
+}
+
+static void max96714_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct max96714_priv *priv = sd_to_max96714(sd);
+
+ max96714_destroy_subdev(priv);
+ i2c_mux_del_adapters(priv->mux);
+ max96714_rxport_disable_poc(priv);
+ fwnode_handle_put(priv->rxport.source.ep_fwnode);
+ v4l2_fwnode_endpoint_free(&priv->vep);
+ max96714_disable_core_hw(priv);
+ gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
+}
+
+static const struct of_device_id max96714_of_ids[] = {
+ { .compatible = "maxim,max96714f" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max96714_of_ids);
+
+static struct i2c_driver max96714_i2c_driver = {
+ .driver = {
+ .name = "max96714",
+ .of_match_table = max96714_of_ids,
+ },
+ .probe = max96714_probe,
+ .remove = max96714_remove,
+};
+
+module_i2c_driver(max96714_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Maxim Integrated GMSL2 Deserializers Driver");
+MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>");
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 4/4] media: i2c: add MAX96717 driver
2023-12-08 14:33 [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des Julien Massot
` (2 preceding siblings ...)
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
@ 2023-12-08 14:33 ` Julien Massot
2023-12-09 4:05 ` kernel test robot
3 siblings, 1 reply; 16+ messages in thread
From: Julien Massot @ 2023-12-08 14:33 UTC (permalink / raw)
To: devicetree, linux-media; +Cc: kernel, Julien Massot
This driver handle the MAX96717 serializer in tunnel mode.
All incoming CSI traffic will be tunneled through the GMSL2
link.
Signed-off-by: Julien Massot <julien.massot@collabora.com>
---
MAINTAINERS | 6 +
drivers/media/i2c/Kconfig | 13 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/max96717.c | 1003 ++++++++++++++++++++++++++++++++++
4 files changed, 1023 insertions(+)
create mode 100644 drivers/media/i2c/max96717.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 1010e7db32f2..232f74998b57 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13022,6 +13022,12 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/max96714.c
+MAX96717 GMSL2 SERIALIZER DRIVER
+M: Julien Massot <julien.massot@collabora.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/i2c/max96717.c
+
MAX9860 MONO AUDIO VOICE CODEC DRIVER
M: Peter Rosin <peda@axentia.se>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 6e2819a9ba96..87858169c39a 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1511,6 +1511,19 @@ config VIDEO_MAX96714
Device driver for the Maxim MAX96714
GMSL2 Deserializer.
+config VIDEO_MAX96717
+ tristate "Maxim MAX96717 GMSL2 Serializer support"
+ depends on OF && I2C && VIDEO_DEV && COMMON_CLK
+ select I2C_MUX
+ select MEDIA_CONTROLLER
+ select GPIOLIB
+ select REGMAP_I2C
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Device driver for the Maxim MAX96717
+ GMSL2 Serializer.
+
endmenu
endif # VIDEO_DEV
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index c6e23d3fdc22..4362b905edfd 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
obj-$(CONFIG_VIDEO_MAX96714) += max96714.o
+obj-$(CONFIG_VIDEO_MAX96717) += max96717.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c
new file mode 100644
index 000000000000..13c70fbe42cc
--- /dev/null
+++ b/drivers/media/i2c/max96717.c
@@ -0,0 +1,1003 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Maxim GMSL2 Serializer Driver
+ *
+ * Copyright (C) 2023 Collabora Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/fwnode.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c-mux.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX96717F_DEVICE_ID 0xc8
+#define MAX96717_PORTS 2
+#define MAX96717_PAD_SINK 0
+#define MAX96717_PAD_SOURCE 1
+
+#define MAX96717_DEFAULT_CLKOUT_RATE 24000000UL
+
+/* DEV */
+#define REG3 0x3
+#define MAX96717_RCLKSEL GENMASK(1, 0)
+#define RCLKSEL_REF_PLL 0x3
+#define MAX96717_REG6 0x6
+#define RCLKEN BIT(5)
+#define MAX96717_DEV_ID 0xd
+#define MAX96717_DEV_REV 0xe
+#define MAX96717_DEV_REV_MASK GENMASK(3, 0)
+
+/* VID_TX Z */
+#define MAX96717_VIDEO_TX2 0x112
+#define MAX96717_VIDEO_PCLKDET BIT(7)
+
+/* GPIO */
+#define MAX96717_GPIO_BASE 0x2be
+#define MAX96717_NUM_GPIO 11
+#define MAX96717_GPIO_REG_A(gpio) (MAX96717_GPIO_BASE + gpio * 3)
+#define MAX96717_GPIO_OUT BIT(4)
+#define MAX96717_GPIO_IN BIT(3)
+#define MAX96717_GPIO_RX_EN BIT(2)
+#define MAX96717_GPIO_TX_EN BIT(1)
+#define MAX96717_GPIO_OUT_DIS BIT(0)
+
+/* FRONTTOP */
+/* MAX96717 only have CSI port 'B' */
+#define MAX96717_FRONTOP0 0x308
+#define MAX96717_START_PORT_B BIT(5)
+
+/* MIPI_RX */
+#define MAX96717_MIPI_RX1 0x331
+#define MAX96717_MIPI_LANES_CNT GENMASK(5, 4)
+#define MAX96717_MIPI_RX2 0x332 /* phy1 Lanes map */
+#define MAX96717_PHY2_LANES_MAP GENMASK(7, 4)
+#define MAX96717_MIPI_RX3 0x333 /* phy2 Lanes map */
+#define MAX96717_PHY1_LANES_MAP GENMASK(3, 0)
+#define MAX96717_MIPI_RX4 0x334 /* phy1 lane polarities */
+#define MAX96717_PHY1_LANES_POL GENMASK(6, 4)
+#define MAX96717_MIPI_RX5 0x335 /* phy2 lane polarities */
+#define MAX96717_PHY2_LANES_POL GENMASK(2, 0)
+
+/* MIPI_RX_EXT */
+#define MAX96717_MIPI_RX_EXT11 0x383
+#define MAX96717_TUN_MODE BIT(7)
+
+/* REF_VTG */
+#define REF_VTG0 0x3f0
+#define REFGEN_PREDEF_EN BIT(6)
+#define REFGEN_PREDEF_FREQ_MASK GENMASK(5, 4)
+#define REFGEN_PREDEF_FREQ_ALT BIT(3)
+#define REFGEN_RST BIT(1)
+#define REFGEN_EN BIT(0)
+
+/* MISC */
+#define PIO_SLEW_1 0x570
+
+struct max96717_hw_data {
+ const char *model;
+ u8 device_id;
+};
+
+static const struct max96717_hw_data max96717f_data = {
+ .model = "max96717f",
+ .device_id = MAX96717F_DEVICE_ID,
+};
+
+struct max96717_priv {
+ const struct max96717_hw_data *data;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct i2c_mux_core *mux;
+ struct v4l2_fwnode_endpoint vep;
+ struct v4l2_subdev sd;
+ struct media_pad pads[MAX96717_PORTS];
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *source_sd;
+ u16 source_sd_pad;
+ u64 enabled_source_streams;
+ u8 pll_predef_index;
+ struct clk_hw clk_hw;
+ struct gpio_chip gpio_chip;
+};
+
+static struct regmap_config max96717_regmap_config = {
+ .name = "max96717",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xFFFF,
+};
+
+static inline struct max96717_priv *sd_to_max96717(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct max96717_priv, sd);
+}
+
+static inline struct max96717_priv *clk_hw_to_max96717(struct clk_hw *hw)
+{
+ return container_of(hw, struct max96717_priv, clk_hw);
+}
+
+static int max96717_read(struct max96717_priv *priv, u16 reg, u8 *val)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int v;
+ int ret;
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret) {
+ dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+ }
+
+ *val = v;
+
+ return ret;
+}
+
+static int max96717_write(struct max96717_priv *priv, u16 reg, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret)
+ dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int max96717_update_bits(struct max96717_priv *priv, u16 reg, u8 mask,
+ u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_update_bits(priv->regmap, reg, mask, val);
+ if (ret)
+ dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int max96717_i2c_mux_select(struct i2c_mux_core *mux, u32 chan)
+{
+ return 0;
+}
+
+static int max96717_i2c_mux_init(struct max96717_priv *priv)
+{
+ priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
+ 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
+ max96717_i2c_mux_select, NULL);
+ if (!priv->mux)
+ return -ENOMEM;
+
+ return i2c_mux_add_adapter(priv->mux, 0, 0, 0);
+}
+
+static inline int max96717_start_csi(struct max96717_priv *priv, bool start)
+{
+ return max96717_update_bits(priv, MAX96717_FRONTOP0,
+ MAX96717_START_PORT_B,
+ start ? MAX96717_START_PORT_B : 0);
+}
+
+static int max96717_gpiochip_get(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+ u8 val;
+ int ret;
+
+ ret = max96717_read(priv, MAX96717_GPIO_REG_A(offset), &val);
+ if (ret)
+ return ret;
+
+ if (val & MAX96717_GPIO_OUT_DIS)
+ return !!(val & MAX96717_GPIO_IN);
+ else
+ return !!(val & MAX96717_GPIO_OUT);
+}
+
+static void max96717_gpiochip_set(struct gpio_chip *gpiochip,
+ unsigned int offset, int value)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ max96717_update_bits(priv, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT, MAX96717_GPIO_OUT);
+}
+
+static int max96717_gpio_get_direction(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+ u8 val;
+ int ret;
+
+ ret = max96717_read(priv, MAX96717_GPIO_REG_A(offset), &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & MAX96717_GPIO_OUT_DIS);
+}
+
+static int max96717_gpio_direction_out(struct gpio_chip *gpiochip,
+ unsigned int offset, int value)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ return max96717_update_bits(priv, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT_DIS | MAX96717_GPIO_OUT,
+ value ? MAX96717_GPIO_OUT : 0);
+}
+
+static int max96717_gpio_direction_in(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ return max96717_update_bits(priv, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT_DIS,
+ MAX96717_GPIO_OUT_DIS);
+}
+
+static int max96717_gpiochip_probe(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct gpio_chip *gc = &priv->gpio_chip;
+ int ret, i;
+
+ gc->label = dev_name(dev);
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+ gc->ngpio = MAX96717_NUM_GPIO;
+ gc->base = -1;
+ gc->can_sleep = true;
+ gc->get_direction = max96717_gpio_get_direction;
+ gc->direction_input = max96717_gpio_direction_in;
+ gc->direction_output = max96717_gpio_direction_out;
+ gc->set = max96717_gpiochip_set;
+ gc->get = max96717_gpiochip_get;
+ gc->of_gpio_n_cells = 2;
+
+ /* Disable GPIO forwarding */
+ for (i = 0; i < gc->ngpio; i++)
+ max96717_update_bits(priv, MAX96717_GPIO_REG_A(i),
+ MAX96717_GPIO_RX_EN | MAX96717_GPIO_TX_EN,
+ 0);
+
+ ret = devm_gpiochip_add_data(dev, gc, priv);
+ if (ret) {
+ dev_err(dev, "Unable to create gpio_chip\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int _max96717_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ static const struct v4l2_mbus_framefmt format = {
+ .width = 1280,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .field = V4L2_FIELD_NONE,
+ };
+ int ret;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int max96717_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
+ return -EBUSY;
+
+ return _max96717_set_routing(sd, state, routing);
+}
+
+static int max96717_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+ u64 stream_source_mask;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ priv->enabled_source_streams)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (format->pad == MAX96717_PAD_SOURCE)
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ /* Set sink format */
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ /* Propagate to source format */
+ fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
+ *fmt = format->format;
+
+ stream_source_mask = BIT(format->stream);
+ ret = v4l2_subdev_state_xlate_streams(state, MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &stream_source_mask);
+ return 0;
+}
+
+static int max96717_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = MAX96717_PAD_SINK,
+ .sink_stream = 0,
+ .source_pad = MAX96717_PAD_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _max96717_set_routing(sd, state, &routing);
+}
+
+static bool max96717_pipe_pclkdet(struct max96717_priv *priv)
+{
+ u8 val;
+
+ max96717_read(priv, MAX96717_VIDEO_TX2, &val);
+
+ return val & MAX96717_VIDEO_PCLKDET;
+}
+
+static int max96717_log_status(struct v4l2_subdev *sd)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Serializer: %s\n", priv->data->model);
+ dev_info(dev, "Pipe: pclkdet:%d\n", max96717_pipe_pclkdet(priv));
+
+ return 0;
+}
+
+static int max96717_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct device *dev = &priv->client->dev;
+ u64 sink_streams;
+ int ret;
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &streams_mask);
+
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, true);
+
+ ret = v4l2_subdev_enable_streams(priv->source_sd, priv->source_sd_pad,
+ sink_streams);
+ if (ret) {
+ dev_err(dev, "Fail to start streams:%llu on remote subdev\n",
+ sink_streams);
+ goto stop_csi;
+ }
+
+ priv->enabled_source_streams |= streams_mask;
+
+ return 0;
+
+stop_csi:
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, false);
+ return ret;
+
+}
+
+static int max96717_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ u64 sink_streams;
+ int ret;
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &streams_mask);
+
+ ret = v4l2_subdev_disable_streams(priv->source_sd, priv->source_sd_pad,
+ sink_streams);
+ if (ret)
+ return ret;
+
+ priv->enabled_source_streams &= ~streams_mask;
+
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, false);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops max96717_pad_ops = {
+ .enable_streams = max96717_enable_streams,
+ .disable_streams = max96717_disable_streams,
+ .set_routing = max96717_set_routing,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = max96717_set_fmt,
+ .init_cfg = max96717_init_cfg,
+};
+
+static const struct v4l2_subdev_core_ops max96717_subdev_core_ops = {
+ .log_status = max96717_log_status,
+};
+
+static const struct v4l2_subdev_ops max96717_subdev_ops = {
+ .core = &max96717_subdev_core_ops,
+ .pad = &max96717_pad_ops,
+};
+
+static const struct media_entity_operations max96717_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int max96717_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *source_subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct max96717_priv *priv = sd_to_max96717(notifier->sd);
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(&source_subdev->entity,
+ source_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n",
+ source_subdev->name);
+ return ret;
+ }
+
+ priv->source_sd = source_subdev;
+ priv->source_sd_pad = ret;
+
+ ret = media_create_pad_link(&source_subdev->entity, priv->source_sd_pad,
+ &priv->sd.entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:0\n",
+ source_subdev->name, priv->source_sd_pad,
+ priv->sd.name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations max96717_notify_ops = {
+ .bound = max96717_notify_bound,
+};
+
+static int max96717_v4l2_notifier_register(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct v4l2_async_connection *asd;
+ struct fwnode_handle *ep_fwnode;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96717_PAD_SINK, 0, 0);
+ if (!ep_fwnode) {
+ dev_err(dev, "No graph endpoint\n");
+ return -ENODEV;
+ }
+
+ v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
+
+ asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep_fwnode,
+ struct v4l2_async_connection);
+
+ fwnode_handle_put(ep_fwnode);
+
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd));
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ priv->notifier.ops = &max96717_notify_ops;
+
+ ret = v4l2_async_nf_register(&priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void max96717_v4l2_notifier_unregister(struct max96717_priv *priv)
+{
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+}
+
+static int max96717_subdev_init(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96717_subdev_ops);
+
+ priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &max96717_entity_ops;
+
+ priv->pads[0].flags = MEDIA_PAD_FL_SINK;
+ priv->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init pads\n");
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "v4l2 subdev init finalized failed\n");
+ goto err_fwnode_put;
+ }
+ ret = max96717_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "v4l2 subdev notifier register failed\n");
+ goto err_free_state;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err_probe(dev, ret, "v4l2_async_register_subdev error\n");
+ goto err_unreg_notif;
+ }
+
+ return 0;
+
+err_unreg_notif:
+ max96717_v4l2_notifier_unregister(priv);
+err_free_state:
+ v4l2_subdev_cleanup(&priv->sd);
+err_fwnode_put:
+ fwnode_handle_put(priv->sd.fwnode);
+ media_entity_cleanup(&priv->sd.entity);
+
+ return ret;
+}
+
+static void max96717_subdev_uninit(struct max96717_priv *priv)
+{
+ v4l2_async_unregister_subdev(&priv->sd);
+ max96717_v4l2_notifier_unregister(priv);
+ v4l2_subdev_cleanup(&priv->sd);
+ fwnode_handle_put(priv->sd.fwnode);
+ media_entity_cleanup(&priv->sd.entity);
+}
+
+struct max96717_pll_predef_freq {
+ unsigned long freq;
+ bool is_alt;
+ u8 val;
+};
+
+static const struct max96717_pll_predef_freq max96717_predef_freqs[] = {
+ { 13500000, true, 0 }, { 19200000, false, 0 },
+ { 24000000, true, 1 }, { 27000000, false, 1 },
+ { 37125000, false, 2 }, { 74250000, false, 3 },
+};
+
+static unsigned long
+max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ return max96717_predef_freqs[priv->pll_predef_index].freq;
+}
+
+static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv,
+ unsigned long rate)
+{
+ u8 i, idx;
+ unsigned long diff_new, diff_old;
+
+ diff_old = U32_MAX;
+ idx = 0;
+
+ for (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) {
+ diff_new = abs(rate - max96717_predef_freqs[i].freq);
+ if (diff_new < diff_old) {
+ diff_old = diff_new;
+ idx = i;
+ }
+ }
+
+ return idx;
+}
+
+static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+ struct device *dev = &priv->client->dev;
+ u8 idx;
+
+ idx = max96717_clk_find_best_index(priv, rate);
+
+ if (rate != max96717_predef_freqs[idx].freq) {
+ dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n",
+ rate, max96717_predef_freqs[idx].freq);
+ }
+
+ return max96717_predef_freqs[idx].freq;
+}
+
+static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+ int ret;
+ u8 val, idx;
+
+ idx = max96717_clk_find_best_index(priv, rate);
+
+ val = FIELD_PREP(REFGEN_PREDEF_FREQ_MASK,
+ max96717_predef_freqs[idx].val);
+
+ if (max96717_predef_freqs[idx].is_alt)
+ val |= REFGEN_PREDEF_FREQ_ALT;
+
+ val |= REFGEN_RST | REFGEN_PREDEF_EN;
+
+ ret = max96717_write(priv, REF_VTG0, val);
+ if (ret)
+ return ret;
+
+ ret = max96717_update_bits(priv, REF_VTG0,
+ REFGEN_RST | REFGEN_EN, REFGEN_EN);
+ if (ret)
+ return ret;
+
+ priv->pll_predef_index = idx;
+
+ return 0;
+}
+
+static int max96717_clk_prepare(struct clk_hw *hw)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ return max96717_update_bits(priv, MAX96717_REG6, RCLKEN, RCLKEN);
+}
+
+static void max96717_clk_unprepare(struct clk_hw *hw)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ max96717_update_bits(priv, MAX96717_REG6, RCLKEN, 0);
+}
+
+static const struct clk_ops max96717_clk_ops = {
+ .prepare = max96717_clk_prepare,
+ .unprepare = max96717_clk_unprepare,
+ .set_rate = max96717_clk_set_rate,
+ .recalc_rate = max96717_clk_recalc_rate,
+ .round_rate = max96717_clk_round_rate,
+};
+
+static int max96717_register_clkout(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ const struct clk_init_data init = {
+ .name = kasprintf(GFP_KERNEL, "%s.%s.clk_out",
+ priv->data->model,
+ dev_name(dev)),
+ .ops = &max96717_clk_ops,
+ };
+
+ if (!init.name)
+ return -ENOMEM;
+
+ /* RCLKSEL Reference PLL output */
+ ret = regmap_update_bits(priv->regmap, REG3, MAX96717_RCLKSEL,
+ RCLKSEL_REF_PLL);
+ if (ret)
+ goto free_init_name;
+
+ /* MFP4 fastest slew rate */
+ ret = regmap_update_bits(priv->regmap, PIO_SLEW_1, BIT(5) | BIT(4), 0);
+ if (ret)
+ goto free_init_name;
+
+ priv->clk_hw.init = &init;
+
+ /* Initialize to 24 MHz */
+ ret = max96717_clk_set_rate(&priv->clk_hw,
+ MAX96717_DEFAULT_CLKOUT_RATE, 0);
+ if (ret < 0)
+ goto free_init_name;
+
+ ret = devm_clk_hw_register(dev, &priv->clk_hw);
+ kfree(init.name);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register clock HW\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &priv->clk_hw);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Cannot add OF clock provider\n");
+
+ return 0;
+
+free_init_name:
+ kfree(init.name);
+ return ret;
+}
+
+static int max96717_init_csi_lanes(struct max96717_priv *priv)
+{
+ struct v4l2_mbus_config_mipi_csi2 *mipi = &priv->vep.bus.mipi_csi2;
+ unsigned long lanes_used = 0;
+ u8 nlanes, lane, val = 0;
+ int ret;
+
+ nlanes = mipi->num_data_lanes;
+
+ max96717_update_bits(priv, MAX96717_MIPI_RX1, MAX96717_MIPI_LANES_CNT,
+ FIELD_PREP(MAX96717_MIPI_LANES_CNT, nlanes - 1));
+ if (ret)
+ return ret;
+
+ for (lane = 0; lane < nlanes + 1; lane++) {
+ if (!mipi->lane_polarities[lane])
+ continue;
+ /* Clock lane */
+ if (lane == 0)
+ val |= BIT(2);
+ else if (lane < 3)
+ val |= BIT(lane - 1);
+ else
+ val |= BIT(lane);
+ }
+
+ max96717_update_bits(priv, MAX96717_MIPI_RX5, MAX96717_PHY2_LANES_POL,
+ FIELD_PREP(MAX96717_PHY2_LANES_POL, val));
+
+ max96717_update_bits(priv, MAX96717_MIPI_RX4, MAX96717_PHY1_LANES_POL,
+ FIELD_PREP(MAX96717_PHY1_LANES_POL, val >> 3));
+
+ val = 0;
+ for (lane = 0; lane < nlanes; lane++) {
+ val |= (mipi->data_lanes[lane] - 1) << (lane*2);
+ lanes_used |= BIT(mipi->data_lanes[lane] - 1);
+ }
+
+ /* Unused lanes need to be mapped as well to not have
+ * the same lanes mapped twice.
+ */
+ for (; lane < 4; lane++) {
+ unsigned int idx = find_first_zero_bit(&lanes_used, 4);
+
+ val |= idx << (lane*2);
+ lanes_used |= BIT(idx);
+ }
+
+ max96717_update_bits(priv, MAX96717_MIPI_RX3,
+ MAX96717_PHY1_LANES_MAP,
+ FIELD_PREP(MAX96717_PHY1_LANES_MAP, val));
+
+ max96717_update_bits(priv, MAX96717_MIPI_RX2,
+ MAX96717_PHY2_LANES_MAP,
+ FIELD_PREP(MAX96717_PHY2_LANES_MAP, val >> 4));
+
+ return 0;
+}
+
+static int max96717_hw_init(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u8 val;
+ int ret;
+
+ ret = max96717_read(priv, MAX96717_DEV_ID, &val);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read the device id\n");
+
+ if (val != priv->data->device_id)
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "Unsupported device id expected %x got %x\n",
+ priv->data->device_id, val);
+
+ ret = max96717_read(priv, MAX96717_DEV_REV, &val);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read device revision");
+
+ dev_dbg(dev, "Found %x (rev %lx)\n", priv->data->device_id,
+ val & MAX96717_DEV_REV_MASK);
+
+ ret = max96717_read(priv, MAX96717_MIPI_RX_EXT11, &val);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read mipi rx extension");
+
+ if (!(val & MAX96717_TUN_MODE))
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "Only supporting tunnel mode");
+
+ return max96717_init_csi_lanes(priv);
+}
+
+static int max96717_parse_dt(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct fwnode_handle *ep_fwnode;
+ unsigned char num_data_lanes;
+ int ret;
+
+ priv->vep.bus_type = V4L2_MBUS_CSI2_DPHY;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96717_PAD_SINK, 0, 0);
+ if (!ep_fwnode)
+ return dev_err_probe(dev, -ENOENT, "no endpoint found\n");
+
+ ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &priv->vep);
+
+ fwnode_handle_put(ep_fwnode);
+
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to parse sink endpoint");
+
+ num_data_lanes = priv->vep.bus.mipi_csi2.num_data_lanes;
+ if (num_data_lanes < 1 || num_data_lanes > 4)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid data lanes should be 1 to 4\n");
+
+ return 0;
+}
+
+static int max96717_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct max96717_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->data = of_device_get_match_data(&client->dev);
+
+ i2c_set_clientdata(client, priv);
+
+ priv->regmap = devm_regmap_init_i2c(client, &max96717_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ return dev_err_probe(dev, ret, "Failed to init regmap\n");
+ }
+
+ ret = max96717_parse_dt(priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to parse the dt\n");
+
+ ret = max96717_hw_init(priv);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize the hardware\n");
+
+ ret = max96717_gpiochip_probe(priv);
+ if (ret) {
+ dev_err(&client->dev, "Failed to init gpiochip\n");
+ return ret;
+ }
+
+ ret = max96717_register_clkout(priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register clkout\n");
+
+ ret = max96717_subdev_init(priv);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize v4l2 subdev\n");
+
+ ret = max96717_i2c_mux_init(priv);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to add remote i2c adapter\n");
+ goto err_subdev_uninit;
+ }
+
+ return 0;
+
+err_subdev_uninit:
+ max96717_subdev_uninit(priv);
+ return ret;
+}
+
+static void max96717_remove(struct i2c_client *client)
+{
+ struct max96717_priv *priv = i2c_get_clientdata(client);
+
+ max96717_subdev_uninit(priv);
+ i2c_mux_del_adapters(priv->mux);
+}
+
+static const struct of_device_id max96717_of_ids[] = {
+ { .compatible = "maxim,max96717f", .data = &max96717f_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max96717_of_ids);
+
+static struct i2c_driver max96717_i2c_driver = {
+ .driver = {
+ .name = "max96717",
+ .of_match_table = max96717_of_ids,
+ },
+ .probe = max96717_probe,
+ .remove = max96717_remove,
+};
+
+module_i2c_driver(max96717_i2c_driver);
+
+MODULE_DESCRIPTION("Maxim GMSL2 MAX96717 Serializer Driver");
+MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
@ 2023-12-08 15:29 ` Rob Herring
2023-12-08 17:16 ` Krzysztof Kozlowski
1 sibling, 0 replies; 16+ messages in thread
From: Rob Herring @ 2023-12-08 15:29 UTC (permalink / raw)
To: Julien Massot; +Cc: linux-media, devicetree, kernel
On Fri, 08 Dec 2023 15:33:56 +0100, Julien Massot wrote:
> Add DT bindings for Maxim MAX96714F GMSL2 Deserializer.
>
> Signed-off-by: Julien Massot <julien.massot@collabora.com>
> ---
> .../bindings/media/i2c/maxim,max96714f.yaml | 163 ++++++++++++++++++
> 1 file changed, 163 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/media/i2c/maxim,max96714f.example.dtb: /example-0/main_i2c2/gmsl-deserializer@28/i2c-gate/gmsl-serializer@40: failed to match any schema with compatible: ['maxim,max96717f']
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20231208143359.469049-2-julien.massot@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer
2023-12-08 14:33 ` [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer Julien Massot
@ 2023-12-08 15:29 ` Rob Herring
2023-12-08 17:17 ` Krzysztof Kozlowski
1 sibling, 0 replies; 16+ messages in thread
From: Rob Herring @ 2023-12-08 15:29 UTC (permalink / raw)
To: Julien Massot; +Cc: kernel, devicetree, linux-media
On Fri, 08 Dec 2023 15:33:57 +0100, Julien Massot wrote:
> Add DT bindings for Maxim MAX96717F GMSL2 Serializer.
>
> Signed-off-by: Julien Massot <julien.massot@collabora.com>
> ---
> .../bindings/media/i2c/maxim,max96717f.yaml | 144 ++++++++++++++++++
> 1 file changed, 144 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/i2c/maxim,max96717f.example.dtb: vd5661@10: port:endpoint:data-lanes:0: [1, 2] is too short
from schema $id: http://devicetree.org/schemas/media/i2c/st,st-vgxy61.yaml#
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20231208143359.469049-3-julien.massot@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
2023-12-08 15:29 ` Rob Herring
@ 2023-12-08 17:16 ` Krzysztof Kozlowski
2024-01-08 13:17 ` Julien Massot
1 sibling, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2023-12-08 17:16 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media; +Cc: kernel
On 08/12/2023 15:33, Julien Massot wrote:
> Add DT bindings for Maxim MAX96714F GMSL2 Deserializer.
>
> Signed-off-by: Julien Massot <julien.massot@collabora.com>
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC (and consider --no-git-fallback argument). It might
happen, that command when run on an older kernel, gives you outdated
entries. Therefore please be sure you base your patches on recent Linux
kernel.
Limited review follows, as robot already pointed out issues...
> ---
> .../bindings/media/i2c/maxim,max96714f.yaml | 163 ++++++++++++++++++
> 1 file changed, 163 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
> new file mode 100644
> index 000000000000..8a2a06e7e279
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
> @@ -0,0 +1,163 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) 2023 Collabora Ltd.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/maxim,max96714f.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: GMSL2 to CSI-2 Deserializer
> +
> +maintainers:
> + - Julien Massot <julien.massot@collabora.com>
> +
> +description: |
> + The MAX96714F deserializer converts GMSL2 serial inputs into MIPI
> + CSI-2 D-PHY or C-PHY formatted output. The device allows the GMSL2 link to
> + simultaneously transmit bidirectional control-channel data while forward
> + video transmissions are in progress. The MAX96714F can connect to one
> + remotely located serializer using industry-standard coax or STP
> + interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
> + the MAX96714F can select individual video stream, while the tunnel mode forward all
> + the MIPI data received by the serializer.
> +
> + The GMSL2 serial link operates at a fixed rate of 3Gbps in the
> + forward direction and 187.5Mbps in the reverse direction.
> +
> +properties:
> + compatible:
> + const: maxim,max96714f
> +
> + reg:
> + description: I2C device address
Drop
> + maxItems: 1
> +
> + enable-gpios: true
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/properties/port
> + unevaluatedProperties: false
> + description: GMSL Input
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> + description:
> + Endpoint for GMSL2-Link port.
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + unevaluatedProperties: false
> + description: CSI-2 Output
> +
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> +
> + properties:
> + data-lanes: true
> + bus-type:
> + enum:
> + - 4 # MEDIA_BUS_TYPE_CSI2_DPHY
> +
> + required:
> + - data-lanes
> + - bus-type
> +
> + required:
> + - port@1
> +
> + i2c-gate:
> + $ref: /schemas/i2c/i2c-controller.yaml
> + unevaluatedProperties: false
> + description: |
> + The MAX96714 will pass through and forward the I2C requests from the
> + incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate
> + subnode to configure a serializer.
> +
> + port0-poc-supply:
> + description: Regulator providing Power over Coax for a particular port
> +
> +required:
> + - compatible
> + - reg
> + - ports
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> + #include <dt-bindings/media/video-interfaces.h>
> +
> + main_i2c2 {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> + #address-cells = <1>;
> + #size-cells = <0>;
> + i2c-gate {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + gmsl-serializer@40 {
> + compatible = "maxim,max96717f";
> + reg = <0x40>;
Not documented.
> +...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer
2023-12-08 14:33 ` [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer Julien Massot
2023-12-08 15:29 ` Rob Herring
@ 2023-12-08 17:17 ` Krzysztof Kozlowski
1 sibling, 0 replies; 16+ messages in thread
From: Krzysztof Kozlowski @ 2023-12-08 17:17 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media; +Cc: kernel
On 08/12/2023 15:33, Julien Massot wrote:
> Add DT bindings for Maxim MAX96717F GMSL2 Serializer.
>
> Signed-off-by: Julien Massot <julien.massot@collabora.com>
> ---
> .../bindings/media/i2c/maxim,max96717f.yaml | 144 ++++++++++++++++++
> 1 file changed, 144 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96717f.yaml
>
...
> +
> + reg:
> + description: I2C device address
drop description
> + maxItems: 1
> +
...
> +
> + i2c-gate {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + vd5661@10 {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/4] media: i2c: add MAX96714 driver
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
@ 2023-12-08 17:18 ` Krzysztof Kozlowski
2024-01-08 13:20 ` Julien Massot
2023-12-09 15:54 ` kernel test robot
2023-12-10 2:13 ` kernel test robot
2 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2023-12-08 17:18 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media; +Cc: kernel
On 08/12/2023 15:33, Julien Massot wrote:
> This driver handle the MAX96714 deserializer in tunnel mode.
> The CSI output will replicate all the CSI traffic capture by
> the remote serializer.
>
> Signed-off-by: Julien Massot <julien.massot@collabora.com>
...
> +static int max96714_get_hw_resources(struct max96714_priv *priv)
> +{
> + struct device *dev = &priv->client->dev;
> +
> + priv->regmap = devm_regmap_init_i2c(priv->client,
> + &max96714_regmap_config);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + priv->gpiod_pwdn = devm_gpiod_get_optional(&priv->client->dev, "enable",
> + GPIOD_OUT_HIGH);
> + if (IS_ERR(priv->gpiod_pwdn))
> + return dev_err_probe(dev, PTR_ERR(priv->gpiod_pwdn),
A powerdown GPIO is not an enable GPIO. Please use correct name - see
gpio-consumers-common.yaml
The same applies to other patch and potentially all others...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 4/4] media: i2c: add MAX96717 driver
2023-12-08 14:33 ` [PATCH v2 4/4] media: i2c: add MAX96717 driver Julien Massot
@ 2023-12-09 4:05 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2023-12-09 4:05 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media
Cc: oe-kbuild-all, kernel, Julien Massot
Hi Julien,
kernel test robot noticed the following build warnings:
[auto build test WARNING on media-tree/master]
[also build test WARNING on linuxtv-media-stage/master linus/master v6.7-rc4 next-20231208]
[cannot apply to sailus-media-tree/streams]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Julien-Massot/dt-bindings-media-add-Maxim-MAX96714F-GMSL2-Deserializer/20231208-223758
base: git://linuxtv.org/media_tree.git master
patch link: https://lore.kernel.org/r/20231208143359.469049-5-julien.massot%40collabora.com
patch subject: [PATCH v2 4/4] media: i2c: add MAX96717 driver
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20231209/202312091123.dCDq07Qy-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231209/202312091123.dCDq07Qy-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312091123.dCDq07Qy-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/media/i2c/max96717.c: In function 'max96717_set_fmt':
>> drivers/media/i2c/max96717.c:332:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable]
332 | int ret;
| ^~~
drivers/media/i2c/max96717.c: In function 'max96717_clk_set_rate':
drivers/media/i2c/max96717.c:697:15: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
697 | val = FIELD_PREP(REFGEN_PREDEF_FREQ_MASK,
| ^~~~~~~~~~
drivers/media/i2c/max96717.c: In function 'max96717_init_csi_lanes':
drivers/media/i2c/max96717.c:804:12: warning: 'ret' is used uninitialized [-Wuninitialized]
804 | if (ret)
| ^
drivers/media/i2c/max96717.c:798:13: note: 'ret' was declared here
798 | int ret;
| ^~~
cc1: some warnings being treated as errors
vim +/ret +332 drivers/media/i2c/max96717.c
325
326 static int max96717_set_fmt(struct v4l2_subdev *sd,
327 struct v4l2_subdev_state *state,
328 struct v4l2_subdev_format *format)
329 {
330 struct max96717_priv *priv = sd_to_max96717(sd);
331 struct v4l2_mbus_framefmt *fmt;
> 332 int ret;
333 u64 stream_source_mask;
334
335 if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
336 priv->enabled_source_streams)
337 return -EBUSY;
338
339 /* No transcoding, source and sink formats must match. */
340 if (format->pad == MAX96717_PAD_SOURCE)
341 return v4l2_subdev_get_fmt(sd, state, format);
342
343 /* Set sink format */
344 fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
345 if (!fmt)
346 return -EINVAL;
347
348 *fmt = format->format;
349
350 /* Propagate to source format */
351 fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
352 format->stream);
353 if (!fmt)
354 return -EINVAL;
355 *fmt = format->format;
356
357 stream_source_mask = BIT(format->stream);
358 ret = v4l2_subdev_state_xlate_streams(state, MAX96717_PAD_SOURCE,
359 MAX96717_PAD_SINK,
360 &stream_source_mask);
361 return 0;
362 }
363
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/4] media: i2c: add MAX96714 driver
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
2023-12-08 17:18 ` Krzysztof Kozlowski
@ 2023-12-09 15:54 ` kernel test robot
2023-12-10 2:13 ` kernel test robot
2 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2023-12-09 15:54 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media
Cc: oe-kbuild-all, kernel, Julien Massot
Hi Julien,
kernel test robot noticed the following build errors:
[auto build test ERROR on media-tree/master]
[also build test ERROR on linuxtv-media-stage/master linus/master v6.7-rc4 next-20231208]
[cannot apply to sailus-media-tree/streams]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Julien-Massot/dt-bindings-media-add-Maxim-MAX96714F-GMSL2-Deserializer/20231208-223758
base: git://linuxtv.org/media_tree.git master
patch link: https://lore.kernel.org/r/20231208143359.469049-4-julien.massot%40collabora.com
patch subject: [PATCH v2 3/4] media: i2c: add MAX96714 driver
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20231209/202312092303.ww5viNmZ-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231209/202312092303.ww5viNmZ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312092303.ww5viNmZ-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/media/i2c/max96714.c: In function 'max96714_csi_status':
>> drivers/media/i2c/max96714.c:380:16: error: implicit declaration of function 'FIELD_GET' [-Werror=implicit-function-declaration]
380 | freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
| ^~~~~~~~~
drivers/media/i2c/max96714.c: In function 'max96714_init_tx_port':
>> drivers/media/i2c/max96714.c:600:15: error: implicit declaration of function 'FIELD_PREP' [-Werror=implicit-function-declaration]
600 | val = FIELD_PREP(MAX96714_CSI2_LANE_CNT_MASK, mipi->num_data_lanes - 1);
| ^~~~~~~~~~
cc1: some warnings being treated as errors
vim +/FIELD_GET +380 drivers/media/i2c/max96714.c
373
374 static void max96714_csi_status(struct max96714_priv *priv)
375 {
376 struct device *dev = &priv->client->dev;
377 u8 freq;
378
379 max96714_read(priv, MAX96714_BACKTOP25, &freq);
> 380 freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
381
382 dev_info(dev, "CSI controller DPLL freq:%u00MHz CSIPHY enabled:%d\n",
383 freq, max96714_tx_port_enabled(priv));
384 }
385
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/4] media: i2c: add MAX96714 driver
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
2023-12-08 17:18 ` Krzysztof Kozlowski
2023-12-09 15:54 ` kernel test robot
@ 2023-12-10 2:13 ` kernel test robot
2 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2023-12-10 2:13 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media
Cc: llvm, oe-kbuild-all, kernel, Julien Massot
Hi Julien,
kernel test robot noticed the following build errors:
[auto build test ERROR on media-tree/master]
[also build test ERROR on linuxtv-media-stage/master linus/master v6.7-rc4 next-20231208]
[cannot apply to sailus-media-tree/streams]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Julien-Massot/dt-bindings-media-add-Maxim-MAX96714F-GMSL2-Deserializer/20231208-223758
base: git://linuxtv.org/media_tree.git master
patch link: https://lore.kernel.org/r/20231208143359.469049-4-julien.massot%40collabora.com
patch subject: [PATCH v2 3/4] media: i2c: add MAX96714 driver
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20231210/202312101007.RRCFzwfA-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231210/202312101007.RRCFzwfA-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312101007.RRCFzwfA-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/media/i2c/max96714.c:380:9: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
^
>> drivers/media/i2c/max96714.c:600:8: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
val = FIELD_PREP(MAX96714_CSI2_LANE_CNT_MASK, mipi->num_data_lanes - 1);
^
2 errors generated.
vim +/FIELD_GET +380 drivers/media/i2c/max96714.c
373
374 static void max96714_csi_status(struct max96714_priv *priv)
375 {
376 struct device *dev = &priv->client->dev;
377 u8 freq;
378
379 max96714_read(priv, MAX96714_BACKTOP25, &freq);
> 380 freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
381
382 dev_info(dev, "CSI controller DPLL freq:%u00MHz CSIPHY enabled:%d\n",
383 freq, max96714_tx_port_enabled(priv));
384 }
385
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer
2023-12-08 17:16 ` Krzysztof Kozlowski
@ 2024-01-08 13:17 ` Julien Massot
0 siblings, 0 replies; 16+ messages in thread
From: Julien Massot @ 2024-01-08 13:17 UTC (permalink / raw)
To: Krzysztof Kozlowski, devicetree, linux-media; +Cc: kernel
Hi Krzysztof,
Thanks for the review.
On 12/8/23 18:16, Krzysztof Kozlowski wrote:
> On 08/12/2023 15:33, Julien Massot wrote:
>> Add DT bindings for Maxim MAX96714F GMSL2 Deserializer.
>>
>> Signed-off-by: Julien Massot <julien.massot@collabora.com>
>
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC (and consider --no-git-fallback argument). It might
> happen, that command when run on an older kernel, gives you outdated
> entries. Therefore please be sure you base your patches on recent Linux
> kernel.
Will do
>
> Limited review follows, as robot already pointed out issues.. >
>> ---
>> .../bindings/media/i2c/maxim,max96714f.yaml | 163 ++++++++++++++++++
>> 1 file changed, 163 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
>> new file mode 100644
>> index 000000000000..8a2a06e7e279
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96714f.yaml
>> @@ -0,0 +1,163 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +# Copyright (C) 2023 Collabora Ltd.
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/media/i2c/maxim,max96714f.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: GMSL2 to CSI-2 Deserializer
>> +
>> +maintainers:
>> + - Julien Massot <julien.massot@collabora.com>
>> +
>> +description: |
>> + The MAX96714F deserializer converts GMSL2 serial inputs into MIPI
>> + CSI-2 D-PHY or C-PHY formatted output. The device allows the GMSL2 link to
>> + simultaneously transmit bidirectional control-channel data while forward
>> + video transmissions are in progress. The MAX96714F can connect to one
>> + remotely located serializer using industry-standard coax or STP
>> + interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
>> + the MAX96714F can select individual video stream, while the tunnel mode forward all
>> + the MIPI data received by the serializer.
>> +
>> + The GMSL2 serial link operates at a fixed rate of 3Gbps in the
>> + forward direction and 187.5Mbps in the reverse direction.
>> +
>> +properties:
>> + compatible:
>> + const: maxim,max96714f
>> +
>> + reg:
>> + description: I2C device address
>
> Drop
Ok
>
>> + maxItems: 1
>> +
>> + enable-gpios: true
>> +
>> + ports:
>> + $ref: /schemas/graph.yaml#/properties/ports
>> +
>> + properties:
>> + port@0:
>> + $ref: /schemas/graph.yaml#/properties/port
>> + unevaluatedProperties: false
>> + description: GMSL Input
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> + description:
>> + Endpoint for GMSL2-Link port.
>> +
>> + port@1:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + unevaluatedProperties: false
>> + description: CSI-2 Output
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> +
>> + properties:
>> + data-lanes: true
>> + bus-type:
>> + enum:
>> + - 4 # MEDIA_BUS_TYPE_CSI2_DPHY
>> +
>> + required:
>> + - data-lanes
>> + - bus-type
>> +
>> + required:
>> + - port@1
>> +
>> + i2c-gate:
>> + $ref: /schemas/i2c/i2c-controller.yaml
>> + unevaluatedProperties: false
>> + description: |
>> + The MAX96714 will pass through and forward the I2C requests from the
>> + incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate
>> + subnode to configure a serializer.
>> +
>> + port0-poc-supply:
>> + description: Regulator providing Power over Coax for a particular port
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/gpio/gpio.h>
>> + #include <dt-bindings/media/video-interfaces.h>
>> +
>> + main_i2c2 {
>
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
Ok V3 will use generic node names.
>
>
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>
>> + i2c-gate {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + gmsl-serializer@40 {
>> + compatible = "maxim,max96717f";
>> + reg = <0x40>;
>
> Not documented.
Ok I will re-post max96717f binding first and then the max96714f binding.
Thank you,
--
Julien Massot
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/4] media: i2c: add MAX96714 driver
2023-12-08 17:18 ` Krzysztof Kozlowski
@ 2024-01-08 13:20 ` Julien Massot
2024-01-08 18:58 ` Krzysztof Kozlowski
0 siblings, 1 reply; 16+ messages in thread
From: Julien Massot @ 2024-01-08 13:20 UTC (permalink / raw)
To: Krzysztof Kozlowski, devicetree, linux-media; +Cc: kernel
On 12/8/23 18:18, Krzysztof Kozlowski wrote:
> On 08/12/2023 15:33, Julien Massot wrote:
>> This driver handle the MAX96714 deserializer in tunnel mode.
>> The CSI output will replicate all the CSI traffic capture by
>> the remote serializer.
>>
>> Signed-off-by: Julien Massot <julien.massot@collabora.com>
>
> ...
>
>> +static int max96714_get_hw_resources(struct max96714_priv *priv)
>> +{
>> + struct device *dev = &priv->client->dev;
>> +
>> + priv->regmap = devm_regmap_init_i2c(priv->client,
>> + &max96714_regmap_config);
>> + if (IS_ERR(priv->regmap))
>> + return PTR_ERR(priv->regmap);
>> +
>> + priv->gpiod_pwdn = devm_gpiod_get_optional(&priv->client->dev, "enable",
>> + GPIOD_OUT_HIGH);
>> + if (IS_ERR(priv->gpiod_pwdn))
>> + return dev_err_probe(dev, PTR_ERR(priv->gpiod_pwdn),
>
> A powerdown GPIO is not an enable GPIO. Please use correct name - see
> gpio-consumers-common.yaml
Ok I will rename it 'pwdn' instead.
Thanks,
--
Julien Massot
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/4] media: i2c: add MAX96714 driver
2024-01-08 13:20 ` Julien Massot
@ 2024-01-08 18:58 ` Krzysztof Kozlowski
0 siblings, 0 replies; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-08 18:58 UTC (permalink / raw)
To: Julien Massot, devicetree, linux-media; +Cc: kernel
On 08/01/2024 14:20, Julien Massot wrote:
>>> +static int max96714_get_hw_resources(struct max96714_priv *priv)
>>> +{
>>> + struct device *dev = &priv->client->dev;
>>> +
>>> + priv->regmap = devm_regmap_init_i2c(priv->client,
>>> + &max96714_regmap_config);
>>> + if (IS_ERR(priv->regmap))
>>> + return PTR_ERR(priv->regmap);
>>> +
>>> + priv->gpiod_pwdn = devm_gpiod_get_optional(&priv->client->dev, "enable",
>>> + GPIOD_OUT_HIGH);
>>> + if (IS_ERR(priv->gpiod_pwdn))
>>> + return dev_err_probe(dev, PTR_ERR(priv->gpiod_pwdn),
>>
>> A powerdown GPIO is not an enable GPIO. Please use correct name - see
>> gpio-consumers-common.yaml
> Ok I will rename it 'pwdn' instead.
Did you open that file and read it?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2024-01-08 18:59 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-08 14:33 [PATCH v2 0/4] Add support for MAX96714F and MAX96717F GMSL2 ser/des Julien Massot
2023-12-08 14:33 ` [PATCH v2 1/4] dt-bindings: media: add Maxim MAX96714F GMSL2 Deserializer Julien Massot
2023-12-08 15:29 ` Rob Herring
2023-12-08 17:16 ` Krzysztof Kozlowski
2024-01-08 13:17 ` Julien Massot
2023-12-08 14:33 ` [PATCH v2 2/4] dt-bindings: media: add Maxim MAX96717F GMSL2 Serializer Julien Massot
2023-12-08 15:29 ` Rob Herring
2023-12-08 17:17 ` Krzysztof Kozlowski
2023-12-08 14:33 ` [PATCH v2 3/4] media: i2c: add MAX96714 driver Julien Massot
2023-12-08 17:18 ` Krzysztof Kozlowski
2024-01-08 13:20 ` Julien Massot
2024-01-08 18:58 ` Krzysztof Kozlowski
2023-12-09 15:54 ` kernel test robot
2023-12-10 2:13 ` kernel test robot
2023-12-08 14:33 ` [PATCH v2 4/4] media: i2c: add MAX96717 driver Julien Massot
2023-12-09 4:05 ` kernel test robot
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).