* [PATCH v3 3/9] ARM: dts: imx6qdl-icore: Add Sound card with codec node
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel, devicetree, linux-kernel, Sascha Hauer,
Fabio Estevam, Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan@openedev.com>
From: Jagan Teki <jagan@amarulasolutions.com>
Add support for Sound card and related codec(via i2c1) nodes
on below Engicam module boards.
- i.CoreM6 DualLite/Solo Starter kit
- i.CoreM6 Quad/Dual Starter kit
- i.CoreM6 Quad/Dual OpenFrame Cap touch 10.1
- i.CoreM6 Quad/Dual OpenFrame Cap touch 12.3
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Matteo Lisi <matteo.lisi@engicam.com>
Cc: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v3:
- Replace fsl,imx-audio-sgtl5000 and use simple-audio-card
Changes for v2:
- Use proper [label:] node-name[@unit-address] for codec
arch/arm/boot/dts/imx6dl-icore.dts | 11 +++++++
arch/arm/boot/dts/imx6q-icore-ofcap10.dts | 11 +++++++
arch/arm/boot/dts/imx6q-icore-ofcap12.dts | 11 +++++++
arch/arm/boot/dts/imx6q-icore.dts | 11 +++++++
arch/arm/boot/dts/imx6qdl-icore.dtsi | 48 +++++++++++++++++++++++++++++++
5 files changed, 92 insertions(+)
diff --git a/arch/arm/boot/dts/imx6dl-icore.dts b/arch/arm/boot/dts/imx6dl-icore.dts
index 6de83c7..0562ce4 100644
--- a/arch/arm/boot/dts/imx6dl-icore.dts
+++ b/arch/arm/boot/dts/imx6dl-icore.dts
@@ -57,3 +57,14 @@
&can2 {
status = "okay";
};
+
+&i2c3 {
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
+ VDDA-supply = <®_2p5v>;
+ VDDIO-supply = <®_3p3v>;
+ VDDD-supply = <®_1p8v>;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-icore-ofcap10.dts b/arch/arm/boot/dts/imx6q-icore-ofcap10.dts
index 49b60ca..f63b87f 100644
--- a/arch/arm/boot/dts/imx6q-icore-ofcap10.dts
+++ b/arch/arm/boot/dts/imx6q-icore-ofcap10.dts
@@ -50,6 +50,17 @@
compatible = "engicam,imx6-icore", "fsl,imx6q";
};
+&i2c3 {
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
+ VDDA-supply = <®_2p5v>;
+ VDDIO-supply = <®_3p3v>;
+ VDDD-supply = <®_1p8v>;
+ };
+};
+
&ldb {
status = "okay";
diff --git a/arch/arm/boot/dts/imx6q-icore-ofcap12.dts b/arch/arm/boot/dts/imx6q-icore-ofcap12.dts
index 9e230f5..68ca828 100644
--- a/arch/arm/boot/dts/imx6q-icore-ofcap12.dts
+++ b/arch/arm/boot/dts/imx6q-icore-ofcap12.dts
@@ -50,6 +50,17 @@
compatible = "engicam,imx6-icore", "fsl,imx6q";
};
+&i2c3 {
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
+ VDDA-supply = <®_2p5v>;
+ VDDIO-supply = <®_3p3v>;
+ VDDD-supply = <®_1p8v>;
+ };
+};
+
&ldb {
status = "okay";
diff --git a/arch/arm/boot/dts/imx6q-icore.dts b/arch/arm/boot/dts/imx6q-icore.dts
index 5613dd9..1ae7294 100644
--- a/arch/arm/boot/dts/imx6q-icore.dts
+++ b/arch/arm/boot/dts/imx6q-icore.dts
@@ -67,6 +67,17 @@
};
};
+&i2c3 {
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
+ VDDA-supply = <®_2p5v>;
+ VDDIO-supply = <®_3p3v>;
+ VDDD-supply = <®_1p8v>;
+ };
+};
+
&ldb {
status = "okay";
diff --git a/arch/arm/boot/dts/imx6qdl-icore.dtsi b/arch/arm/boot/dts/imx6qdl-icore.dtsi
index 56d0c5d..1bd7cdb 100644
--- a/arch/arm/boot/dts/imx6qdl-icore.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore.dtsi
@@ -55,6 +55,25 @@
default-brightness-level = <7>;
};
+ reg_1p8v: regulator-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "1P8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+
+ reg_2p5v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
reg_3p3v: regulator-3p3v {
compatible = "regulator-fixed";
regulator-name = "3P3V";
@@ -87,6 +106,31 @@
#clock-cells = <0>;
clock-frequency = <25000000>; /* 25MHz for example */
};
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "imx6qdl-icore-sgtl5000";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink_master>;
+ simple-audio-card,frame-master = <&dailink_master>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Line", "Line In",
+ "Line", "Line Out",
+ "Headphone", "Headphone Jack";
+ simple-audio-card,routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+
+ simple-audio-card,cpu {
+ sound-dai = <&ssi1>;
+ };
+
+ dailink_master: simple-audio-card,codec {
+ sound-dai = <&sgtl5000>;
+ };
+ };
};
&can1 {
@@ -149,6 +193,10 @@
status = "okay";
};
+&ssi1 {
+ status = "okay";
+};
+
&uart4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart4>;
--
1.9.1
^ permalink raw reply related
* [PATCH v3 4/9] ARM: dts: imx6dl-icore-rqs: Add sgtl5000 codec node
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel, devicetree, linux-kernel, Sascha Hauer,
Fabio Estevam, Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan@openedev.com>
From: Jagan Teki <jagan@amarulasolutions.com>
- Moved sound card node to imx6qdl-icore-rqs.dtsi
- Added codec node in imx6dl-icore-rqs
- Replace codec: sgtl5000@0a => sgtl5000: codec@a
on imx6q-icore-rqs.dts to [label:] node-name[@unit-address]
according to devicetree specification from ePAPER v1.1
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Matteo Lisi <matteo.lisi@engicam.com>
Cc: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v3:
- squash previous [PATCH v2 10/15] and [PATCH v2 11/15]
Changes for v2:
- Newly added patch
arch/arm/boot/dts/imx6dl-icore-rqs.dts | 11 +++++++++++
arch/arm/boot/dts/imx6q-icore-rqs.dts | 15 +--------------
arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi | 13 +++++++++++++
3 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/arch/arm/boot/dts/imx6dl-icore-rqs.dts b/arch/arm/boot/dts/imx6dl-icore-rqs.dts
index cf42c2f..053e7cb 100644
--- a/arch/arm/boot/dts/imx6dl-icore-rqs.dts
+++ b/arch/arm/boot/dts/imx6dl-icore-rqs.dts
@@ -49,3 +49,14 @@
model = "Engicam i.CoreM6 DualLite/Solo RQS Starter Kit";
compatible = "engicam,imx6-icore-rqs", "fsl,imx6dl";
};
+
+&i2c3 {
+ sgtl5000: codec@a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
+ VDDA-supply = <®_2p5v>;
+ VDDIO-supply = <®_3p3v>;
+ VDDD-supply = <®_1p8v>;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-icore-rqs.dts b/arch/arm/boot/dts/imx6q-icore-rqs.dts
index e451b4c..d45e4f5 100644
--- a/arch/arm/boot/dts/imx6q-icore-rqs.dts
+++ b/arch/arm/boot/dts/imx6q-icore-rqs.dts
@@ -47,23 +47,10 @@
/ {
model = "Engicam i.CoreM6 Quad/Dual RQS Starter Kit";
compatible = "engicam,imx6-icore-rqs", "fsl,imx6q";
-
- sound {
- compatible = "fsl,imx-audio-sgtl5000";
- model = "imx-audio-sgtl5000";
- ssi-controller = <&ssi1>;
- audio-codec = <&codec>;
- audio-routing =
- "MIC_IN", "Mic Jack",
- "Mic Jack", "Mic Bias",
- "Headphone Jack", "HP_OUT";
- mux-int-port = <1>;
- mux-ext-port = <4>;
- };
};
&i2c3 {
- codec: sgtl5000@0a {
+ sgtl5000: codec@a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
clocks = <&clks IMX6QDL_CLK_CKO>;
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
index 5fab5be..d24e531 100644
--- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
@@ -118,6 +118,19 @@
clocks = <&clks IMX6QDL_CLK_LVDS2_GATE>;
clock-names = "refclk";
};
+
+ sound {
+ compatible = "fsl,imx-audio-sgtl5000";
+ model = "imx-audio-sgtl5000";
+ ssi-controller = <&ssi1>;
+ audio-codec = <&sgtl5000>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <1>;
+ mux-ext-port = <4>;
+ };
};
&clks {
--
1.9.1
^ permalink raw reply related
* [PATCH v3 5/9] ARM: dts: imx6qdl-icore-rqs: Replace to use simple-audio-card
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: devicetree, Matteo Lisi, linux-kernel, Jagan Teki, Sascha Hauer,
Fabio Estevam, Michael Trimarchi, linux-arm-kernel
In-Reply-To: <1491501735-1649-1-git-send-email-jagan@openedev.com>
From: Jagan Teki <jagan@amarulasolutions.com>
This patch replace fsl,imx-audio-sgtl5000 and use simple-audio-card
for Engicam i.CoreM6 RQS QDL platform boards.
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Matteo Lisi <matteo.lisi@engicam.com>
Cc: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v3:
- Newly added patch
arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
index d24e531..0e79a5b 100644
--- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
@@ -120,16 +120,28 @@
};
sound {
- compatible = "fsl,imx-audio-sgtl5000";
- model = "imx-audio-sgtl5000";
- ssi-controller = <&ssi1>;
- audio-codec = <&sgtl5000>;
- audio-routing =
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "imx6qdl-icore-sgtl5000";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink_master>;
+ simple-audio-card,frame-master = <&dailink_master>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Line", "Line In",
+ "Line", "Line Out",
+ "Headphone", "Headphone Jack";
+ simple-audio-card,routing =
"MIC_IN", "Mic Jack",
"Mic Jack", "Mic Bias",
"Headphone Jack", "HP_OUT";
- mux-int-port = <1>;
- mux-ext-port = <4>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&ssi1>;
+ };
+
+ dailink_master: simple-audio-card,codec {
+ sound-dai = <&sgtl5000>;
+ };
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 6/9] ARM: dts: imx6dl-icore: Add LVDS support
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel, devicetree, linux-kernel, Sascha Hauer,
Fabio Estevam, Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan@openedev.com>
From: Jagan Teki <jagan@amarulasolutions.com>
Add LVDS display support for OpenFrame Capacitive touch 7 inc
display which is supported by Engicam i.CoreM6 DualLite/Solo Starter Kit.
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Matteo Lisi <matteo.lisi@engicam.com>
Cc: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v3,v2:
- none
arch/arm/boot/dts/imx6dl-icore.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/imx6dl-icore.dts b/arch/arm/boot/dts/imx6dl-icore.dts
index 0562ce4..ea9ab05 100644
--- a/arch/arm/boot/dts/imx6dl-icore.dts
+++ b/arch/arm/boot/dts/imx6dl-icore.dts
@@ -68,3 +68,28 @@
VDDD-supply = <®_1p8v>;
};
};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ fsl,data-mapping = "spwg";
+ fsl,data-width = <18>;
+ status = "okay";
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing0 {
+ clock-frequency = <60000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <30>;
+ hfront-porch = <30>;
+ vback-porch = <5>;
+ vfront-porch = <5>;
+ hsync-len = <64>;
+ vsync-len = <20>;
+ };
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 7/9] ARM: dts: imx6dl-icore: Add touchscreen node
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Fabio Estevam,
Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan-oRp2ZoJdM/RWk0Htik3J/w@public.gmane.org>
From: Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
max11801 touchscreen on Engicam iCoreM6 DualLite/Solo module is
connected via i2c1, so add max11801: touchscreen@48 on i2c1.
Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Matteo Lisi <matteo.lisi-4s7YQHO/iPVBDgjK7y7TUQ@public.gmane.org>
Cc: Michael Trimarchi <michael-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Signed-off-by: Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
---
Changes for v3,v2:
- none
arch/arm/boot/dts/imx6dl-icore.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/imx6dl-icore.dts b/arch/arm/boot/dts/imx6dl-icore.dts
index ea9ab05..27f37cd 100644
--- a/arch/arm/boot/dts/imx6dl-icore.dts
+++ b/arch/arm/boot/dts/imx6dl-icore.dts
@@ -58,6 +58,15 @@
status = "okay";
};
+&i2c1 {
+ max11801: touchscreen@48 {
+ compatible = "maxim,max11801";
+ reg = <0x48>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
&i2c3 {
sgtl5000: codec@a {
compatible = "fsl,sgtl5000";
--
1.9.1
--
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 v3 8/9] ARM: dts: imx6qdl-icore-rqs: Add CAN nodes
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel, devicetree, linux-kernel, Sascha Hauer,
Fabio Estevam, Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan@openedev.com>
From: Jagan Teki <jagan@amarulasolutions.com>
Add support for can1 and can2 nodes on Engicam i.CoreM6 RQS
QDL module boards.
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Matteo Lisi <matteo.lisi@engicam.com>
Cc: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v3:
- none
Changes for v2:
- s/flexcan/can
- s/pinctrl_flexcan/pinctrl_can
arch/arm/boot/dts/imx6dl-icore-rqs.dts | 8 ++++++++
arch/arm/boot/dts/imx6q-icore-rqs.dts | 8 ++++++++
arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi | 26 ++++++++++++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/arch/arm/boot/dts/imx6dl-icore-rqs.dts b/arch/arm/boot/dts/imx6dl-icore-rqs.dts
index 053e7cb..74335c4 100644
--- a/arch/arm/boot/dts/imx6dl-icore-rqs.dts
+++ b/arch/arm/boot/dts/imx6dl-icore-rqs.dts
@@ -60,3 +60,11 @@
VDDD-supply = <®_1p8v>;
};
};
+
+&can1 {
+ status = "okay";
+};
+
+&can2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-icore-rqs.dts b/arch/arm/boot/dts/imx6q-icore-rqs.dts
index d45e4f5..2d4539a 100644
--- a/arch/arm/boot/dts/imx6q-icore-rqs.dts
+++ b/arch/arm/boot/dts/imx6q-icore-rqs.dts
@@ -49,6 +49,14 @@
compatible = "engicam,imx6-icore-rqs", "fsl,imx6q";
};
+&can1 {
+ status = "okay";
+};
+
+&can2 {
+ status = "okay";
+};
+
&i2c3 {
sgtl5000: codec@a {
compatible = "fsl,sgtl5000";
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
index 0e79a5b..998fa77 100644
--- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
@@ -145,6 +145,18 @@
};
};
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can1>;
+ xceiver-supply = <®_3p3v>;
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can2>;
+ xceiver-supply = <®_3p3v>;
+};
+
&clks {
assigned-clocks = <&clks IMX6QDL_CLK_LVDS2_SEL>;
assigned-clock-parents = <&clks IMX6QDL_CLK_OSC>;
@@ -296,6 +308,20 @@
>;
};
+ pinctrl_can1: can1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b020
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b020
+ >;
+ };
+
+ pinctrl_can2: can2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b020
+ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b020
+ >;
+ };
+
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
--
1.9.1
^ permalink raw reply related
* [PATCH v3 9/9] ARM: dts: imx6ul-isiot: Add FEC node support
From: Jagan Teki @ 2017-04-06 18:02 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Fabio Estevam,
Matteo Lisi, Michael Trimarchi, Jagan Teki
In-Reply-To: <1491501735-1649-1-git-send-email-jagan-oRp2ZoJdM/RWk0Htik3J/w@public.gmane.org>
From: Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Add support for fec1 node on Engicam Is.IoT variant boards.
Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Matteo Lisi <matteo.lisi-4s7YQHO/iPVBDgjK7y7TUQ@public.gmane.org>
Cc: Michael Trimarchi <michael-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Signed-off-by: Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
---
Changes for v3:
- none
Changes for v2:
- Newly added patch
arch/arm/boot/dts/imx6ul-isiot.dtsi | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm/boot/dts/imx6ul-isiot.dtsi b/arch/arm/boot/dts/imx6ul-isiot.dtsi
index 7e947e5..ccc5477 100644
--- a/arch/arm/boot/dts/imx6ul-isiot.dtsi
+++ b/arch/arm/boot/dts/imx6ul-isiot.dtsi
@@ -129,6 +129,24 @@
status = "okay";
};
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ phy-mode = "rmii";
+ phy-handle = <ðphy0>;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+ };
+};
+
&pwm8 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm8>;
@@ -159,6 +177,21 @@
};
&iomuxc {
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET2_RX_DATA0__ENET1_MDIO 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA1__ENET1_MDC 0x1b0b0
+ MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
+ MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10 0x1b0b0
+ >;
+ };
+
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
--
1.9.1
--
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 v3] regulator: Add driver for voltage controlled regulators
From: Mark Brown @ 2017-04-06 18:21 UTC (permalink / raw)
To: Matthias Kaehlcke
Cc: Liam Girdwood, Rob Herring, Mark Rutland,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Douglas Anderson, Brian Norris
In-Reply-To: <20170331205035.126001-1-mka-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 815 bytes --]
On Fri, Mar 31, 2017 at 01:50:35PM -0700, Matthias Kaehlcke wrote:
> +- compatible : must be "vctrl-regulator".
> +- regulator-min-microvolt : smallest voltage consumers may set
> +- regulator-max-microvolt : largest voltage consumers may set
> +- ctrl-regulator: : the name of the regulator supplying the control
> + voltage.
This looks good except for this bit where we read the regulator name out
of the DT, that's generally a sign of bad practice for things that are
less simple passives than things like this or fixed voltage regulators.
As with the supplies for fixed voltage regulators just pick a name for
the supply (ctrl seems fine to me) and use that, neither option is
perfect but at elast this less typing for everyone and it's consistent
with what other similar things are already doing.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH] of: change fixup of dma-ranges size to error
From: Frank Rowand @ 2017-04-06 18:37 UTC (permalink / raw)
To: Rob Herring
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_Jsq+GLBtaezUiTbm0DAA2+MjcvxAcCsS-qJrr05YcTO5tdw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 04/06/17 07:03, Rob Herring wrote:
> On Thu, Apr 6, 2017 at 1:18 AM, <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> From: Frank Rowand <frank.rowand-7U/KSKJipcs@public.gmane.org>
>>
>> of_dma_get_range() has workaround code to fixup a device tree that
>> incorrectly specified a mask instead of a size for property
>> dma-ranges. That device tree was fixed a year ago in v4.6, so
>> the workaround is no longer needed. Leave a data validation
>> check in place, but no longer do the fixup. Move the check
>> one level deeper in the call stack so that other possible users
>> of dma-ranges will also be protected.
>>
>> The fix to the device tree was in
>> commit c91cb9123cdd ("dtb: amd: Fix DMA ranges in device tree").
>
> NACK.
> This was by design. You can't represent a size of 2^64 or 2^32.
I agree that being unable to represent a size of 2^32 in a u32 and
a size of 2^64 in a u64 is the underlying issue.
But the code to convert a mask to a size is _not_ design, it is a
hack that temporarily worked around a device tree that did not follow
the dma-ranges binding in the ePAPR.
That device tree was corrected a year ago to provide a size instead of
a mask.
> Well, technically you can for the latter, but then you have to grow
> #size-cells to 2 for an otherwise all 32-bit system which seems kind
> of pointless and wasteful. You could further restrict this to only
> allow ~0 and not just any case with bit 0 set.
>
> I'm pretty sure AMD is not the only system. There were 32-bit systems too.
I examined all instances of property dma-ranges in in tree dts files in
Linux 4.11-rc1. There are none that incorrectly specify mask instead of
size.
#size-cells only changes to 2 for the dma-ranges property and the ranges
property when size is 2^32, so that is a very small amount of space.
The patch does not allow for a size of 2^64. If a system requires a
size of 2^64 then the type of size needs to increase to be larger
than a u64. If you would like for the code to be defensive and
detect a device tree providing a size of 2^64 then I can add a
check to of_dma_get_range() to return -EINVAL if #size-cells > 2.
When that error triggers, the type of size can be changed.
>
> Rob
>
--
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 V10 00/12] IOMMU probe deferral support
From: Frank Rowand @ 2017-04-06 18:46 UTC (permalink / raw)
To: Rob Herring, Sricharan R
Cc: Robin Murphy, Will Deacon, Joerg Roedel, Lorenzo Pieralisi,
Linux IOMMU, linux-arm-kernel@lists.infradead.org, linux-arm-msm,
Marek Szyprowski, bhelgaas@google.com, linux-pci@vger.kernel.org,
linux-acpi@vger.kernel.org, Tomasz Nowicki, Hanjun Guo,
Sinan Kaya, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CAL_JsqJH9C9sNGBSLH88bJ=uKF7RibHDAUZUW9M2xeO2AM-FUw@mail.gmail.com>
On 04/04/17 18:23, Rob Herring wrote:
> On Tue, Apr 4, 2017 at 5:18 AM, Sricharan R <sricharan@codeaurora.org> wrote:
>> This series calls the dma ops configuration for the devices
>> at a generic place so that it works for all busses.
>> The dma_configure_ops for a device is now called during
>> the device_attach callback just before the probe of the
>> bus/driver is called. Similarly dma_deconfigure is called during
>> device/driver_detach path.
>
> For patches 3, 4, 6, 7, 8:
>
> Acked-by: Rob Herring <robh@kernel.org>
> .
>
And a few hours later, I had the opposite opinion on a couple of
patches, so there is some ongoing discussion working this out.
-Frank
^ permalink raw reply
* Re: [RFC 4/8] regulator: core: Check enabling bypass respects constraints
From: Mark Brown @ 2017-04-06 18:52 UTC (permalink / raw)
To: Leonard Crestez
Cc: Sascha Hauer, Liam Girdwood, Viresh Kumar, Rafael J. Wysocki,
Shawn Guo, Robin Gong, Anson Huang, Irina Tirdea, Rob Herring,
Mark Rutland, Fabio Estevam, Octavian Purdila,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1490730595.15830.1.camel-3arQi8VN3Tc@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 3543 bytes --]
On Tue, Mar 28, 2017 at 10:49:55PM +0300, Leonard Crestez wrote:
> On Tue, 2017-03-28 at 17:47 +0100, Mark Brown wrote:
> > To repeat what I said previously the whole point of bypassing is to not
> > do regulation and generally the constraints in the unregulated idle case
> > are substantially more relaxed. This would break use cases relying on
> > the existing behaviour which wouldn't expect to affect the parent
> > voltage at all, either stopping things working or making them less
> > efficient by needlessly regulating the voltage down which defeats the
> > main point of bypassing.
> So what you want is to prevent voltage changes unless strictly
> required, even lowering? What I want is to get the minimum voltage in
> the SOC because that's where power is being consumed.
So your end goal here is to bypass a regulator which is forced into your
system design by being integrated into the SoC which isn't able to
regulate down to a low enough voltage for your use case? I guess one
question is if you need to use the regulator at all?
> It's not at all obvious that in bypass mode the output constraints of a
> regulator need not be respected by the core. I expected the opposite,
> this is something that should be documented.
SubmittingPatches... Bear in mind that most regulators are fixed
voltage in a given system so bypass would be very difficult to use if it
tried to pass the constraints upstream.
> But if the bypassed regulator has a downstream consumer then it's
> requirements should definitely still be met in bypass mode, right? I
> could set my maximum voltage directly from cpufreq in that case.
What we're interpreting bypass mode as meaning is "stop regulating".
There will still be some limits but we're expecting them to be enforced
in the extremes of the constraints in the parent regulators.
> Or should a bypassed regulator ignore all other requests? One of the
> behaviors that this patch series relies on is that calling set_voltage
> on a bypassed regulator propagates this request to the supply and picks
> the minimum voltage there. An alternative implementation would be to
Yes, the expectation is that if anything is being changed it won't have
any effect until regulation is reenabled but we're not particularly
expecting much activity on bypassed regulators.
> call set_voltage directly on the supply regulator by changing the
> "{arm,soc,pu}-supply" references in DT to point to the PMIC instead.
> Would that be better?
That's more what's expected here.
> Both approaches work. Relying on propagation feels like it is the
> "right way" to handle this, even if it's harder to get right and the
> regulator core does not entirely support it. But it's possible that
> this is based on a misunderstanding of what "bypass" is actually
> supposed to do.
Another option would be to add a regulator configuration which allowed
the regulator to transparently go into bypass mode if the parent could
do things directly, only enabling regulation if the parent couldn't
support. That would mean you'd loose the supply cleanup function which
is typically part of why there are LDOs in the system but it sounds like
you're OK with that in at least your use case.
We could also perhaps have a way to set the regulator into permanent
bypass mode from the constraints for use cases that just never need it
and then remap the supply relationship at probe time (which avoids any
special runtime casing) for something even simpler.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Applied "ASoC: cs35l35: Add DT binding to specify usage of an external boost supply" to the asoc tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
To: Charles Keepax; +Cc: Brian Austin, Mark Brown
In-Reply-To: <1491483134-28079-3-git-send-email-ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
The patch
ASoC: cs35l35: Add DT binding to specify usage of an external boost supply
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 0c67fb5544061cb990e07a73e1b7ba1f8ca22479 Mon Sep 17 00:00:00 2001
From: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Date: Thu, 6 Apr 2017 13:52:14 +0100
Subject: [PATCH] ASoC: cs35l35: Add DT binding to specify usage of an external
boost supply
Add a device tree binding to let the driver know that the amplifier is
configured to use an external boost supply.
Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Acked-by: Brian Austin <brian.austin-jGc1dHjMKG3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Documentation/devicetree/bindings/sound/cs35l35.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/cs35l35.txt b/Documentation/devicetree/bindings/sound/cs35l35.txt
index 958f0eabfdfc..457d176dcee0 100644
--- a/Documentation/devicetree/bindings/sound/cs35l35.txt
+++ b/Documentation/devicetree/bindings/sound/cs35l35.txt
@@ -33,6 +33,10 @@ Optional properties:
- cirrus,shared-boost : Boolean to enable ClassH tracking of Advisory Signal
if 2 Devices share Boost BST_CTL
+ - cirrus,external-boost : Boolean to specify the device is using an external
+ boost supply, note that sharing a boost from another cs35l35 would constitute
+ using an external supply for the slave device
+
- cirrus,sp-drv-strength : Value for setting the Serial Port drive strength
Table 3-10 of the datasheet lists drive-strength specifications
0 = 1x (Default)
--
2.11.0
--
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
* Applied "ASoC: cs35l35: Correct handling of PDN_DONE with external boost" to the asoc tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
To: Charles Keepax; +Cc: Brian Austin, Mark Brown
In-Reply-To: <1491483134-28079-2-git-send-email-ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
The patch
ASoC: cs35l35: Correct handling of PDN_DONE with external boost
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 77b329d1943d38a5acdbaf9d57754975bce701d4 Mon Sep 17 00:00:00 2001
From: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Date: Thu, 6 Apr 2017 13:52:13 +0100
Subject: [PATCH] ASoC: cs35l35: Correct handling of PDN_DONE with external
boost
When using an external boost supply the PDN_DONE bit is not set, update
the handling in this case to use to use an appropriate fixed delay.
Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Acked-by: Brian Austin <brian.austin-jGc1dHjMKG3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
include/sound/cs35l35.h | 2 ++
sound/soc/codecs/cs35l35.c | 32 ++++++++++++++++++++++++--------
2 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/include/sound/cs35l35.h b/include/sound/cs35l35.h
index 983c610eba2e..88744bbd6728 100644
--- a/include/sound/cs35l35.h
+++ b/include/sound/cs35l35.h
@@ -96,6 +96,8 @@ struct cs35l35_platform_data {
int adv_channel;
/* Shared Boost for stereo */
bool shared_bst;
+ /* Specifies this amp is using an external boost supply */
+ bool ext_bst;
/* ClassH Algorithm */
struct classh_cfg classh_algo;
/* Monitor Config */
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 1db07a6296a4..6ecb7ddae9cf 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -162,6 +162,27 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg)
}
}
+static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35)
+{
+ int ret;
+
+ if (cs35l35->pdata.ext_bst) {
+ usleep_range(5000, 5500);
+ return 0;
+ }
+
+ reinit_completion(&cs35l35->pdn_done);
+
+ ret = wait_for_completion_timeout(&cs35l35->pdn_done,
+ msecs_to_jiffies(100));
+ if (ret == 0) {
+ dev_err(cs35l35->dev, "PDN_DONE did not complete\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -191,14 +212,7 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
CS35L35_AMP_DIGSFT_MASK, 0);
- reinit_completion(&cs35l35->pdn_done);
-
- ret = wait_for_completion_timeout(&cs35l35->pdn_done,
- msecs_to_jiffies(100));
- if (ret == 0) {
- dev_err(codec->dev, "TIMEOUT PDN_DONE did not complete in 100ms\n");
- ret = -ETIMEDOUT;
- }
+ ret = cs35l35_wait_for_pdn(cs35l35);
regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
CS35L35_MCLK_DIS_MASK,
@@ -1198,6 +1212,8 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client,
"cirrus,shared-boost");
}
+ pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost");
+
pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc");
classh = of_get_child_by_name(np, "cirrus,classh-internal-algo");
--
2.11.0
--
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
* Applied "ASoC: cs35l35: Improve power down time" to the asoc tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
To: Charles Keepax; +Cc: Brian Austin, Mark Brown
In-Reply-To: <1491483134-28079-1-git-send-email-ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
The patch
ASoC: cs35l35: Improve power down time
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 2c84afb52ebea59e9862fcb8234126b7ae1d1960 Mon Sep 17 00:00:00 2001
From: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Date: Thu, 6 Apr 2017 13:52:12 +0100
Subject: [PATCH] ASoC: cs35l35: Improve power down time
Shorten the time it takes to power down the amp by disabling the volume
ramp whilst doing the final shutdown. The driver has already muted the
amplifier at this stage so doing the volume ramp serves no purpose.
Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Acked-by: Brian Austin <brian.austin-jGc1dHjMKG3QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
sound/soc/codecs/cs35l35.c | 8 ++++++++
sound/soc/codecs/cs35l35.h | 3 +++
2 files changed, 11 insertions(+)
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 9688274f7c90..1db07a6296a4 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -187,6 +187,10 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
CS35L35_PDN_ALL_MASK, 1);
+ /* Already muted, so disable volume ramp for faster shutdown */
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+ CS35L35_AMP_DIGSFT_MASK, 0);
+
reinit_completion(&cs35l35->pdn_done);
ret = wait_for_completion_timeout(&cs35l35->pdn_done,
@@ -199,6 +203,10 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
CS35L35_MCLK_DIS_MASK,
1 << CS35L35_MCLK_DIS_SHIFT);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+ CS35L35_AMP_DIGSFT_MASK,
+ 1 << CS35L35_AMP_DIGSFT_SHIFT);
break;
default:
dev_err(codec->dev, "Invalid event = 0x%x\n", event);
diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h
index 156d2f0e6fd8..54e9ac536b20 100644
--- a/sound/soc/codecs/cs35l35.h
+++ b/sound/soc/codecs/cs35l35.h
@@ -190,6 +190,9 @@
#define CS35L35_AMP_GAIN_ZC_MASK 0x10
#define CS35L35_AMP_GAIN_ZC_SHIFT 4
+#define CS35L35_AMP_DIGSFT_MASK 0x02
+#define CS35L35_AMP_DIGSFT_SHIFT 1
+
/* CS35L35_SP_FMT_CTL3 */
#define CS35L35_SP_I2S_DRV_MASK 0x03
#define CS35L35_SP_I2S_DRV_SHIFT 0
--
2.11.0
--
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
* Applied "ASoC: Add support for Maxim Integrated MAX98927 Amplifier" to the asoc tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
Cc: Mark Brown, lgirdwood
In-Reply-To: <1490922994-19294-1-git-send-email-ryans.lee@maximintegrated.com>
The patch
ASoC: Add support for Maxim Integrated MAX98927 Amplifier
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 7c0c2000716e64151b3c0c62026c18f31537ebe9 Mon Sep 17 00:00:00 2001
From: Ryan Lee <ryans.lee@maximintegrated.com>
Date: Tue, 4 Apr 2017 02:23:08 +0900
Subject: [PATCH] ASoC: Add support for Maxim Integrated MAX98927 Amplifier
Signed-off-by: Ryan Lee <ryans.lee@maximintegrated.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
.../devicetree/bindings/sound/max98925.txt | 22 -
.../devicetree/bindings/sound/max98926.txt | 32 -
.../devicetree/bindings/sound/max9892x.txt | 41 +
sound/soc/codecs/Kconfig | 5 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98927.c | 841 +++++++++++++++++++++
sound/soc/codecs/max98927.h | 272 +++++++
7 files changed, 1161 insertions(+), 54 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/sound/max98925.txt
delete mode 100644 Documentation/devicetree/bindings/sound/max98926.txt
create mode 100644 Documentation/devicetree/bindings/sound/max9892x.txt
create mode 100644 sound/soc/codecs/max98927.c
create mode 100644 sound/soc/codecs/max98927.h
diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt
deleted file mode 100644
index 27be63e2aa0d..000000000000
--- a/Documentation/devicetree/bindings/sound/max98925.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-max98925 audio CODEC
-
-This device supports I2C.
-
-Required properties:
-
- - compatible : "maxim,max98925"
-
- - vmon-slot-no : slot number used to send voltage information
-
- - imon-slot-no : slot number used to send current information
-
- - reg : the I2C address of the device for I2C
-
-Example:
-
-codec: max98925@1a {
- compatible = "maxim,max98925";
- vmon-slot-no = <0>;
- imon-slot-no = <2>;
- reg = <0x1a>;
-};
diff --git a/Documentation/devicetree/bindings/sound/max98926.txt b/Documentation/devicetree/bindings/sound/max98926.txt
deleted file mode 100644
index 0b7f4e4d5f9a..000000000000
--- a/Documentation/devicetree/bindings/sound/max98926.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-max98926 audio CODEC
-
-This device supports I2C.
-
-Required properties:
-
- - compatible : "maxim,max98926"
-
- - vmon-slot-no : slot number used to send voltage information
- or in inteleave mode this will be used as
- interleave slot.
-
- - imon-slot-no : slot number used to send current information
-
- - interleave-mode : When using two MAX98926 in a system it is
- possible to create ADC data that that will
- overflow the frame size. Digital Audio Interleave
- mode provides a means to output VMON and IMON data
- from two devices on a single DOUT line when running
- smaller frames sizes such as 32 BCLKS per LRCLK or
- 48 BCLKS per LRCLK.
-
- - reg : the I2C address of the device for I2C
-
-Example:
-
-codec: max98926@1a {
- compatible = "maxim,max98926";
- vmon-slot-no = <0>;
- imon-slot-no = <2>;
- reg = <0x1a>;
-};
diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt
new file mode 100644
index 000000000000..f6171591ddc6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/max9892x.txt
@@ -0,0 +1,41 @@
+Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier
+
+This device supports I2C.
+
+Required properties:
+
+ - compatible : should be one of the following
+ - "maxim,max98925"
+ - "maxim,max98926"
+ - "maxim,max98927"
+
+ - vmon-slot-no : slot number used to send voltage information
+ or in inteleave mode this will be used as
+ interleave slot.
+ MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0
+ MAX98927 slot range : 0 ~ 15, Default : 0
+
+ - imon-slot-no : slot number used to send current information
+ MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0
+ MAX98927 slot range : 0 ~ 15, Default : 0
+
+ - interleave-mode : When using two MAX9892X in a system it is
+ possible to create ADC data that that will
+ overflow the frame size. Digital Audio Interleave
+ mode provides a means to output VMON and IMON data
+ from two devices on a single DOUT line when running
+ smaller frames sizes such as 32 BCLKS per LRCLK or
+ 48 BCLKS per LRCLK.
+ Range : 0 (off), 1 (on), Default : 0
+
+ - reg : the I2C address of the device for I2C
+
+Example:
+
+codec: max98927@3a {
+ compatible = "maxim,max98927";
+ vmon-slot-no = <0>;
+ imon-slot-no = <1>;
+ interleave-mode = <0>;
+ reg = <0x3a>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9e1718a8cb1c..65e31ab88280 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9867 if I2C
select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX98926 if I2C
+ select SND_SOC_MAX98927 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9860 if I2C
select SND_SOC_MAX9768 if I2C
@@ -585,6 +586,10 @@ config SND_SOC_MAX98925
config SND_SOC_MAX98926
tristate
+config SND_SOC_MAX98927
+ tristate "Maxim Integrated MAX98927 Speaker Amplifier"
+ depends on I2C
+
config SND_SOC_MAX9850
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7e1dad79610b..64656c43200c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -84,6 +84,7 @@ snd-soc-max98371-objs := max98371.o
snd-soc-max9867-objs := max9867.o
snd-soc-max98925-objs := max98925.o
snd-soc-max98926-objs := max98926.o
+snd-soc-max98927-objs := max98927.o
snd-soc-max9850-objs := max9850.o
snd-soc-max9860-objs := max9860.o
snd-soc-mc13783-objs := mc13783.o
@@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
+obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
new file mode 100644
index 000000000000..b5ee29499e16
--- /dev/null
+++ b/sound/soc/codecs/max98927.c
@@ -0,0 +1,841 @@
+/*
+ * max98927.c -- MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2016 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/tlv.h>
+#include "max98927.h"
+
+static struct reg_default max98927_reg[] = {
+ {MAX98927_R0001_INT_RAW1, 0x00},
+ {MAX98927_R0002_INT_RAW2, 0x00},
+ {MAX98927_R0003_INT_RAW3, 0x00},
+ {MAX98927_R0004_INT_STATE1, 0x00},
+ {MAX98927_R0005_INT_STATE2, 0x00},
+ {MAX98927_R0006_INT_STATE3, 0x00},
+ {MAX98927_R0007_INT_FLAG1, 0x00},
+ {MAX98927_R0008_INT_FLAG2, 0x00},
+ {MAX98927_R0009_INT_FLAG3, 0x00},
+ {MAX98927_R000A_INT_EN1, 0x00},
+ {MAX98927_R000B_INT_EN2, 0x00},
+ {MAX98927_R000C_INT_EN3, 0x00},
+ {MAX98927_R000D_INT_FLAG_CLR1, 0x00},
+ {MAX98927_R000E_INT_FLAG_CLR2, 0x00},
+ {MAX98927_R000F_INT_FLAG_CLR3, 0x00},
+ {MAX98927_R0010_IRQ_CTRL, 0x00},
+ {MAX98927_R0011_CLK_MON, 0x00},
+ {MAX98927_R0012_WDOG_CTRL, 0x00},
+ {MAX98927_R0013_WDOG_RST, 0x00},
+ {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00},
+ {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00},
+ {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00},
+ {MAX98927_R0017_PIN_CFG, 0x55},
+ {MAX98927_R0018_PCM_RX_EN_A, 0x00},
+ {MAX98927_R0019_PCM_RX_EN_B, 0x00},
+ {MAX98927_R001A_PCM_TX_EN_A, 0x00},
+ {MAX98927_R001B_PCM_TX_EN_B, 0x00},
+ {MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0x00},
+ {MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0x00},
+ {MAX98927_R001E_PCM_TX_CH_SRC_A, 0x00},
+ {MAX98927_R001F_PCM_TX_CH_SRC_B, 0x00},
+ {MAX98927_R0020_PCM_MODE_CFG, 0x40},
+ {MAX98927_R0021_PCM_MASTER_MODE, 0x00},
+ {MAX98927_R0022_PCM_CLK_SETUP, 0x22},
+ {MAX98927_R0023_PCM_SR_SETUP1, 0x00},
+ {MAX98927_R0024_PCM_SR_SETUP2, 0x00},
+ {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, 0x00},
+ {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, 0x00},
+ {MAX98927_R0027_ICC_RX_EN_A, 0x00},
+ {MAX98927_R0028_ICC_RX_EN_B, 0x00},
+ {MAX98927_R002B_ICC_TX_EN_A, 0x00},
+ {MAX98927_R002C_ICC_TX_EN_B, 0x00},
+ {MAX98927_R002E_ICC_HIZ_MANUAL_MODE, 0x00},
+ {MAX98927_R002F_ICC_TX_HIZ_EN_A, 0x00},
+ {MAX98927_R0030_ICC_TX_HIZ_EN_B, 0x00},
+ {MAX98927_R0031_ICC_LNK_EN, 0x00},
+ {MAX98927_R0032_PDM_TX_EN, 0x00},
+ {MAX98927_R0033_PDM_TX_HIZ_CTRL, 0x00},
+ {MAX98927_R0034_PDM_TX_CTRL, 0x00},
+ {MAX98927_R0035_PDM_RX_CTRL, 0x00},
+ {MAX98927_R0036_AMP_VOL_CTRL, 0x00},
+ {MAX98927_R0037_AMP_DSP_CFG, 0x02},
+ {MAX98927_R0038_TONE_GEN_DC_CFG, 0x00},
+ {MAX98927_R0039_DRE_CTRL, 0x01},
+ {MAX98927_R003A_AMP_EN, 0x00},
+ {MAX98927_R003B_SPK_SRC_SEL, 0x00},
+ {MAX98927_R003C_SPK_GAIN, 0x00},
+ {MAX98927_R003D_SSM_CFG, 0x01},
+ {MAX98927_R003E_MEAS_EN, 0x00},
+ {MAX98927_R003F_MEAS_DSP_CFG, 0x04},
+ {MAX98927_R0040_BOOST_CTRL0, 0x00},
+ {MAX98927_R0041_BOOST_CTRL3, 0x00},
+ {MAX98927_R0042_BOOST_CTRL1, 0x00},
+ {MAX98927_R0043_MEAS_ADC_CFG, 0x00},
+ {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00},
+ {MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00},
+ {MAX98927_R0046_ADC_CH0_DIVIDE, 0x00},
+ {MAX98927_R0047_ADC_CH1_DIVIDE, 0x00},
+ {MAX98927_R0048_ADC_CH2_DIVIDE, 0x00},
+ {MAX98927_R0049_ADC_CH0_FILT_CFG, 0x00},
+ {MAX98927_R004A_ADC_CH1_FILT_CFG, 0x00},
+ {MAX98927_R004B_ADC_CH2_FILT_CFG, 0x00},
+ {MAX98927_R004C_MEAS_ADC_CH0_READ, 0x00},
+ {MAX98927_R004D_MEAS_ADC_CH1_READ, 0x00},
+ {MAX98927_R004E_MEAS_ADC_CH2_READ, 0x00},
+ {MAX98927_R0051_BROWNOUT_STATUS, 0x00},
+ {MAX98927_R0052_BROWNOUT_EN, 0x00},
+ {MAX98927_R0053_BROWNOUT_INFINITE_HOLD, 0x00},
+ {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR, 0x00},
+ {MAX98927_R0055_BROWNOUT_LVL_HOLD, 0x00},
+ {MAX98927_R005A_BROWNOUT_LVL1_THRESH, 0x00},
+ {MAX98927_R005B_BROWNOUT_LVL2_THRESH, 0x00},
+ {MAX98927_R005C_BROWNOUT_LVL3_THRESH, 0x00},
+ {MAX98927_R005D_BROWNOUT_LVL4_THRESH, 0x00},
+ {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS, 0x00},
+ {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL, 0x00},
+ {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL, 0x00},
+ {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE, 0x00},
+ {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT, 0x00},
+ {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1, 0x00},
+ {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2, 0x00},
+ {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3, 0x00},
+ {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT, 0x00},
+ {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1, 0x00},
+ {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2, 0x00},
+ {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3, 0x00},
+ {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT, 0x00},
+ {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1, 0x00},
+ {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2, 0x00},
+ {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3, 0x00},
+ {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT, 0x00},
+ {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, 0x00},
+ {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2, 0x00},
+ {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3, 0x00},
+ {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, 0x00},
+ {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY, 0x00},
+ {MAX98927_R0084_ENV_TRACK_REL_RATE, 0x00},
+ {MAX98927_R0085_ENV_TRACK_HOLD_RATE, 0x00},
+ {MAX98927_R0086_ENV_TRACK_CTRL, 0x00},
+ {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, 0x00},
+ {MAX98927_R00FF_GLOBAL_SHDN, 0x00},
+ {MAX98927_R0100_SOFT_RESET, 0x00},
+ {MAX98927_R01FF_REV_ID, 0x40},
+};
+
+static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ unsigned int mode = 0;
+ unsigned int format = 0;
+ unsigned int invert = 0;
+
+ dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mode = MAX98927_PCM_MASTER_MODE_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ max98927->master = true;
+ mode = MAX98927_PCM_MASTER_MODE_MASTER;
+ break;
+ default:
+ dev_err(codec->dev, "DAI clock mode unsupported");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MASK,
+ mode);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
+ break;
+ default:
+ dev_err(codec->dev, "DAI invert mode unsupported");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
+ invert);
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ max98927->iface |= SND_SOC_DAIFMT_I2S;
+ format = MAX98927_PCM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
+ format = MAX98927_PCM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_PDM:
+ max98927->iface |= SND_SOC_DAIFMT_PDM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* pcm channel configuration */
+ if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
+
+ } else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+
+ /* pdm channel configuration */
+ if (max98927->iface & SND_SOC_DAIFMT_PDM) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 1);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 3);
+ } else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 0);
+ return 0;
+}
+
+/* codec MCLK rate in master mode */
+static const int rate_table[] = {
+ 5644800, 6000000, 6144000, 6500000,
+ 9600000, 11289600, 12000000, 12288000,
+ 13000000, 19200000,
+};
+
+static int max98927_set_clock(struct max98927_priv *max98927,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_codec *codec = max98927->codec;
+ /* BCLK/LRCLK ratio calculation */
+ int blr_clk_ratio = params_channels(params) * max98927->ch_size;
+ int value;
+
+ if (max98927->master) {
+ int i;
+ /* match rate to closest value */
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i] >= max98927->sysclk)
+ break;
+ }
+ if (i == ARRAY_SIZE(rate_table)) {
+ dev_err(codec->dev, "failed to find proper clock rate.\n");
+ return -EINVAL;
+ }
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+ i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+ }
+
+ switch (blr_clk_ratio) {
+ case 32:
+ value = 2;
+ break;
+ case 48:
+ value = 3;
+ break;
+ case 64:
+ value = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+ value);
+ return 0;
+}
+
+static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sampling_rate = 0;
+ unsigned int chan_sz = 0;
+
+ /* pcm mode configuration */
+ switch (snd_pcm_format_width(params_format(params))) {
+ case 16:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(codec->dev, "format unsupported %d",
+ params_format(params));
+ goto err;
+ }
+
+ max98927->ch_size = snd_pcm_format_width(params_format(params));
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ dev_dbg(codec->dev, "format supported %d",
+ params_format(params));
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 8000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_8000;
+ break;
+ case 11025:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_11025;
+ break;
+ case 12000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_12000;
+ break;
+ case 16000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_16000;
+ break;
+ case 22050:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_22050;
+ break;
+ case 24000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_24000;
+ break;
+ case 32000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_32000;
+ break;
+ case 44100:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_44100;
+ break;
+ case 48000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
+ break;
+ default:
+ dev_err(codec->dev, "rate %d not supported\n",
+ params_rate(params));
+ goto err;
+ }
+ /* set DAI_SR to correct LRCLK frequency */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0023_PCM_SR_SETUP1,
+ MAX98927_PCM_SR_SET1_SR_MASK,
+ sampling_rate);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+
+ /* set sampling rate of IV */
+ if (max98927->interleave_mode &&
+ sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate - 3);
+ else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
+ return max98927_set_clock(max98927, params);
+err:
+ return -EINVAL;
+}
+
+#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
+
+#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ max98927->sysclk = freq;
+ return 0;
+}
+
+static const struct snd_soc_dai_ops max98927_dai_ops = {
+ .set_sysclk = max98927_dai_set_sysclk,
+ .set_fmt = max98927_dai_set_fmt,
+ .hw_params = max98927_dai_hw_params,
+};
+
+static int max98927_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 1);
+ /* enable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 0);
+ /* disable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static const char * const max98927_switch_text[] = {
+ "Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+ SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+ 3, max98927_switch_text);
+
+static const struct snd_kcontrol_new max98927_dai_controls =
+ SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
+ 0, 0, max98927_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+ &max98927_dai_controls),
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
+static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
+
+static bool max98927_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B:
+ case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B:
+ case MAX98927_R002E_ICC_HIZ_MANUAL_MODE
+ ... MAX98927_R004E_MEAS_ADC_CH2_READ:
+ case MAX98927_R0051_BROWNOUT_STATUS
+ ... MAX98927_R0055_BROWNOUT_LVL_HOLD:
+ case MAX98927_R005A_BROWNOUT_LVL1_THRESH
+ ... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE:
+ case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT
+ ... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+ case MAX98927_R00FF_GLOBAL_SHDN:
+ case MAX98927_R0100_SOFT_RESET:
+ case MAX98927_R01FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+};
+
+static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const max98927_boost_voltage_text[] = {
+ "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
+ "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
+ "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
+ "9.5V", "9.625V", "9.75V", "9.875V", "10V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
+ MAX98927_R0040_BOOST_CTRL0, 0,
+ max98927_boost_voltage_text);
+
+static const char * const max98927_current_limit_text[] = {
+ "1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A",
+ "1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A",
+ "2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A",
+ "3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
+ MAX98927_R0042_BOOST_CTRL1, 1,
+ max98927_current_limit_text);
+
+static const struct snd_kcontrol_new max98927_snd_controls[] = {
+ SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
+ 0, 6, 0,
+ max98927_spk_tlv),
+ SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
+ 0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
+ max98927_digital_tlv),
+ SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
+ MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+ SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+ SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
+ MAX98927_DRE_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+ SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
+ SOC_ENUM("Current Limit", max98927_current_limit),
+};
+
+static const struct snd_soc_dapm_route max98927_audio_map[] = {
+ {"Amp Enable", NULL, "DAI_OUT"},
+ {"DAI Sel Mux", "Left", "Amp Enable"},
+ {"DAI Sel Mux", "Right", "Amp Enable"},
+ {"DAI Sel Mux", "LeftRight", "Amp Enable"},
+ {"BE_OUT", NULL, "DAI Sel Mux"},
+};
+
+static struct snd_soc_dai_driver max98927_dai[] = {
+ {
+ .name = "max98927-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98927_RATES,
+ .formats = MAX98927_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98927_RATES,
+ .formats = MAX98927_FORMATS,
+ },
+ .ops = &max98927_dai_ops,
+ }
+};
+
+static int max98927_probe(struct snd_soc_codec *codec)
+{
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ max98927->codec = codec;
+ codec->control_data = max98927->regmap;
+ codec->cache_bypass = 1;
+
+ /* Software Reset */
+ regmap_write(max98927->regmap,
+ MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+
+ /* IV default slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ 0x80);
+ regmap_write(max98927->regmap,
+ MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+ 0x1);
+ /* Set inital volume (+13dB) */
+ regmap_write(max98927->regmap,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ 0x38);
+ regmap_write(max98927->regmap,
+ MAX98927_R003C_SPK_GAIN,
+ 0x05);
+ /* Enable DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R0037_AMP_DSP_CFG,
+ 0x03);
+ /* Enable IMON VMON DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R003F_MEAS_DSP_CFG,
+ 0xF7);
+ /* Boost Output Voltage & Current limit */
+ regmap_write(max98927->regmap,
+ MAX98927_R0040_BOOST_CTRL0,
+ 0x1C);
+ regmap_write(max98927->regmap,
+ MAX98927_R0042_BOOST_CTRL1,
+ 0x3E);
+ /* Measurement ADC config */
+ regmap_write(max98927->regmap,
+ MAX98927_R0043_MEAS_ADC_CFG,
+ 0x04);
+ regmap_write(max98927->regmap,
+ MAX98927_R0044_MEAS_ADC_BASE_MSB,
+ 0x00);
+ regmap_write(max98927->regmap,
+ MAX98927_R0045_MEAS_ADC_BASE_LSB,
+ 0x24);
+ /* Brownout Level */
+ regmap_write(max98927->regmap,
+ MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+ 0x06);
+ /* Envelope Tracking configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+ 0x08);
+ regmap_write(max98927->regmap,
+ MAX98927_R0086_ENV_TRACK_CTRL,
+ 0x01);
+ regmap_write(max98927->regmap,
+ MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+ 0x10);
+
+ /* voltage, current slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001E_PCM_TX_CH_SRC_A,
+ (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
+ max98927->v_l_slot)&0xFF);
+
+ if (max98927->v_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->v_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->v_l_slot,
+ 1 << max98927->v_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->v_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->v_l_slot - 8),
+ 1 << (max98927->v_l_slot - 8));
+ }
+
+ if (max98927->i_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->i_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->i_l_slot,
+ 1 << max98927->i_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->i_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->i_l_slot - 8),
+ 1 << (max98927->i_l_slot - 8));
+ }
+
+ /* Set interleave mode */
+ if (max98927->interleave_mode)
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001F_PCM_TX_CH_SRC_B,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+ return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
+ .probe = max98927_probe,
+ .component_driver = {
+ .controls = max98927_snd_controls,
+ .num_controls = ARRAY_SIZE(max98927_snd_controls),
+ .dapm_widgets = max98927_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
+ .dapm_routes = max98927_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
+ },
+};
+
+static const struct regmap_config max98927_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = MAX98927_R01FF_REV_ID,
+ .reg_defaults = max98927_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98927_reg),
+ .readable_reg = max98927_readable_register,
+ .volatile_reg = max98927_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static void max98927_slot_config(struct i2c_client *i2c,
+ struct max98927_priv *max98927)
+{
+ int value;
+
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "vmon-slot-no", &value))
+ max98927->v_l_slot = value & 0xF;
+ else
+ max98927->v_l_slot = 0;
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "imon-slot-no", &value))
+ max98927->i_l_slot = value & 0xF;
+ else
+ max98927->i_l_slot = 1;
+}
+
+static int max98927_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+
+ int ret = 0, value;
+ int reg = 0;
+ struct max98927_priv *max98927 = NULL;
+
+ max98927 = devm_kzalloc(&i2c->dev,
+ sizeof(*max98927), GFP_KERNEL);
+
+ if (!max98927) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ i2c_set_clientdata(i2c, max98927);
+
+ /* update interleave mode info */
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "interleave_mode", &value)) {
+ if (value > 0)
+ max98927->interleave_mode = 1;
+ else
+ max98927->interleave_mode = 0;
+ } else
+ max98927->interleave_mode = 0;
+
+ /* regmap initialization */
+ max98927->regmap
+ = devm_regmap_init_i2c(i2c, &max98927_regmap);
+ if (IS_ERR(max98927->regmap)) {
+ ret = PTR_ERR(max98927->regmap);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ /* Check Revision ID */
+ ret = regmap_read(max98927->regmap,
+ MAX98927_R01FF_REV_ID, ®);
+ if (ret < 0) {
+ dev_err(&i2c->dev,
+ "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
+ return ret;
+ }
+ dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg);
+
+ /* voltage/current slot configuration */
+ max98927_slot_config(i2c, max98927);
+
+ /* codec registeration */
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
+ max98927_dai, ARRAY_SIZE(max98927_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+ return ret;
+}
+
+static int max98927_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id max98927_i2c_id[] = {
+ { "max98927", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max98927_of_match[] = {
+ { .compatible = "maxim,max98927", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max98927_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98927_acpi_match[] = {
+ { "MX98927", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, max98927_acpi_match);
+#endif
+
+static struct i2c_driver max98927_i2c_driver = {
+ .driver = {
+ .name = "max98927",
+ .of_match_table = of_match_ptr(max98927_of_match),
+ .acpi_match_table = ACPI_PTR(max98927_acpi_match),
+ .pm = NULL,
+ },
+ .probe = max98927_i2c_probe,
+ .remove = max98927_i2c_remove,
+ .id_table = max98927_i2c_id,
+};
+
+module_i2c_driver(max98927_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98927 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
new file mode 100644
index 000000000000..ece6a608cbe1
--- /dev/null
+++ b/sound/soc/codecs/max98927.h
@@ -0,0 +1,272 @@
+/*
+ * max98927.h -- MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright 2013-15 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef _MAX98927_H
+#define _MAX98927_H
+
+/* Register Values */
+#define MAX98927_R0001_INT_RAW1 0x0001
+#define MAX98927_R0002_INT_RAW2 0x0002
+#define MAX98927_R0003_INT_RAW3 0x0003
+#define MAX98927_R0004_INT_STATE1 0x0004
+#define MAX98927_R0005_INT_STATE2 0x0005
+#define MAX98927_R0006_INT_STATE3 0x0006
+#define MAX98927_R0007_INT_FLAG1 0x0007
+#define MAX98927_R0008_INT_FLAG2 0x0008
+#define MAX98927_R0009_INT_FLAG3 0x0009
+#define MAX98927_R000A_INT_EN1 0x000A
+#define MAX98927_R000B_INT_EN2 0x000B
+#define MAX98927_R000C_INT_EN3 0x000C
+#define MAX98927_R000D_INT_FLAG_CLR1 0x000D
+#define MAX98927_R000E_INT_FLAG_CLR2 0x000E
+#define MAX98927_R000F_INT_FLAG_CLR3 0x000F
+#define MAX98927_R0010_IRQ_CTRL 0x0010
+#define MAX98927_R0011_CLK_MON 0x0011
+#define MAX98927_R0012_WDOG_CTRL 0x0012
+#define MAX98927_R0013_WDOG_RST 0x0013
+#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
+#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
+#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
+#define MAX98927_R0017_PIN_CFG 0x0017
+#define MAX98927_R0018_PCM_RX_EN_A 0x0018
+#define MAX98927_R0019_PCM_RX_EN_B 0x0019
+#define MAX98927_R001A_PCM_TX_EN_A 0x001A
+#define MAX98927_R001B_PCM_TX_EN_B 0x001B
+#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
+#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
+#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
+#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
+#define MAX98927_R0020_PCM_MODE_CFG 0x0020
+#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
+#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
+#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
+#define MAX98927_R0024_PCM_SR_SETUP2 0x0024
+#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
+#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
+#define MAX98927_R0027_ICC_RX_EN_A 0x0027
+#define MAX98927_R0028_ICC_RX_EN_B 0x0028
+#define MAX98927_R002B_ICC_TX_EN_A 0x002B
+#define MAX98927_R002C_ICC_TX_EN_B 0x002C
+#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
+#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
+#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
+#define MAX98927_R0031_ICC_LNK_EN 0x0031
+#define MAX98927_R0032_PDM_TX_EN 0x0032
+#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
+#define MAX98927_R0034_PDM_TX_CTRL 0x0034
+#define MAX98927_R0035_PDM_RX_CTRL 0x0035
+#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
+#define MAX98927_R0037_AMP_DSP_CFG 0x0037
+#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
+#define MAX98927_R0039_DRE_CTRL 0x0039
+#define MAX98927_R003A_AMP_EN 0x003A
+#define MAX98927_R003B_SPK_SRC_SEL 0x003B
+#define MAX98927_R003C_SPK_GAIN 0x003C
+#define MAX98927_R003D_SSM_CFG 0x003D
+#define MAX98927_R003E_MEAS_EN 0x003E
+#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
+#define MAX98927_R0040_BOOST_CTRL0 0x0040
+#define MAX98927_R0041_BOOST_CTRL3 0x0041
+#define MAX98927_R0042_BOOST_CTRL1 0x0042
+#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
+#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
+#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
+#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
+#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
+#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
+#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
+#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
+#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
+#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
+#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
+#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
+#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
+#define MAX98927_R0052_BROWNOUT_EN 0x0052
+#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
+#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
+#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
+#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
+#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
+#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
+#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
+#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
+#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
+#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
+#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
+#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
+#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
+#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
+#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
+#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
+#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
+#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
+#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
+#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
+#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
+#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
+#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
+#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
+#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
+#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
+#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
+#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
+#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
+#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
+#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
+#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
+#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
+#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
+#define MAX98927_R0100_SOFT_RESET 0x0100
+#define MAX98927_R01FF_REV_ID 0x01FF
+
+/* MAX98927_R0018_PCM_RX_EN_A */
+#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001A_PCM_TX_EN_A */
+#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001E_PCM_TX_CH_SRC_A */
+#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98927_R001F_PCM_TX_CH_SRC_B */
+#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
+
+/* MAX98927_R0020_PCM_MODE_CFG */
+#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
+#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
+
+#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98927_R0021_PCM_MASTER_MODE */
+#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
+#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
+#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
+
+#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
+#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
+
+/* MAX98927_R0022_PCM_CLK_SETUP */
+#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98927_R0023_PCM_SR_SETUP1 */
+#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
+
+#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98927_R0024_PCM_SR_SETUP2 */
+#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
+
+/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+
+/* MAX98927_R0035_PDM_RX_CTRL */
+#define MAX98927_PDM_RX_EN_MASK (0x1 << 0)
+
+/* MAX98927_R0036_AMP_VOL_CTRL */
+#define MAX98927_AMP_VOL_SEL (0x1 << 7)
+#define MAX98927_AMP_VOL_SEL_WIDTH (1)
+#define MAX98927_AMP_VOL_SEL_SHIFT (7)
+#define MAX98927_AMP_VOL_MASK (0x7f << 0)
+#define MAX98927_AMP_VOL_WIDTH (7)
+#define MAX98927_AMP_VOL_SHIFT (0)
+
+/* MAX98927_R0037_AMP_DSP_CFG */
+#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
+#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
+#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
+#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
+#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
+
+/* MAX98927_R0039_DRE_CTRL */
+#define MAX98927_DRE_CTRL_DRE_EN (0x1 << 0)
+#define MAX98927_DRE_EN_SHIFT 0x1
+
+/* MAX98927_R003A_AMP_EN */
+#define MAX98927_AMP_EN_MASK (0x1 << 0)
+
+/* MAX98927_R003B_SPK_SRC_SEL */
+#define MAX98927_SPK_SRC_MASK (0x3 << 0)
+
+/* MAX98927_R003C_SPK_GAIN */
+#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
+#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
+#define MAX98927_SPK_GAIN_WIDTH (3)
+
+/* MAX98927_R003E_MEAS_EN */
+#define MAX98927_MEAS_V_EN (0x1 << 0)
+#define MAX98927_MEAS_I_EN (0x1 << 1)
+
+/* MAX98927_R0040_BOOST_CTRL0 */
+#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
+#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
+#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
+
+/* MAX98927_R0052_BROWNOUT_EN */
+#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
+#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
+#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
+#define MAX98927_BROWNOUT_DSP_SHIFT (2)
+
+/* MAX98927_R0100_SOFT_RESET */
+#define MAX98927_SOFT_RESET (0x1 << 0)
+
+/* MAX98927_R00FF_GLOBAL_SHDN */
+#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
+
+struct max98927_priv {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct max98927_pdata *pdata;
+ unsigned int spk_gain;
+ unsigned int sysclk;
+ unsigned int v_l_slot;
+ unsigned int i_l_slot;
+ bool interleave_mode;
+ unsigned int ch_size;
+ unsigned int rate;
+ unsigned int iface;
+ unsigned int master;
+ unsigned int digital_gain;
+};
+#endif
--
2.11.0
^ permalink raw reply related
* Applied "regulator: helpers: Add regmap set_pull_down helper" to the regulator tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
To: Charles Keepax; +Cc: Mark Brown
In-Reply-To: <1490710484-25277-5-git-send-email-ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
The patch
regulator: helpers: Add regmap set_pull_down helper
has been applied to the regulator tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From f7d37bc3cb20828ac43b22cbd40222877ee2c46a Mon Sep 17 00:00:00 2001
From: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Date: Tue, 28 Mar 2017 15:14:41 +0100
Subject: [PATCH] regulator: helpers: Add regmap set_pull_down helper
Add a helper function regulator_set_pull_down_regmap to allow regmap
based regulators to easily enable pull down.
Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
drivers/regulator/helpers.c | 18 ++++++++++++++++++
include/linux/regulator/driver.h | 8 ++++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index a75e7da49af8..2ae7c3ac5940 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -464,6 +464,24 @@ int regulator_set_soft_start_regmap(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_set_soft_start_regmap);
/**
+ * regulator_set_pull_down_regmap - Default set_pull_down() using regmap
+ *
+ * @rdev: device to operate on.
+ */
+int regulator_set_pull_down_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ val = rdev->desc->pull_down_val_on;
+ if (!val)
+ val = rdev->desc->pull_down_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->pull_down_reg,
+ rdev->desc->pull_down_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_pull_down_regmap);
+
+/**
* regulator_get_bypass_regmap - Default get_bypass() using regmap
*
* @rdev: device to operate on.
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 1054c033e783..8a9078dd2a5f 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -296,6 +296,10 @@ enum regulator_type {
* @soft_start_mask: Mask for control when using regmap set_soft_start
* @soft_start_val_on: Enabling value for control when using regmap
* set_soft_start
+ * @pull_down_reg: Register for control when using regmap set_pull_down
+ * @pull_down_mask: Mask for control when using regmap set_pull_down
+ * @pull_down_val_on: Enabling value for control when using regmap
+ * set_pull_down
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
@@ -352,6 +356,9 @@ struct regulator_desc {
unsigned int soft_start_reg;
unsigned int soft_start_mask;
unsigned int soft_start_val_on;
+ unsigned int pull_down_reg;
+ unsigned int pull_down_mask;
+ unsigned int pull_down_val_on;
unsigned int enable_time;
@@ -484,6 +491,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
int regulator_set_soft_start_regmap(struct regulator_dev *rdev);
+int regulator_set_pull_down_regmap(struct regulator_dev *rdev);
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable);
--
2.11.0
--
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
* Applied "regulator: helpers: Add regmap set_soft_start helper" to the regulator tree
From: Mark Brown @ 2017-04-06 18:55 UTC (permalink / raw)
To: Charles Keepax; +Cc: Mark Brown
In-Reply-To: <1490710484-25277-4-git-send-email-ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
The patch
regulator: helpers: Add regmap set_soft_start helper
has been applied to the regulator tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From a7a453f56a1a116027f84ac53b365eb045a0e279 Mon Sep 17 00:00:00 2001
From: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Date: Tue, 28 Mar 2017 15:14:40 +0100
Subject: [PATCH] regulator: helpers: Add regmap set_soft_start helper
Add a helper function regulator_set_soft_start_regmap to allow regmap
based regulators to easily enable soft start.
Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
drivers/regulator/helpers.c | 18 ++++++++++++++++++
include/linux/regulator/driver.h | 8 ++++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 379cdacc05d8..a75e7da49af8 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -446,6 +446,24 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
/**
+ * regulator_set_soft_start_regmap - Default set_soft_start() using regmap
+ *
+ * @rdev: device to operate on.
+ */
+int regulator_set_soft_start_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ val = rdev->desc->soft_start_val_on;
+ if (!val)
+ val = rdev->desc->soft_start_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->soft_start_reg,
+ rdev->desc->soft_start_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_soft_start_regmap);
+
+/**
* regulator_get_bypass_regmap - Default get_bypass() using regmap
*
* @rdev: device to operate on.
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index dac8e7b16bc6..1054c033e783 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -292,6 +292,10 @@ enum regulator_type {
* set_active_discharge
* @active_discharge_reg: Register for control when using regmap
* set_active_discharge
+ * @soft_start_reg: Register for control when using regmap set_soft_start
+ * @soft_start_mask: Mask for control when using regmap set_soft_start
+ * @soft_start_val_on: Enabling value for control when using regmap
+ * set_soft_start
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
@@ -345,6 +349,9 @@ struct regulator_desc {
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
+ unsigned int soft_start_reg;
+ unsigned int soft_start_mask;
+ unsigned int soft_start_val_on;
unsigned int enable_time;
@@ -476,6 +483,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int new_selector);
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
+int regulator_set_soft_start_regmap(struct regulator_dev *rdev);
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable);
--
2.11.0
--
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 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Russell King - ARM Linux @ 2017-04-06 19:00 UTC (permalink / raw)
To: Dave Gerlach
Cc: Tony Lindgren, Rob Herring, Santosh Shilimkar,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Keerthy J
In-Reply-To: <5cd63e14-52df-6010-4193-c926cdd76839-l0cyMroinI0@public.gmane.org>
On Wed, Apr 05, 2017 at 09:48:26AM -0500, Dave Gerlach wrote:
> Russell,
> On 04/05/2017 09:33 AM, Tony Lindgren wrote:
> >* Russell King - ARM Linux <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> [170405 07:02]:
> >>I'm not going to comment on this yet, but I'll instead comment on the
> >>newly appeared sram_exec_copy() stuff.
> >>
> >>So, a few years ago, we went to significant effort in ARM land to come
> >>up with a way to _safely_ copy assembler from the kernel into SRAM,
> >>because copying code to SRAM that is compiled in thumb mode and then
> >>executing it is _not_ as simple as memcpy(), cast the pointer to a
> >>function pointer, and then call the function pointer.
> >>
> >>The SRAM stuff throws all that out, instead preferring the dumb memcpy()
> >>approach.
> >>
> >>This needs resolving, and I'd like to see it resolved to the satisfaction
> >>of architecture maintainers before we progress any further down this
> >>route.
>
> I'm sure you are referring to fncpy, correct? This is what we used before
> with ARM specific code to do the copy, but we've moved into drivers now.
Right, and as I explained above, fncpy() exists with very good reason.
The following does not work on ARM:
sram = alloc(function_size);
memcpy(sram, function, function_size);
sram_ptr = (function_cast_t)sram;
sram_ptr(args);
when the function is Thumb. There are two problems with the above code
that fncpy() solves, both stemming from the same root cause:
1. The address of "function" will be offset by one byte, so the memcpy()
will miss copying the first byte of the function.
2. sram_ptr will not be offset by one byte.
This is because, with Thumb functions, the "address" of the function is
offset by one byte - by the architecture requirements - to indicate that
it is to be called in Thumb mode.
> What are your thoughts on exposing fncpy outside of arch/arm?
You may use it by including asm/fncpy.h, but you may not move it out of
that file. fncpy() is there exactly because it's _architecture_ specific.
If you're looking to make this generic, then we need cross-arch agreement
on how we can copy functions, and I'd recommend that fncpy() becomes that
generic copy function. fncpy() has advantages over memcpy() besides
encoding the architecture specific knowledge - the biggest one is that
it guarantees type safety as well. It ensures that the function pointer
that it's returning conforms with the function it's being asked to copy.
It strikes me, looking at the SRAM stuff, that the baby has been
completely thrown out with the bath water...
And really, this SRAM stuff _should_ have been through architecture
maintainer review before being merged into mainline so that these issues
could have been highlighted before hand.
This looks to me like yet another huge big review failure in kernel land,
because people are insistant on continually dividing stuff up by
sub-directory. This has got to stop.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
--
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 v2] Extend pca9532 device tree support
From: Jacek Anaszewski @ 2017-04-06 19:00 UTC (permalink / raw)
To: Pavel Machek, Felix Brack
Cc: rpurdie-Fm38FmjxZ/leoWH0uzbU5w, mark.rutland-5wv7dgnIgG8,
riku.voipio-X3B1VOXEql0, linux-leds-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170406155005.GA10363@amd>
Hi Pavel,
On 04/06/2017 05:50 PM, Pavel Machek wrote:
> Hi!
>
>>> diff --git a/Documentation/devicetree/bindings/leds/leds-pca9532.txt b/Documentation/devicetree/bindings/leds/leds-pca9532.txt
>>> index 198f3ba..8374075 100644
>>> --- a/Documentation/devicetree/bindings/leds/leds-pca9532.txt
>>> +++ b/Documentation/devicetree/bindings/leds/leds-pca9532.txt
>>> @@ -17,6 +17,8 @@ Optional sub-node properties:
>>> - label: see Documentation/devicetree/bindings/leds/common.txt
>>> - type: Output configuration, see dt-bindings/leds/leds-pca9532.h (default NONE)
>>> - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
>>> + - default-state: see Documentation/devicetree/bindings/leds/common.txt
>>> + This property is only valid for sub-nodes of type <PCA9532_TYPE_LED>.
>>>
>>> Example:
>>> #include <dt-bindings/leds/leds-pca9532.h>
>>> @@ -33,6 +35,14 @@ Example:
>>> label = "pca:green:power";
>>> type = <PCA9532_TYPE_LED>;
>>> };
>>> + kernel-booting {
>>> + type = <PCA9532_TYPE_LED>;
>>> + default-state = "on";
>>> + };
>>> + sys-stat {
>>> + type = <PCA9532_TYPE_LED>;
>>> + default-state = "keep"; // don't touch, was set by U-Boot
>>> + };
>>
>> Adjusted above indentation to match the preceding lines.
>
>>> @@ -475,6 +494,16 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
>>> of_property_read_u32(child, "type", &pdata->leds[i].type);
>>> of_property_read_string(child, "linux,default-trigger",
>>> &pdata->leds[i].default_trigger);
>>> + if (!of_property_read_string(child, "default-state", &state)) {
>>> + if (!strcmp(state, "on"))
>>> + pdata->leds[i].state = PCA9532_ON;
>>> + else if (!strcmp(state, "keep"))
>>> + pdata->leds[i].state = PCA9532_KEEP;
>>> + else if (!strcmp(state, "pwm0"))
>>> + pdata->leds[i].state = PCA9532_PWM0;
>>> + else if (!strcmp(state, "pwm1"))
>>> + pdata->leds[i].state = PCA9532_PWM1;
>>> + }
>>> if (++i >= maxleds) {
>>> of_node_put(child);
>>> break;
>
> This seems to look for "pwm0" and "pwm1" strings, which do not seem to
> be documented.
>
> Plus... is it useful to have default-state? We already have default
> trigger. If we keep the value by default (on PC, we do something like
> that) this patch should not be neccessary?
Thanks for the heads-up. Dropping the patch for now.
I guess that pwm0/1 got propagated to v2 by an omission.
Regarding default-on: Felix, do you have any use case that require
default-on set to "keep"?
--
Best regards,
Jacek Anaszewski
--
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 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Dave Gerlach @ 2017-04-06 19:09 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Tony Lindgren, Rob Herring, Santosh Shilimkar,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Keerthy J
In-Reply-To: <20170406190008.GO23750-l+eeeJia6m9URfEZ8mYm6t73F7V6hmMc@public.gmane.org>
On 04/06/2017 02:00 PM, Russell King - ARM Linux wrote:
> On Wed, Apr 05, 2017 at 09:48:26AM -0500, Dave Gerlach wrote:
>> Russell,
>> On 04/05/2017 09:33 AM, Tony Lindgren wrote:
>>> * Russell King - ARM Linux <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> [170405 07:02]:
>>>> I'm not going to comment on this yet, but I'll instead comment on the
>>>> newly appeared sram_exec_copy() stuff.
>>>>
>>>> So, a few years ago, we went to significant effort in ARM land to come
>>>> up with a way to _safely_ copy assembler from the kernel into SRAM,
>>>> because copying code to SRAM that is compiled in thumb mode and then
>>>> executing it is _not_ as simple as memcpy(), cast the pointer to a
>>>> function pointer, and then call the function pointer.
>>>>
>>>> The SRAM stuff throws all that out, instead preferring the dumb memcpy()
>>>> approach.
>>>>
>>>> This needs resolving, and I'd like to see it resolved to the satisfaction
>>>> of architecture maintainers before we progress any further down this
>>>> route.
>>
>> I'm sure you are referring to fncpy, correct? This is what we used before
>> with ARM specific code to do the copy, but we've moved into drivers now.
>
> Right, and as I explained above, fncpy() exists with very good reason.
> The following does not work on ARM:
>
> sram = alloc(function_size);
>
> memcpy(sram, function, function_size);
>
> sram_ptr = (function_cast_t)sram;
>
> sram_ptr(args);
>
> when the function is Thumb. There are two problems with the above code
> that fncpy() solves, both stemming from the same root cause:
>
> 1. The address of "function" will be offset by one byte, so the memcpy()
> will miss copying the first byte of the function.
>
> 2. sram_ptr will not be offset by one byte.
>
> This is because, with Thumb functions, the "address" of the function is
> offset by one byte - by the architecture requirements - to indicate that
> it is to be called in Thumb mode.
Thanks for the explanation.
>
>> What are your thoughts on exposing fncpy outside of arch/arm?
>
> You may use it by including asm/fncpy.h, but you may not move it out of
> that file. fncpy() is there exactly because it's _architecture_ specific.
Yes agreed, and I already include asm/cacheflush.h for ARM arch to make use of
the set_memory_* APIs you helped extend.
>
> If you're looking to make this generic, then we need cross-arch agreement
> on how we can copy functions, and I'd recommend that fncpy() becomes that
> generic copy function. fncpy() has advantages over memcpy() besides
> encoding the architecture specific knowledge - the biggest one is that
> it guarantees type safety as well. It ensures that the function pointer
> that it's returning conforms with the function it's being asked to copy.
I agree with this, I sent a patch yesterday here [1] that uses fncpy instead of
memcpy. I also laid out the constraint that an arch will just need to define
fncpy that guarantees safe copy of a function in order to make use of the
sram_exec functionality. It is already only selected for CONFIG_ARM in Kconfig
because of the dependency on set_memory_* APIs.
[1] http://www.spinics.net/lists/linux-omap/msg136517.html
>
> It strikes me, looking at the SRAM stuff, that the baby has been
> completely thrown out with the bath water...
>
> And really, this SRAM stuff _should_ have been through architecture
> maintainer review before being merged into mainline so that these issues
> could have been highlighted before hand.
>
> This looks to me like yet another huge big review failure in kernel land,
> because people are insistant on continually dividing stuff up by
> sub-directory. This has got to stop.
>
This just seemed like a logical place for me to add this as executable SRAM is a
shared resource and if the generic sram driver is handling allocation of memory
regions it should handle the page attributes of these regions as well.
Regards,
Dave
--
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 V10 06/12] of: device: Fix overflow of coherent_dma_mask
From: Frank Rowand @ 2017-04-06 19:24 UTC (permalink / raw)
To: Robin Murphy, Sricharan R, will.deacon, joro, lorenzo.pieralisi,
iommu, linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt, devicetree,
linux-kernel, sudeep.holla, rjw, lenb, catalin.marinas, arnd,
linux-arch, gregkh
In-Reply-To: <b081f333-084d-ffa5-635f-f7f1c0232ac3@arm.com>
On 04/06/17 03:24, Robin Murphy wrote:
> On 06/04/17 08:01, Frank Rowand wrote:
>> On 04/04/17 03:18, Sricharan R wrote:
>>> Size of the dma-range is calculated as coherent_dma_mask + 1
>>> and passed to arch_setup_dma_ops further. It overflows when
>>> the coherent_dma_mask is set for full 64 bits 0xFFFFFFFFFFFFFFFF,
>>> resulting in size getting passed as 0 wrongly. Fix this by
>>> passsing in max(mask, mask + 1). Note that in this case
>>> when the mask is set to full 64bits, we will be passing the mask
>>> itself to arch_setup_dma_ops instead of the size. The real fix
>>> for this should be to make arch_setup_dma_ops receive the
>>> mask and handle it, to be done in the future.
>>>
>>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>>> ---
>>> drivers/of/device.c | 2 +-
>>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/of/device.c b/drivers/of/device.c
>>> index c17c19d..c2ae6bb 100644
>>> --- a/drivers/of/device.c
>>> +++ b/drivers/of/device.c
>>> @@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np)
>>> ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
>>> if (ret < 0) {
>>> dma_addr = offset = 0;
>>> - size = dev->coherent_dma_mask + 1;
>>> + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
>>> } else {
>>> offset = PFN_DOWN(paddr - dma_addr);
>>> dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
>>>
>>
>> NACK.
>>
>> Passing an invalid size to arch_setup_dma_ops() is only part of the problem.
>> size is also used in of_dma_configure() before calling arch_setup_dma_ops():
>>
>> dev->coherent_dma_mask = min(dev->coherent_dma_mask,
>> DMA_BIT_MASK(ilog2(dma_addr + size)));
>> *dev->dma_mask = min((*dev->dma_mask),
>> DMA_BIT_MASK(ilog2(dma_addr + size)));
>>
>> which would be incorrect for size == 0xffffffffffffffffULL when
>> dma_addr != 0. So the proposed fix really is not papering over
>> the base problem very well.
>
> I'm not sure I agree there. Granted, there exist many more problematic
> aspects than are dealt with here (I've got more patches cooking to sort
> out some of the other issues we have with dma-ranges), but considering
> size specifically:
>
> - It is not possible to explicitly specify a range with a size of 2^64
> in DT. If someone does specify a size of 0, they've done a silly thing
> and should not be surprised that it ends badly.
>
> - It *is* perfectly legitimate for bus code (or a previous device
> driver, once we start coming here at probe time) to have set a device's
> DMA mask to 0xffffffffffffffffULL. If this code then blindly overflows
> and infers an invalid size of 0 from that, breaking things in the
> process, that is this code's fault alone. It just so happens that
> nothing managed to trigger the latent problem until patch #7 here shakes
> up the callsites.
The existing code that uses size does not appear capable of dealing with
the case of DMA mask of 0xffffffffffffffffULL since 2^64 does not fit
into size.
The code affected by the DMA mask is not within my area of knowledge, so
take the following with a grain of salt. If a DMA mask of
0xffffffffffffffffULL is provided, would the code still work without error
(though with reduced capability) if the mask was changed to
0xefffffffffffffffULL? I would guess that the location to do so would
be where dev->coherent_dma_mask is set, or some other location that
is not of_dma_configure(). This would just be a temporary workaround.
> Yes, wacky impossible base + size combinations in DT were a theoretical
> problem before, and remain a theoretical problem, but also fall into the
> "how did you ever expect this to work?" category. There's certainly
> plenty more we can do to improve the DT parsing/validation, but that
> still doesn't apply to this path where the information is *not* coming
> from the DT at all.
>
>> I agree that the proper solution involves passing a mask instead
>> of a size to arch_setup_dma_ops().
>
> Having started writing that patch too, I can tell you it's a big bugger
> touching multiple architectures and fixing up various drivers doing
> stupid things, hence why I'm happy with this point fix being the lesser
> of two evils in terms of not holding up this mostly-orthogonal series.
>
> Robin.
>
>>
>> -Frank
>>
>
>
^ permalink raw reply
* [PATCH] of: Make of_match_node() an inline stub for CONFIG_OF=n
From: Florian Fainelli @ 2017-04-06 19:32 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: andrew-g2DYL2Zd6BY,
vivien.didelot-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/, Florian Fainelli,
Rob Herring, Frank Rowand,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE
Make of_match_node() an inline function when CONFIG_OF=n which allows the
compiler to eliminate warnings about unused variables.
Suggested-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Signed-off-by: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
include/linux/of.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/linux/of.h b/include/linux/of.h
index 21e6323de0f3..2803a85e81ec 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -839,7 +839,11 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag
}
#define of_match_ptr(_ptr) NULL
-#define of_match_node(_matches, _node) NULL
+static inline const struct of_device_id *of_match_node(
+ const struct of_device_id *matches, const struct device_node *node)
+{
+ return NULL;
+}
#endif /* CONFIG_OF */
/* Default string compare functions, Allow arch asm/prom.h to override */
--
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 related
* Re: [PATCH V10 06/12] of: device: Fix overflow of coherent_dma_mask
From: Frank Rowand @ 2017-04-06 19:34 UTC (permalink / raw)
To: Sricharan R, robin.murphy-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
joro-zLv9SwRftAIdnm+yROfE0A, lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <b77e3405-f060-bcd5-99f6-7d76f9edf08a-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/06/17 04:01, Sricharan R wrote:
> Hi Frank,
>
> On 4/6/2017 12:31 PM, Frank Rowand wrote:
>> On 04/04/17 03:18, Sricharan R wrote:
>>> Size of the dma-range is calculated as coherent_dma_mask + 1
>>> and passed to arch_setup_dma_ops further. It overflows when
>>> the coherent_dma_mask is set for full 64 bits 0xFFFFFFFFFFFFFFFF,
>>> resulting in size getting passed as 0 wrongly. Fix this by
>>> passsing in max(mask, mask + 1). Note that in this case
>>> when the mask is set to full 64bits, we will be passing the mask
>>> itself to arch_setup_dma_ops instead of the size. The real fix
>>> for this should be to make arch_setup_dma_ops receive the
>>> mask and handle it, to be done in the future.
>>>
>>> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>>> ---
>>> drivers/of/device.c | 2 +-
>>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/of/device.c b/drivers/of/device.c
>>> index c17c19d..c2ae6bb 100644
>>> --- a/drivers/of/device.c
>>> +++ b/drivers/of/device.c
>>> @@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np)
>>> ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
>>> if (ret < 0) {
>>> dma_addr = offset = 0;
>>> - size = dev->coherent_dma_mask + 1;
>>> + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
>>> } else {
>>> offset = PFN_DOWN(paddr - dma_addr);
>>> dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
>>>
>>
>> NACK.
>>
>> Passing an invalid size to arch_setup_dma_ops() is only part of the problem.
>> size is also used in of_dma_configure() before calling arch_setup_dma_ops():
>>
>> dev->coherent_dma_mask = min(dev->coherent_dma_mask,
>> DMA_BIT_MASK(ilog2(dma_addr + size)));
>> *dev->dma_mask = min((*dev->dma_mask),
>> DMA_BIT_MASK(ilog2(dma_addr + size)));
>>
>> which would be incorrect for size == 0xffffffffffffffffULL when
>> dma_addr != 0. So the proposed fix really is not papering over
>> the base problem very well.
>>
>
> Ok, but with your fix for of_dma_get_range and the above fix,
> dma_addr will be '0' when size = 0xffffffffffffffffULL,
> but DMA_BIT_MASK(ilog2(dma_addr + size)) would be wrong though,
> making coherent_dma_mask to be smaller 0x7fffffffffffffffULL.
Yes, that was my point. Setting size to 0x7fffffffffffffffULL
affects several places. Another potential location (based only
on the function header comment, not from reading the code) is
iommu_dma_init_domain(). The header comment says:
* @base and @size should be exact multiples of IOMMU page granularity to
* avoid rounding surprises.
I have not read enough context to really understand of_dma_configure(), but
it seems there is yet another issue in how the error return case from
of_dma_get_range() is handled (with the existing code, as well as if
my patch gets accepted). An error return value can mean _either_
there is no dma-ranges property _or_ "an other problem occurred". Should
the "an other problem occurred" case be handled by defaulting size to
a value based on dev->coherent_dma_mask (the current case) or should the
attempt to set up the DMA configuration just fail?
>
> Regards,
> Sricharan
>
>> I agree that the proper solution involves passing a mask instead
>> of a size to arch_setup_dma_ops().
>>
>
^ permalink raw reply
* Re: [PATCH] of: Make of_match_node() an inline stub for CONFIG_OF=n
From: Andrew Lunn @ 2017-04-06 19:54 UTC (permalink / raw)
To: Florian Fainelli
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
vivien.didelot-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/, Rob Herring,
Frank Rowand, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE
In-Reply-To: <20170406193224.10046-1-f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, Apr 06, 2017 at 12:32:24PM -0700, Florian Fainelli wrote:
> Make of_match_node() an inline function when CONFIG_OF=n which allows the
> compiler to eliminate warnings about unused variables.
>
> Suggested-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
> Signed-off-by: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Thanks Florian,
Reviewed-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Andrew
--
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 v4 2/2] i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Peter Rosin @ 2017-04-06 20:03 UTC (permalink / raw)
To: michael.hennerich-OyLXuOCK7orQT0dZR+AlfA,
wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, linus.walleij-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <376f970f-9e0f-1d44-3813-93691c849b83-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
On 2017-04-06 13:31, Michael Hennerich wrote:
> On 06.04.2017 10:39, Peter Rosin wrote:
>> Hi Michael,
>>
>> I would still like to hear from someone with more gpio experience.
>
> I'll ping Linus.
>
>>
>> Anyway, from my point of view, there's just a few minor things left,
>> with comments inline as usual.
>>
>> Thanks for you patience!
s/you/your/
>
> Thanks for review.
>
>>
>> Cheers,
>> peda
>>
>> On 2017-04-05 15:07, michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org wrote:
>>> From: Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
>>>
>>> This patch adds support for the Analog Devices / Linear Technology
>>> LTC4306 and LTC4305 4/2 Channel I2C Bus Multiplexer/Switches.
>>> The LTC4306 optionally provides two general purpose input/output pins
>>> (GPIOs) that can be configured as logic inputs, opendrain outputs or
>>> push-pull outputs via the generic GPIOLIB framework.
>>>
>>> Signed-off-by: Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
>>>
>>> ---
>>>
>>> Changes since v1:
>>>
>>> - Sort makefile entries
>>> - Sort driver includes
>>> - Use proper defines
>>> - Miscellaneous coding style fixups
>>> - Rename mux select callback
>>> - Revise i2c-mux-idle-disconnect handling
>>> - Add ENABLE GPIO handling on error and device removal.
>>> - Remove surplus of_match_device call.
>>>
>>> Changes since v2:
>>>
>>> - Stop double error reporting (i2c_mux_add_adapter)
>>> - Change subject
>>> - Split dt bindings to separate patch
>>>
>>> Changes since v3:
>>>
>>> - Change subject and add spaces
>>> - Convert to I2C_MUX_LOCKED
>>> - Convert to regmap
>>> - Remove local register cache
>>> - Restore previous ENABLE GPIO handling
>>> - Initially pulse ENABLE low
>>> - Eliminate i2c client struct in driver state structure
>>> - Simplify error return path
>>> - Misc minor cleanups
>>> ---
>>> MAINTAINERS | 8 +
>>> drivers/i2c/muxes/Kconfig | 11 ++
>>> drivers/i2c/muxes/Makefile | 1 +
>>> drivers/i2c/muxes/i2c-mux-ltc4306.c | 310 ++++++++++++++++++++++++++++++++++++
>>> 4 files changed, 330 insertions(+)
>>> create mode 100644 drivers/i2c/muxes/i2c-mux-ltc4306.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index c776906..9a27a19 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -7698,6 +7698,14 @@ S: Maintained
>>> F: Documentation/hwmon/ltc4261
>>> F: drivers/hwmon/ltc4261.c
>>>
>>> +LTC4306 I2C MULTIPLEXER DRIVER
>>> +M: Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
>>> +W: http://ez.analog.com/community/linux-device-drivers
>>> +L: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>>> +S: Supported
>>> +F: drivers/i2c/muxes/i2c-mux-ltc4306.c
>>> +F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
>>> +
>>> LTP (Linux Test Project)
>>> M: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
>>> M: Cyril Hrubis <chrubis-AlSwsSmVLrQ@public.gmane.org>
>>> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
>>> index 10b3d17..41153b4 100644
>>> --- a/drivers/i2c/muxes/Kconfig
>>> +++ b/drivers/i2c/muxes/Kconfig
>>> @@ -30,6 +30,17 @@ config I2C_MUX_GPIO
>>> This driver can also be built as a module. If so, the module
>>> will be called i2c-mux-gpio.
>>>
>>> +config I2C_MUX_LTC4306
>>> + tristate "LTC LTC4306/5 I2C multiplexer"
>>> + select GPIOLIB
>>> + select REGMAP_I2C
>>> + help
>>> + If you say yes here you get support for the LTC LTC4306 or LTC4305
>>
>> This reads a bit funny, and I think you should just spell out the
>> first LTC? But perhaps not in the tristate above though, depending
>> on how long it gets?
>
> Ok - I rename LTC -> Analog Devices
>
>>
>>> + I2C mux/switch devices.
>>> +
>>> + This driver can also be built as a module. If so, the module
>>> + will be called i2c-mux-ltc4306.
>>> +
>>> config I2C_MUX_PCA9541
>>> tristate "NXP PCA9541 I2C Master Selector"
>>> help
>>> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
>>> index 9948fa4..ff7618c 100644
>>> --- a/drivers/i2c/muxes/Makefile
>>> +++ b/drivers/i2c/muxes/Makefile
>>> @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
>>> obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
>>>
>>> obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
>>> +obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
>>> obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
>>> obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
>>> obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
>>> diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
>>> new file mode 100644
>>> index 0000000..7d34434
>>> --- /dev/null
>>> +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
>>> @@ -0,0 +1,310 @@
>>> +/*
>>> + * Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch
>>> + *
>>> + * Copyright (C) 2017 Analog Devices Inc.
>>> + *
>>> + * Licensed under the GPL-2.
>>> + *
>>> + * Based on: i2c-mux-pca954x.c
>>> + *
>>> + * Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf
>>> + */
>>> +
>>> +#include <linux/device.h>
>>> +#include <linux/gpio.h>
>>> +#include <linux/gpio/consumer.h>
>>> +#include <linux/gpio/driver.h>
>>> +#include <linux/i2c-mux.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/slab.h>
>>> +
>>> +#define LTC4305_MAX_NCHANS 2
>>> +#define LTC4306_MAX_NCHANS 4
>>> +
>>> +#define LTC_REG_STATUS 0x0
>>> +#define LTC_REG_CONFIG 0x1
>>> +#define LTC_REG_MODE 0x2
>>> +#define LTC_REG_SWITCH 0x3
>>> +
>>> +#define LTC_DOWNSTREAM_ACCL_EN BIT(6)
>>> +#define LTC_UPSTREAM_ACCL_EN BIT(7)
>>> +
>>> +#define LTC_GPIO_ALL_INPUT 0xC0
>>> +#define LTC_SWITCH_MASK 0xF0
>>> +
>>> +enum ltc_type {
>>> + ltc_4305,
>>> + ltc_4306,
>>> +};
>>> +
>>> +struct chip_desc {
>>> + u8 nchans;
>>> + u8 num_gpios;
>>> +};
>>> +
>>> +struct ltc4306 {
>>> + struct regmap *regmap;
>>> + struct gpio_chip gpiochip;
>>> + const struct chip_desc *chip;
>>> +};
>>> +
>>> +static const struct chip_desc chips[] = {
>>> + [ltc_4305] = {
>>> + .nchans = LTC4305_MAX_NCHANS,
>>> + },
>>> + [ltc_4306] = {
>>> + .nchans = LTC4306_MAX_NCHANS,
>>> + .num_gpios = 2,
>>> + },
>>> +};
>>> +
>>> +static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg)
>>> +{
>>> + return (reg == LTC_REG_CONFIG) ? true : false;
>>> +}
>>> +
>>> +static const struct regmap_config ltc4306_regmap_config = {
>>> + .reg_bits = 8,
>>> + .val_bits = 8,
>>> + .max_register = LTC_REG_SWITCH,
>>> + .volatile_reg = ltc4306_is_volatile_reg,
>>> + .cache_type = REGCACHE_RBTREE,
>>
>> Did you consider REGCACHE_FLAT? There are very few registers and no hole
>> in the map, and maintaining a tree seems like total overkill.
>
> There is no reason to use REGCACHE_FLAT, in our case it will be a single
> node.
Ok, so that makes me wonder what need REGCACHE_FLAT satisfies? To me,
a flat regmap seems like a perfect fit here. Oh well...
>>
>>> +};
>>> +
>>> +static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
>>> +{
>>> + struct ltc4306 *data = gpiochip_get_data(chip);
>>> + unsigned int val;
>>> + int ret;
>>> +
>>> + ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val);
>>> + if (ret < 0)
>>> + return ret;
>>> +
>>> + return (val & BIT(1 - offset));
>>
>> The outer parentheses do not add anything, and I think they might remain
>> from when you just removed a double negation at some point. But is it
>> good practice to indicate "high" with anything other than one? Sure, the
>> gpiolib function that wraps the ->get() op does the !! dance for you,
>> but even so, every single one of the half dozen random gpio providers I
>> looked at had code to coerce the value to 0/1 (or error). Which makes me
>> think you should also have it. And the gpio_chip documentation on ->get()
>> agrees with me...
>
> I'll restore the double negations.
Thanks!
>>
>>> +}
>>> +
>>> +static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset,
>>> + int value)
>>> +{
>>> + struct ltc4306 *data = gpiochip_get_data(chip);
>>> +
>>> + regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset),
>>> + value ? BIT(5 - offset) : 0);
>>> +}
>>> +
>>> +static int ltc4306_gpio_direction_input(struct gpio_chip *chip,
>>> + unsigned int offset)
>>> +{
>>> + struct ltc4306 *data = gpiochip_get_data(chip);
>>> +
>>> + return regmap_update_bits(data->regmap, LTC_REG_MODE,
>>> + BIT(7 - offset), BIT(7 - offset));
>>> +}
>>> +
>>> +static int ltc4306_gpio_direction_output(struct gpio_chip *chip,
>>> + unsigned int offset, int value)
>>> +{
>>> + struct ltc4306 *data = gpiochip_get_data(chip);
>>> +
>>> + ltc4306_gpio_set(chip, offset, value);
>>> + return regmap_update_bits(data->regmap, LTC_REG_MODE,
>>> + BIT(7 - offset), 0);
>>> +}
>>> +
>>> +static int ltc4306_gpio_set_config(struct gpio_chip *chip,
>>> + unsigned int offset, unsigned long config)
>>> +{
>>> + struct ltc4306 *data = gpiochip_get_data(chip);
>>> + unsigned int val;
>>> +
>>> + switch (pinconf_to_config_param(config)) {
>>> + case PIN_CONFIG_DRIVE_OPEN_DRAIN:
>>> + val = 0;
>>> + break;
>>> + case PIN_CONFIG_DRIVE_PUSH_PULL:
>>> + val = BIT(4 - offset);
>>> + break;
>>> + default:
>>> + return -ENOTSUPP;
>>> + }
>>> +
>>> + return regmap_update_bits(data->regmap, LTC_REG_MODE,
>>> + BIT(4 - offset), val);
>>> +}
>>> +
>>> +static int ltc4306_gpio_init(struct ltc4306 *data)
>>> +{
>>> + struct device *dev = regmap_get_device(data->regmap);
>>> +
>>> + if (!data->chip->num_gpios)
>>> + return 0;
>>> +
>>> + data->gpiochip.label = dev_name(dev);
>>> + data->gpiochip.base = -1;
>>> + data->gpiochip.ngpio = data->chip->num_gpios;
>>> + data->gpiochip.parent = dev;
>>> + data->gpiochip.can_sleep = true;
>>> + data->gpiochip.direction_input = ltc4306_gpio_direction_input;
>>> + data->gpiochip.direction_output = ltc4306_gpio_direction_output;
>>
>> I'm missing a get_direction op?
>
> No - its purely optional - the vast majority of gpiochips don't
> implement it.
>
> linux/drivers/gpio$ grep -lr --include \*.c get_direction | wc
> 36 36 523
> linux/drivers/gpio$ grep -Lr --include \*.c get_direction | wc
> 101 101 1461
Ok, but while optional, why not provide it? The implementation would
be about as simple as ltc4306_gpio_get, no?
>>
>>> + data->gpiochip.get = ltc4306_gpio_get;
>>> + data->gpiochip.set = ltc4306_gpio_set;
>>> + data->gpiochip.set_config = ltc4306_gpio_set_config;
>>> + data->gpiochip.owner = THIS_MODULE;
>>> +
>>> + /* gpiolib assumes all GPIOs default input */
>>> + regmap_write(data->regmap, LTC_REG_MODE, LTC_GPIO_ALL_INPUT);
>>> +
>>> + return devm_gpiochip_add_data(dev, &data->gpiochip, data);
>>> +}
>>> +
>>> +static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan)
>>> +{
>>> + struct ltc4306 *data = i2c_mux_priv(muxc);
>>> +
>>> + return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
>>> + LTC_SWITCH_MASK, BIT(7 - chan));
>>
>> Since the bits outside the mask are ignored for writes, I'd go with
>> regmap_write. Especially since those bits are volatile, which admittedly
>> will not have much impact until there is a need to read those volatile
>> bits outside the mask. But still.
>
> Yes they are volatile - but not declared as such.
> So regmap cache just ignores them.
> And we totally ignore these RONLY status bits, too.
Of course. I was referring to future changes that would perhaps
need to get at those status bits.
> regmap_write() will always write and ignore the cache, while
> regmap_update_bits() uses the cached value.
Ah, I was not aware of that.
> Are these callbacks guaranteed to be never called with the same CHAN
> sequentially? if yes - use regmap_write() otherwise its more efficient
> to use regmap_update_bits().
If you have the mux disconnect on idle, then yes, we are guaranteed
to not call with the same "CHAN". But, if not disconnecting and given
the above, it is more efficient to rely on the cache given the above
properties of regmap. So, let's do it your way and keep update_bits
and worry about volatile etc when/if it happens.
Ok, move on, nothing to see. And thanks for explaining.
Cheers,
peda
>>
>>> +}
>>> +
>>> +static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
>>> +{
>>> + struct ltc4306 *data = i2c_mux_priv(muxc);
>>> +
>>> + return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
>>> + LTC_SWITCH_MASK, 0);
>>
>> Dito.
>>
>>> +}
>>> +
>>> +static const struct i2c_device_id ltc4306_id[] = {
>>> + { "ltc4305", ltc_4305 },
>>> + { "ltc4306", ltc_4306 },
>>> + { }
>>> +};
>>> +MODULE_DEVICE_TABLE(i2c, ltc4306_id);
>>> +
>>> +static const struct of_device_id ltc4306_of_match[] = {
>>> + { .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] },
>>> + { .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] },
>>> + { }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, ltc4306_of_match);
>>> +
>>> +static int ltc4306_probe(struct i2c_client *client,
>>> + const struct i2c_device_id *id)
>>> +{
>>> + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
>>> + struct device_node *of_node = client->dev.of_node;
>>> + struct i2c_mux_core *muxc;
>>> + struct ltc4306 *data;
>>> + struct gpio_desc *gpio;
>>> + bool idle_disc = false;
>>> + int num, ret;
>>> +
>>> + if (of_node)
>>> + idle_disc = of_property_read_bool(of_node,
>>> + "i2c-mux-idle-disconnect");
>>> +
>>> + muxc = i2c_mux_alloc(adap, &client->dev,
>>> + LTC4306_MAX_NCHANS, sizeof(*data),
>>
>> Hmmm, I didn't see this before, but if you do some more rearranging, it
>> should be possible to replace LTC4306_MAX_NCHANS with data->chip->nchans
>> and reduce resource waste for ltc4305. But it's just storage for two
>> pointers which is really really minor... Feel free to ignore.
>>
>> But you want to set a good example, right :-)
>>
>>> + I2C_MUX_LOCKED, ltc4306_select_mux,
>>> + idle_disc ? ltc4306_deselect_mux : NULL);
>>> + if (!muxc)
>>> + return -ENOMEM;
>>> + data = i2c_mux_priv(muxc);
>>> +
>>> + i2c_set_clientdata(client, muxc);
>>> +
>>> + data->regmap = devm_regmap_init_i2c(client, <c4306_regmap_config);
>>> + if (IS_ERR(data->regmap)) {
>>> + ret = PTR_ERR(data->regmap);
>>> + dev_err(&client->dev, "Failed to allocate register map: %d\n",
>>> + ret);
>>> + return ret;
>>> + }
>>> +
>>> + /* Reset and enable the mux if an enable GPIO is specified. */
>>> + gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
>>> + if (IS_ERR(gpio))
>>> + return PTR_ERR(gpio);
>>> +
>>> + if (gpio) {
>>> + udelay(1);
>>> + gpiod_set_value(gpio, 1);
>>> + }
>>> +
>>> + /*
>>> + * Write the mux register at addr to verify
>>> + * that the mux is in fact present. This also
>>> + * initializes the mux to disconnected state.
>>> + */
>>> + if (regmap_write(data->regmap, LTC_REG_SWITCH, 0) < 0) {
>>> + dev_warn(&client->dev, "probe failed\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + if (of_node) {
>>> + unsigned int val = 0;
>>> +
>>> + data->chip = of_device_get_match_data(&client->dev);
>>> +
>>> + if (of_property_read_bool(of_node,
>>> + "ltc,downstream-accelerators-enable"))
>>> + val |= LTC_DOWNSTREAM_ACCL_EN;
>>> +
>>> + if (of_property_read_bool(of_node,
>>> + "ltc,upstream-accelerators-enable"))
>>> + val |= LTC_UPSTREAM_ACCL_EN;
>>> +
>>> + if (regmap_write(data->regmap, LTC_REG_CONFIG, val) < 0)
>>> + return -ENODEV;
>>> + } else {
>>> + data->chip = &chips[id->driver_data];
>>> + }
>>> +
>>> + ret = ltc4306_gpio_init(data);
>>> + if (ret < 0)
>>> + return ret;
>>> +
>>> + /* Now create an adapter for each channel */
>>> + for (num = 0; num < data->chip->nchans; num++) {
>>> + ret = i2c_mux_add_adapter(muxc, 0, num, 0);
>>> + if (ret) {
>>> + i2c_mux_del_adapters(muxc);
>>> + return ret;
>>> + }
>>> + }
>>> +
>>> + dev_info(&client->dev,
>>> + "registered %d multiplexed busses for I2C switch %s\n",
>>> + num, client->name);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int ltc4306_remove(struct i2c_client *client)
>>> +{
>>> + struct i2c_mux_core *muxc = i2c_get_clientdata(client);
>>> +
>>> + i2c_mux_del_adapters(muxc);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static struct i2c_driver ltc4306_driver = {
>>> + .driver = {
>>> + .name = "ltc4306",
>>> + .of_match_table = of_match_ptr(ltc4306_of_match),
>>> + },
>>> + .probe = ltc4306_probe,
>>> + .remove = ltc4306_remove,
>>> + .id_table = ltc4306_id,
>>> +};
>>> +
>>> +module_i2c_driver(ltc4306_driver);
>>> +
>>> +MODULE_AUTHOR("Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>");
>>> +MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver");
>>> +MODULE_LICENSE("GPL v2");
>>>
>>
>>
>
>
--
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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox