Devicetree
 help / color / mirror / Atom feed
* [PATCH 4/8] ARM: dts: armada-xp-linksys-mamba: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: vivien.didelot, Florian Fainelli, Jason Cooper, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Rob Herring, Mark Rutland,
	Russell King,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-xp-linksys-mamba.dts | 53 +++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 83ac884c0f8a..42ea8764814c 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -302,6 +302,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -398,3 +400,54 @@
 		spi-max-frequency = <40000000>;
 	};
 };
+
+&mdio {
+	status = "okay";
+
+	switch@0 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				label = "lan4";
+			};
+
+			port@1 {
+				reg = <1>;
+				label = "lan3";
+			};
+
+			port@2 {
+				reg = <2>;
+				label = "lan2";
+			};
+
+			port@3 {
+				reg = <3>;
+				label = "lan1";
+			};
+
+			port@4 {
+				reg = <4>;
+				label = "internet";
+			};
+
+			port@5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth0>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH 3/8] ARM: dts: armada-388-clearfog: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Andrew Lunn, Florian Fainelli, Jason Cooper,
	vivien.didelot, Russell King, open list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Rob Herring, Gregory Clement, Sebastian Hesselbarth
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net:
dsa: Document new binding"). The legacy binding node is kept included, but is
marked disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-388-clearfog.dts | 65 +++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/arch/arm/boot/dts/armada-388-clearfog.dts b/arch/arm/boot/dts/armada-388-clearfog.dts
index 71ce201c903e..35207aa1f4ec 100644
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
@@ -351,6 +351,8 @@
 	};
 
 	dsa@0 {
+		status = "okay";
+
 		compatible = "marvell,dsa";
 		dsa,ethernet = <&eth1>;
 		dsa,mii-bus = <&mdio>;
@@ -444,3 +446,66 @@
 		status = "disabled";
 	};
 };
+
+&mdio {
+	status = "okay";
+
+	switch@4 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <4>;
+		pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>;
+		pinctrl-names = "default";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				label = "lan5";
+			};
+
+			port@1 {
+				reg = <1>;
+				label = "lan4";
+			};
+
+			port@2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port@3 {
+				reg = <3>;
+				label = "lan2";
+			};
+
+			port@4 {
+				reg = <4>;
+				label = "lan1";
+			};
+
+			port@5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth1>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+
+			port@6 {
+				/* 88E1512 external phy */
+				reg = <6>;
+				label = "lan6";
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH 2/8] ARM: dts: armada-38x: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Andrew Lunn, Florian Fainelli, Jason Cooper,
	vivien.didelot, Russell King, open list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Rob Herring, Gregory Clement, Sebastian Hesselbarth
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-385-linksys.dtsi | 52 ++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index 8f0e508f64ae..20d5e8b00f2d 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -103,8 +103,56 @@
 				};
 			};
 
-			mdio {
+			mdio@72004 {
 				status = "okay";
+
+				switch@0 {
+					compatible = "marvell,mv88e6095";
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0>;
+							label = "lan4";
+						};
+
+						port@1 {
+							reg = <1>;
+							label = "lan3";
+						};
+
+						port@2 {
+							reg = <2>;
+							label = "lan2";
+						};
+
+						port@3 {
+							reg = <3>;
+							label = "lan1";
+						};
+
+						port@4 {
+							reg = <4>;
+							label = "wan";
+						};
+
+						port@5 {
+							reg = <5>;
+							label = "cpu";
+							ethernet = <&eth2>;
+
+							fixed-link {
+								speed = <1000>;
+								full-duplex;
+							};
+						};
+					};
+				};
 			};
 
 			sata@a8000 {
@@ -261,6 +309,8 @@
 	};
 
 	dsa@0 {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
-- 
2.9.3

^ permalink raw reply related

* [PATCH 1/8] ARM: dts: armada-370-rd: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: vivien.didelot, Florian Fainelli, Jason Cooper, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Rob Herring, Mark Rutland,
	Russell King,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-370-rd.dts | 44 +++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index c3fd6e49212f..9c6e924ac0b3 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -173,6 +173,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -235,6 +237,48 @@
 	phy0: ethernet-phy@0 {
 		reg = <0>;
 	};
+
+	switch: switch@10 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <16>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				label = "lan0";
+			};
+
+			port@1 {
+			       reg = <1>;
+			       label = "lan1";
+			};
+
+			port@2 {
+			       reg = <2>;
+			       label = "lan2";
+			};
+
+			port@3 {
+			       reg = <3>;
+			       label = "lan3";
+			};
+
+			port@5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth1>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
 };
 
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH 0/8] ARM: dts: Switch to new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: vivien.didelot-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/, Florian Fainelli,
	Jason Cooper, Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Rob Herring, Mark Rutland, Russell King,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list

Hi all,

This patch series converts the in-tree users to utilize the new (relatively)
DSA binding that was introduced with commit 8c5ad1d6179d ("net: dsa: Document
new binding"). The legacy binding node is kept included, but is marked
disabled.

In about 2-3 releases we may consider removing the old DSA binding entirely
from the kernel.

Thank you!

Florian Fainelli (8):
  ARM: dts: armada-370-rd: Utilize new DSA binding
  ARM: dts: armada-38x: Utilize new DSA binding
  ARM: dts: armada-388-clearfog: Utilize new DSA binding
  ARM: dts: armada-xp-linksys-mamba: Utilize new DSA binding
  ARM: dts: kirkwood-dir665: Utilize new DSA binding
  ARM: dts: kirkwood-linksys-viper: Utilize new DSA binding
  ARM: dts: kirkwood-mv88f6281gtw-ge: Utilize new DSA binding
  ARM: dts: kirkwood-rd88f6281: Utilize new DSA binding

 arch/arm/boot/dts/armada-370-rd.dts            | 44 +++++++++++++++++
 arch/arm/boot/dts/armada-385-linksys.dtsi      | 52 ++++++++++++++++++++-
 arch/arm/boot/dts/armada-388-clearfog.dts      | 65 ++++++++++++++++++++++++++
 arch/arm/boot/dts/armada-xp-linksys-mamba.dts  | 53 +++++++++++++++++++++
 arch/arm/boot/dts/kirkwood-dir665.dts          | 49 +++++++++++++++++++
 arch/arm/boot/dts/kirkwood-linksys-viper.dts   | 49 +++++++++++++++++++
 arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts | 49 +++++++++++++++++++
 arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts    | 11 +++++
 arch/arm/boot/dts/kirkwood-rd88f6281.dtsi      | 44 +++++++++++++++++
 9 files changed, 415 insertions(+), 1 deletion(-)

-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH V7 4/4] dts/imx6q-b850v3: Use GE B850v3 LVDS/DP++ Bridge
From: Peter Senna Tschudin @ 2017-01-01 20:24 UTC (permalink / raw)
  To: airlied-cv59FeDIM0c, architt-sgV2jX0FEOL9JmXXK+q4OQ,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, daniel.vetter-/w4YWyX8dFk,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, devicetree-u79uwXL29TY76Z2rM5mHXA,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	enric.balletbo-ZGY8ohtN/8qB+jHODAdFcQ,
	eballetbo-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	heiko-4mtYJXux2i+zQB+pC5nmwQ,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	javier-0uQlZySMnqxg9hUCZPvPmw, jslaby-AlSwsSmVLrQ,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-0h96xk9xTtrk1uMJSBkQmQ, mark.rutland-5wv7dgnIgG8,
	martin.donnelly-JJi787mZWgc, martyn.welch-ZGY8ohtN/8pPYcu2f3hruQ,
	mchehab-JPH+aEBZ4P+UEJcrhfAQsw, pawel.moll-5wv7dgnIgG8,
	peter.senna-ZGY8ohtN/8qB+jHODAdFcQ,
	peter.senna-Re5JQEeQqe8AvxtiuMwx3w,
	p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A
  Cc: Rob Herring, Fabio Estevam
In-Reply-To: <cover.1483301745.git.peter.senna-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>

Configures the GE B850v3 LVDS/DP++ bridge on the dts file.

Cc: Martyn Welch <martyn.welch-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
Cc: Martin Donnelly <martin.donnelly-JJi787mZWgc@public.gmane.org>
Cc: Javier Martinez Canillas <javier-0uQlZySMnqxg9hUCZPvPmw@public.gmane.org>
Cc: Enric Balletbo i Serra <enric.balletbo-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
Cc: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Fabio Estevam <fabio.estevam-3arQi8VN3Tc@public.gmane.org>
Signed-off-by: Peter Senna Tschudin <peter.senna-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
---
 arch/arm/boot/dts/imx6q-b850v3.dts | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q-b850v3.dts b/arch/arm/boot/dts/imx6q-b850v3.dts
index 167f744..ce0ca3a 100644
--- a/arch/arm/boot/dts/imx6q-b850v3.dts
+++ b/arch/arm/boot/dts/imx6q-b850v3.dts
@@ -72,6 +72,13 @@
 		fsl,data-mapping = "spwg";
 		fsl,data-width = <24>;
 		status = "okay";
+
+		port@4 {
+			reg = <4>;
+			lvds0_out: endpoint {
+				remote-endpoint = <&b850v3_lvds_dp_bridge_in>;
+			};
+		};
 	};
 };
 
@@ -142,3 +149,26 @@
 		reg = <0x4a>;
 	};
 };
+
+&mux2_i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+
+	b850v3-lvds-dp-bridge@73 {
+		compatible = "ge,b850v3-lvds-dp";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg = <0x73 0x72>;
+		reg-names = "main", "edid";
+
+		interrupt-parent = <&gpio2>;
+		interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+		port {
+			b850v3_lvds_dp_bridge_in: endpoint {
+				remote-endpoint = <&lvds0_out>;
+			};
+		};
+	};
+};
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH V7 3/4] drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
From: Peter Senna Tschudin @ 2017-01-01 20:24 UTC (permalink / raw)
  To: airlied, architt, akpm, daniel.vetter, davem, devicetree,
	dri-devel, enric.balletbo, eballetbo, galak, gregkh, heiko,
	ijc+devicetree, javier, jslaby, kernel, linux-arm-kernel, linux,
	linux-kernel, linux, mark.rutland, martin.donnelly, martyn.welch,
	mchehab, pawel.moll, peter.senna, peter.senna, p.zabel,
	thierry.reding, rmk+kernel, robh+dt, shawnguo
  Cc: Rob Herring, Fabio Estevam
In-Reply-To: <cover.1483301745.git.peter.senna@collabora.com>

Add a driver that create a drm_bridge and a drm_connector for the LVDS
to DP++ display bridge of the GE B850v3.

There are two physical bridges on the video signal pipeline: a
STDP4028(LVDS to DP) and a STDP2690(DP to DP++).  The hardware and
firmware made it complicated for this binding to comprise two device
tree nodes, as the design goal is to configure both bridges based on
the LVDS signal, which leave the driver powerless to control the video
processing pipeline. The two bridges behaves as a single bridge, and
the driver is only needed for telling the host about EDID / HPD, and
for giving the host powers to ack interrupts. The video signal pipeline
is as follows:

  Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output

Cc: Martyn Welch <martyn.welch@collabora.co.uk>
Cc: Martin Donnelly <martin.donnelly@ge.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
CC: David Airlie <airlied@linux.ie>
CC: Thierry Reding <treding@nvidia.com>
CC: Thierry Reding <thierry.reding@gmail.com>
CC: Archit Taneja <architt@codeaurora.org>
Reviewed-by: Enric Balletbo <enric.balletbo@collabora.com>
Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
---
 drivers/gpu/drm/bridge/Kconfig             |  11 +
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c | 384 +++++++++++++++++++++++++++++
 3 files changed, 396 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index eb8688e..e3e1f3b 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -48,6 +48,17 @@ config DRM_DW_HDMI_I2S_AUDIO
 	  Support the I2S Audio interface which is part of the Synopsis
 	  Designware HDMI block.
 
+config DRM_GE_B850V3_LVDS_DP
+	tristate "GE B850v3 LVDS to DP++ display bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_PANEL
+	---help---
+          This is a driver for the display bridge of
+          GE B850v3 that convert dual channel LVDS
+          to DP++. This is used with the i.MX6 imx-ldb
+          driver.
+
 config DRM_NXP_PTN3460
 	tristate "NXP PTN3460 DP/LVDS bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 2e83a785..886d0fd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
+obj-$(CONFIG_DRM_GE_B850V3_LVDS_DP) += ge_b850v3_lvds_dp.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
diff --git a/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
new file mode 100644
index 0000000..4574f6e
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c
@@ -0,0 +1,384 @@
+/*
+ * Driver for GE B850v3 DP display bridge
+
+ * Copyright (c) 2016, Collabora Ltd.
+ * Copyright (c) 2016, General Electric Company
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
+ * display bridge of the GE B850v3. There are two physical bridges on the video
+ * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). However
+ * the physical bridges are automatically configured by the input video signal,
+ * and the driver has no access to the video processing pipeline. The driver is
+ * only needed to read EDID from the STDP2690 and to handle HPD events from the
+ * STDP4028. The driver communicates with both bridges over i2c. The video
+ * signal pipeline is as follows:
+ *
+ *   Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drmP.h>
+
+#define DEFAULT_EDID_REG 0x72
+#define DEFAULT_EDID_REG_NAME "edid"
+
+#define EDID_EXT_BLOCK_CNT 0x7E
+
+#define STDP4028_IRQ_OUT_CONF_REG 0x02
+#define STDP4028_DPTX_IRQ_EN_REG 0x3C
+#define STDP4028_DPTX_IRQ_STS_REG 0x3D
+#define STDP4028_DPTX_STS_REG 0x3E
+
+#define STDP4028_DPTX_DP_IRQ_EN 0x1000
+
+#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
+#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
+#define STDP4028_DPTX_IRQ_CONFIG \
+		(STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
+
+#define STDP4028_DPTX_HOTPLUG_STS 0x0200
+#define STDP4028_DPTX_LINK_STS 0x1000
+#define STDP4028_CON_STATE_CONNECTED \
+		(STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
+
+#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
+#define STDP4028_DPTX_LINK_CH_STS 0x2000
+#define STDP4028_DPTX_IRQ_CLEAR \
+		(STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
+
+struct ge_b850v3_lvds_dp {
+	struct drm_connector connector;
+	struct drm_bridge bridge;
+	struct i2c_client *ge_b850v3_lvds_dp_i2c;
+	struct i2c_client *edid_i2c;
+	struct edid *edid;
+	struct mutex edid_mutex;
+	struct mutex irq_reg_mutex;
+};
+
+static inline struct ge_b850v3_lvds_dp *
+		bridge_to_ge_b850v3_lvds_dp(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ge_b850v3_lvds_dp, bridge);
+}
+
+static inline struct ge_b850v3_lvds_dp *
+		connector_to_ge_b850v3_lvds_dp(struct drm_connector *connector)
+{
+	return container_of(connector, struct ge_b850v3_lvds_dp, connector);
+}
+
+u8 *stdp2690_get_edid(struct i2c_client *client)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	unsigned char start = 0x00;
+	unsigned int total_size;
+	u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
+
+	struct i2c_msg msgs[] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0,
+			.len	= 1,
+			.buf	= &start,
+		}, {
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= EDID_LENGTH,
+			.buf	= block,
+		}
+	};
+
+	if (!block)
+		return NULL;
+
+	if (i2c_transfer(adapter, msgs, 2) != 2) {
+		DRM_ERROR("Unable to read EDID.\n");
+		goto err;
+	}
+
+	if (!drm_edid_block_valid(block, 0, false, NULL)) {
+		DRM_ERROR("Invalid EDID block\n");
+		goto err;
+	}
+
+	total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
+	if (total_size > EDID_LENGTH) {
+		kfree(block);
+		block = kmalloc(total_size, GFP_KERNEL);
+		if (!block)
+			return NULL;
+
+		/* Yes, read the entire buffer, and do not skip the first
+		 * EDID_LENGTH bytes.
+		 */
+		start = 0x00;
+		msgs[1].len = total_size;
+		msgs[1].buf = block;
+
+		if (i2c_transfer(adapter, msgs, 2) != 2) {
+			DRM_ERROR("Unable to read EDID extension blocks.\n");
+			goto err;
+		}
+	}
+
+	return block;
+
+err:
+	kfree(block);
+	return NULL;
+}
+
+static int ge_b850v3_lvds_dp_get_modes(struct drm_connector *connector)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge;
+	struct i2c_client *client;
+	int num_modes = 0;
+
+	ptn_bridge = connector_to_ge_b850v3_lvds_dp(connector);
+	client = ptn_bridge->edid_i2c;
+
+	mutex_lock(&ptn_bridge->edid_mutex);
+
+	kfree(ptn_bridge->edid);
+	ptn_bridge->edid = (struct edid *) stdp2690_get_edid(client);
+
+	if (ptn_bridge->edid) {
+		drm_mode_connector_update_edid_property(connector,
+				ptn_bridge->edid);
+		num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
+	}
+
+	mutex_unlock(&ptn_bridge->edid_mutex);
+
+	return num_modes;
+}
+
+
+static enum drm_mode_status ge_b850v3_lvds_dp_mode_valid(
+		struct drm_connector *connector, struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static const struct
+drm_connector_helper_funcs ge_b850v3_lvds_dp_connector_helper_funcs = {
+	.get_modes = ge_b850v3_lvds_dp_get_modes,
+	.mode_valid = ge_b850v3_lvds_dp_mode_valid,
+};
+
+static enum drm_connector_status ge_b850v3_lvds_dp_detect(
+		struct drm_connector *connector, bool force)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge =
+			connector_to_ge_b850v3_lvds_dp(connector);
+	struct i2c_client *ge_b850v3_lvds_dp_i2c =
+			ptn_bridge->ge_b850v3_lvds_dp_i2c;
+	s32 link_state;
+
+	link_state = i2c_smbus_read_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_DPTX_STS_REG);
+
+	if (link_state == STDP4028_CON_STATE_CONNECTED)
+		return connector_status_connected;
+
+	if (link_state == 0)
+		return connector_status_disconnected;
+
+	return connector_status_unknown;
+}
+
+static const struct drm_connector_funcs ge_b850v3_lvds_dp_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = ge_b850v3_lvds_dp_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static irqreturn_t ge_b850v3_lvds_dp_irq_handler(int irq, void *dev_id)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge = dev_id;
+	struct i2c_client *ge_b850v3_lvds_dp_i2c
+			= ptn_bridge->ge_b850v3_lvds_dp_i2c;
+
+	mutex_lock(&ptn_bridge->irq_reg_mutex);
+
+	i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
+
+	mutex_unlock(&ptn_bridge->irq_reg_mutex);
+
+	if (ptn_bridge->connector.dev)
+		drm_kms_helper_hotplug_event(ptn_bridge->connector.dev);
+
+	return IRQ_HANDLED;
+}
+
+static int ge_b850v3_lvds_dp_attach(struct drm_bridge *bridge)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge
+			= bridge_to_ge_b850v3_lvds_dp(bridge);
+	struct drm_connector *connector = &ptn_bridge->connector;
+	struct i2c_client *ge_b850v3_lvds_dp_i2c
+			= ptn_bridge->ge_b850v3_lvds_dp_i2c;
+	int ret;
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(connector,
+			&ge_b850v3_lvds_dp_connector_helper_funcs);
+
+	ret = drm_connector_init(bridge->dev, connector,
+			&ge_b850v3_lvds_dp_connector_funcs,
+			DRM_MODE_CONNECTOR_DisplayPort);
+	if (ret) {
+		DRM_ERROR("Failed to initialize connector with drm\n");
+		return ret;
+	}
+
+	ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
+	if (ret)
+		return ret;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	/* Configures the bridge to re-enable interrupts after each ack. */
+	i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_IRQ_OUT_CONF_REG, STDP4028_DPTX_DP_IRQ_EN);
+
+	/* Enable interrupts */
+	i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_DPTX_IRQ_EN_REG, STDP4028_DPTX_IRQ_CONFIG);
+
+	return 0;
+}
+
+static void ge_b850v3_lvds_dp_detach(struct drm_bridge *bridge)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge
+			= bridge_to_ge_b850v3_lvds_dp(bridge);
+	struct i2c_client *ge_b850v3_lvds_dp_i2c
+			= ptn_bridge->ge_b850v3_lvds_dp_i2c;
+
+	/* Disable interrupts */
+	i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_DPTX_IRQ_EN_REG, ~STDP4028_DPTX_IRQ_CONFIG);
+}
+
+static const struct drm_bridge_funcs ge_b850v3_lvds_dp_funcs = {
+	.attach = ge_b850v3_lvds_dp_attach,
+	.detach = ge_b850v3_lvds_dp_detach,
+};
+
+static int ge_b850v3_lvds_dp_probe(struct i2c_client *ge_b850v3_lvds_dp_i2c,
+				const struct i2c_device_id *id)
+{
+	struct device *dev = &ge_b850v3_lvds_dp_i2c->dev;
+	struct ge_b850v3_lvds_dp *ptn_bridge;
+
+	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
+	if (!ptn_bridge)
+		return -ENOMEM;
+
+	mutex_init(&ptn_bridge->edid_mutex);
+	mutex_init(&ptn_bridge->irq_reg_mutex);
+
+	ptn_bridge->ge_b850v3_lvds_dp_i2c = ge_b850v3_lvds_dp_i2c;
+	ptn_bridge->bridge.driver_private = ptn_bridge;
+	i2c_set_clientdata(ge_b850v3_lvds_dp_i2c, ptn_bridge);
+
+	ptn_bridge->edid_i2c = i2c_new_secondary_device(ge_b850v3_lvds_dp_i2c,
+			DEFAULT_EDID_REG_NAME, DEFAULT_EDID_REG);
+
+	if (!ptn_bridge->edid_i2c) {
+		dev_err(dev, "Error registering edid i2c_client, aborting...\n");
+		return -ENODEV;
+	}
+
+	ptn_bridge->bridge.funcs = &ge_b850v3_lvds_dp_funcs;
+	ptn_bridge->bridge.of_node = dev->of_node;
+	drm_bridge_add(&ptn_bridge->bridge);
+
+	/* Clear pending interrupts since power up. */
+	i2c_smbus_write_word_data(ge_b850v3_lvds_dp_i2c,
+			STDP4028_DPTX_IRQ_STS_REG, STDP4028_DPTX_IRQ_CLEAR);
+
+	if (!ge_b850v3_lvds_dp_i2c->irq)
+		return 0;
+
+	return devm_request_threaded_irq(&ge_b850v3_lvds_dp_i2c->dev,
+			ge_b850v3_lvds_dp_i2c->irq, NULL,
+			ge_b850v3_lvds_dp_irq_handler,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+			"ge-b850v3-lvds-dp", ptn_bridge);
+}
+
+static int ge_b850v3_lvds_dp_remove(struct i2c_client *ge_b850v3_lvds_dp_i2c)
+{
+	struct ge_b850v3_lvds_dp *ptn_bridge =
+		i2c_get_clientdata(ge_b850v3_lvds_dp_i2c);
+
+	i2c_unregister_device(ptn_bridge->edid_i2c);
+
+	drm_bridge_remove(&ptn_bridge->bridge);
+
+	kfree(ptn_bridge->edid);
+
+	return 0;
+}
+
+static const struct i2c_device_id ge_b850v3_lvds_dp_i2c_table[] = {
+	{"b850v3-lvds-dp", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ge_b850v3_lvds_dp_i2c_table);
+
+static const struct of_device_id ge_b850v3_lvds_dp_match[] = {
+	{ .compatible = "ge,b850v3-lvds-dp" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ge_b850v3_lvds_dp_match);
+
+static struct i2c_driver ge_b850v3_lvds_dp_driver = {
+	.id_table	= ge_b850v3_lvds_dp_i2c_table,
+	.probe		= ge_b850v3_lvds_dp_probe,
+	.remove		= ge_b850v3_lvds_dp_remove,
+	.driver		= {
+		.name		= "b850v3-lvds-dp",
+		.of_match_table = ge_b850v3_lvds_dp_match,
+	},
+};
+module_i2c_driver(ge_b850v3_lvds_dp_driver);
+
+MODULE_AUTHOR("Peter Senna Tschudin <peter.senna@collabora.com>");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk>");
+MODULE_DESCRIPTION("GE LVDS to DP++ display bridge)");
+MODULE_LICENSE("GPL v2");
-- 
2.5.5

^ permalink raw reply related

* [PATCH V7 2/4] MAINTAINERS: Add entry for GE B850v3 LVDS/DP++ Bridge
From: Peter Senna Tschudin @ 2017-01-01 20:24 UTC (permalink / raw)
  To: airlied, architt, akpm, daniel.vetter, davem, devicetree,
	dri-devel, enric.balletbo, eballetbo, galak, gregkh, heiko,
	ijc+devicetree, javier, jslaby, kernel, linux-arm-kernel, linux,
	linux-kernel, linux, mark.rutland, martin.donnelly, martyn.welch,
	mchehab, pawel.moll, peter.senna, peter.senna, p.zabel,
	thierry.reding, rmk+kernel, robh+dt, shawnguo
  Cc: Rob Herring, Fabio Estevam
In-Reply-To: <cover.1483301745.git.peter.senna@collabora.com>

Update the MAINTAINERS file for the GE B850v3 LVDS/DP++ Bridge.

Cc: Martyn Welch <martyn.welch@collabora.co.uk>
Cc: Martin Donnelly <martin.donnelly@ge.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
CC: David Airlie <airlied@linux.ie>
CC: Thierry Reding <treding@nvidia.com>
CC: Thierry Reding <thierry.reding@gmail.com>
CC: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fdd9d5e3..1d3f17a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5371,6 +5371,14 @@ W:	https://linuxtv.org
 S:	Maintained
 F:	drivers/media/radio/radio-gemtek*
 
+GENERAL ELECTRIC B850V3 LVDS/DP++ BRIDGE
+M:	Peter Senna Tschudin <peter.senna@collabora.com>
+M:	Martin Donnelly <martin.donnelly@ge.com>
+M:	Martyn Welch <martyn.welch@collabora.co.uk>
+S:	Maintained
+F:	drivers/gpu/drm/bridge/ge_b850v3_dp2.c
+F:	Documentation/devicetree/bindings/ge/b850v3_dp2_bridge.txt
+
 GENERIC GPIO I2C DRIVER
 M:	Haavard Skinnemoen <hskinnemoen@gmail.com>
 S:	Supported
-- 
2.5.5

^ permalink raw reply related

* [PATCH V7 1/4] Documentation/devicetree/bindings: b850v3_lvds_dp
From: Peter Senna Tschudin @ 2017-01-01 20:24 UTC (permalink / raw)
  To: airlied, architt, akpm, daniel.vetter, davem, devicetree,
	dri-devel, enric.balletbo, eballetbo, galak, gregkh, heiko,
	ijc+devicetree, javier, jslaby, kernel, linux-arm-kernel, linux,
	linux-kernel, linux, mark.rutland, martin.donnelly, martyn.welch,
	mchehab, pawel.moll, peter.senna, peter.senna, p.zabel,
	thierry.reding, rmk+kernel, robh+dt, shawnguo
  Cc: Rob Herring, Fabio Estevam
In-Reply-To: <cover.1483301745.git.peter.senna@collabora.com>

Devicetree bindings documentation for the GE B850v3 LVDS/DP++
display bridge.

Cc: Martyn Welch <martyn.welch@collabora.co.uk>
Cc: Martin Donnelly <martin.donnelly@ge.com>
Cc: Javier Martinez Canillas <javier@dowhile0.org>
Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Peter Senna Tschudin <peter.senna@collabora.com>
---
There was an Acked-by from Rob Herring <robh@kernel.org> for V6, but I changed
the bindings to use i2c_new_secondary_device() so I removed it from the commit
message.

 .../devicetree/bindings/ge/b850v3-lvds-dp.txt      | 39 ++++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt

diff --git a/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt b/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
new file mode 100644
index 0000000..1bc6ebf
--- /dev/null
+++ b/Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
@@ -0,0 +1,39 @@
+Driver for GE B850v3 LVDS/DP++ display bridge
+
+Required properties:
+  - compatible : should be "ge,b850v3-lvds-dp".
+  - reg : should contain the main address which is used to ack the
+    interrupts and address for edid.
+  - reg-names : comma separeted list of register names. Valid values
+    are "main", and "edid".
+  - interrupt-parent : phandle of the interrupt controller that services
+    interrupts to the device
+  - interrupts : one interrupt should be described here, as in
+    <0 IRQ_TYPE_LEVEL_HIGH>.
+  - port : should describe the video signal connection between the host
+    and the bridge.
+
+Example:
+
+&mux2_i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+
+	b850v3-lvds-dp-bridge@73  {
+		compatible = "ge,b850v3-lvds-dp";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg = <0x73 0x72>;
+		reg-names = "main", "edid";
+
+		interrupt-parent = <&gpio2>;
+		interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+		port {
+			b850v3_dp_bridge_in: endpoint {
+				remote-endpoint = <&lvds0_out>;
+			};
+		};
+	};
+};
-- 
2.5.5

^ permalink raw reply related

* [PATCH V7 0/4] Add driver for GE B850v3 LVDS/DP++ Bridge
From: Peter Senna Tschudin @ 2017-01-01 20:24 UTC (permalink / raw)
  To: airlied-cv59FeDIM0c, architt-sgV2jX0FEOL9JmXXK+q4OQ,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, daniel.vetter-/w4YWyX8dFk,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, devicetree-u79uwXL29TY76Z2rM5mHXA,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	enric.balletbo-ZGY8ohtN/8qB+jHODAdFcQ,
	eballetbo-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	heiko-4mtYJXux2i+zQB+pC5nmwQ,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	javier-0uQlZySMnqxg9hUCZPvPmw, jslaby-AlSwsSmVLrQ,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-0h96xk9xTtrk1uMJSBkQmQ, mark.rutland-5wv7dgnIgG8,
	martin.donnelly-JJi787mZWgc, martyn.welch-ZGY8ohtN/8pPYcu2f3hruQ,
	mchehab-JPH+aEBZ4P+UEJcrhfAQsw, pawel.moll-5wv7dgnIgG8,
	peter.senna-ZGY8ohtN/8qB+jHODAdFcQ,
	peter.senna-Re5JQEeQqe8AvxtiuMwx3w,
	p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A

The series adds a driver that creates a drm_bridge and a drm_connector for the
LVDS to DP++ display bridge of the GE B850v3.

There are two physical bridges on the video signal pipeline: a STDP4028(LVDS to
DP) and a STDP2690(DP to DP++).  The hardware and firmware made it complicated
for this binding to comprise two device tree nodes, as the design goal is to
configure both bridges based on the LVDS signal, which leave the driver
powerless to control the video processing pipeline. The two bridges behaves as
a single bridge, and the driver is only needed for telling the host about EDID /
HPD, and for giving the host powers to ack interrupts. The video signal
pipeline is as follows:

  Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output

This series depends on commit dc80d7038883 ("drm/imx-ldb: Add support to
drm-bridge") which is already on linux-next.

The patches from the series:
 [1/4] Devicetree documentation for the GE B850v3 LVDS/DP++ Bridge

 [2/4] Update the MAINTAINERS file

 [3/4] Add the driver, make changes to Kconfig and Makefile

 [4/4] Make the changes to the B850v3 dts file to enable the GE B850v3
       LVDS/DP++ Bridge.

Tested on next20161224.

Changes from V6:
 - Removed check for pixel clock as the bridge supports up to 330Mhz while the
   host is limited to 264 MHz in very specific conditions.
 - Added a second mutex to avoid concurrency issues while acking interrupts
   from threaded interrupt handlers.
 - Renamed the edid mutex to be more descriptive.
 - Added a .detach() function that disables the interrupts.
 - Adopted i2c_new_secondary_device() and updated the dts and documentation to
   match the new method.
 - Removed useless test to drm_bridge_add()
 - Did some refactoring around devm_request_threaded_irq()
 - Added a missing call to i2c_unregister_device() on the i2c_driver.remove()
   function.

Changes from V5:
 - Change to MAINTAINERS in a separate patch
 - Reworked interrupt handler initialization
 - Removed useless calls to: drm_connector_register(),
   drm_helper_hpd_irq_event(), and drm_bridge_enable()

Changes from V4:
 - Renamed the i2c_driver.name from "ge,b850v3-lvds-dp" to "b850v3-lvds-dp" to
   remove the comma from the driver name

Changes from V3:
 - Removed the patch that was configuring the mapping between IPUs and external
   displays on the dts file

Peter Senna Tschudin (4):
  Documentation/devicetree/bindings: b850v3_lvds_dp
  MAINTAINERS: Add entry for GE B850v3 LVDS/DP++ Bridge
  drm/bridge: Add driver for GE B850v3 LVDS/DP++ Bridge
  dts/imx6q-b850v3: Use GE B850v3 LVDS/DP++ Bridge

 .../devicetree/bindings/ge/b850v3-lvds-dp.txt      |  39 +++
 MAINTAINERS                                        |   8 +
 arch/arm/boot/dts/imx6q-b850v3.dts                 |  30 ++
 drivers/gpu/drm/bridge/Kconfig                     |  11 +
 drivers/gpu/drm/bridge/Makefile                    |   1 +
 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c         | 384 +++++++++++++++++++++
 6 files changed, 473 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/ge/b850v3-lvds-dp.txt
 create mode 100644 drivers/gpu/drm/bridge/ge_b850v3_lvds_dp.c

-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] net: stmmac: remove unused duplicate property snps,axi_all
From: David Miller @ 2017-01-01 16:55 UTC (permalink / raw)
  To: niklas.cassel-VrBV9hrLPhE
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	peppe.cavallaro-qxv4g6HH51o, alexandre.torgue-qxv4g6HH51o,
	niklass-VrBV9hrLPhE, eric-op+oiCINJLTt9jDmeYuA0g,
	gabriel.fernandez-QSEj5FYQhm4dnm+yROfE0A,
	manabian-Re5JQEeQqe8AvxtiuMwx3w, vpalatin-F7+t8E8rja9g9hUCZPvPmw,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1483102609-21926-1-git-send-email-niklass-VrBV9hrLPhE@public.gmane.org>

From: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>
Date: Fri, 30 Dec 2016 13:56:46 +0100

> From: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>
> 
> For core revision 3.x Address-Aligned Beats is available in two registers.
> The DT property snps,aal was created for AAL in the DMA bus register,
> which is a read/write bit.
> The DT property snps,axi_all was created for AXI_AAL in the AXI bus mode
> register, which is a read only bit that reflects the value of AAL in the
> DMA bus register.
> 
> Since the value of snps,axi_all is never used in the driver,
> and since the property was created for a bit that is read only,
> it should be safe to remove the property.
> 
> Acked-by: Giuseppe Cavallaro <peppe.cavallaro-qxv4g6HH51o@public.gmane.org>
> Signed-off-by: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>

Applied to net-next, thanks.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
From: Andy Shevchenko @ 2017-01-01 15:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel@vger.kernel.org, Wolfram Sang, Rob Herring,
	Mark Rutland, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, Linux Documentation List
In-Reply-To: <1480493823-21462-8-git-send-email-peda@axentia.se>

On Wed, Nov 30, 2016 at 10:17 AM, Peter Rosin <peda@axentia.se> wrote:
> This is a generic simple i2c mux that uses the generic multiplexer
> subsystem to do the muxing.

> +static const struct of_device_id i2c_mux_of_match[] = {
> +       { .compatible = "i2c-mux-simple,parent-locked",
> +         .data = (void *)0, },
> +       { .compatible = "i2c-mux-simple,mux-locked",
> +         .data = (void *)1, },
> +       {},
> +};

Perhaps

#define I2C_MUX_LOCKED_PARENT  0
#define I2C_MUX_LOCKED         1

?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v6 0/9] mux controller abstraction and iio/i2c muxes
From: Jonathan Cameron @ 2017-01-01 11:28 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480493823-21462-1-git-send-email-peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

On 30/11/16 08:16, Peter Rosin wrote:
> Hi!
Just a quick note to encourage people to take a look at this series
if they have the time (I can't talk as it took me almost exactly a
month to take a proper look).

It actually ended up a good deal simpler than I expected so I'm falling
on the side of this making sense rather than pushing all mux complexity
into a 'card driver'.  Covers a lot of cases without a proliferation of
code which is nice.

One addition that may make sense is to provide hooks to allow 'card
drivers' where they are needed. I can certainly conceive of devices
where the complexity does rise to the point where they make sense.
However, we can add them when needed.

Peter, don't give up on this set just yet!

Happy New Year,

Jonathan
> 
> v5 -> v6 changes
> - fix stupidity in mux_chip_priv, mux_gpio_remove and adg792a_remove.
> - change the devicetree bindings for the iio-mux to use a list of strings
>   (channels property) instead of a list children.
> 
> v4 -> v5 changes
> - remove support for fancier dt layouts and go back to the phandle
>   approach from v2 and before, killing the horrible non-working
>   refcounting crap from v4 and avoiding a bunch of life-time issues
>   in v3.
> - introduce the concept of a mux-chip, that can hold one or more
>   mux-controllers (inspired by the pwm subsystem).
> - add dt #mux-control-cells property needed to get to the desired
>   mux controller if a mux chip provides more than one.
> - take away the option to build the mux-core as a module.
> - if the mux controller has an idle state, make sure the mux controller
>   is set up in the idle state initially (when it should be idle).
> - do not use a variable length array on the stack in mux_gpio_set to
>   temporarily store the gpio state, preallocate space instead.
> - fix resource leak on one failure path in mux_gpio_probe.
> - driver for Analog Devices ADG792A/G, literally the first mux chip
>   I found on the Internet with an i2c interface (that was not a
>   dedicated i2c multiplexer like PCA9547) which I used to verify
>   that the abstractions in the mux core are up to the task. Untested,
>   just proof of concept that at least looks pretty and compiles...
> - various touch-ups.
> 
> v3 -> v4 changes
> - rebased onto next-20161122 (depends on recent _available iio changes).
> - added support for having the mux-controller in a child node of a
>   mux-consumer if it is a sole consumer, to hopefully even further satisfy
>   the complaint from Rob (and later Lars-Peter) about dt complexity.
> - the above came at the cost of some rather horrible refcounting code,
>   please review and suggest how it should be done...
> - changed to register a device class instead of a bus.
> - pass in the parent device into mux_control_alloc and require less
>   work from mux-control drivers.
> - changed device names from mux:control%d to mux%d
> - move kernel-doc from mux-core.c to mux.h (and add some bits).
> - give the gpio driver a chance to update all mux pins at once.
> - factor out iio ext_info lookup into new helper function. /Lars-Peter
> - use an unsigned type for the iio ext_info count. /Lars-Peter
> - unified "brag strings" in the file headers.
> 
> v2 -> v3 changes
> - have the mux-controller in the parent node of any mux-controller consumer,
>   to hopefully satisfy complaint from Rob about dt complexity.
> - improve commit message of the mux subsystem commit, making it more
>   general, as requested by Jonathan.
> - remove priv member from struct mux_control and calculate it on the
>   fly. /Jonathan
> - make the function comments in mux-core.c kernel doc. /Jonathan
> - add devm_mux_control_* to Documentation/driver.model/devres.txt. /Jonathan
> - add common dt bindings for mux-controllers, refer to them from the
>   mux-gpio bindings. /Rob
> - clarify how the gpio pins map to the mux state. /Rob
> - separate CONFIG_ variables for the mux core and the mux gpio driver.
> - improve Kconfig help texts.
> - make CONFIG_MUX_GPIO depend on CONFIG_GPIOLIB.
> - keep track of the number of mux states in the mux core.
> - since the iio channel number is used as mux state, it was possible
>   to drop the state member from the mux_child struct.
> - cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
>   problems from ots origin (i2c-mux-gpio).
> - select the mux control subsystem in config for the i2c-mux-simple driver.
> - add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
>   nothing in this to be ashamed of.
> 
> v1 -> v2 changes
> - fixup export of mux_control_put reported by kbuild
> - drop devicetree iio-ext-info property as noted by Lars-Peter,
>   and replace the functionality by exposing all ext_info
>   attributes of the parent channel for each of the muxed
>   channels. A cache on top of that and each muxed channel
>   gets its own view of the ext_info of the parent channel.
> - implement idle-state for muxes
> - clear out the cache on failure in order to force a mux
>   update on the following use
> - cleanup the probe of i2c-mux-simple driver
> - fix a bug in the i2c-mux-simple driver, where failure in
>   the selection of the mux caused a deadlock when the mux
>   was later unconditionally deselected.
> 
> I have a piece of hardware that is using the same 3 GPIO pins
> to control four 8-way muxes. Three of them control ADC lines
> to an ADS1015 chip with an iio driver, and the last one
> controls the SDA line of an i2c bus. We have some deployed
> code to handle this, but you do not want to see it or ever
> hear about it. I'm not sure why I even mention it. Anyway,
> the situation has nagged me to no end for quite some time.
> 
> So, after first getting more intimate with the i2c muxing code
> and later discovering the drivers/iio/inkern.c file and
> writing a couple of drivers making use of it, I came up with
> what I think is an acceptable solution; add a generic mux
> controller driver (and subsystem) that is shared between all
> instances, and combine that with an iio mux driver and a new
> generic i2c mux driver. The new i2c mux I called "simple"
> since it is only hooking the i2c muxing and the new mux
> controller (much like the alsa simple card driver does for ASoC).
> 
> One thing that I would like to do, but don't see a solution
> for, is to move the mux control code that is present in
> various drivers in drivers/i2c/muxes to this new minimalistic
> muxing subsystem, thus converting all present i2c muxes (but
> perhaps not gates and arbitrators) to be i2c-mux-simple muxes.
> 
> I'm using an rwsem to lock a mux, but that isn't really a
> perfect fit. Is there a better locking primitive that I don't
> know about that fits better? I had a mutex at one point, but
> that didn't allow any concurrent accesses at all. At least
> the rwsem allows concurrent access as long as all users
> agree on the mux state, but I suspect that the rwsem will
> degrade to the mutex situation pretty quickly if there is
> any contention.
> 
> Also, the "mux" name feels a bit ambitious, there are many muxes
> in the world, and this tiny bit of code is probably not good
> enough to be a nice fit for all...
> 
> Cheers,
> Peter
> 
> Peter Rosin (9):
>   dt-bindings: document devicetree bindings for mux-controllers and
>     mux-gpio
>   misc: minimal mux subsystem and gpio-based mux controller
>   iio: inkern: api for manipulating ext_info of iio channels
>   dt-bindings: iio: iio-mux: document iio-mux bindings
>   iio: multiplexer: new iio category and iio-mux driver
>   dt-bindings: i2c: i2c-mux-simple: document i2c-mux-simple bindings
>   i2c: i2c-mux-simple: new driver
>   dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
>     mux
>   misc: mux-adg792a: add mux controller driver for ADG792A/G
> 
>  .../devicetree/bindings/i2c/i2c-mux-simple.txt     |  81 ++++
>  .../bindings/iio/multiplexer/iio-mux.txt           |  40 ++
>  .../devicetree/bindings/misc/mux-adg792a.txt       |  64 +++
>  .../devicetree/bindings/misc/mux-controller.txt    | 127 ++++++
>  .../devicetree/bindings/misc/mux-gpio.txt          |  68 +++
>  Documentation/driver-model/devres.txt              |   6 +-
>  MAINTAINERS                                        |  14 +
>  drivers/i2c/muxes/Kconfig                          |  13 +
>  drivers/i2c/muxes/Makefile                         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c                 | 179 ++++++++
>  drivers/iio/Kconfig                                |   1 +
>  drivers/iio/Makefile                               |   1 +
>  drivers/iio/inkern.c                               |  60 +++
>  drivers/iio/multiplexer/Kconfig                    |  18 +
>  drivers/iio/multiplexer/Makefile                   |   6 +
>  drivers/iio/multiplexer/iio-mux.c                  | 456 +++++++++++++++++++++
>  drivers/misc/Kconfig                               |  42 ++
>  drivers/misc/Makefile                              |   3 +
>  drivers/misc/mux-adg792a.c                         | 154 +++++++
>  drivers/misc/mux-core.c                            | 311 ++++++++++++++
>  drivers/misc/mux-gpio.c                            | 138 +++++++
>  include/linux/iio/consumer.h                       |  37 ++
>  include/linux/mux.h                                | 197 +++++++++
>  23 files changed, 2016 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-simple.txt
>  create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-controller.txt
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-gpio.txt
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
>  create mode 100644 drivers/iio/multiplexer/Kconfig
>  create mode 100644 drivers/iio/multiplexer/Makefile
>  create mode 100644 drivers/iio/multiplexer/iio-mux.c
>  create mode 100644 drivers/misc/mux-adg792a.c
>  create mode 100644 drivers/misc/mux-core.c
>  create mode 100644 drivers/misc/mux-gpio.c
>  create mode 100644 include/linux/mux.h
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v6 9/9] misc: mux-adg792a: add mux controller driver for ADG792A/G
From: Jonathan Cameron @ 2017-01-01 11:24 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc
In-Reply-To: <1480493823-21462-10-git-send-email-peda@axentia.se>

On 30/11/16 08:17, Peter Rosin wrote:
> Analog Devices ADG792A/G is a triple 4:1 mux.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Looks pretty good. Some minor suggestions inline.

This convinced me of two things:
1. Need a separate subsystem directory for muxes - having them under misc
is going to lead to long term mess.
2. Devm alloc and registration functions will make the drivers all simpler.

Also, browsing through ADIs list of muxes and switches it's clear that
one classic case will be where an i2c octal or similar switch is used with
outputs wired together in weird combinations to act as a mux.  Going to
be 'fun' describing that.

There are also potentially cross point switches to be described ;)
(I had to look up what one of those was ;)

Crosspoints aren't implausible as front ends for ADCs as you might
want to be able rapidly sample any 2 of say 16 channels coming from
for example a max14661.  We'd have to figure out how to add buffered
capture support with sensible restrictions to the iio-mux driver
to do that - realistically I think we would just not allow buffered
capture with the mux having to switch.  Without hardware support
(i.e. an ADC with external mux control) it would be too slow.

Always good to bury some idle thoughts deep in the review of a random
driver ;) I'll never be able to remember where they were let alone
anyone else.

Jonathan

> ---
>  drivers/misc/Kconfig       |  12 ++++
>  drivers/misc/Makefile      |   1 +
>  drivers/misc/mux-adg792a.c | 154 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 167 insertions(+)
>  create mode 100644 drivers/misc/mux-adg792a.c
> 
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 2ce675e410c5..45567a444bbf 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -780,6 +780,18 @@ menuconfig MULTIPLEXER
>  
>  if MULTIPLEXER
>  
> +config MUX_ADG792A
> +	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
> +	depends on I2C
> +	help
> +	  ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
> +
> +	  The driver supports both operating the three multiplexers in
> +	  parellel and operating them independently.
parallel
> +
> +	  To compile the driver as a module, choose M here: the module will
> +	  be called mux-adg792a.
> +
>  config MUX_GPIO
>  	tristate "GPIO-controlled Multiplexer"
>  	depends on OF && GPIOLIB
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 0befa2bba762..10ab8d34c9e5 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>  obj-$(CONFIG_CXL_BASE)		+= cxl/
>  obj-$(CONFIG_PANEL)             += panel.o
>  obj-$(CONFIG_MULTIPLEXER)      	+= mux-core.o
> +obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
>  obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
>  
>  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
> diff --git a/drivers/misc/mux-adg792a.c b/drivers/misc/mux-adg792a.c
> new file mode 100644
> index 000000000000..7d309a78af65
> --- /dev/null
> +++ b/drivers/misc/mux-adg792a.c
> @@ -0,0 +1,154 @@
> +/*
> + * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +
> +#define ADG792A_LDSW		BIT(0)
> +#define ADG792A_RESET		BIT(1)
> +#define ADG792A_DISABLE(mux)	(0x50 | (mux))
> +#define ADG792A_DISABLE_ALL	(0x5f)
> +#define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
> +#define ADG792A_MUX_ALL(state)	(0xc0 | (state))
> +
> +#define ADG792A_DISABLE_STATE	(4)
> +#define ADG792A_KEEP_STATE	(5)
> +
> +static int adg792a_set(struct mux_control *mux, int state)
> +{
> +	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
> +	u8 cmd;
> +
> +	if (mux->chip->controllers == 1) {
> +		/* parallel mux controller operation */
> +		if (state == ADG792A_DISABLE_STATE)
> +			cmd = ADG792A_DISABLE_ALL;
> +		else
> +			cmd = ADG792A_MUX_ALL(state);
> +	} else {
> +		unsigned int controller = mux_control_get_index(mux);
> +
> +		if (state == ADG792A_DISABLE_STATE)
> +			cmd = ADG792A_DISABLE(controller);
> +		else
> +			cmd = ADG792A_MUX(controller, state);
> +	}
> +
> +	return i2c_smbus_write_byte_data(i2c, cmd, ADG792A_LDSW);
> +}
> +
> +static const struct mux_control_ops adg792a_ops = {
> +	.set = adg792a_set,
> +};
> +
> +static int adg792a_probe(struct i2c_client *i2c,
> +			 const struct i2c_device_id *id)
> +{
> +	struct device *dev = &i2c->dev;
> +	struct mux_chip *mux_chip;
> +	bool parallel;
> +	int ret;
> +	int i;
> +
> +	parallel = of_property_read_bool(i2c->dev.of_node, "adi,parallel");
> +
> +	mux_chip = mux_chip_alloc(dev, parallel ? 1 : 3, 0);
This makes me wonder if we can have a more generic binding.
mux-poles = 3 vs mux-poles = 1?

> +	if (!mux_chip)
> +		return -ENOMEM;
> +
> +	mux_chip->ops = &adg792a_ops;
> +	dev_set_drvdata(dev, mux_chip);
> +
> +	ret = i2c_smbus_write_byte_data(i2c, ADG792A_DISABLE_ALL,
> +					ADG792A_RESET | ADG792A_LDSW);
> +	if (ret < 0)
> +		goto free_mux_chip;
> +
> +	for (i = 0; i < mux_chip->controllers; ++i) {
> +		struct mux_control *mux = &mux_chip->mux[i];
> +		u32 idle_state;
> +
> +		mux->states = 4;
> +
> +		ret = of_property_read_u32_index(i2c->dev.of_node,
> +						 "adi,idle-state", i,
> +						 &idle_state);
> +		if (ret >= 0) {
> +			if (idle_state > ADG792A_KEEP_STATE) {
> +				dev_err(dev, "invalid idle-state %u\n",
> +					idle_state);
> +				ret = -EINVAL;
> +				goto free_mux_chip;
> +			}
> +			if (idle_state != ADG792A_KEEP_STATE)
> +				mux->idle_state = idle_state;
> +		}
> +	}
> +
> +	ret = mux_chip_register(mux_chip);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to register mux-chip\n");
> +		goto free_mux_chip;
> +	}
> +
> +	if (parallel)
> +		dev_info(dev, "1 triple 4-way mux-controller registered\n");
I'd use the relay / switch standard description for this so 
'triple pole, quadruple throw mux registered'.
> +	else
> +		dev_info(dev, "3 4-way mux-controllers registered\n");
'3x single pole, quadruple throw muxes registered'.
> +
> +	return 0;
> +
> +free_mux_chip:
> +	mux_chip_free(mux_chip);
> +	return ret;
> +}
> +
> +static int adg792a_remove(struct i2c_client *i2c)
> +{
> +	struct mux_chip *mux_chip = dev_get_drvdata(&i2c->dev);
> +
Definitely looking like it's worth managed versions of mux_chip_register and
mux_chip_alloc given this is another case where they would let us get rid
of the remove function entirely.
> +	mux_chip_unregister(mux_chip);
> +	mux_chip_free(mux_chip);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id adg792a_id[] = {
> +	{ .name = "adg792a", },
> +	{ .name = "adg792g", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, adg792a_id);
> +
> +static const struct of_device_id adg792a_of_match[] = {
> +	{ .compatible = "adi,adg792a", },
> +	{ .compatible = "adi,adg792g", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, adg792a_of_match);
> +
> +static struct i2c_driver adg792a_driver = {
> +	.driver		= {
> +		.name		= "adg792a",
> +		.of_match_table = of_match_ptr(adg792a_of_match),
> +	},
> +	.probe		= adg792a_probe,
> +	.remove		= adg792a_remove,
> +	.id_table	= adg792a_id,
> +};
> +module_i2c_driver(adg792a_driver);
> +
> +MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply

* Re: [PATCH v6 8/9] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux
From: Jonathan Cameron @ 2017-01-01 11:00 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc
In-Reply-To: <1480493823-21462-9-git-send-email-peda@axentia.se>

On 30/11/16 08:17, Peter Rosin wrote:
> Analog Devices ADG792A/G is a triple 4:1 mux.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Few comments inline.  Worth adding anything about the gpio (output pins) to
the binding at this stage as well?  Would certainly be nice to support
them.

Jonathan
> ---
>  .../devicetree/bindings/misc/mux-adg792a.txt       | 64 ++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/mux-adg792a.txt
> 
> diff --git a/Documentation/devicetree/bindings/misc/mux-adg792a.txt b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
> new file mode 100644
> index 000000000000..4677f9ab1c55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/mux-adg792a.txt
> @@ -0,0 +1,64 @@
> +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
> +
> +Required properties:
> +- compatible : "adi,adg792a" or "adi,adg792g"
> +- #mux-control-cells : <0> if parallel, or <1> if not.
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- adi,parallel : if present, the three muxes are bound together with a single
> +  mux controller, controlling all three muxes in parallel.
> +- adi,idle-state : if present, array of states the three mux controllers will
> +  have when idle (or, if parallel, a single idle-state).
Hmm. These are actually a policy decision.  As only one policy will make
sense for a given set of hardware probably fine to have it in here I guess.
Might be worth adding a note to say this though.
> +
> +Mux controller states 0 through 3 correspond to signals A through D in the
> +datasheet. Mux controller states 4 and 5 are only available as possible idle
> +states. State 4 represents that nothing is connected, and state 5 represents
> +that the mux controller keeps the mux in its previously selected state during
> +the idle period. State 5 is the default idle state.
I'm never a great fan of magic numbers.  Can we represent this more cleanly by
breaking it into multiple properties?
Optional:
adi,idle-switch-to-channel : switch to this channel when idle.
adi,idle-high-impedance : <boolean> the nothing connected state?

If neither present leaves it in previous state?
> +
> +Example:
> +
> +	/* three independent mux controllers (of which one is used) */
> +	&i2c0 {
> +		mux: adg792a@50 {
> +			compatible = "adi,adg792a";
> +			reg = <0x50>;
> +			#mux-control-cells = <1>;
> +		};
> +	};
> +
> +	adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&mux 1>;
> +
> +		channels = "sync-1", "", "out";
> +	};
> +
> +
> +	/*
> +	 * Three parallel muxes with one mux controller, useful e.g. if
> +	 * the adc is differential, thus needing two signals to be muxed
> +	 * simultaneously for correct operation.
> +	 */
> +	&i2c0 {
> +		pmux: adg792a@50 {
> +			compatible = "adi,adg792a";
> +			reg = <0x50>;
> +			#mux-control-cells = <0>;
> +			adi,parallel;
> +		};
> +	};
> +
> +	diff-adc-mux {
> +		compatible = "iio-mux";
> +		io-channels = <&adc 0>;
> +		io-channel-names = "parent";
> +
> +		mux-controls = <&pmux>;
> +
> +		channels = "sync-1", "", "out";
> +	};
> 

^ permalink raw reply

* Re: [PATCH v6 7/9] i2c: i2c-mux-simple: new driver
From: Jonathan Cameron @ 2017-01-01 10:31 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480493823-21462-8-git-send-email-peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

On 30/11/16 08:17, Peter Rosin wrote:
> This is a generic simple i2c mux that uses the generic multiplexer
> subsystem to do the muxing.
> 
> The user can select if the mux is to be mux-locked and parent-locked
> as described in Documentation/i2c/i2c-topology.
> 
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
Looks good to me though as I haven't really commented on it I'll give
an Ack rather than a reviewed by.

Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
>  drivers/i2c/muxes/Kconfig          |  13 +++
>  drivers/i2c/muxes/Makefile         |   1 +
>  drivers/i2c/muxes/i2c-mux-simple.c | 179 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 193 insertions(+)
>  create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c
> 
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index 10b3d17ae3ea..565921e09a96 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -73,6 +73,19 @@ config I2C_MUX_REG
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called i2c-mux-reg.
>  
> +config I2C_MUX_SIMPLE
> +	tristate "Simple I2C multiplexer"
> +	select MULTIPLEXER
> +	depends on OF
> +	help
> +	  If you say yes to this option, support will be included for a
> +	  simple generic I2C multiplexer. This driver provides access to
> +	  I2C busses connected through a MUX, which is controlled
> +	  by a generic MUX controller.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called i2c-mux-simple.
> +
>  config I2C_DEMUX_PINCTRL
>  	tristate "pinctrl-based I2C demultiplexer"
>  	depends on PINCTRL && OF
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 9948fa45037f..6821d95c92a3 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -11,5 +11,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
>  obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
>  obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
>  obj-$(CONFIG_I2C_MUX_REG)	+= i2c-mux-reg.o
> +obj-$(CONFIG_I2C_MUX_SIMPLE)	+= i2c-mux-simple.o
>  
>  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
> diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c
> new file mode 100644
> index 000000000000..4a03493e1ad7
> --- /dev/null
> +++ b/drivers/i2c/muxes/i2c-mux-simple.c
> @@ -0,0 +1,179 @@
> +/*
> + * Generic simple I2C multiplexer
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-mux.h>
> +#include <linux/module.h>
> +#include <linux/mux.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +struct mux {
> +	struct mux_control *control;
> +
> +	bool do_not_deselect;
> +};
> +
> +static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +	int ret;
> +
> +	ret = mux_control_select(mux->control, chan);
> +	mux->do_not_deselect = ret < 0;
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct mux *mux = i2c_mux_priv(muxc);
> +
> +	if (mux->do_not_deselect)
> +		return 0;
> +
> +	return mux_control_deselect(mux->control);
> +}
> +
> +static struct i2c_adapter *mux_parent_adapter(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct device_node *parent_np;
> +	struct i2c_adapter *parent;
> +
> +	parent_np = of_parse_phandle(np, "i2c-parent", 0);
> +	if (!parent_np) {
> +		dev_err(dev, "Cannot parse i2c-parent\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +	parent = of_find_i2c_adapter_by_node(parent_np);
> +	of_node_put(parent_np);
> +	if (!parent)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return parent;
> +}
> +
> +static const struct of_device_id i2c_mux_of_match[] = {
> +	{ .compatible = "i2c-mux-simple,parent-locked",
> +	  .data = (void *)0, },
> +	{ .compatible = "i2c-mux-simple,mux-locked",
> +	  .data = (void *)1, },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
> +
> +static int i2c_mux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child;
> +	const struct of_device_id *match;
> +	struct i2c_mux_core *muxc;
> +	struct mux *mux;
> +	struct i2c_adapter *parent;
> +	int children;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return -ENOMEM;
> +
> +	mux->control = devm_mux_control_get(dev, NULL);
> +	if (IS_ERR(mux->control)) {
> +		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get control-mux\n");
> +		return PTR_ERR(mux->control);
> +	}
> +
> +	parent = mux_parent_adapter(dev);
> +	if (IS_ERR(parent)) {
> +		if (PTR_ERR(parent) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get i2c-parent adapter\n");
> +		return PTR_ERR(parent);
> +	}
> +
> +	children = of_get_child_count(np);
> +
> +	muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
> +			     i2c_mux_select, i2c_mux_deselect);
> +	if (!muxc) {
> +		ret = -ENOMEM;
> +		goto err_parent;
> +	}
> +	muxc->priv = mux;
> +
> +	platform_set_drvdata(pdev, muxc);
> +
> +	match = of_match_device(of_match_ptr(i2c_mux_of_match), dev);
> +	if (match)
> +		muxc->mux_locked = !!of_device_get_match_data(dev);
> +
> +	for_each_child_of_node(np, child) {
> +		u32 chan;
> +
> +		ret = of_property_read_u32(child, "reg", &chan);
> +		if (ret < 0) {
> +			dev_err(dev, "no reg property for node '%s'\n",
> +				child->name);
> +			goto err_children;
> +		}
> +
> +		if (chan >= mux->control->states) {
> +			dev_err(dev, "invalid reg %u\n", chan);
> +			ret = -EINVAL;
> +			goto err_children;
> +		}
> +
> +		ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
> +		if (ret)
> +			goto err_children;
> +	}
> +
> +	dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
> +
> +	return 0;
> +
> +err_children:
> +	i2c_mux_del_adapters(muxc);
> +err_parent:
> +	i2c_put_adapter(parent);
> +
> +	return ret;
> +}
> +
> +static int i2c_mux_remove(struct platform_device *pdev)
> +{
> +	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
> +
> +	i2c_mux_del_adapters(muxc);
> +	i2c_put_adapter(muxc->parent);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver i2c_mux_driver = {
> +	.probe	= i2c_mux_probe,
> +	.remove	= i2c_mux_remove,
> +	.driver	= {
> +		.name	= "i2c-mux-simple",
> +		.of_match_table = i2c_mux_of_match,
> +	},
> +};
> +module_platform_driver(i2c_mux_driver);
> +
> +MODULE_DESCRIPTION("Simple I2C multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply

* Re: [PATCH 2/2] pinctrl: Introduce TI IOdelay configuration driver
From: kbuild test robot @ 2017-01-01  2:02 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: kbuild-all-JC7UmRfGjtg, Linus Walleij, Gary Bisson,
	Grygorii Strashko, Mark Rutland, Nishanth Menon, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Lokesh Vutla
In-Reply-To: <20161230183732.5595-3-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>

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

Hi Nishanth,

[auto build test ERROR on pinctrl/for-next]
[also build test ERROR on v4.10-rc1 next-20161224]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Tony-Lindgren/Add-TI-iodelay-driver-using-pinctrl-cells/20161231-024542
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git for-next
config: i386-allyesconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_get_pingroup':
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:383:6: error: implicit declaration of function 'pinctrl_generic_get_group' [-Werror=implicit-function-declaration]
     g = pinctrl_generic_get_group(iod->pctl, selector);
         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:383:4: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     g = pinctrl_generic_get_group(iod->pctl, selector);
       ^
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:391:10: error: dereferencing pointer to incomplete type 'struct group_desc'
     return g->data;
             ^~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_dt_node_to_map':
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:562:10: error: implicit declaration of function 'pinctrl_generic_add_group' [-Werror=implicit-function-declaration]
     error = pinctrl_generic_add_group(iod->pctl, np->name, pins, i, g);
             ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: At top level:
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:729:22: error: 'pinctrl_generic_get_group_count' undeclared here (not in a function)
     .get_groups_count = pinctrl_generic_get_group_count,
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:730:20: error: 'pinctrl_generic_get_group_name' undeclared here (not in a function)
     .get_group_name = pinctrl_generic_get_group_name,
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:731:20: error: 'pinctrl_generic_get_group_pins' undeclared here (not in a function)
     .get_group_pins = pinctrl_generic_get_group_pins,
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_get_pingroup':
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:392:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   cc1: some warnings being treated as errors

vim +391 drivers/pinctrl/ti/pinctrl-ti-iodelay.c

   377	 */
   378	static struct ti_iodelay_pingroup *
   379	ti_iodelay_get_pingroup(struct ti_iodelay_device *iod, unsigned int selector)
   380	{
   381		struct group_desc *g;
   382	
 > 383		g = pinctrl_generic_get_group(iod->pctl, selector);
   384		if (!g) {
   385			dev_err(iod->dev, "%s could not find pingroup %i\n", __func__,
   386				selector);
   387	
   388			return NULL;
   389		}
   390	
 > 391		return g->data;
   392	}
   393	
   394	/**
   395	 * ti_iodelay_pin_to_offset() - get pin register offset based on the pin index
   396	 * @iod: iodelay driver instance
   397	 * @selector: Pin index
   398	 */
   399	static unsigned int ti_iodelay_pin_to_offset(struct ti_iodelay_device *iod,
   400						     unsigned int selector)
   401	{
   402		const struct ti_iodelay_reg_data *r = iod->reg_data;
   403		unsigned int offset;
   404	
   405		offset = selector * r->regmap_config->reg_stride;
   406		offset *= r->reg_nr_per_pin;
   407		offset += r->reg_start_offset;
   408	
   409		return offset;
   410	}
   411	
   412	/**
   413	 * ti_iodelay_offset_to_pin() - get a pin index based on the register offset
   414	 * @iod: iodelay driver instance
   415	 * @offset: register offset from the base
   416	 */
   417	static int ti_iodelay_offset_to_pin(struct ti_iodelay_device *iod,
   418					    unsigned int offset)
   419	{
   420		const struct ti_iodelay_reg_data *r = iod->reg_data;
   421		unsigned int index;
   422	
   423		if (offset > r->regmap_config->max_register) {
   424			dev_err(iod->dev, "mux offset out of range: 0x%x (0x%x)\n",
   425				offset, r->regmap_config->max_register);
   426			return -EINVAL;
   427		}
   428	
   429		index = (offset - r->reg_start_offset) / r->regmap_config->reg_stride;
   430		index /= r->reg_nr_per_pin;
   431	
   432		return index;
   433	}
   434	
   435	/**
   436	 *
   437	 * @pctldev: Pin controller driver
   438	 * @np: Device node
   439	 * @pinctrl_spec: Parsed arguments from device tree
   440	 * @pins: Array of pins in the pin group
   441	 * @pin_index: Pin index in the pin array
   442	 * @data: Pin controller driver specific data
   443	 *
   444	 */
   445	static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev,
   446					    struct device_node *np,
   447					    const struct of_phandle_args *pinctrl_spec,
   448					    int *pins, int pin_index, void *data)
   449	{
   450		struct ti_iodelay_device *iod;
   451		struct ti_iodelay_cfg *cfg = data;
   452		const struct ti_iodelay_reg_data *r;
   453		struct pinctrl_pin_desc *pd;
   454		int pin;
   455	
   456		iod = pinctrl_dev_get_drvdata(pctldev);
   457		if (!iod)
   458			return -EINVAL;
   459	
   460		r = iod->reg_data;
   461	
   462		if (pinctrl_spec->args_count < r->reg_nr_per_pin) {
   463			dev_err(iod->dev, "invalid args_count for spec: %i\n",
   464				pinctrl_spec->args_count);
   465	
   466			return -EINVAL;
   467		}
   468	
   469		/* Index plus two value cells */
   470		cfg[pin_index].offset = pinctrl_spec->args[0];
   471		cfg[pin_index].a_delay = pinctrl_spec->args[1] & 0xffff;
   472		cfg[pin_index].g_delay = pinctrl_spec->args[2] & 0xffff;
   473	
   474		pin = ti_iodelay_offset_to_pin(iod, cfg[pin_index].offset);
   475		if (pin < 0) {
   476			dev_err(iod->dev, "could not add functions for %s %ux\n",
   477				np->name, cfg[pin_index].offset);
   478			return -ENODEV;
   479		}
   480		pins[pin_index] = pin;
   481	
   482		pd = &iod->pa[pin];
   483		pd->drv_data = &cfg[pin_index];
   484	
   485		dev_dbg(iod->dev, "%s offset=%x a_delay = %d g_delay = %d\n",
   486			np->name, cfg[pin_index].offset, cfg[pin_index].a_delay,
   487			cfg[pin_index].g_delay);
   488	
   489		return 0;
   490	}
   491	
   492	/**
   493	 * ti_iodelay_dt_node_to_map() - Map a device tree node to appropriate group
   494	 * @pctldev: pinctrl device representing IODelay device
   495	 * @np: Node Pointer (device tree)
   496	 * @map: Pinctrl Map returned back to pinctrl framework
   497	 * @num_maps: Number of maps (1)
   498	 *
   499	 * Maps the device tree description into a group of configuration parameters
   500	 * for iodelay block entry.
   501	 *
   502	 * Return: 0 in case of success, else appropriate error value
   503	 */
   504	static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev,
   505					     struct device_node *np,
   506					     struct pinctrl_map **map,
   507					     unsigned int *num_maps)
   508	{
   509		struct ti_iodelay_device *iod;
   510		struct ti_iodelay_cfg *cfg;
   511		struct ti_iodelay_pingroup *g;
   512		const char *name = "pinctrl-pin-array";
   513		int rows, *pins, error = -EINVAL, i;
   514	
   515		iod = pinctrl_dev_get_drvdata(pctldev);
   516		if (!iod)
   517			return -EINVAL;
   518	
   519		rows = pinctrl_count_index_with_args(np, name);
   520		if (rows == -EINVAL)
   521			return rows;
   522	
   523		*map = devm_kzalloc(iod->dev, sizeof(**map), GFP_KERNEL);
   524		if (!*map)
   525			return -ENOMEM;
   526		*num_maps = 0;
   527	
   528		g = devm_kzalloc(iod->dev, sizeof(*g), GFP_KERNEL);
   529		if (!g) {
   530			error = -ENOMEM;
   531			goto free_map;
   532		}
   533	
   534		pins = devm_kzalloc(iod->dev, sizeof(*pins) * rows, GFP_KERNEL);
   535		if (!pins)
   536			goto free_group;
   537	
   538		cfg = devm_kzalloc(iod->dev, sizeof(*cfg) * rows, GFP_KERNEL);
   539		if (!cfg) {
   540			error = -ENOMEM;
   541			goto free_pins;
   542		}
   543	
   544		for (i = 0; i < rows; i++) {
   545			struct of_phandle_args pinctrl_spec;
   546	
   547			error = pinctrl_parse_index_with_args(np, name, i,
   548							      &pinctrl_spec);
   549			if (error)
   550				goto free_data;
   551	
   552			error = ti_iodelay_node_iterator(pctldev, np, &pinctrl_spec,
   553							 pins, i, cfg);
   554			if (error)
   555				goto free_data;
   556		}
   557	
   558		g->cfg = cfg;
   559		g->ncfg = i;
   560		g->config = PIN_CONFIG_END;
   561	
 > 562		error = pinctrl_generic_add_group(iod->pctl, np->name, pins, i, g);
   563		if (error < 0)
   564			goto free_data;
   565	

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

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

^ permalink raw reply

* Re: [PATCH linux 5/6] hwmon: occ: Add hwmon implementation for the P8 OCC
From: kbuild test robot @ 2017-01-01  0:25 UTC (permalink / raw)
  To: eajames.ibm
  Cc: kbuild-all, linux, jdelvare, corbet, mark.rutland, robh+dt, wsa,
	andrew, joel, devicetree, linux-doc, linux-hwmon, linux-i2c,
	linux-kernel, Edward A. James
In-Reply-To: <1483120568-21082-6-git-send-email-eajames.ibm@gmail.com>

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

Hi Edward,

[auto build test ERROR on hwmon/hwmon-next]
[also build test ERROR on v4.10-rc1 next-20161224]
[cannot apply to linux/master]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/eajames-ibm-gmail-com/drivers-hwmon-Add-On-Chip-Controller-driver/20161231-021324
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
config: x86_64-randconfig-n0-01010656 (attached as .config)
compiler: gcc-4.8 (Debian 4.8.4-1) 4.8.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

>> ERROR: "occ_sysfs_start" [drivers/hwmon/occ/p8_occ_i2c.ko] undefined!
>> ERROR: "occ_sysfs_stop" [drivers/hwmon/occ/p8_occ_i2c.ko] undefined!
>> ERROR: "occ_stop" [drivers/hwmon/occ/occ_p8.ko] undefined!
>> ERROR: "occ_start" [drivers/hwmon/occ/occ_p8.ko] undefined!
>> ERROR: "occ_get_sensor" [drivers/hwmon/occ/occ_p8.ko] undefined!

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

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

^ permalink raw reply

* Re: [PATCH v5 5/7] i2c: designware: add SLAVE mode functions
From: kbuild test robot @ 2016-12-31 23:45 UTC (permalink / raw)
  Cc: kbuild-all-JC7UmRfGjtg, wsa-z923LK4zBo2bacvFa/9K2g,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
	mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
	Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <15538bd29b3ab62608a4e9153af6ee5d4bdc79e2.1482934380.git.lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>

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

Hi Luis,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.10-rc1 next-20161224]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Luis-Oliveira/i2c-designware-Cleaning-and-comment-style-fixes/20161229-010120
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
config: i386-randconfig-c0-01010626 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/i2c/busses/i2c-designware-slave.c: In function 'i2c_dw_irq_handler_slave':
>> drivers/i2c/busses/i2c-designware-slave.c:293:3: error: implicit declaration of function 'i2c_slave_event' [-Werror=implicit-function-declaration]
      i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
      ^
>> drivers/i2c/busses/i2c-designware-slave.c:293:31: error: 'I2C_SLAVE_WRITE_REQUESTED' undeclared (first use in this function)
      i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
                                  ^
   drivers/i2c/busses/i2c-designware-slave.c:293:31: note: each undeclared identifier is reported only once for each function it appears in
   In file included from include/linux/err.h:4:0,
                    from drivers/i2c/busses/i2c-designware-slave.c:23:
>> drivers/i2c/busses/i2c-designware-slave.c:300:6: error: 'I2C_SLAVE_WRITE_RECEIVED' undeclared (first use in this function)
         I2C_SLAVE_WRITE_RECEIVED, &val)) {
         ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^
   drivers/i2c/busses/i2c-designware-slave.c:299:5: note: in expansion of macro 'if'
        if (!i2c_slave_event(dev->slave,
        ^
>> drivers/i2c/busses/i2c-designware-slave.c:312:7: error: 'I2C_SLAVE_READ_REQUESTED' undeclared (first use in this function)
          I2C_SLAVE_READ_REQUESTED, &val))
          ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^
   drivers/i2c/busses/i2c-designware-slave.c:311:4: note: in expansion of macro 'if'
       if (!i2c_slave_event(dev->slave,
       ^
>> drivers/i2c/busses/i2c-designware-slave.c:318:36: error: 'I2C_SLAVE_READ_PROCESSED' undeclared (first use in this function)
      if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
                                       ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^
   drivers/i2c/busses/i2c-designware-slave.c:318:3: note: in expansion of macro 'if'
      if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
      ^
>> drivers/i2c/busses/i2c-designware-slave.c:322:31: error: 'I2C_SLAVE_STOP' undeclared (first use in this function)
      i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
                                  ^
   drivers/i2c/busses/i2c-designware-slave.c: At top level:
>> drivers/i2c/busses/i2c-designware-slave.c:359:2: error: unknown field 'reg_slave' specified in initializer
     .reg_slave = i2c_dw_reg_slave,
     ^
   drivers/i2c/busses/i2c-designware-slave.c:359:2: warning: excess elements in struct initializer
   drivers/i2c/busses/i2c-designware-slave.c:359:2: warning: (near initialization for 'i2c_dw_algo')
>> drivers/i2c/busses/i2c-designware-slave.c:360:2: error: unknown field 'unreg_slave' specified in initializer
     .unreg_slave = i2c_dw_unreg_slave,
     ^
   drivers/i2c/busses/i2c-designware-slave.c:360:2: warning: excess elements in struct initializer
   drivers/i2c/busses/i2c-designware-slave.c:360:2: warning: (near initialization for 'i2c_dw_algo')
   cc1: some warnings being treated as errors

vim +/i2c_slave_event +293 drivers/i2c/busses/i2c-designware-slave.c

   287			dw_readl(dev, DW_IC_CLR_START_DET);
   288		if (stat & DW_IC_INTR_ACTIVITY)
   289			dw_readl(dev, DW_IC_CLR_ACTIVITY);
   290		if (stat & DW_IC_INTR_RX_OVER)
   291			dw_readl(dev, DW_IC_CLR_RX_OVER);
   292		if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
 > 293			i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
   294	
   295		if (slave_activity) {
   296			if (stat & DW_IC_INTR_RD_REQ) {
   297				if (stat & DW_IC_INTR_RX_FULL) {
   298					val = dw_readl(dev, DW_IC_DATA_CMD);
   299					if (!i2c_slave_event(dev->slave,
 > 300					 I2C_SLAVE_WRITE_RECEIVED, &val)) {
   301						dev_dbg(dev->dev, "Byte %X acked!",
   302						 val);
   303					}
   304					dw_readl(dev, DW_IC_CLR_RD_REQ);
   305					stat = i2c_dw_read_clear_intrbits_slave(dev);
   306				} else {
   307					dw_readl(dev, DW_IC_CLR_RD_REQ);
   308					dw_readl(dev, DW_IC_CLR_RX_UNDER);
   309					stat = i2c_dw_read_clear_intrbits_slave(dev);
   310				}
   311				if (!i2c_slave_event(dev->slave,
 > 312						 I2C_SLAVE_READ_REQUESTED, &val))
   313					dw_writel(dev, val, DW_IC_DATA_CMD);
   314			}
   315		}
   316	
   317		if (stat & DW_IC_INTR_RX_DONE) {
 > 318			if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
   319			 &val))
   320				dw_readl(dev, DW_IC_CLR_RX_DONE);
   321	
 > 322			i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
   323			stat = i2c_dw_read_clear_intrbits_slave(dev);
   324			return true;
   325		}
   326	
   327		if (stat & DW_IC_INTR_RX_FULL) {
   328			val = dw_readl(dev, DW_IC_DATA_CMD);
   329			if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
   330			 &val))
   331				dev_dbg(dev->dev, "Byte %X acked!", val);
   332		} else {
   333			i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
   334			stat = i2c_dw_read_clear_intrbits_slave(dev);
   335		}
   336	
   337		if (stat & DW_IC_INTR_TX_OVER)
   338			dw_readl(dev, DW_IC_CLR_TX_OVER);
   339	
   340		return 1;
   341	}
   342	
   343	static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
   344	{
   345		struct dw_i2c_dev *dev = dev_id;
   346		int ret;
   347	
   348		i2c_dw_read_clear_intrbits_slave(dev);
   349		ret = i2c_dw_irq_handler_slave(dev);
   350	
   351		if (ret > 0)
   352			complete(&dev->cmd_complete);
   353	
   354		return IRQ_RETVAL(ret);
   355	}
   356	
   357	static struct i2c_algorithm i2c_dw_algo = {
   358		.functionality = i2c_dw_func,
 > 359		.reg_slave = i2c_dw_reg_slave,
 > 360		.unreg_slave = i2c_dw_unreg_slave,
   361	};
   362	
   363	void i2c_dw_disable_slave(struct dw_i2c_dev *dev)

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

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

^ permalink raw reply

* Re: [PATCH 2/2] pinctrl: Introduce TI IOdelay configuration driver
From: kbuild test robot @ 2016-12-31 22:52 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: kbuild-all-JC7UmRfGjtg, Linus Walleij, Gary Bisson,
	Grygorii Strashko, Mark Rutland, Nishanth Menon, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Lokesh Vutla
In-Reply-To: <20161230183732.5595-3-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>

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

Hi Nishanth,

[auto build test ERROR on pinctrl/for-next]
[also build test ERROR on v4.10-rc1 next-20161224]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Tony-Lindgren/Add-TI-iodelay-driver-using-pinctrl-cells/20161231-024542
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git for-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_get_pingroup':
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:383:6: error: implicit declaration of function 'pinctrl_generic_get_group' [-Werror=implicit-function-declaration]
     g = pinctrl_generic_get_group(iod->pctl, selector);
         ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:383:4: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     g = pinctrl_generic_get_group(iod->pctl, selector);
       ^
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:391:10: error: dereferencing pointer to incomplete type 'struct group_desc'
     return g->data;
             ^~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_dt_node_to_map':
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:562:10: error: implicit declaration of function 'pinctrl_generic_add_group' [-Werror=implicit-function-declaration]
     error = pinctrl_generic_add_group(iod->pctl, np->name, pins, i, g);
             ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: At top level:
>> drivers/pinctrl/ti/pinctrl-ti-iodelay.c:729:22: error: 'pinctrl_generic_get_group_count' undeclared here (not in a function)
     .get_groups_count = pinctrl_generic_get_group_count,
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:730:20: error: 'pinctrl_generic_get_group_name' undeclared here (not in a function)
     .get_group_name = pinctrl_generic_get_group_name,
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:731:20: error: 'pinctrl_generic_get_group_pins' undeclared here (not in a function)
     .get_group_pins = pinctrl_generic_get_group_pins,
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c: In function 'ti_iodelay_get_pingroup':
   drivers/pinctrl/ti/pinctrl-ti-iodelay.c:392:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   cc1: some warnings being treated as errors

vim +/pinctrl_generic_get_group +383 drivers/pinctrl/ti/pinctrl-ti-iodelay.c

   377	 */
   378	static struct ti_iodelay_pingroup *
   379	ti_iodelay_get_pingroup(struct ti_iodelay_device *iod, unsigned int selector)
   380	{
   381		struct group_desc *g;
   382	
 > 383		g = pinctrl_generic_get_group(iod->pctl, selector);
   384		if (!g) {
   385			dev_err(iod->dev, "%s could not find pingroup %i\n", __func__,
   386				selector);
   387	
   388			return NULL;
   389		}
   390	
 > 391		return g->data;
   392	}
   393	
   394	/**

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

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

^ permalink raw reply

* Re: [PATCH v3] net: ethernet: faraday: To support device tree usage.
From: Arnd Bergmann @ 2016-12-31 20:23 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Greentime Hu, netdev, devicetree, andrew, linux-kernel, jiri
In-Reply-To: <351d1ae7-ca51-7962-0e52-38cdc69bcebd@gmail.com>

On Saturday, December 31, 2016 10:48:39 AM CET Florian Fainelli wrote:
> 
> On 12/29/2016 11:37 PM, Greentime Hu wrote:
> > Signed-off-by: Greentime Hu <green.hu@gmail.com>
> 
> This is not enough, you need to add a Device Tree binding document under
> Documentation/devicetree/bindings/net/ which documents this compatible
> string, as well as additional properties that may be required to
> describe this hardware block.

We already have

Documentation/devicetree/bindings/net/moxa,moxart-mac.txt

for the same hardware (though used by a different driver).

I'd suggest renaming that one to a more generic file name and
adding the new compatible string there.

Aside from that, every patch should also have a changelog comment.

	Arnd

^ permalink raw reply

* Re: [PATCH v3] net: ethernet: faraday: To support device tree usage.
From: Florian Fainelli @ 2016-12-31 18:48 UTC (permalink / raw)
  To: Greentime Hu, netdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, andrew-g2DYL2Zd6BY,
	arnd-r2nGTMty4D4, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	jiri-rHqAuBHg3fBzbRFIqnYvSA
In-Reply-To: <1483083470-15779-1-git-send-email-green.hu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>



On 12/29/2016 11:37 PM, Greentime Hu wrote:
> Signed-off-by: Greentime Hu <green.hu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This is not enough, you need to add a Device Tree binding document under
Documentation/devicetree/bindings/net/ which documents this compatible
string, as well as additional properties that may be required to
describe this hardware block.

-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [v2 2/2] MIPS: BMIPS: Add support SPI device nodes
From: Florian Fainelli @ 2016-12-31 18:42 UTC (permalink / raw)
  To: Jaedon Shin, Ralf Baechle, Mark Brown
  Cc: Kevin Cernekee, Rob Herring, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161230063001.944-3-jaedon.shin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Hi Jaedon,

On 12/29/2016 10:30 PM, Jaedon Shin wrote:
> Adds SPI device nodes to BCM7xxx MIPS based SoCs.
> 
> Signed-off-by: Jaedon Shin <jaedon.shin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---

> +
> +&qspi {
> +	status = "okay";
> +
> +	m25p80@0 {
> +		compatible = "m25p80";
> +		reg = <0>;
> +		spi-max-frequency = <0x2625a00>;

Sorry for not noticing this earlier, can we have the frequency in a
decimal form?

With that fixed, feel free to add:

Reviewed-by: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Thanks!
-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2] clk: cdce925: add support for CDCE913, CDCE937, and CDCE949
From: Akinobu Mita @ 2016-12-31 18:04 UTC (permalink / raw)
  To: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: Akinobu Mita, Mike Looijmans, Michael Turquette, Stephen Boyd

The CDCE925 is a member of the CDCE(L)9xx programmable clock generator
family.  There are also CDCE913, CDCE937, CDCE949 which have different
number of PLLs and outputs.

The clk-cdce925 driver supports only CDCE925 in the family.  This adds
support for the CDCE913, CDCE937, CDCE949, too.

Signed-off-by: Akinobu Mita <akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>
Cc: Michael Turquette <mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
* Changes from v1
- Add Acked-by line from Rob Herring
- Rename local variable 'cdce925_regmap_config' to 'config',
  suggested by Stephen Boyd

 .../devicetree/bindings/clock/ti,cdce925.txt       |  15 ++-
 drivers/clk/Kconfig                                |  11 ++-
 drivers/clk/clk-cdce925.c                          | 108 ++++++++++++++++-----
 3 files changed, 100 insertions(+), 34 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt
index 4c7669a..0d01f2d 100644
--- a/Documentation/devicetree/bindings/clock/ti,cdce925.txt
+++ b/Documentation/devicetree/bindings/clock/ti,cdce925.txt
@@ -1,15 +1,22 @@
-Binding for TO CDCE925 programmable I2C clock synthesizers.
+Binding for TI CDCE913/925/937/949 programmable I2C clock synthesizers.
 
 Reference
 This binding uses the common clock binding[1].
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] http://www.ti.com/product/cdce925
+[2] http://www.ti.com/product/cdce913
+[3] http://www.ti.com/product/cdce925
+[4] http://www.ti.com/product/cdce937
+[5] http://www.ti.com/product/cdce949
 
 The driver provides clock sources for each output Y1 through Y5.
 
 Required properties:
- - compatible: Shall be "ti,cdce925"
+ - compatible: Shall be one of the following:
+	- "ti,cdce913": 1-PLL, 3 Outputs
+	- "ti,cdce925": 2-PLL, 5 Outputs
+	- "ti,cdce937": 3-PLL, 7 Outputs
+	- "ti,cdce949": 4-PLL, 9 Outputs
  - reg: I2C device address.
  - clocks: Points to a fixed parent clock that provides the input frequency.
  - #clock-cells: From common clock bindings: Shall be 1.
@@ -18,7 +25,7 @@ Optional properties:
  - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a
                  board, or to compensate for external influences.
 
-For both PLL1 and PLL2 an optional child node can be used to specify spread
+For all PLL1, PLL2, ... an optional child node can be used to specify spread
 spectrum clocking parameters for a board.
   - spread-spectrum: SSC mode as defined in the data sheet.
   - spread-spectrum-center: Use "centered" mode instead of "max" mode. When
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d051edd..8f67dc9 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -104,16 +104,17 @@ config COMMON_CLK_CDCE706
 	  This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
 
 config COMMON_CLK_CDCE925
-	tristate "Clock driver for TI CDCE925 devices"
+	tristate "Clock driver for TI CDCE913/925/937/949 devices"
 	depends on I2C
 	depends on OF
 	select REGMAP_I2C
 	help
 	---help---
-	  This driver supports the TI CDCE925 programmable clock synthesizer.
-	  The chip contains two PLLs with spread-spectrum clocking support and
-	  five output dividers. The driver only supports the following setup,
-	  and uses a fixed setting for the output muxes.
+	  This driver supports the TI CDCE913/925/937/949 programmable clock
+	  synthesizer. Each chip has different number of PLLs and outputs.
+	  For example, the CDCE925 contains two PLLs with spread-spectrum
+	  clocking support and five output dividers. The driver only supports
+	  the following setup, and uses a fixed setting for the output muxes.
 	  Y1 is derived from the input clock
 	  Y2 and Y3 derive from PLL1
 	  Y4 and Y5 derive from PLL2
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c
index f793b2d..c933be0 100644
--- a/drivers/clk/clk-cdce925.c
+++ b/drivers/clk/clk-cdce925.c
@@ -1,8 +1,8 @@
 /*
- * Driver for TI Dual PLL CDCE925 clock synthesizer
+ * Driver for TI Multi PLL CDCE913/925/937/949 clock synthesizer
  *
- * This driver always connects the Y1 to the input clock, Y2/Y3 to PLL1
- * and Y4/Y5 to PLL2. PLL frequency is set on a first-come-first-serve
+ * This driver always connects the Y1 to the input clock, Y2/Y3 to PLL1,
+ * Y4/Y5 to PLL2, and so on. PLL frequency is set on a first-come-first-serve
  * basis. Clients can directly request any frequency that the chip can
  * deliver using the standard clk framework. In addition, the device can
  * be configured and activated via the devicetree.
@@ -19,11 +19,32 @@
 #include <linux/slab.h>
 #include <linux/gcd.h>
 
-/* The chip has 2 PLLs which can be routed through dividers to 5 outputs.
+/* Each chip has different number of PLLs and outputs, for example:
+ * The CECE925 has 2 PLLs which can be routed through dividers to 5 outputs.
  * Model this as 2 PLL clocks which are parents to the outputs.
  */
-#define NUMBER_OF_PLLS	2
-#define NUMBER_OF_OUTPUTS	5
+
+enum {
+	CDCE913,
+	CDCE925,
+	CDCE937,
+	CDCE949,
+};
+
+struct clk_cdce925_chip_info {
+	int num_plls;
+	int num_outputs;
+};
+
+static const struct clk_cdce925_chip_info clk_cdce925_chip_info_tbl[] = {
+	[CDCE913] = { .num_plls = 1, .num_outputs = 3 },
+	[CDCE925] = { .num_plls = 2, .num_outputs = 5 },
+	[CDCE937] = { .num_plls = 3, .num_outputs = 7 },
+	[CDCE949] = { .num_plls = 4, .num_outputs = 9 },
+};
+
+#define MAX_NUMBER_OF_PLLS	4
+#define MAX_NUMBER_OF_OUTPUTS	9
 
 #define CDCE925_REG_GLOBAL1	0x01
 #define CDCE925_REG_Y1SPIPDIVH	0x02
@@ -43,7 +64,7 @@ struct clk_cdce925_output {
 	struct clk_hw hw;
 	struct clk_cdce925_chip *chip;
 	u8 index;
-	u16 pdiv; /* 1..127 for Y2-Y5; 1..1023 for Y1 */
+	u16 pdiv; /* 1..127 for Y2-Y9; 1..1023 for Y1 */
 };
 #define to_clk_cdce925_output(_hw) \
 	container_of(_hw, struct clk_cdce925_output, hw)
@@ -60,8 +81,9 @@ struct clk_cdce925_pll {
 struct clk_cdce925_chip {
 	struct regmap *regmap;
 	struct i2c_client *i2c_client;
-	struct clk_cdce925_pll pll[NUMBER_OF_PLLS];
-	struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS];
+	const struct clk_cdce925_chip_info *chip_info;
+	struct clk_cdce925_pll pll[MAX_NUMBER_OF_PLLS];
+	struct clk_cdce925_output clk[MAX_NUMBER_OF_OUTPUTS];
 };
 
 /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
@@ -284,6 +306,18 @@ static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv)
 	case 4:
 		regmap_update_bits(data->chip->regmap, 0x27, 0x7F, pdiv);
 		break;
+	case 5:
+		regmap_update_bits(data->chip->regmap, 0x36, 0x7F, pdiv);
+		break;
+	case 6:
+		regmap_update_bits(data->chip->regmap, 0x37, 0x7F, pdiv);
+		break;
+	case 7:
+		regmap_update_bits(data->chip->regmap, 0x46, 0x7F, pdiv);
+		break;
+	case 8:
+		regmap_update_bits(data->chip->regmap, 0x47, 0x7F, pdiv);
+		break;
 	}
 }
 
@@ -302,6 +336,14 @@ static void cdce925_clk_activate(struct clk_cdce925_output *data)
 	case 4:
 		regmap_update_bits(data->chip->regmap, 0x24, 0x03, 0x03);
 		break;
+	case 5:
+	case 6:
+		regmap_update_bits(data->chip->regmap, 0x34, 0x03, 0x03);
+		break;
+	case 7:
+	case 8:
+		regmap_update_bits(data->chip->regmap, 0x44, 0x03, 0x03);
+		break;
 	}
 }
 
@@ -474,15 +516,6 @@ static const struct clk_ops cdce925_clk_y1_ops = {
 	.set_rate = cdce925_clk_y1_set_rate,
 };
 
-
-static struct regmap_config cdce925_regmap_config = {
-	.name = "configuration0",
-	.reg_bits = 8,
-	.val_bits = 8,
-	.cache_type = REGCACHE_RBTREE,
-	.max_register = 0x2F,
-};
-
 #define CDCE925_I2C_COMMAND_BLOCK_TRANSFER	0x00
 #define CDCE925_I2C_COMMAND_BYTE_TRANSFER	0x80
 
@@ -582,13 +615,19 @@ static int cdce925_probe(struct i2c_client *client,
 	struct clk_cdce925_chip *data;
 	struct device_node *node = client->dev.of_node;
 	const char *parent_name;
-	const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,};
+	const char *pll_clk_name[MAX_NUMBER_OF_PLLS] = {NULL,};
 	struct clk_init_data init;
 	u32 value;
 	int i;
 	int err;
 	struct device_node *np_output;
 	char child_name[6];
+	struct regmap_config config = {
+		.name = "configuration0",
+		.reg_bits = 8,
+		.val_bits = 8,
+		.cache_type = REGCACHE_RBTREE,
+	};
 
 	dev_dbg(&client->dev, "%s\n", __func__);
 	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
@@ -596,8 +635,11 @@ static int cdce925_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	data->i2c_client = client;
+	data->chip_info = &clk_cdce925_chip_info_tbl[id->driver_data];
+	config.max_register = CDCE925_OFFSET_PLL +
+		data->chip_info->num_plls * 0x10 - 1;
 	data->regmap = devm_regmap_init(&client->dev, &regmap_cdce925_bus,
-			&client->dev, &cdce925_regmap_config);
+			&client->dev, &config);
 	if (IS_ERR(data->regmap)) {
 		dev_err(&client->dev, "failed to allocate register map\n");
 		return PTR_ERR(data->regmap);
@@ -626,7 +668,7 @@ static int cdce925_probe(struct i2c_client *client,
 	init.num_parents = parent_name ? 1 : 0;
 
 	/* Register PLL clocks */
-	for (i = 0; i < NUMBER_OF_PLLS; ++i) {
+	for (i = 0; i < data->chip_info->num_plls; ++i) {
 		pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d",
 			client->dev.of_node->name, i);
 		init.name = pll_clk_name[i];
@@ -684,7 +726,7 @@ static int cdce925_probe(struct i2c_client *client,
 	init.ops = &cdce925_clk_ops;
 	init.flags = CLK_SET_RATE_PARENT;
 	init.num_parents = 1;
-	for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) {
+	for (i = 1; i < data->chip_info->num_outputs; ++i) {
 		init.name = kasprintf(GFP_KERNEL, "%s.Y%d",
 			client->dev.of_node->name, i+1);
 		data->clk[i].chip = data;
@@ -702,6 +744,16 @@ static int cdce925_probe(struct i2c_client *client,
 			/* Mux Y4/5 to PLL2 */
 			init.parent_names = &pll_clk_name[1];
 			break;
+		case 5:
+		case 6:
+			/* Mux Y6/7 to PLL3 */
+			init.parent_names = &pll_clk_name[2];
+			break;
+		case 7:
+		case 8:
+			/* Mux Y8/9 to PLL4 */
+			init.parent_names = &pll_clk_name[3];
+			break;
 		}
 		err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
 		kfree(init.name); /* clock framework made a copy of the name */
@@ -720,7 +772,7 @@ static int cdce925_probe(struct i2c_client *client,
 	err = 0;
 
 error:
-	for (i = 0; i < NUMBER_OF_PLLS; ++i)
+	for (i = 0; i < data->chip_info->num_plls; ++i)
 		/* clock framework made a copy of the name */
 		kfree(pll_clk_name[i]);
 
@@ -728,13 +780,19 @@ static int cdce925_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id cdce925_id[] = {
-	{ "cdce925", 0 },
+	{ "cdce913", CDCE913 },
+	{ "cdce925", CDCE925 },
+	{ "cdce937", CDCE937 },
+	{ "cdce949", CDCE949 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, cdce925_id);
 
 static const struct of_device_id clk_cdce925_of_match[] = {
+	{ .compatible = "ti,cdce913" },
 	{ .compatible = "ti,cdce925" },
+	{ .compatible = "ti,cdce937" },
+	{ .compatible = "ti,cdce949" },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, clk_cdce925_of_match);
@@ -750,5 +808,5 @@ static struct i2c_driver cdce925_driver = {
 module_i2c_driver(cdce925_driver);
 
 MODULE_AUTHOR("Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>");
-MODULE_DESCRIPTION("cdce925 driver");
+MODULE_DESCRIPTION("TI CDCE913/925/937/949 driver");
 MODULE_LICENSE("GPL");
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v6 5/9] iio: multiplexer: new iio category and iio-mux driver
From: Jonathan Cameron @ 2016-12-31 16:21 UTC (permalink / raw)
  To: Peter Rosin, linux-kernel
  Cc: Wolfram Sang, Rob Herring, Mark Rutland, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Jonathan Corbet,
	Arnd Bergmann, Greg Kroah-Hartman, linux-i2c, devicetree,
	linux-iio, linux-doc
In-Reply-To: <1480493823-21462-6-git-send-email-peda@axentia.se>

On 30/11/16 08:16, Peter Rosin wrote:
> When a multiplexer changes how an iio device behaves (for example
> by feeding different signals to an ADC), this driver can be used
> to create one virtual iio channel for each multiplexer state.
> 
> Depends on the generic multiplexer subsystem.
> 
> Cache any ext_info values from the parent iio channel, creating a private
> copy of the ext_info attributes for each multiplexer state/channel.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
Other than binding naming, I'm happy with this - so pending that changing...

Reviewed-by: Jonathan Cameron <jic23@kernel.org>

If it makes sense I can obviously take this via IIO once the core is in
place.

Jonathan
> ---
>  MAINTAINERS                       |   1 +
>  drivers/iio/Kconfig               |   1 +
>  drivers/iio/Makefile              |   1 +
>  drivers/iio/multiplexer/Kconfig   |  18 ++
>  drivers/iio/multiplexer/Makefile  |   6 +
>  drivers/iio/multiplexer/iio-mux.c | 456 ++++++++++++++++++++++++++++++++++++++
>  6 files changed, 483 insertions(+)
>  create mode 100644 drivers/iio/multiplexer/Kconfig
>  create mode 100644 drivers/iio/multiplexer/Makefile
>  create mode 100644 drivers/iio/multiplexer/iio-mux.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 77045ae15865..16490fbd1721 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6239,6 +6239,7 @@ M:	Peter Rosin <peda@axentia.se>
>  L:	linux-iio@vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
> +F:	drivers/iio/multiplexer/iio-mux.c
>  
>  IIO SUBSYSTEM AND DRIVERS
>  M:	Jonathan Cameron <jic23@kernel.org>
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index a918270d6f54..b3c8c6ef0dff 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
>  source "drivers/iio/imu/Kconfig"
>  source "drivers/iio/light/Kconfig"
>  source "drivers/iio/magnetometer/Kconfig"
> +source "drivers/iio/multiplexer/Kconfig"
>  source "drivers/iio/orientation/Kconfig"
>  if IIO_TRIGGER
>     source "drivers/iio/trigger/Kconfig"
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> index 33fa4026f92c..93c769cd99bf 100644
> --- a/drivers/iio/Makefile
> +++ b/drivers/iio/Makefile
> @@ -28,6 +28,7 @@ obj-y += humidity/
>  obj-y += imu/
>  obj-y += light/
>  obj-y += magnetometer/
> +obj-y += multiplexer/
>  obj-y += orientation/
>  obj-y += potentiometer/
>  obj-y += potentiostat/
> diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
> new file mode 100644
> index 000000000000..70a044510686
> --- /dev/null
> +++ b/drivers/iio/multiplexer/Kconfig
> @@ -0,0 +1,18 @@
> +#
> +# Multiplexer drivers
> +#
> +# When adding new entries keep the list in alphabetical order
> +
> +menu "Multiplexers"
> +
> +config IIO_MUX
> +	tristate "IIO multiplexer driver"
> +	select MULTIPLEXER
> +	depends on OF
> +	help
> +	  Say yes here to build support for the IIO multiplexer.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called iio-mux.
> +
> +endmenu
> diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
> new file mode 100644
> index 000000000000..68be3c4abd07
> --- /dev/null
> +++ b/drivers/iio/multiplexer/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for industrial I/O multiplexer drivers
> +#
> +
> +# When adding new entries keep the list in alphabetical order
> +obj-$(CONFIG_IIO_MUX) += iio-mux.o
> diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
> new file mode 100644
> index 000000000000..92dfee2dfed1
> --- /dev/null
> +++ b/drivers/iio/multiplexer/iio-mux.c
> @@ -0,0 +1,456 @@
> +/*
> + * IIO multiplexer driver
> + *
> + * Copyright (C) 2016 Axentia Technologies AB
> + *
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/iio/consumer.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/mux.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +
> +struct mux_ext_info_cache {
> +	char *data;
> +	size_t size;
> +};
> +
> +struct mux_child {
> +	struct mux_ext_info_cache *ext_info_cache;
> +};
> +
> +struct mux {
> +	int cached_state;
> +	struct mux_control *control;
> +	struct iio_channel *parent;
> +	struct iio_dev *indio_dev;
> +	struct iio_chan_spec *chan;
> +	struct iio_chan_spec_ext_info *ext_info;
> +	struct mux_child *child;
> +};
> +
> +static int iio_mux_select(struct mux *mux, int idx)
> +{
> +	struct mux_child *child = &mux->child[idx];
> +	struct iio_chan_spec const *chan = &mux->chan[idx];
> +	int ret;
> +	int i;
> +
> +	ret = mux_control_select(mux->control, chan->channel);
> +	if (ret < 0) {
> +		mux->cached_state = -1;
> +		return ret;
> +	}
> +
> +	if (mux->cached_state == chan->channel)
> +		return 0;
> +
> +	if (chan->ext_info) {
> +		for (i = 0; chan->ext_info[i].name; ++i) {
> +			const char *attr = chan->ext_info[i].name;
> +			struct mux_ext_info_cache *cache;
> +
> +			cache = &child->ext_info_cache[i];
> +
> +			if (cache->size < 0)
> +				continue;
> +
> +			ret = iio_write_channel_ext_info(mux->parent, attr,
> +							 cache->data,
> +							 cache->size);
> +
> +			if (ret < 0) {
> +				mux_control_deselect(mux->control);
> +				mux->cached_state = -1;
> +				return ret;
> +			}
> +		}
> +	}
> +	mux->cached_state = chan->channel;
> +
> +	return 0;
> +}
> +
> +static void iio_mux_deselect(struct mux *mux)
> +{
> +	mux_control_deselect(mux->control);
> +}
> +
> +static int mux_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *chan,
> +			int *val, int *val2, long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = iio_read_channel_raw(mux->parent, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = iio_read_channel_scale(mux->parent, val, val2);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_read_avail(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *chan,
> +			  const int **vals, int *type, int *length,
> +			  long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		*type = IIO_VAL_INT;
> +		ret = iio_read_avail_channel_raw(mux->parent, vals, length);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_write_raw(struct iio_dev *indio_dev,
> +			 struct iio_chan_spec const *chan,
> +			 int val, int val2, long mask)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	int ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		ret = iio_write_channel_raw(mux->parent, val);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static const struct iio_info mux_info = {
> +	.read_raw = mux_read_raw,
> +	.read_avail = mux_read_avail,
> +	.write_raw = mux_write_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static ssize_t mux_read_ext_info(struct iio_dev *indio_dev, uintptr_t private,
> +				 struct iio_chan_spec const *chan, char *buf)
> +{
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	ssize_t ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = iio_read_channel_ext_info(mux->parent,
> +					mux->ext_info[private].name,
> +					buf);
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private,
> +				  struct iio_chan_spec const *chan,
> +				  const char *buf, size_t len)
> +{
> +	struct device *dev = indio_dev->dev.parent;
> +	struct mux *mux = iio_priv(indio_dev);
> +	int idx = chan - mux->chan;
> +	char *new;
> +	ssize_t ret;
> +
> +	ret = iio_mux_select(mux, idx);
> +	if (ret < 0)
> +		return ret;
> +
> +	new = devm_kmemdup(dev, buf, len + 1, GFP_KERNEL);
> +	if (!new) {
> +		iio_mux_deselect(mux);
> +		return -ENOMEM;
> +	}
> +
> +	new[len] = 0;
> +
> +	ret = iio_write_channel_ext_info(mux->parent,
> +					 mux->ext_info[private].name,
> +					 buf, len);
> +	if (ret < 0) {
> +		iio_mux_deselect(mux);
> +		devm_kfree(dev, new);
> +		return ret;
> +	}
> +
> +	devm_kfree(dev, mux->child[idx].ext_info_cache[private].data);
> +	mux->child[idx].ext_info_cache[private].data = new;
> +	mux->child[idx].ext_info_cache[private].size = len;
> +
> +	iio_mux_deselect(mux);
> +
> +	return ret;
> +}
> +
> +static int mux_configure_channel(struct device *dev, struct mux *mux,
> +				 u32 state, const char *label, int idx)
> +{
> +	struct mux_child *child = &mux->child[idx];
> +	struct iio_chan_spec *chan = &mux->chan[idx];
> +	struct iio_chan_spec const *pchan = mux->parent->channel;
> +	char *page = NULL;
> +	int num_ext_info;
> +	int i;
> +	int ret;
> +
> +	chan->indexed = 1;
> +	chan->output = pchan->output;
> +	chan->datasheet_name = label;
> +	chan->ext_info = mux->ext_info;
> +
> +	ret = iio_get_channel_type(mux->parent, &chan->type);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get parent channel type\n");
> +		return ret;
> +	}
> +
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> +
> +	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
> +
> +	if (state >= mux->control->states) {
> +		dev_err(dev, "too many channels\n");
> +		return -EINVAL;
> +	}
> +
> +	chan->channel = state;
> +
> +	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
> +	if (num_ext_info) {
> +		page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
> +		if (!page)
> +			return -ENOMEM;
> +	}
> +	child->ext_info_cache = devm_kzalloc(dev,
> +					     sizeof(*child->ext_info_cache) *
> +					     num_ext_info, GFP_KERNEL);
> +	for (i = 0; i < num_ext_info; ++i) {
> +		child->ext_info_cache[i].size = -1;
> +
> +		if (!pchan->ext_info[i].write)
> +			continue;
> +		if (!pchan->ext_info[i].read)
> +			continue;
> +
> +		ret = iio_read_channel_ext_info(mux->parent,
> +						mux->ext_info[i].name,
> +						page);
> +		if (ret < 0) {
> +			dev_err(dev, "failed to get ext_info '%s'\n",
> +				pchan->ext_info[i].name);
> +			return ret;
> +		}
> +		if (ret >= PAGE_SIZE) {
> +			dev_err(dev, "too large ext_info '%s'\n",
> +				pchan->ext_info[i].name);
> +			return -EINVAL;
> +		}
> +
> +		child->ext_info_cache[i].data = devm_kmemdup(dev, page, ret + 1,
> +							     GFP_KERNEL);
> +		child->ext_info_cache[i].data[ret] = 0;
> +		child->ext_info_cache[i].size = ret;
> +	}
> +
> +	if (page)
> +		devm_kfree(dev, page);
> +
> +	return 0;
> +}
> +
> +/*
> + * Same as of_property_for_each_string(), but also keeps track of the
> + * index of each string.
> + */
> +#define of_property_for_each_string_index(np, propname, prop, s, i)	\
> +	for (prop = of_find_property(np, propname, NULL),		\
> +	     s = of_prop_next_string(prop, NULL),			\
> +	     i = 0;							\
> +	     s;								\
> +	     s = of_prop_next_string(prop, s),				\
> +	     i++)
> +
> +static int mux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct iio_dev *indio_dev;
> +	struct iio_channel *parent;
> +	struct mux *mux;
> +	struct property *prop;
> +	const char *label;
> +	u32 state;
> +	int sizeof_ext_info;
> +	int children;
> +	int sizeof_priv;
> +	int i;
> +	int ret;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	parent = devm_iio_channel_get(dev, "parent");
> +	if (IS_ERR(parent)) {
> +		if (PTR_ERR(parent) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get parent channel\n");
> +		return PTR_ERR(parent);
> +	}
> +
> +	sizeof_ext_info = iio_get_channel_ext_info_count(parent);
> +	if (sizeof_ext_info) {
> +		sizeof_ext_info += 1; /* one extra entry for the sentinel */
> +		sizeof_ext_info *= sizeof(*mux->ext_info);
> +	}
> +
> +	children = 0;
> +	of_property_for_each_string(np, "channels", prop, label) {
> +		if (*label)
> +			children++;
> +	}
> +	if (children <= 0) {
> +		dev_err(dev, "not even a single child\n");
> +		return -EINVAL;
> +	}
> +
> +	sizeof_priv = sizeof(*mux);
> +	sizeof_priv += sizeof(*mux->child) * children;
> +	sizeof_priv += sizeof(*mux->chan) * children;
> +	sizeof_priv += sizeof_ext_info;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	mux = iio_priv(indio_dev);
> +	mux->child = (struct mux_child *)(mux + 1);
> +	mux->chan = (struct iio_chan_spec *)(mux->child + children);
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	mux->parent = parent;
> +	mux->cached_state = -1;
> +
> +	indio_dev->name = dev_name(dev);
> +	indio_dev->dev.parent = dev;
> +	indio_dev->info = &mux_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = mux->chan;
> +	indio_dev->num_channels = children;
> +	if (sizeof_ext_info) {
> +		mux->ext_info = devm_kmemdup(dev,
> +					     parent->channel->ext_info,
> +					     sizeof_ext_info, GFP_KERNEL);
> +		if (!mux->ext_info)
> +			return -ENOMEM;
> +
> +		for (i = 0; mux->ext_info[i].name; ++i) {
> +			if (parent->channel->ext_info[i].read)
> +				mux->ext_info[i].read = mux_read_ext_info;
> +			if (parent->channel->ext_info[i].write)
> +				mux->ext_info[i].write = mux_write_ext_info;
> +			mux->ext_info[i].private = i;
> +		}
> +	}
> +
> +	mux->control = devm_mux_control_get(dev, NULL);
> +	if (IS_ERR(mux->control)) {
> +		if (PTR_ERR(mux->control) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get control-mux\n");
> +		return PTR_ERR(mux->control);
> +	}
> +
> +	i = 0;
> +	of_property_for_each_string_index(np, "channels", prop, label, state) {
> +		if (!*label)
> +			continue;
> +
> +		ret = mux_configure_channel(dev, mux, state, label, i++);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	ret = devm_iio_device_register(dev, indio_dev);
> +	if (ret) {
> +		dev_err(dev, "failed to register iio device\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mux_match[] = {
> +	{ .compatible = "iio-mux" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mux_match);
> +
> +static struct platform_driver mux_driver = {
> +	.probe = mux_probe,
> +	.driver = {
> +		.name = "iio-mux",
> +		.of_match_table = mux_match,
> +	},
> +};
> +module_platform_driver(mux_driver);
> +
> +MODULE_DESCRIPTION("IIO multiplexer driver");
> +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply


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