* Re: [PATCH V7 4/7] mfd: da9061: MFD core support
From: Lee Jones @ 2017-04-04 8:34 UTC (permalink / raw)
To: Steve Twiss
Cc: LINUX-KERNEL, DEVICETREE, Dmitry Torokhov, Eduardo Valentin,
Guenter Roeck, LINUX-INPUT, LINUX-PM, LINUX-WATCHDOG,
Liam Girdwood, Mark Brown, Mark Rutland, Rob Herring,
Support Opensource, Wim Van Sebroeck, Zhang Rui
In-Reply-To: <6ED8E3B22081A4459DAC7699F3695FB7018CD6B207-68WUHU125fLzLL1Oxlh9IgLouzNaz+3S@public.gmane.org>
On Mon, 03 Apr 2017, Steve Twiss wrote:
> On 03 April 2017 15:31, Lee Jones wrote:
>
> > Subject: Re: [PATCH V7 4/7] mfd: da9061: MFD core support
> >
> > On Mon, 03 Apr 2017, Steve Twiss wrote:
> > > On 03 April 2017 15:12, Lee Jones wrote:
> > >
> > > > > @@ -475,7 +855,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
> > > > > return -EINVAL;
> > > > > }
> > > > >
> > > > > - chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
> > > > > + switch (chip->chip_type) {
> > > > > + case(COMPAT_TYPE_DA9061):
> > > >
> > > > Brackets around the case value?
> > > >
> > > > That's a new one on me.
> > >
> > > Hm. Do you want me to resend it without braces?
> >
> > Yes please. And a space after the 'case'.
>
> Hi Lee,
>
> I have resent PATCH V7 to change "case(X):" to be "case X:".
> - Removed brackets surrounding case statements for
> case COMPAT_TYPE_DA9061:
> case COMPAT_TYPE_DA9062:
Okay, good.
> New patch is here:
> https://lkml.org/lkml/2017/4/3/462
>
> The patch it is called by the same title "[PATCH V7 4/7] mfd: da9061: MFD core support".
> I've not updated the whole patch-set or changed the patch version number from V7.
I don't see it in my inbox?
You should always change the version, or things get confusing.
Even if it's a small change, you can differentiate by v7.1 or similar.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" 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 v3 00/11] add thermal throttling to Allwinner A33 SoC
From: Lee Jones @ 2017-04-04 8:31 UTC (permalink / raw)
To: Quentin Schulz
Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, wens-jdAy2FN1RRM,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, jic23-DgEjT+Ai2ygdnm+yROfE0A,
knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
pmeerw-jW+XmwGofnusTnJN9+BGXg,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-input-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, icenowy-ymACFijhrKM
In-Reply-To: <20170321153611.16228-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Tue, 21 Mar 2017, Quentin Schulz wrote:
> The Allwinner SoCs all have an ADC that can also act as a touchscreen
> controller and a thermal sensor. The first four channels can be used
> either for the ADC or the touchscreen and the fifth channel is used for
> the thermal sensor. We currently have a driver for the two latter
> functions in drivers/input/touchscreen/sun4i-ts.c but we don't have
> access to the ADC feature at all. It is meant to replace the current
> driver by using MFD and subdrivers for existing bindings.
>
> The Allwinner A33 only has a thermal sensor present in the GPADC. In
> addition, there is not an existing DT binding for the GPADC. Thus, we do
> not need the sun4i-gpadc MFD driver which was made to keep DT compatibility
> and probe subdrivers without the need to add DT subnodes.
>
> This series of patch adds the thermal sensor for the A33 and GPU/CPU
> thermal throttling. It also adds the cpu-supply property to the CPU node
> needed by the Sinlinx SinA33 and Olinuxino A33 to adapt their CPU regulator
> voltage depending on the currently used OPP. The other A33 boards all have
> their cpu-supply property set.
>
> This series also fixes the missing operating-points-v2 property in cpu DT
> nodes. Finally, it also adds all remaining OPPs which can be found in
> Allwinner 3.4 linux and fex files of all A33 boards.
>
> This series of patch is based on this[1] series of patch.
>
> v3:
> - fixed compatible name in DT and in documentation,
> - fixed DT node name and label,
> - added explanations in commit logs,
> - moved frequencies that need overvolting to board DTS instead of A33 DTSI,
> - fixed a typo in if is_enabled condition,
> - removed all patches concerning Olimex Olinuxino (no HW to test on),
What is the plan for this series?
I'm guessing there are no hard dependencies on the ARM parts?
If not, I'm happy to take the changes to 'drivers/*'.
> [1] https://lkml.org/lkml/2016/12/13/298 : "[PATCH v9] add support for Allwinner
> SoCs ADC"
>
> Thanks,
> Quentin
>
> Maxime Ripard (1):
> ARM: sun8i: a33: Add devfreq-based GPU cooling
>
> Quentin Schulz (10):
> ARM: sun8i: a33: add operating-points-v2 property to all nodes
> ARM: sun8i: a33: add all operating points
> ARM: dts: sun8i: sina33: add cpu-supply
> Documentation: DT: bindings: mfd: add A33 GPADC binding
> Documentation: DT: bindings: input: touschcreen: remove sun4i
> documentation
> iio: adc: sun4i-gpadc-iio: move code used in MFD probing to new
> function
> iio: adc: sun4i-gpadc-iio: add support for A33 thermal sensor
> ARM: dtsi: sun8i: a33: add thermal sensor
> ARM: dtsi: sun8i: a33: add CPU thermal throttling
> ARM: sun8i: sina33: add highest OPP of CPUs
>
> .../touchscreen/sun4i.txt => mfd/sun4i-gpadc.txt} | 21 +++
> arch/arm/boot/dts/sun8i-a23-a33.dtsi | 1 +
> arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts | 18 +++
> arch/arm/boot/dts/sun8i-a33.dtsi | 141 +++++++++++++++++
> drivers/iio/adc/Kconfig | 2 +-
> drivers/iio/adc/sun4i-gpadc-iio.c | 170 +++++++++++++++++----
> include/linux/mfd/sun4i-gpadc.h | 4 +
> 7 files changed, 324 insertions(+), 33 deletions(-)
> rename Documentation/devicetree/bindings/{input/touchscreen/sun4i.txt => mfd/sun4i-gpadc.txt} (64%)
>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH v3 5/7] mfd: Add Device Tree bindings document for TI tps6105x chip
From: Lee Jones @ 2017-04-04 8:27 UTC (permalink / raw)
To: Javier Martinez Canillas
Cc: linux-kernel, devicetree, Rob Herring, Mark Rutland
In-Reply-To: <b1118a87-9b39-bb04-d43e-f8f2b366904b@osg.samsung.com>
On Mon, 03 Apr 2017, Javier Martinez Canillas wrote:
> Hello Lee,
>
> On 04/03/2017 07:15 AM, Lee Jones wrote:
>
> [snip]
>
> >> +
> >> +The TP61050/TPS61052 is a high-power "white LED driver". This boost converter
> >> +is also used for other things than white LEDs, and also contains a GPIO pin.
> >
> > What functions does it offer?
> >
>
> Same comment than before, I'm not really familiar with this driver. But I'll
> look what are the MFD cell instantiated to better understand dev functions
> and expand this documentation accordingly.
Writing documentation for H/W you are unfamiliar with is a bad idea IMHO.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
From: Neil Armstrong @ 2017-04-04 8:10 UTC (permalink / raw)
To: airlied-cv59FeDIM0c
Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1490109950-21421-10-git-send-email-narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
On 03/21/2017 04:25 PM, Neil Armstrong wrote:
> Add HDMI output and connector nodes.
>
> Signed-off-by: Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> ---
> .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 39 ++++++++++++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 32 ++++++++++++++++++
> .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts | 23 +++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 23 +++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 12 +++++++
> .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts | 23 +++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 13 ++++++++
> .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 23 +++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 3 ++
> 9 files changed, 191 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> index 7a078be..a84e276 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> @@ -98,6 +98,27 @@
> clocks = <&wifi32k>;
> clock-names = "ext_clock";
> };
> +
> + cvbs-connector {
> + compatible = "composite-video-connector";
> +
> + port {
> + cvbs_connector_in: endpoint {
> + remote-endpoint = <&cvbs_vdac_out>;
> + };
> + };
> + };
> +
> + hdmi-connector {
> + compatible = "hdmi-connector";
> + type = "a";
> +
> + port {
> + hdmi_connector_in: endpoint {
> + remote-endpoint = <&hdmi_tx_tmds_out>;
> + };
> + };
> + };
> };
>
> /* This UART is brought out to the DB9 connector */
> @@ -188,3 +209,21 @@
> ðmac {
> status = "okay";
> };
> +
> +&cvbs_vdac_port {
> + cvbs_vdac_out: endpoint {
> + remote-endpoint = <&cvbs_connector_in>;
> + };
> +};
> +
> +&hdmi_tx {
> + status = "okay";
> + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> + pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> + hdmi_tx_tmds_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> index 94c6f95..0dda058 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> @@ -465,6 +465,38 @@
> cvbs_vdac_port: port@0 {
> reg = <0>;
> };
> +
> + /* HDMI-TX output port */
> + hdmi_tx_port: port@1 {
> + reg = <1>;
> +
> + hdmi_tx_out: endpoint {
> + remote-endpoint = <&hdmi_tx_in>;
> + };
> + };
> + };
> +
> + hdmi_tx: hdmi-tx@c883a000 {
> + compatible = "amlogic,meson-gx-dw-hdmi";
> + reg = <0x0 0xc883a000 0x0 0x1c>;
> + interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + status = "disabled";
> +
> + /* VPU VENC Input */
> + hdmi_tx_venc_port: port@0 {
> + reg = <0>;
> +
> + hdmi_tx_in: endpoint {
> + remote-endpoint = <&hdmi_tx_out>;
> + };
> + };
> +
> + /* TMDS Output */
> + hdmi_tx_tmds_port: port@1 {
> + reg = <1>;
> + };
> };
> };
> };
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> index 4cbd626..a2c999f 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> @@ -152,6 +152,17 @@
> };
> };
> };
> +
> + hdmi-connector {
> + compatible = "hdmi-connector";
> + type = "a";
> +
> + port {
> + hdmi_connector_in: endpoint {
> + remote-endpoint = <&hdmi_tx_tmds_out>;
> + };
> + };
> + };
> };
>
> &uart_AO {
> @@ -245,3 +256,15 @@
> remote-endpoint = <&cvbs_connector_in>;
> };
> };
> +
> +&hdmi_tx {
> + status = "okay";
> + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> + pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> + hdmi_tx_tmds_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> index 4a96e0f..1c96fc8 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> @@ -135,6 +135,17 @@
> };
> };
> };
> +
> + hdmi-connector {
> + compatible = "hdmi-connector";
> + type = "a";
> +
> + port {
> + hdmi_connector_in: endpoint {
> + remote-endpoint = <&hdmi_tx_tmds_out>;
> + };
> + };
> + };
> };
>
> /* This UART is brought out to the DB9 connector */
> @@ -250,3 +261,15 @@
> remote-endpoint = <&cvbs_connector_in>;
> };
> };
> +
> +&hdmi_tx {
> + status = "okay";
> + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> + pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> + hdmi_tx_tmds_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> index 04b3324..9716e65 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> @@ -524,3 +524,15 @@
> &vpu {
> compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
> };
> +
> +&hdmi_tx {
> + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> + resets = <&reset RESET_HDMITX_CAPB3>,
> + <&reset RESET_HDMI_SYSTEM_RESET>,
> + <&reset RESET_HDMI_TX>;
> + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
> + clocks = <&clkc CLKID_HDMI_PCLK>,
> + <&clkc CLKID_CLK81>,
> + <&clkc CLKID_GCLK_VENCI_INT0>;
> + clock-names = "isfr", "iahb", "venci";
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> index cea4a3e..8873c05 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> @@ -127,6 +127,17 @@
> };
> };
> };
> +
> + hdmi-connector {
> + compatible = "hdmi-connector";
> + type = "a";
> +
> + port {
> + hdmi_connector_in: endpoint {
> + remote-endpoint = <&hdmi_tx_tmds_out>;
> + };
> + };
> + };
> };
>
> &uart_AO {
> @@ -219,3 +230,15 @@
> remote-endpoint = <&cvbs_connector_in>;
> };
> };
> +
> +&hdmi_tx {
> + status = "okay";
> + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> + pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> + hdmi_tx_tmds_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> index fe11b5f..9dcac25 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> @@ -44,6 +44,7 @@
> #include "meson-gx.dtsi"
> #include <dt-bindings/clock/gxbb-clkc.h>
> #include <dt-bindings/gpio/meson-gxl-gpio.h>
> +#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
>
> / {
> compatible = "amlogic,meson-gxl";
> @@ -381,3 +382,15 @@
> &vpu {
> compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
> };
> +
> +&hdmi_tx {
> + compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> + resets = <&reset RESET_HDMITX_CAPB3>,
> + <&reset RESET_HDMI_SYSTEM_RESET>,
> + <&reset RESET_HDMI_TX>;
> + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
> + clocks = <&clkc CLKID_HDMI_PCLK>,
> + <&clkc CLKID_CLK81>,
> + <&clkc CLKID_GCLK_VENCI_INT0>;
> + clock-names = "isfr", "iahb", "venci";
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> index 5a337d3..0e68c62e 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> @@ -100,6 +100,17 @@
> };
> };
> };
> +
> + hdmi-connector {
> + compatible = "hdmi-connector";
> + type = "a";
> +
> + port {
> + hdmi_connector_in: endpoint {
> + remote-endpoint = <&hdmi_tx_tmds_out>;
> + };
> + };
> + };
> };
>
> /* This UART is brought out to the DB9 connector */
> @@ -183,3 +194,15 @@
> remote-endpoint = <&cvbs_connector_in>;
> };
> };
> +
> +&hdmi_tx {
> + status = "okay";
> + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> + pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> + hdmi_tx_tmds_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> index ddea730..fe451cc 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> @@ -130,3 +130,6 @@
> compatible = "amlogic,meson-gxm-vpu", "amlogic,meson-gx-vpu";
> };
>
> +&hdmi_tx {
> + compatible = "amlogic,meson-gxm-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> +};
>
Hi Kevin,
Please take this one for the amlogic arm-soc DT tree.
It may need a rebase, please tell me then I'll repost this one rebased on your 4.12/dt64 branch.
Thanks,
Neil
--
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] i2c/muxes/i2c-mux-ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Michael Hennerich @ 2017-04-04 7:50 UTC (permalink / raw)
To: Peter Rosin, wsa, robh+dt, mark.rutland, linus.walleij
Cc: linux-i2c, devicetree, linux-gpio, linux-kernel
In-Reply-To: <0d4c068f-d909-64be-421d-4500da7ebd4c@axentia.se>
On 31.03.2017 17:29, Peter Rosin wrote:
> Hi!
>
> Sorry for my incremental reviewing...
>
> There's a question for the gpio people below that I would like
> to have some confirmation on. Thanks!
Hi Peter,
Please find comments in-line.
>
> On 2017-03-29 12:15, michael.hennerich@analog.com wrote:
>> From: Michael Hennerich <michael.hennerich@analog.com>
>>
>> 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@analog.com>
>>
>> ---
>>
>> 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.
>> ---
>> .../devicetree/bindings/i2c/i2c-mux-ltc4306.txt | 61 ++++
>> MAINTAINERS | 8 +
>> drivers/i2c/muxes/Kconfig | 10 +
>> drivers/i2c/muxes/Makefile | 1 +
>> drivers/i2c/muxes/i2c-mux-ltc4306.c | 367 +++++++++++++++++++++
>> 5 files changed, 447 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
>> create mode 100644 drivers/i2c/muxes/i2c-mux-ltc4306.c
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
>> new file mode 100644
>> index 0000000..1e98c6b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
>> @@ -0,0 +1,61 @@
>> +* Linear Technology / Analog Devices I2C bus switch
>> +
>> +Required Properties:
>> +
>> + - compatible: Must contain one of the following.
>> + "lltc,ltc4305", "lltc,ltc4306"
>> + - reg: The I2C address of the device.
>> +
>> + The following required properties are defined externally:
>> +
>> + - Standard I2C mux properties. See i2c-mux.txt in this directory.
>> + - I2C child bus nodes. See i2c-mux.txt in this directory.
>> +
>> +Optional Properties:
>> +
>> + - enable-gpios: Reference to the GPIO connected to the enable input.
>> + - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
>> + children in idle state. This is necessary for example, if there are several
>> + multiplexers on the bus and the devices behind them use same I2C addresses.
>> + - gpio-controller: Marks the device node as a GPIO Controller.
>> + - #gpio-cells: Should be two. The first cell is the pin number and
>> + the second cell is used to specify flags.
>> + See ../gpio/gpio.txt for more information.
>> + - ltc,downstream-accelerators-enable: Enables the rise time accelerators
>> + on the downstream port.
>> + - ltc,upstream-accelerators-enable: Enables the rise time accelerators
>> + on the upstream port.
>> +
>> +Example:
>> +
>> + ltc4306: i2c-mux@4a {
>> + compatible = "lltc,ltc4306";
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + reg = <0x4a>;
>> +
>> + gpio-controller;
>> + #gpio-cells = <2>;
>> +
>> + i2c@0 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + reg = <0>;
>> +
>> + eeprom@50 {
>> + compatible = "at,24c02";
>> + reg = <0x50>;
>> + };
>> + };
>> +
>> + i2c@1 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + reg = <1>;
>> +
>> + eeprom@50 {
>> + compatible = "at,24c02";
>> + reg = <0x50>;
>> + };
>> + };
>> + };
>> 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@analog.com>
>> +W: http://ez.analog.com/community/linux-device-drivers
>> +L: linux-i2c@vger.kernel.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@gentoo.org>
>> M: Cyril Hrubis <chrubis@suse.cz>
>> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
>> index 10b3d17..f501b3b 100644
>> --- a/drivers/i2c/muxes/Kconfig
>> +++ b/drivers/i2c/muxes/Kconfig
>> @@ -30,6 +30,16 @@ 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
>> + help
>> + If you say yes here you get support for the LTC LTC4306 or LTC4305
>> + 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..c15a8a4
>> --- /dev/null
>> +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
>> @@ -0,0 +1,367 @@
>> +/*
>> + * 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/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)
>
> Maybe align the BIT(x) parts with a tab, like you do above...
sure
>
>> +
>> +#define LTC_GPIO_ALL_INPUT 0xC0
>> +
>> +enum ltc_type {
>> + ltc_4305,
>> + ltc_4306,
>> +};
>> +
>> +struct chip_desc {
>> + u8 nchans;
>> + u8 num_gpios;
>> +};
>> +
>> +struct ltc4306 {
>> + struct i2c_client *client;
>> + struct gpio_desc *en_gpio;
>> + struct gpio_chip gpiochip;
>> + const struct chip_desc *chip;
>> + u8 regs[LTC_REG_SWITCH + 1];
>> +};
>> +
>> +/* Provide specs for the PCA954x types we know about */
>> +static const struct chip_desc chips[] = {
>> + [ltc_4305] = {
>> + .nchans = LTC4305_MAX_NCHANS,
>> + },
>> + [ltc_4306] = {
>> + .nchans = LTC4306_MAX_NCHANS,
>> + .num_gpios = 2,
>> + },
>> +};
>> +
>> +static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
>> +{
>> + struct ltc4306 *data = gpiochip_get_data(chip);
>> + int ret = 0;
>
> This assignment is not needed.
right
>
>> +
>> + if (gpiochip_line_is_open_drain(chip, offset) ||
>> + (data->regs[LTC_REG_MODE] & BIT(7 - offset))) {
>
> I wonder about this open-coded register cache. So, gpio people, is there
> a guarantee from gpiolib that only one gpio_chip operation is in flight
> concurrently? Because I don't see any evidence of that. With that in
> mind, I think some locking is needed?
I thought there is a per chip mutex in the gpiolib. But I can't find
anything like this either. Since these two gpios can be used from
different internal or external users. The locking seem to be needed.
This gets us back to the regmap option. I did a quick grep, and 9 out of
205 drivers using regmap i2c, also use i2c_smbus... concurrently.
grep -Rl regmap_init_i2c ./drivers | xargs grep -l i2c_smbus_ | grep "\.c"
Mostly to work around non uniform transfer layouts.
I'll check with Mark Brown on this topic.
>
>> + /* Open Drain or Input */
>> + ret = i2c_smbus_read_byte_data(data->client, LTC_REG_CONFIG);
>> + if (ret < 0)
>> + return ret;
>> +
>> + return !!(ret & BIT(1 - offset));
>> + } else {
>> + return !!(data->regs[LTC_REG_CONFIG] & BIT(5 - offset));
>> + }
>> +}
>> +
>> +static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset,
>> + int value)
>> +{
>> + struct ltc4306 *data = gpiochip_get_data(chip);
>> +
>> + if (value)
>> + data->regs[LTC_REG_CONFIG] |= BIT(5 - offset);
>> + else
>> + data->regs[LTC_REG_CONFIG] &= ~BIT(5 - offset);
>> +
>> + i2c_smbus_write_byte_data(data->client, LTC_REG_CONFIG,
>> + data->regs[LTC_REG_CONFIG]);
>> +}
>> +
>> +static int ltc4306_gpio_direction_input(struct gpio_chip *chip,
>> + unsigned int offset)
>> +{
>> + struct ltc4306 *data = gpiochip_get_data(chip);
>> +
>> + data->regs[LTC_REG_MODE] |= BIT(7 - offset);
>> +
>> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
>> + data->regs[LTC_REG_MODE]);
>> +}
>> +
>> +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);
>> + data->regs[LTC_REG_MODE] &= ~BIT(7 - offset);
>> +
>> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
>> + data->regs[LTC_REG_MODE]);
>> +}
>> +
>> +static int ltc4306_gpio_set_config(struct gpio_chip *chip,
>> + unsigned int offset, unsigned long config)
>> +{
>> + struct ltc4306 *data = gpiochip_get_data(chip);
>> +
>> + switch (pinconf_to_config_param(config)) {
>> + case PIN_CONFIG_DRIVE_OPEN_DRAIN:
>> + data->regs[LTC_REG_MODE] &= ~BIT(4 - offset);
>> + break;
>> + case PIN_CONFIG_DRIVE_PUSH_PULL:
>> + data->regs[LTC_REG_MODE] |= BIT(4 - offset);
>> + break;
>> + default:
>> + return -ENOTSUPP;
>> + }
>> +
>> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
>> + data->regs[LTC_REG_MODE]);
>> +}
>> +
>> +static int ltc4306_gpio_init(struct ltc4306 *data)
>> +{
>> + if (!data->chip->num_gpios)
>> + return 0;
>> +
>> + data->gpiochip.label = dev_name(&data->client->dev);
>> + data->gpiochip.base = -1;
>> + data->gpiochip.ngpio = data->chip->num_gpios;
>> + data->gpiochip.parent = &data->client->dev;
>> + data->gpiochip.can_sleep = true;
>> + data->gpiochip.direction_input = ltc4306_gpio_direction_input;
>> + data->gpiochip.direction_output = ltc4306_gpio_direction_output;
>> + 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 */
>> + data->regs[LTC_REG_MODE] |= LTC_GPIO_ALL_INPUT;
>> + i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
>> + data->regs[LTC_REG_MODE]);
>> +
>> + return devm_gpiochip_add_data(&data->client->dev,
>> + &data->gpiochip, data);
>> +}
>> +
>> +/*
>> + * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
>> + * as they will try to lock the adapter a second time.
>> + */
>> +static int ltc4306_reg_write(struct i2c_adapter *adap,
>> + struct i2c_client *client, u8 reg, u8 val)
>> +{
>> + int ret;
>> +
>> + if (adap->algo->master_xfer) {
>> + struct i2c_msg msg;
>> + char buf[2];
>> +
>> + msg.addr = client->addr;
>> + msg.flags = 0;
>> + msg.len = 2;
>> + buf[0] = reg;
>> + buf[1] = val;
>> + msg.buf = buf;
>> + ret = __i2c_transfer(adap, &msg, 1);
>> + } else {
>> + union i2c_smbus_data data;
>> +
>> + data.byte = val;
>> + ret = adap->algo->smbus_xfer(adap, client->addr,
>> + client->flags,
>> + I2C_SMBUS_WRITE,
>> + reg,
>> + I2C_SMBUS_BYTE_DATA, &data);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan)
>> +{
>> + struct ltc4306 *data = i2c_mux_priv(muxc);
>> + struct i2c_client *client = data->client;
>> + u8 regval;
>> + int ret = 0;
>> +
>> + regval = BIT(7 - chan);
>> +
>> + /* Only select the channel if its different from the last channel */
>> + if (data->regs[LTC_REG_SWITCH] != regval) {
>> + ret = ltc4306_reg_write(muxc->parent, client,
>> + LTC_REG_SWITCH, regval);
>> + data->regs[LTC_REG_SWITCH] = ret < 0 ? 0 : regval;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
>> +{
>> + struct ltc4306 *data = i2c_mux_priv(muxc);
>> + struct i2c_client *client = data->client;
>> +
>> + /* Deselect all channels */
>> + data->regs[LTC_REG_SWITCH] = 0;
>> +
>> + return ltc4306_reg_write(muxc->parent, client,
>> + LTC_REG_SWITCH, data->regs[LTC_REG_SWITCH]);
>> +}
>> +
>> +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;
>> + bool idle_disconnect_dt = false;
>> + struct i2c_mux_core *muxc;
>> + struct ltc4306 *data;
>> + int num, ret;
>> +
>> + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
>> + return -ENODEV;
>> +
>> + if (of_node) {
>> + idle_disconnect_dt =
>> + of_property_read_bool(of_node,
>> + "i2c-mux-idle-disconnect");
>
> If you rename the variable "disconnect" or something similar and
> shorter, you can avoid the interesting indentation.
ok
>
>> + }
>> +
>> + muxc = i2c_mux_alloc(adap, &client->dev,
>> + LTC4306_MAX_NCHANS, sizeof(*data), 0,
>> + ltc4306_select_mux, idle_disconnect_dt ?
>> + ltc4306_deselect_mux : NULL);
>> + if (!muxc)
>> + return -ENOMEM;
>> + data = i2c_mux_priv(muxc);
>> +
>> + i2c_set_clientdata(client, muxc);
>> + data->client = client;
>> +
>> + /* Enable the mux if an enable GPIO is specified. */
>> + data->en_gpio = devm_gpiod_get_optional(&client->dev, "enable",
>> + GPIOD_OUT_HIGH);
>> + if (IS_ERR(data->en_gpio))
>> + return PTR_ERR(data->en_gpio);
>> +
>> + /*
>> + * Write the mux register at addr to verify
>> + * that the mux is in fact present. This also
>> + * initializes the mux to disconnected state.
>> + */
>> + if (i2c_smbus_write_byte_data(client, LTC_REG_SWITCH, 0) < 0) {
>> + dev_warn(&client->dev, "probe failed\n");
>> + ret = -ENODEV;
>> + goto gpio_default;
>> + }
>> +
>> + if (of_node) {
>> + data->chip = of_device_get_match_data(&client->dev);
>> +
>> + if (of_property_read_bool(of_node,
>> + "ltc,downstream-accelerators-enable"))
>> + data->regs[LTC_REG_CONFIG] |= LTC_DOWNSTREAM_ACCL_EN;
>> +
>> + if (of_property_read_bool(of_node,
>> + "ltc,upstream-accelerators-enable"))
>> + data->regs[LTC_REG_CONFIG] |= LTC_UPSTREAM_ACCL_EN;
>> +
>> + if (i2c_smbus_write_byte_data(client, LTC_REG_CONFIG,
>> + data->regs[LTC_REG_CONFIG]) < 0) {
>> + dev_warn(&client->dev, "probe failed\n");
>> + ret = -ENODEV;
>> + goto gpio_default;
>> + }
>> + } else {
>> + data->chip = &chips[id->driver_data];
>> + }
>> +
>> + ret = ltc4306_gpio_init(data);
>> + if (ret < 0)
>> + goto gpio_default;
>> +
>> + /* 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) {
>> + dev_err(&client->dev,
>> + "failed to register multiplexed adapter %d\n",
>> + num);
>> + goto add_adapter_failed;
>> + }
>> + }
>> +
>> + dev_info(&client->dev,
>> + "registered %d multiplexed busses for I2C switch %s\n",
>> + num, client->name);
>> +
>> + return 0;
>> +
>> +add_adapter_failed:
>> + i2c_mux_del_adapters(muxc);
>> +gpio_default:
>> + gpiod_direction_input(data->en_gpio);
>
> This was actually not what I had in mind when I asked about it in v1, and
> this looks a bit strange. You have no way of knowing if the pin was
> configured as input when probe was called, and I don't see code like this
> all over the place. Maybe it's is ok to not disable the chip over
> suspend/resume, I was just asking because it looked a bit strange to grab
> a pin and then forget about it. Now that I think about it some more, it's
> probably ok to do just that since it is perhaps not possible to make the
> chip draw less power by deasserting enable, but what do I know?
GPIOs are assumed by default inputs. So if you want to undo the actions
in probe. The logical consequence is to move them back to inputs, and
let the external PULL-UP or PULL-DOWN on the ENABLE decide what happens.
I would also prefer to leave it enabled, so that the GPIOs can retain
it's last state. Well I think the device draws a bit less power when
disabled. But we don't support runtime PM anyways.
>
> However, it might be a good idea to toggle enable and deliberately reset
> the chip in probe?
Will do.
>
> Cheers,
> peda
>
>> + return ret;
>> +}
>> +
>> +static int ltc4306_remove(struct i2c_client *client)
>> +{
>> + struct i2c_mux_core *muxc = i2c_get_clientdata(client);
>> + struct ltc4306 *data = i2c_mux_priv(muxc);
>> +
>> + i2c_mux_del_adapters(muxc);
>> + gpiod_direction_input(data->en_gpio);
>> +
>> + 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@analog.com>");
>> +MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver");
>> +MODULE_LICENSE("GPL v2");
>>
>
>
--
Greetings,
Michael
--
Analog Devices GmbH Otl-Aicher Strasse 60-64 80807 München
Sitz der Gesellschaft München, Registergericht München HRB 40368,
Geschäftsführer: Peter Kolberg, Ali Raza Husain, Eileen Wynne
^ permalink raw reply
* Re: [PATCH v2 1/2] dt-bindings: Document the STM32 QSPI bindings
From: Ludovic BARRE @ 2017-04-04 7:28 UTC (permalink / raw)
To: Rob Herring
Cc: Cyrille Pitchen, Marek Vasut, David Woodhouse, Brian Norris,
Boris Brezillon, Richard Weinberger, Alexandre Torgue,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170403165735.sopfhlxzefkzrbfh@rob-hp-laptop>
Hi Rob
thanks for review
my comments below
br
Ludo
On 04/03/2017 06:57 PM, Rob Herring wrote:
> On Fri, Mar 31, 2017 at 07:02:03PM +0200, Ludovic Barre wrote:
>> From: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>>
>> This patch adds documentation of device tree bindings for the STM32
>> QSPI controller.
>>
>> Signed-off-by: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>> ---
>> .../devicetree/bindings/mtd/stm32-quadspi.txt | 45 ++++++++++++++++++++++
>> 1 file changed, 45 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>> new file mode 100644
>> index 0000000..95a8ebd
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>> @@ -0,0 +1,45 @@
>> +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
>> +
>> +Required properties:
>> +- compatible: should be "st,stm32f469-qspi"
>> +- reg: contains the register location and length.
>> + (optional) the memory mapping address and length
> Why optional? Either the h/w has it or doesn't. If some chips don't,
> they should have a different compatible string.
in fact, the stm32 qspi controller can operate in any of the following
modes:
-indirect mode: all the operations are performed using the qspi registers
with read/write.
-read memory-mapped mode: the external Flash memory is mapped to the
microcontroller address space and is seen by the system as if it was
an internal memory (use memcpy_fromio). this mode improve read throughput
if qspi_mm is defined the qspi controller use read memory-mapped mode
else the controller transfers in indirect mode.
>> +- reg-names: list of the names corresponding to the previous register
>> + Should contain "qspi" to register location
>> + (optional) "qspi_mm" if read in memory map mode (improve read throughput)
>> +- interrupts: should contain the interrupt for the device
>> +- clocks: the phandle of the clock needed by the QSPI controller
>> +- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
>> +
>> +Optional properties:
>> +- resets: must contain the phandle to the reset controller.
>> +
>> +A spi flash must be a child of the nor_flash node and could have some
>> +properties. Also see jedec,spi-nor.txt.
>> +
>> +Required properties:
>> +- reg: chip-Select number (QSPI controller may connect 2 nor flashes)
>> +- spi-max-frequency: max frequency of spi bus
>> +
>> +Optional property:
>> +- spi-rx-bus-width: the bus width (number of data wires)
> Just "see ../spi/spi-bus.txt" for the description
ok
>
>> +
>> +Example:
>> +
>> +qspi: qspi@a0001000 {
> spi@...
ok
>> + compatible = "st,stm32f469-qspi";
>> + reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
>> + reg-names = "qspi", "qspi_mm";
>> + interrupts = <91>;
>> + resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
>> + clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&pinctrl_qspi0>;
>> +
>> + flash@0 {
>> + reg = <0>;
>> + spi-rx-bus-width = <4>;
>> + spi-max-frequency = <108000000>;
>> + ...
>> + };
>> +};
>> --
>> 2.7.4
>>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/4] input: misc: introduce Atmel PTC driver
From: Ludovic Desroches @ 2017-04-04 6:47 UTC (permalink / raw)
To: Alexandre Belloni
Cc: devicetree, dmitry.torokhov, linux-kernel, Ludovic Desroches,
Ludovic Desroches, linux-input, linux-arm-kernel
In-Reply-To: <20170403155840.vln4wg56iunrmdcw@piout.net>
On Mon, Apr 03, 2017 at 05:58:40PM +0200, Alexandre Belloni wrote:
> On 31/03/2017 at 17:22:47 +0200, Ludovic Desroches wrote:
> > From: Ludovic Desroches <ludovic.desroches@atmel.com>
>
> I think you probably want to switch to your microchip email.
>
> Also, this requires a proper commit message.
I'll fix this, I'll take the cover letter as commit message and update
the mail address.
>
> >
> > Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
> > +struct atmel_ptc {
> > + void __iomem *ppp_regs;
> > + void __iomem *firmware;
> > + int irq;
> > + uint8_t imr;
> > + volatile struct atmel_qtm_mailbox __iomem *qtm_mb;
> > + struct clk *clk_per;
> > + struct clk *clk_int_osc;
> > + struct clk *clk_slow;
> > + struct device *dev;
> > + struct completion ppp_ack;
> > + unsigned int button_keycode[ATMEL_PTC_MAX_NODES];
> > + struct input_dev *buttons_input;
> > + struct input_dev *scroller_input[ATMEL_PTC_MAX_SCROLLERS];
> > + bool buttons_registered;
> > + bool scroller_registered[ATMEL_PTC_MAX_SCROLLERS];
> > + uint32_t button_event[ATMEL_PTC_MAX_NODES/32];
> > + uint32_t button_state[ATMEL_PTC_MAX_NODES/32];
> > + uint32_t scroller_event;
> > + uint32_t scroller_state;
>
> You should use u8, u16 and u32 instead of uint8_t, uint16_t and
> uint32_t.
Do you want me to also change the atmel_ptc.h header and use __u8 and co?
Since I share it with bare metal software, uintxx_t was more convenient.
>
> > diff --git a/include/uapi/linux/atmel_ptc.h b/include/uapi/linux/atmel_ptc.h
> > new file mode 100644
> > index 0000000..d15c4df
> > --- /dev/null
> > +++ b/include/uapi/linux/atmel_ptc.h
>
>
> Is there any sample application showing how to configure the PTC?
>
Tooling and examples are in development.
The tool allows you to produce the atmel_ptc.conf binary or to tweak the
configuration in real time with commands such as:
- set node_group_conf count 10
- get node_config 0
- dump_conf
- export_conf atmel_ptc.conf
The application only use input devices.
Ludovic
^ permalink raw reply
* [RESEND PATCH v4] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Quentin Schulz @ 2017-04-04 6:34 UTC (permalink / raw)
To: sre-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, wens-jdAy2FN1RRM,
linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
lee.jones-QSEj5FYQhm4dnm+yROfE0A, icenowy-ymACFijhrKM
Cc: Quentin Schulz, liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
battery voltage, battery charge and discharge currents, AC-in and VBUS
voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
This adds support for most of AXP20X and AXP22X ADCs.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
Reviewed-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Lee, could you merge this through the mfd tree please?
=> https://lkml.org/lkml/2017/3/22/47
v4:
- added missing space at the beginning of a comment,
- tidied axp20x_adc_offset_voltage and axp20x_write_raw to use switch case
instead of if conditions,
- added MODULE_DEVICE_TABLE for axp20x_adc_id_match for module autoloading,
- merged two lines in axp20x_remove,
v3:
- moved from switch to if condition in axp20x_adc_raw and
axp22x_adc_raw,
- removed DT support as DT node has been dropped,
- use of platform_device_id
- correctly defined the name of the iio device (name used to probe the
driver),
- added goto for errors in probe,
- added iio_map_array_unregister to the remove function,
v2:
- removed unused defines,
- changed BIT(x) to 1 << x when describing bits purpose for which 2 <<
x or 3 << x exists, to be consistent,
- changed ADC rate defines to macro formulas,
- reordered IIO channels, now different measures (current/voltage) of
the same part of the PMIC (e.g. battery), have the same IIO channel in
their respective IIO type. When a part of the PMIC have only one
measure, a number is jumped,
- left IIO channel mapping in DT to use iio_map structure,
- removed indexing of ADC internal temperature,
- removed unused iio_dev structure in axp20x_adc_iio,
- added a structure for data specific to AXP20X or AXP22X PMICs instead
of using an ID and an if condition when needing to separate the
behaviour of both,
- added a comment on batt_chrg_i really being on 12bits rather than
what the Chinese datasheets say (13 bits),
- corrected the offset for AXP22X PMIC temperature,
- set the ADC rate to a value (100Hz) shared by the AXP20X and AXP22X,
- created macro formulas to compute the ADC rate for each,
- added a condition on presence of ADC_EN2 reg before setting/resetting
it,
- switched from devm_iio_device_unregister to the non-devm function
because of the need for a remove function,
- removed some dead code,
drivers/iio/adc/Kconfig | 10 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/axp20x_adc.c | 617 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 628 insertions(+)
create mode 100644 drivers/iio/adc/axp20x_adc.c
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index d777a97..d15e1bd 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
To compile this driver as a module, choose M here: the module will be
called at91-sama5d2_adc.
+config AXP20X_ADC
+ tristate "X-Powers AXP20X and AXP22X ADC driver"
+ depends on MFD_AXP20X
+ help
+ Say yes here to have support for X-Powers power management IC (PMIC)
+ AXP20X and AXP22X ADC devices.
+
+ To compile this driver as a module, choose M here: the module will be
+ called axp20x_adc.
+
config AXP288_ADC
tristate "X-Powers AXP288 ADC driver"
depends on MFD_AXP20X
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index b11bb57..17899b5 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
+obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
new file mode 100644
index 0000000..11e1771
--- /dev/null
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -0,0 +1,617 @@
+/* ADC driver for AXP20X and AXP22X PMICs
+ *
+ * Copyright (c) 2016 Free Electrons NextThing Co.
+ * Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/machine.h>
+#include <linux/mfd/axp20x.h>
+
+#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
+
+#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
+#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
+
+#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
+#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
+#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0))
+#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
+
+#define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
+#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
+#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
+
+#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
+ { \
+ .type = _type, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .address = _reg, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = _name, \
+ }
+
+#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
+ { \
+ .type = _type, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .address = _reg, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) |\
+ BIT(IIO_CHAN_INFO_OFFSET),\
+ .datasheet_name = _name, \
+ }
+
+struct axp_data;
+
+struct axp20x_adc_iio {
+ struct regmap *regmap;
+ struct axp_data *data;
+};
+
+enum axp20x_adc_channel_v {
+ AXP20X_ACIN_V = 0,
+ AXP20X_VBUS_V,
+ AXP20X_TS_IN,
+ AXP20X_GPIO0_V,
+ AXP20X_GPIO1_V,
+ AXP20X_IPSOUT_V,
+ AXP20X_BATT_V,
+};
+
+enum axp20x_adc_channel_i {
+ AXP20X_ACIN_I = 0,
+ AXP20X_VBUS_I,
+ AXP20X_BATT_CHRG_I,
+ AXP20X_BATT_DISCHRG_I,
+};
+
+enum axp22x_adc_channel_v {
+ AXP22X_TS_IN = 0,
+ AXP22X_BATT_V,
+};
+
+enum axp22x_adc_channel_i {
+ AXP22X_BATT_CHRG_I = 1,
+ AXP22X_BATT_DISCHRG_I,
+};
+
+static struct iio_map axp20x_maps[] = {
+ {
+ .consumer_dev_name = "axp20x-usb-power-supply",
+ .consumer_channel = "vbus_v",
+ .adc_channel_label = "vbus_v",
+ }, {
+ .consumer_dev_name = "axp20x-usb-power-supply",
+ .consumer_channel = "vbus_i",
+ .adc_channel_label = "vbus_i",
+ }, {
+ .consumer_dev_name = "axp20x-ac-power-supply",
+ .consumer_channel = "acin_v",
+ .adc_channel_label = "acin_v",
+ }, {
+ .consumer_dev_name = "axp20x-ac-power-supply",
+ .consumer_channel = "acin_i",
+ .adc_channel_label = "acin_i",
+ }, {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_v",
+ .adc_channel_label = "batt_v",
+ }, {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_chrg_i",
+ .adc_channel_label = "batt_chrg_i",
+ }, {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_dischrg_i",
+ .adc_channel_label = "batt_dischrg_i",
+ }, { /* sentinel */ }
+};
+
+static struct iio_map axp22x_maps[] = {
+ {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_v",
+ .adc_channel_label = "batt_v",
+ }, {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_chrg_i",
+ .adc_channel_label = "batt_chrg_i",
+ }, {
+ .consumer_dev_name = "axp20x-battery-power-supply",
+ .consumer_channel = "batt_dischrg_i",
+ .adc_channel_label = "batt_dischrg_i",
+ }, { /* sentinel */ }
+};
+
+/*
+ * Channels are mapped by physical system. Their channels share the same index.
+ * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
+ * The only exception is for the battery. batt_v will be in_voltage6_raw and
+ * charge current in_current6_raw and discharge current will be in_current7_raw.
+ */
+static const struct iio_chan_spec axp20x_adc_channels[] = {
+ AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
+ AXP20X_ACIN_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
+ AXP20X_ACIN_I_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
+ AXP20X_VBUS_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
+ AXP20X_VBUS_I_ADC_H),
+ {
+ .type = IIO_TEMP,
+ .address = AXP20X_TEMP_ADC_H,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .datasheet_name = "pmic_temp",
+ },
+ AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+ AXP20X_GPIO0_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
+ AXP20X_GPIO1_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
+ AXP20X_IPSOUT_V_HIGH_H),
+ AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
+ AXP20X_BATT_V_H),
+ AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+ AXP20X_BATT_CHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+ AXP20X_BATT_DISCHRG_I_H),
+};
+
+static const struct iio_chan_spec axp22x_adc_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .address = AXP22X_PMIC_TEMP_H,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .datasheet_name = "pmic_temp",
+ },
+ AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
+ AXP20X_BATT_V_H),
+ AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+ AXP20X_BATT_CHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+ AXP20X_BATT_DISCHRG_I_H),
+};
+
+static int axp20x_adc_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int size = 12;
+
+ /*
+ * N.B.: Unlike the Chinese datasheets tell, the charging current is
+ * stored on 12 bits, not 13 bits. Only discharging current is on 13
+ * bits.
+ */
+ if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
+ size = 13;
+ else
+ size = 12;
+
+ *val = axp20x_read_variable_width(info->regmap, chan->address, size);
+ if (*val < 0)
+ return *val;
+
+ return IIO_VAL_INT;
+}
+
+static int axp22x_adc_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int size;
+
+ /*
+ * N.B.: Unlike the Chinese datasheets tell, the charging current is
+ * stored on 12 bits, not 13 bits. Only discharging current is on 13
+ * bits.
+ */
+ if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
+ size = 13;
+ else
+ size = 12;
+
+ *val = axp20x_read_variable_width(info->regmap, chan->address, size);
+ if (*val < 0)
+ return *val;
+
+ return IIO_VAL_INT;
+}
+
+static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case AXP20X_ACIN_V:
+ case AXP20X_VBUS_V:
+ *val = 1;
+ *val2 = 700000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP20X_GPIO0_V:
+ case AXP20X_GPIO1_V:
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP20X_BATT_V:
+ *val = 1;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP20X_IPSOUT_V:
+ *val = 1;
+ *val2 = 400000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp20x_adc_scale_current(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case AXP20X_ACIN_I:
+ *val = 0;
+ *val2 = 625000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP20X_VBUS_I:
+ *val = 0;
+ *val2 = 375000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP20X_BATT_DISCHRG_I:
+ case AXP20X_BATT_CHRG_I:
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
+ int *val2)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp20x_adc_scale_voltage(chan->channel, val, val2);
+
+ case IIO_CURRENT:
+ return axp20x_adc_scale_current(chan->channel, val, val2);
+
+ case IIO_TEMP:
+ *val = 100;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
+ int *val2)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ if (chan->channel != AXP22X_BATT_V)
+ return -EINVAL;
+
+ *val = 1;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_CURRENT:
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_TEMP:
+ *val = 100;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
+ int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
+ if (ret < 0)
+ return ret;
+
+ switch (channel) {
+ case AXP20X_GPIO0_V:
+ *val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
+ break;
+
+ case AXP20X_GPIO1_V:
+ *val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *val = !!(*val) * 700000;
+
+ return IIO_VAL_INT;
+}
+
+static int axp20x_adc_offset(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
+
+ case IIO_TEMP:
+ *val = -1447;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp20x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ return axp20x_adc_offset(indio_dev, chan, val);
+
+ case IIO_CHAN_INFO_SCALE:
+ return axp20x_adc_scale(chan, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ return axp20x_adc_raw(indio_dev, chan, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp22x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -2677;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ return axp22x_adc_scale(chan, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ return axp22x_adc_raw(indio_dev, chan, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axp20x_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int reg, regval;
+
+ /*
+ * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
+ * for (independently) GPIO0 and GPIO1 when in ADC mode.
+ */
+ if (mask != IIO_CHAN_INFO_OFFSET)
+ return -EINVAL;
+
+ if (val != 0 && val != 700000)
+ return -EINVAL;
+
+ switch (chan->channel) {
+ case AXP20X_GPIO0_V:
+ reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
+ regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
+ break;
+
+ case AXP20X_GPIO1_V:
+ reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
+ regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
+ regval);
+}
+
+static const struct iio_info axp20x_adc_iio_info = {
+ .read_raw = axp20x_read_raw,
+ .write_raw = axp20x_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct iio_info axp22x_adc_iio_info = {
+ .read_raw = axp22x_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int axp20x_adc_rate(int rate)
+{
+ return AXP20X_ADC_RATE_HZ(rate);
+}
+
+static int axp22x_adc_rate(int rate)
+{
+ return AXP22X_ADC_RATE_HZ(rate);
+}
+
+struct axp_data {
+ const struct iio_info *iio_info;
+ int num_channels;
+ struct iio_chan_spec const *channels;
+ unsigned long adc_en1_mask;
+ int (*adc_rate)(int rate);
+ bool adc_en2;
+ struct iio_map *maps;
+};
+
+static const struct axp_data axp20x_data = {
+ .iio_info = &axp20x_adc_iio_info,
+ .num_channels = ARRAY_SIZE(axp20x_adc_channels),
+ .channels = axp20x_adc_channels,
+ .adc_en1_mask = AXP20X_ADC_EN1_MASK,
+ .adc_rate = axp20x_adc_rate,
+ .adc_en2 = true,
+ .maps = axp20x_maps,
+};
+
+static const struct axp_data axp22x_data = {
+ .iio_info = &axp22x_adc_iio_info,
+ .num_channels = ARRAY_SIZE(axp22x_adc_channels),
+ .channels = axp22x_adc_channels,
+ .adc_en1_mask = AXP22X_ADC_EN1_MASK,
+ .adc_rate = axp22x_adc_rate,
+ .adc_en2 = false,
+ .maps = axp22x_maps,
+};
+
+static const struct platform_device_id axp20x_adc_id_match[] = {
+ { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
+ { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
+
+static int axp20x_probe(struct platform_device *pdev)
+{
+ struct axp20x_adc_iio *info;
+ struct iio_dev *indio_dev;
+ struct axp20x_dev *axp20x_dev;
+ int ret;
+
+ axp20x_dev = dev_get_drvdata(pdev->dev.parent);
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+ platform_set_drvdata(pdev, indio_dev);
+
+ info->regmap = axp20x_dev->regmap;
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
+
+ indio_dev->name = platform_get_device_id(pdev)->name;
+ indio_dev->info = info->data->iio_info;
+ indio_dev->num_channels = info->data->num_channels;
+ indio_dev->channels = info->data->channels;
+
+ /* Enable the ADCs on IP */
+ regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
+
+ if (info->data->adc_en2)
+ /* Enable GPIO0/1 and internal temperature ADCs */
+ regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
+ AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
+
+ /* Configure ADCs rate */
+ regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
+ info->data->adc_rate(100));
+
+ ret = iio_map_array_register(indio_dev, info->data->maps);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
+ goto fail_map;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not register the device\n");
+ goto fail_register;
+ }
+
+ return 0;
+
+fail_register:
+ iio_map_array_unregister(indio_dev);
+
+fail_map:
+ regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
+
+ if (info->data->adc_en2)
+ regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
+
+ return ret;
+}
+
+static int axp20x_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_map_array_unregister(indio_dev);
+
+ regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
+
+ if (info->data->adc_en2)
+ regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
+
+ return 0;
+}
+
+static struct platform_driver axp20x_adc_driver = {
+ .driver = {
+ .name = "axp20x-adc",
+ },
+ .id_table = axp20x_adc_id_match,
+ .probe = axp20x_probe,
+ .remove = axp20x_remove,
+};
+
+module_platform_driver(axp20x_adc_driver);
+
+MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
+MODULE_LICENSE("GPL");
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v2] clk: stm32h7: Add stm32h743 clock driver
From: Gabriel Fernandez @ 2017-04-04 6:33 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Rutland, devicetree@vger.kernel.org, Daniel Thompson,
Radosław Pietrzyk, Alexandre Torgue, Arnd Bergmann,
Nicolas Pitre, Andrea Merello, Michael Turquette, Olivier Bideau,
Stephen Boyd, Russell King, linux-kernel@vger.kernel.org,
Ludovic Barre, Maxime Coquelin, Amelie Delaunay, Lee Jones,
linux-clk, linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAL_JsqJYu+4puvB-WhaLVtjHASVOdY0acM2OxxMpZOvG9MAziQ@mail.gmail.com>
On 04/03/2017 06:04 PM, Rob Herring wrote:
> On Mon, Apr 3, 2017 at 9:39 AM, Rob Herring <robh@kernel.org> wrote:
>> On Wed, Mar 29, 2017 at 11:08:22AM +0200, gabriel.fernandez@st.com wrote:
>>> From: Gabriel Fernandez <gabriel.fernandez@st.com>
>>>
>>> This patch enables clocks for STM32H743 boards.
>>>
>>> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
>>>
>>> Just for the MFD changes:
>>> Acked-by: Lee Jones <lee.jones@linaro.org>
>>>
>>> +Required properties for pll node:
>>> +- compatible: Should be:
>>> + "stm32h7-pll"
>> stm,stm32h7-pll
> Err, I meant st,stm32h7-pll.
Oops, sorry i will fix it.
Thank's
Gabriel
>> With that,
>>
>> Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2] i2c/muxes/i2c-mux-ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Michael Hennerich @ 2017-04-04 6:32 UTC (permalink / raw)
To: Peter Rosin, 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: <dcc59f26-6dec-dbf1-22d9-b681daf788a2-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On 03.04.2017 16:20, Peter Rosin wrote:
> On 2017-04-03 15:36, Michael Hennerich wrote:
>> On 03.04.2017 14:03, Peter Rosin wrote:
>>> On 2017-03-31 17:29, Peter Rosin wrote:
>>>> Hi!
>>>>
>>>> Sorry for my incremental reviewing...
>>>>
>>>
>>> Another incremental...
>>>
>>>> On 2017-03-29 12:15, michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org wrote:
>>>>> +
>>>>> + /* 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) {
>>>>> + dev_err(&client->dev,
>>>>> + "failed to register multiplexed adapter %d\n",
>>>>> + num);
>>>
>>> Just a heads up, I submitted a series to remove a bunch of dev_err calls
>>> when i2c_mux_add_adapter fails. See https://lkml.org/lkml/2017/4/3/115
>>>
>>> You can remove this one as well.
>>>
>>> And please use a subject of the form:
>>> i2c: mux: ltc4306: <message>
>> ok - no problem.
>
> You managed to drop the spaces after the new colons in the subject.
>
> And maybe there is a problem, because I don't see any reaction to any of
> the review comments I made in https://lkml.org/lkml/2017/3/31/525
>
> Was that on purpose? Sure, the gpio "jury" is still out on the bigger
> question so maybe you're waiting for that, but there were a few nitpicks
> as well. Anyway, sorry again for failing to compile all comments up front.
Hi Peter,
sorry - this was not on purpose. I simply missed your second to last
incremental review. I fix the subject now finally.
Thanks for your patience.
>
>> I sent out a new patch. Per Rob's request, I split out the dt-bindings
>> into a separate patch.
>
> Thanks. I think(?) it is customary to have the bindings first, and then
> implement that "specification" in followup patches. No big deal though...
>
> Cheers,
> peda
>
>
--
Greetings,
Michael
--
Analog Devices GmbH Otl-Aicher Strasse 60-64 80807 München
Sitz der Gesellschaft München, Registergericht München HRB 40368,
Geschäftsführer: Peter Kolberg, Ali Raza Husain, Eileen Wynne
--
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 V3 0/5] iommu/arm-smmu: Add runtime pm/sleep support
From: Sricharan R @ 2017-04-04 5:15 UTC (permalink / raw)
To: Will Deacon, Rob Clark
Cc: Mark Rutland, devicetree@vger.kernel.org, Mathieu Poirier,
linux-arm-msm, Stephen Boyd, iommu@lists.linux-foundation.org,
Rob Herring, linux-clk, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20170403172307.GI5706@arm.com>
Hi Will,
On 4/3/2017 10:53 PM, Will Deacon wrote:
> On Fri, Mar 31, 2017 at 10:58:16PM -0400, Rob Clark wrote:
>> On Fri, Mar 31, 2017 at 1:54 PM, Will Deacon <will.deacon@arm.com> wrote:
>>> On Thu, Mar 09, 2017 at 09:05:43PM +0530, Sricharan R wrote:
>>>> This series provides the support for turning on the arm-smmu's
>>>> clocks/power domains using runtime pm. This is done using the
>>>> recently introduced device links patches, which lets the symmu's
>>>> runtime to follow the master's runtime pm, so the smmu remains
>>>> powered only when the masters use it.
>>>
>>> Do you have any numbers for the power savings you achieve with this?
>>> How often do we actually manage to stop the SMMU clocks on an SoC with
>>> a handful of masters?
>>>
>>> In other words, is this too coarse-grained to be useful, or is it common
>>> that all the devices upstream of the SMMU are suspended?
>>
>> well, if you think about a phone/tablet with a command mode panel,
>> pretty much all devices will be suspended most of the time ;-)
>
> Well, that's really what I was asking about. I assumed that periodic
> modem/radio transactions would keep the SMMU clocked, so would like to get a
> rough idea of the power savings achieved with this coarse-grained approach.
>
One main reason for introducing this was to enable power for
the iommus separately in those places where the iommu gets
accessed without the context of the master, pm runtime was
done to use the device links feature and also those iommus
had their power-domains to be enabled (during the iommu probe,
faults) (downstream was modelling those power-domains as
'regulators' which was not correct) and have to be clocked
as well.
I was in the process of trying to measure the power difference
that this would achieve. One concern here is, this series depends
on the device link between master and iommu.
So essentially the masters have to be pm runtime adapted fully
to use this. For my testing i was using couple of them (mdp, gpu),
by just enabling pm runtime for them, not full pm runtime though.
But i will come-up with the numbers by instrumenting little more.
The downstream code explicitly turns on the iommu clocks/regulators
in the standalone path (called without master context and after
that, lets the master to control the iommu clocks ( the iommu
clocks are populated in master DT data as well), so ensures iommu
is clocked only when really needed by the master. So number
measured from downstream should also give the power numbers in
another way.
Regards,
Sricharan
--
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a
member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* RE: Device Tree Binding for Intel FPGA Video and Image Processing Suite
From: Ong, Hean Loong @ 2017-04-04 3:57 UTC (permalink / raw)
To: Rob Herring; +Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_JsqJa6rdk=fxHVkHdjFrkBx-E6hGUfoZt2cAzaMvq2TJkNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Rob,
Apologies for the mistake. Below are the bindings
From 23a9e274bb517b8e232c5aa4cf9737de1644b708 Mon Sep 17 00:00:00 2001
From: Ong, Hean Loong <hean.loong.ong@intel.com>
Date: Thu, 30 Mar 2017 17:59:37 +0800
Subject: [PATCHv0] Intel FPGA Video and Image Processing Suite device tree binding
Device tree binding for Intel FPGA Video and Image
Processing Suite. The binding involved would be generated
from the Altera (Intel) Qsys system. The bindings would
set the max width, max height, buts per pixel and memory
port width. The device tree binding only supports the Intel
Arria10 devkit and its variants. Vendor name retained as
altr.
Signed-off-by: Ong, Hean Loong <hean.loong.ong@intel.com>
---
.../devicetree/bindings/gpu/altr,vip-fb2.txt | 24 ++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/gpu/altr,vip-fb2.txt
diff --git a/Documentation/devicetree/bindings/gpu/altr,vip-fb2.txt b/Documentation/devicetree/bindings/gpu/altr,vip-fb2.txt
new file mode 100644
index 0000000..9ba3209
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/altr,vip-fb2.txt
@@ -0,0 +1,24 @@
+Intel Video and Image Processing(VIP) Frame Buffer II bindings
+
+Supported hardware: Arria 10 and above with display port IP
+
+Required properties:
+- compatible: "altr,vip-frame-buffer-2.0"
+- reg: Physical base address and length of the framebuffer controller's
+ registers.
+- max-width: The width of the framebuffer in pixels.
+- max-height: The height of the framebuffer in pixels.
+- bits-per-symbol: only "8" is currently supported
+- mem-port-width = the bus width of the avalon master port on the frame reader
+
+Example:
+
+dp_0_frame_buf: vip@0x100000280 {
+ compatible = "altr,vip-frame-buffer-2.0";
+ reg = <0x00000001 0x00000280 0x00000040>;
+ altr,max-width = <1280>;
+ altr,max-height = <720>;
+ altr,bits-per-symbol = <8>;
+ altr,mem-port-width = <128>;
+};
+
--
1.7.1
^ permalink raw reply related
* Re: [PATCHv2] phy: cpcap-usb: Add CPCAP PMIC USB support
From: Tony Lindgren @ 2017-04-04 3:27 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Marcel Partap, Michael Scott
In-Reply-To: <3661b0cc-bf79-0347-ae4c-db6bdfdf6293-l0cyMroinI0@public.gmane.org>
Hi,
* Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org> [170330 04:51]:
> On Monday 27 March 2017 08:35 PM, Tony Lindgren wrote:
> > Seems this can be also done when implementing PM runtime handling.
> > If you want some of these changes done for the initial patch,
> > please let me know.
>
> I think it's better we get extcon stuff in the initial patch so that we don't
> have to maintain some piece of code for legacy dt. Others can be added later.
Sure, I'll take a look at that hopefully this week at some
point.
Regards,
Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] ARM: dts: omap4-droid4: Fix interrupt triggering for cpcap
From: Tony Lindgren @ 2017-04-04 3:25 UTC (permalink / raw)
To: linux-omap-u79uwXL29TY76Z2rM5mHXA
Cc: Benoît Cousson, devicetree-u79uwXL29TY76Z2rM5mHXA,
Charles Keepax, Marcel Partap, Michael Scott, Sebastian Reichel
The CPCAP PMIC interrupt is level high sensitive despite it being
requested as edge high triggered in the Motorola Linux kernel.
Note that also the related driver change is needed posted as
"mfd: cpcap: Fix interrupt to use level interrupt".
Fixes: 56e1d40d3bea ("mfd: cpcap: Add minimal support")
Cc: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Cc: Marcel Partap <mpartap-hi6Y0CQ0nG0@public.gmane.org>
Cc: Michael Scott <michael.scott-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
---
arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -11,7 +11,7 @@
compatible = "motorola,cpcap", "st,6556002";
reg = <0>; /* cs0 */
interrupt-parent = <&gpio1>;
- interrupts = <7 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
--
2.12.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v5 5/5] ARM: keystone: Drop PM domain support for k2g
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: Nishanth Menon, devicetree, Dave Gerlach, Lokesh Vutla, Keerthy,
linux-pm, linux-kernel, Tero Kristo, Russell King, Sudeep Holla,
Olof Johansson, linux-arm-kernel
In-Reply-To: <20170404024732.32699-1-d-gerlach@ti.com>
K2G will use a different power domain driver than the rest of the
keystone family in order to make use of the TI SCI protocol so prevent
the standard keystone pm_domain code from registering itself in
preparation for a new driver.
Acked-by: Santosh Shilimkar <ssantosh@kernel.org>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
arch/arm/mach-keystone/pm_domain.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c
index 8cbb35765a19..fe57e2692629 100644
--- a/arch/arm/mach-keystone/pm_domain.c
+++ b/arch/arm/mach-keystone/pm_domain.c
@@ -32,7 +32,9 @@ static struct pm_clk_notifier_block platform_domain_notifier = {
};
static const struct of_device_id of_keystone_table[] = {
- {.compatible = "ti,keystone"},
+ {.compatible = "ti,k2hk"},
+ {.compatible = "ti,k2e"},
+ {.compatible = "ti,k2l"},
{ /* end of list */ },
};
--
2.11.0
^ permalink raw reply related
* [PATCH v5 4/5] soc: ti: Add ti_sci_pm_domains driver
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-pm, devicetree,
Nishanth Menon, Dave Gerlach, Keerthy, Russell King, Tero Kristo,
Sudeep Holla, Olof Johansson
In-Reply-To: <20170404024732.32699-1-d-gerlach@ti.com>
Introduce a ti_sci_pm_domains driver to act as a generic pm domain
provider to allow each device to attach and associate it's ti-sci-id so
that it can be controlled through the TI SCI protocol.
This driver implements a simple genpd where each device node has a
phandle to the power domain node and also must provide an index which
represents the ID to be passed with TI SCI representing the device using
a single phandle cell. The driver manually parses the phandle to get the
cell value. Through this interface the genpd dev_ops start and stop
hooks will use TI SCI to turn on and off each device as determined by
pm_runtime usage.
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Acked-by: Santosh Shilimkar <ssantosh@kernel.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
MAINTAINERS | 1 +
arch/arm/mach-keystone/Kconfig | 1 +
drivers/soc/ti/Kconfig | 12 +++
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_pm_domains.c | 202 +++++++++++++++++++++++++++++++++++++
5 files changed, 217 insertions(+)
create mode 100644 drivers/soc/ti/ti_sci_pm_domains.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ae43f3e95b47..ca8026c39fc8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12384,6 +12384,7 @@ F: drivers/firmware/ti_sci*
F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h
+F: drivers/soc/ti/ti_sci_pm_domains.c
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 554357035f30..db122356b410 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -10,6 +10,7 @@ config ARCH_KEYSTONE
select ARCH_SUPPORTS_BIG_ENDIAN
select ZONE_DMA if ARM_LPAE
select PINCTRL
+ select PM_GENERIC_DOMAINS if PM
help
Support for boards based on the Texas Instruments Keystone family of
SoCs.
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 3557c5e32a93..39e152abe6b9 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -38,4 +38,16 @@ config WKUP_M3_IPC
to communicate and use the Wakeup M3 for PM features like suspend
resume and boots it using wkup_m3_rproc driver.
+config TI_SCI_PM_DOMAINS
+ tristate "TI SCI PM Domains Driver"
+ depends on TI_SCI_PROTOCOL
+ depends on PM_GENERIC_DOMAINS
+ help
+ Generic power domain implementation for TI device implementing
+ the TI SCI protocol.
+
+ To compile this as a module, choose M here. The module will be
+ called ti_sci_pm_domains. Note this is needed early in boot before
+ rootfs may be available.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 48ff3a79634f..7d572736c86e 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
+obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
new file mode 100644
index 000000000000..b0b283810e72
--- /dev/null
+++ b/drivers/soc/ti/ti_sci_pm_domains.c
@@ -0,0 +1,202 @@
+/*
+ * TI SCI Generic Power Domain Driver
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ * Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+/**
+ * struct ti_sci_genpd_dev_data: holds data needed for every device attached
+ * to this genpd
+ * @idx: index of the device that identifies it with the system
+ * control processor.
+ */
+struct ti_sci_genpd_dev_data {
+ int idx;
+};
+
+/**
+ * struct ti_sci_pm_domain: TI specific data needed for power domain
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ * communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd: generic_pm_domain for use with the genpd framework
+ */
+struct ti_sci_pm_domain {
+ const struct ti_sci_handle *ti_sci;
+ struct device *dev;
+ struct generic_pm_domain pd;
+};
+
+#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
+
+/**
+ * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
+ * @dev: pointer to device associated with this genpd
+ *
+ * Returns device_id stored from ti,sci_id property
+ */
+static int ti_sci_dev_id(struct device *dev)
+{
+ struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
+ struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
+
+ return sci_dev_data->idx;
+}
+
+/**
+ * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
+ * @dev: pointer to device associated with this genpd
+ *
+ * Returns ti_sci_handle to be used to communicate with system
+ * control processor.
+ */
+static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
+{
+ struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
+ struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
+
+ return ti_sci_genpd->ti_sci;
+}
+
+/**
+ * ti_sci_dev_start(): genpd device start hook called to turn device on
+ * @dev: pointer to device associated with this genpd to be powered on
+ */
+static int ti_sci_dev_start(struct device *dev)
+{
+ const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
+ int idx = ti_sci_dev_id(dev);
+
+ return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
+}
+
+/**
+ * ti_sci_dev_stop(): genpd device stop hook called to turn device off
+ * @dev: pointer to device associated with this genpd to be powered off
+ */
+static int ti_sci_dev_stop(struct device *dev)
+{
+ const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
+ int idx = ti_sci_dev_id(dev);
+
+ return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
+}
+
+static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args pd_args;
+ struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
+ struct ti_sci_genpd_dev_data *sci_dev_data;
+ struct generic_pm_domain_data *genpd_data;
+ int idx, ret = 0;
+
+ ret = of_parse_phandle_with_args(np, "power-domains",
+ "#power-domain-cells", 0, &pd_args);
+ if (ret < 0)
+ return ret;
+
+ if (pd_args.args_count != 1)
+ return -EINVAL;
+
+ idx = pd_args.args[0];
+
+ /*
+ * Check the validity of the requested idx, if the index is not valid
+ * the PMMC will return a NAK here and we will not allocate it.
+ */
+ ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
+ if (ret)
+ return -EINVAL;
+
+ sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
+ if (!sci_dev_data)
+ return -ENOMEM;
+
+ sci_dev_data->idx = idx;
+
+ genpd_data = dev_gpd_data(dev);
+ genpd_data->data = sci_dev_data;
+
+ return 0;
+}
+
+static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
+ struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
+
+ kfree(sci_dev_data);
+ genpd_data->data = NULL;
+}
+
+static const struct of_device_id ti_sci_pm_domain_matches[] = {
+ { .compatible = "ti,sci-pm-domain", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
+
+static int ti_sci_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ti_sci_pm_domain *ti_sci_pd;
+ int ret;
+
+ ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
+ if (!ti_sci_pd)
+ return -ENOMEM;
+
+ ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(ti_sci_pd->ti_sci))
+ return PTR_ERR(ti_sci_pd->ti_sci);
+
+ ti_sci_pd->dev = dev;
+
+ ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
+ ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
+
+ ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
+ ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
+
+ pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+
+ ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
+
+ return ret;
+}
+
+static struct platform_driver ti_sci_pm_domains_driver = {
+ .probe = ti_sci_pm_domain_probe,
+ .driver = {
+ .name = "ti_sci_pm_domains",
+ .of_match_table = ti_sci_pm_domain_matches,
+ },
+};
+module_platform_driver(ti_sci_pm_domains_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI System Control Interface (SCI) Power Domain driver");
+MODULE_AUTHOR("Dave Gerlach");
--
2.11.0
^ permalink raw reply related
* [PATCH v5 3/5] dt-bindings: Add TI SCI PM Domains
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: Nishanth Menon, devicetree, Dave Gerlach, Keerthy, linux-pm,
linux-kernel, Tero Kristo, Russell King, Sudeep Holla,
Olof Johansson, linux-arm-kernel
In-Reply-To: <20170404024732.32699-1-d-gerlach@ti.com>
Add a generic power domain implementation, TI SCI PM Domains, that
will hook into the genpd framework and allow the TI SCI protocol to
control device power states.
Also, provide macros representing each device index as understood
by TI SCI to be used in the device node power-domain references.
These are identifiers for the K2G devices managed by the PMMC.
Acked-by: Santosh Shilimkar <ssantosh@kernel.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
v4->v5: Drop last sentence of first paragraph to avoid describing Linux
driver behavior in dt binding doc.
.../devicetree/bindings/soc/ti/sci-pm-domain.txt | 57 ++++++++++++++
MAINTAINERS | 2 +
include/dt-bindings/genpd/k2g.h | 90 ++++++++++++++++++++++
3 files changed, 149 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
create mode 100644 include/dt-bindings/genpd/k2g.h
diff --git a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
new file mode 100644
index 000000000000..c705db07d820
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
@@ -0,0 +1,57 @@
+Texas Instruments TI-SCI Generic Power Domain
+---------------------------------------------
+
+Some TI SoCs contain a system controller (like the PMMC, etc...) that is
+responsible for controlling the state of the IPs that are present.
+Communication between the host processor running an OS and the system
+controller happens through a protocol known as TI-SCI [1].
+
+[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
+
+PM Domain Node
+==============
+The PM domain node represents the global PM domain managed by the PMMC, which
+in this case is the implementation as documented by the generic PM domain
+bindings in Documentation/devicetree/bindings/power/power_domain.txt. Because
+this relies on the TI SCI protocol to communicate with the PMMC it must be a
+child of the pmmc node.
+
+Required Properties:
+--------------------
+- compatible: should be "ti,sci-pm-domain"
+- #power-domain-cells: Must be 1 so that an id can be provided in each
+ device node.
+
+Example (K2G):
+-------------
+ pmmc: pmmc {
+ compatible = "ti,k2g-sci";
+ ...
+
+ k2g_pds: power-controller {
+ compatible = "ti,sci-pm-domain";
+ #power-domain-cells = <1>;
+ };
+ };
+
+PM Domain Consumers
+===================
+Hardware blocks belonging to a PM domain should contain a "power-domains"
+property that is a phandle pointing to the corresponding PM domain node
+along with an index representing the device id to be passed to the PMMC
+for device control.
+
+Required Properties:
+--------------------
+- power-domains: phandle pointing to the corresponding PM domain node
+ and an ID representing the device.
+
+See dt-bindings/genpd/k2g.h for the list of valid identifiers for k2g.
+
+Example (K2G):
+--------------------
+ uart0: serial@02530c00 {
+ compatible = "ns16550a";
+ ...
+ power-domains = <&k2g_pds K2G_DEV_UART0>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 1b0a87ffffab..ae43f3e95b47 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12382,6 +12382,8 @@ S: Maintained
F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
F: drivers/firmware/ti_sci*
F: include/linux/soc/ti/ti_sci_protocol.h
+F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
+F: include/dt-bindings/genpd/k2g.h
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/include/dt-bindings/genpd/k2g.h b/include/dt-bindings/genpd/k2g.h
new file mode 100644
index 000000000000..1f31f17e19eb
--- /dev/null
+++ b/include/dt-bindings/genpd/k2g.h
@@ -0,0 +1,90 @@
+/*
+ * TI K2G SoC Device definitions
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_GENPD_K2G_H
+#define _DT_BINDINGS_GENPD_K2G_H
+
+/* Documented in http://processors.wiki.ti.com/index.php/TISCI */
+
+#define K2G_DEV_PMMC0 0x0000
+#define K2G_DEV_MLB0 0x0001
+#define K2G_DEV_DSS0 0x0002
+#define K2G_DEV_MCBSP0 0x0003
+#define K2G_DEV_MCASP0 0x0004
+#define K2G_DEV_MCASP1 0x0005
+#define K2G_DEV_MCASP2 0x0006
+#define K2G_DEV_DCAN0 0x0008
+#define K2G_DEV_DCAN1 0x0009
+#define K2G_DEV_EMIF0 0x000a
+#define K2G_DEV_MMCHS0 0x000b
+#define K2G_DEV_MMCHS1 0x000c
+#define K2G_DEV_GPMC0 0x000d
+#define K2G_DEV_ELM0 0x000e
+#define K2G_DEV_SPI0 0x0010
+#define K2G_DEV_SPI1 0x0011
+#define K2G_DEV_SPI2 0x0012
+#define K2G_DEV_SPI3 0x0013
+#define K2G_DEV_ICSS0 0x0014
+#define K2G_DEV_ICSS1 0x0015
+#define K2G_DEV_USB0 0x0016
+#define K2G_DEV_USB1 0x0017
+#define K2G_DEV_NSS0 0x0018
+#define K2G_DEV_PCIE0 0x0019
+#define K2G_DEV_GPIO0 0x001b
+#define K2G_DEV_GPIO1 0x001c
+#define K2G_DEV_TIMER64_0 0x001d
+#define K2G_DEV_TIMER64_1 0x001e
+#define K2G_DEV_TIMER64_2 0x001f
+#define K2G_DEV_TIMER64_3 0x0020
+#define K2G_DEV_TIMER64_4 0x0021
+#define K2G_DEV_TIMER64_5 0x0022
+#define K2G_DEV_TIMER64_6 0x0023
+#define K2G_DEV_MSGMGR0 0x0025
+#define K2G_DEV_BOOTCFG0 0x0026
+#define K2G_DEV_ARM_BOOTROM0 0x0027
+#define K2G_DEV_DSP_BOOTROM0 0x0029
+#define K2G_DEV_DEBUGSS0 0x002b
+#define K2G_DEV_UART0 0x002c
+#define K2G_DEV_UART1 0x002d
+#define K2G_DEV_UART2 0x002e
+#define K2G_DEV_EHRPWM0 0x002f
+#define K2G_DEV_EHRPWM1 0x0030
+#define K2G_DEV_EHRPWM2 0x0031
+#define K2G_DEV_EHRPWM3 0x0032
+#define K2G_DEV_EHRPWM4 0x0033
+#define K2G_DEV_EHRPWM5 0x0034
+#define K2G_DEV_EQEP0 0x0035
+#define K2G_DEV_EQEP1 0x0036
+#define K2G_DEV_EQEP2 0x0037
+#define K2G_DEV_ECAP0 0x0038
+#define K2G_DEV_ECAP1 0x0039
+#define K2G_DEV_I2C0 0x003a
+#define K2G_DEV_I2C1 0x003b
+#define K2G_DEV_I2C2 0x003c
+#define K2G_DEV_EDMA0 0x003f
+#define K2G_DEV_SEMAPHORE0 0x0040
+#define K2G_DEV_INTC0 0x0041
+#define K2G_DEV_GIC0 0x0042
+#define K2G_DEV_QSPI0 0x0043
+#define K2G_DEV_ARM_64B_COUNTER0 0x0044
+#define K2G_DEV_TETRIS0 0x0045
+#define K2G_DEV_CGEM0 0x0046
+#define K2G_DEV_MSMC0 0x0047
+#define K2G_DEV_CBASS0 0x0049
+#define K2G_DEV_BOARD0 0x004c
+#define K2G_DEV_EDMA1 0x004f
+
+#endif
--
2.11.0
^ permalink raw reply related
* [PATCH v5 2/5] PM / Domains: Do not check if simple providers have phandle cells
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-pm, devicetree,
Nishanth Menon, Dave Gerlach, Keerthy, Russell King, Tero Kristo,
Sudeep Holla, Olof Johansson
In-Reply-To: <20170404024732.32699-1-d-gerlach@ti.com>
There is no reason that a platform genpd driver registered using
of_genpd_add_provider_simple needs to be constrained to having no cells
in the "power-domains" phandle. Currently the genpd framework will fail
if any arguments are passed with for a simple provider but the framework
does not actually care, so remove the check for phandle argument count.
This will allow greater flexibility for genpd providers to use their own
arguments that are passed in the phandle and interpret them however they
see fit.
Acked-by: Kevin Hilman <khilman@baylibre.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
drivers/base/power/domain.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e697dec9d25b..8e0550c27394 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1622,8 +1622,6 @@ static struct generic_pm_domain *genpd_xlate_simple(
struct of_phandle_args *genpdspec,
void *data)
{
- if (genpdspec->args_count != 0)
- return ERR_PTR(-EINVAL);
return data;
}
--
2.11.0
^ permalink raw reply related
* [PATCH v5 1/5] PM / Domains: Add generic data pointer to genpd data struct
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: Nishanth Menon, devicetree, Dave Gerlach, Keerthy, linux-pm,
linux-kernel, Tero Kristo, Russell King, Sudeep Holla,
Olof Johansson, linux-arm-kernel
In-Reply-To: <20170404024732.32699-1-d-gerlach@ti.com>
Add a void *data pointer to struct generic_pm_domain_data. Because this
exists for each device associated with a genpd it will allow us to
assign per-device data if needed on a platform for control of that
specific device.
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
include/linux/pm_domain.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 5339ed5bd6f9..b213d22daefd 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -117,6 +117,7 @@ struct generic_pm_domain_data {
struct pm_domain_data base;
struct gpd_timing_data td;
struct notifier_block nb;
+ void *data;
};
#ifdef CONFIG_PM_GENERIC_DOMAINS
--
2.11.0
^ permalink raw reply related
* [PATCH v5 0/5] ARM: K2G: Add support for TI-SCI Generic PM Domains
From: Dave Gerlach @ 2017-04-04 2:47 UTC (permalink / raw)
To: Ulf Hansson, Rafael J . Wysocki, Kevin Hilman, Santosh Shilimkar,
Rob Herring, Arnd Bergmann
Cc: Nishanth Menon, devicetree, Dave Gerlach, Keerthy, linux-pm,
linux-kernel, Tero Kristo, Russell King, Sudeep Holla,
Olof Johansson, linux-arm-kernel
Hi,
This is v5 of the series to add support for TI-SCI Generic PM Domains with
all ACKs in place and ready for Santosh to merge.
Previous versions can be found here:
v4: https://www.spinics.net/lists/arm-kernel/msg566778.html
v3: https://www.spinics.net/lists/kernel/msg2413975.html
v2: https://www.spinics.net/lists/kernel/msg2364612.html
v1: http://www.spinics.net/lists/arm-kernel/msg525204.html
Mostly just a resend of v4 with all ACKs and Reviewed-by tags in place with
the exception of a dropped sentence in patch 3 to avoid referencing Linux
specific behavior in the DT binding doc. Otherwise everything else is
unmodified.
Ulf and Santosh, I kept your Reviewed-by and Acked-by tags in Patch 3 because
the change was so minor and I still wanted to give you credit for taking the
time to review the patch, any issues and I'd be happy to change that.
Regards,
Dave
Dave Gerlach (5):
PM / Domains: Add generic data pointer to genpd data struct
PM / Domains: Do not check if simple providers have phandle cells
dt-bindings: Add TI SCI PM Domains
soc: ti: Add ti_sci_pm_domains driver
ARM: keystone: Drop PM domain support for k2g
.../devicetree/bindings/soc/ti/sci-pm-domain.txt | 57 ++++++
MAINTAINERS | 3 +
arch/arm/mach-keystone/Kconfig | 1 +
arch/arm/mach-keystone/pm_domain.c | 4 +-
drivers/base/power/domain.c | 2 -
drivers/soc/ti/Kconfig | 12 ++
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_pm_domains.c | 202 +++++++++++++++++++++
include/dt-bindings/genpd/k2g.h | 90 +++++++++
include/linux/pm_domain.h | 1 +
10 files changed, 370 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
create mode 100644 drivers/soc/ti/ti_sci_pm_domains.c
create mode 100644 include/dt-bindings/genpd/k2g.h
--
2.11.0
^ permalink raw reply
* [PATCH] arm64: dts: uniphier: add cdns, phy-dll-delay-sdclk(-hsmmc) for eMMC
From: Masahiro Yamada @ 2017-04-04 2:04 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Mark Rutland, devicetree, Catalin Marinas, Will Deacon,
linux-kernel, Masahiro Yamada, Rob Herring
Adjust the PHY parameters for more stable access to the eMMC device.
Set the SDCLK output delay value to 21 (including HS200/400 modes).
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi | 2 ++
arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
index 42f1803..25a525c 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
@@ -313,6 +313,8 @@
cdns,phy-input-delay-legacy = <4>;
cdns,phy-input-delay-mmc-highspeed = <2>;
cdns,phy-input-delay-mmc-ddr = <3>;
+ cdns,phy-dll-delay-sdclk = <21>;
+ cdns,phy-dll-delay-sdclk-hsmmc = <21>;
};
usb0: usb@5a800100 {
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
index e4499ff..c85e6e2 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
@@ -387,6 +387,8 @@
cdns,phy-input-delay-legacy = <4>;
cdns,phy-input-delay-mmc-highspeed = <2>;
cdns,phy-input-delay-mmc-ddr = <3>;
+ cdns,phy-dll-delay-sdclk = <21>;
+ cdns,phy-dll-delay-sdclk-hsmmc = <21>;
};
soc-glue@5f800000 {
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2 1/5] dt-bindings: gpu: add bindings for the ARM Mali Midgard GPU
From: Rob Herring @ 2017-04-04 2:00 UTC (permalink / raw)
To: Guillaume Tucker
Cc: Mark Rutland, Sjoerd Simons, Enric Balletbo i Serra, John Reitan,
Wookey, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <db45d0d68957d699f13a0d92f4f84d8ebfd0270e.1491118230.git.guillaume.tucker-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
On Sun, Apr 02, 2017 at 08:59:44AM +0100, Guillaume Tucker wrote:
> The ARM Mali Midgard GPU family is present in a number of SoCs
> from many different vendors such as Samsung Exynos and Rockchip.
>
> Import the device tree bindings documentation from the r16p0
> release of the Mali Midgard GPU kernel driver:
>
> https://developer.arm.com/-/media/Files/downloads/mali-drivers/kernel/mali-midgard-gpu/TX011-SW-99002-r16p0-00rel0.tgz
>
> The following optional bindings have been omitted in this initial
> version as they are only used in very specific cases:
>
> * snoop_enable_smc
> * snoop_disable_smc
> * jm_config
> * power_model
> * system-coherency
> * ipa-model
>
> The example has been simplified accordingly.
>
> The compatible string definition has been limited to
> "arm,mali-midgard" to avoid checkpatch.pl warnings and to match
> what the driver actually expects (as of r16p0 out-of-tree).
>
> CC: John Reitan <john.reitan-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Guillaume Tucker <guillaume.tucker-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> ---
> .../devicetree/bindings/gpu/arm,mali-midgard.txt | 53 ++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
>
> diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
> new file mode 100644
> index 000000000000..da8fc6d21bbf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
> @@ -0,0 +1,53 @@
> +#
> +# (C) COPYRIGHT 2013-2016 ARM Limited.
> +# Copyright (C) 2017 Collabora Ltd
> +#
> +# This program is free software and is provided to you under the terms of the
> +# GNU General Public License version 2 as published by the Free Software
> +# Foundation, and any use by you of this program is subject to the terms
> +# of such GNU licence.
> +#
> +
> +
> +ARM Mali Midgard GPU
> +====================
> +
> +Required properties:
> +
> +- compatible : Should be "arm,mali-midgard".
As Neil said...
> +- reg : Physical base address of the device and length of the register area.
> +- interrupts : Contains the three IRQ lines required by Mali Midgard devices.
> +- interrupt-names : Contains the names of IRQ resources in the order they were
> + provided in the interrupts property. Must contain: "JOB, "MMU", "GPU".
> +
> +Optional:
> +
> +- clocks : Phandle to clock for the Mali Midgard device.
> +- clock-names : Shall be "clk_mali".
"clk_" is redundant. Actually, if there is only 1 clock, then just drop
names. But there's not at least a core and bus clock?
> +- mali-supply : Phandle to regulator for the Mali device. Refer to
> + Documentation/devicetree/bindings/regulator/regulator.txt for details.
> +- operating-points : Refer to Documentation/devicetree/bindings/power/opp.txt
> + for details.
Is this going to be sufficient vs. operating-points-v2? Or should it be
a power domain with OPPs?
> +
> +Example for a Mali-T602:
> +
> +gpu@0xfc010000 {
Drop the '0x'.
> + compatible = "arm,mali-midgard";
> + reg = <0xfc010000 0x4000>;
> + interrupts = <0 36 4>, <0 37 4>, <0 38 4>;
> + interrupt-names = "JOB", "MMU", "GPU";
> +
> + clocks = <&pclk_mali>;
> + clock-names = "clk_mali";
> + mali-supply = <&vdd_mali>;
> + operating-points = <
> + /* KHz uV */
> + 533000 1250000,
> + 450000 1150000,
> + 400000 1125000,
> + 350000 1075000,
> + 266000 1025000,
> + 160000 925000,
> + 100000 912500,
> + >;
> +};
> --
> 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
* Re: [RFC PATCH 4/5] dt-bindings: soc/fsl: Update reserved memory binding for QBMan
From: Scott Wood @ 2017-04-04 0:32 UTC (permalink / raw)
To: Roy Pledge, Rob Herring
Cc: robin.murphy-5wv7dgnIgG8@public.gmane.org,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Madalin-Cristian Bucur
In-Reply-To: <VI1PR04MB32166AA6361CD6F24DBC3AAF86080-mr6QIVyDiCHPlBEOArXH089NdZoXdze2vxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
On Mon, 2017-04-03 at 19:49 +0000, Roy Pledge wrote:
> On 4/3/2017 11:42 AM, Rob Herring wrote:
> >
> > On Wed, Mar 29, 2017 at 05:13:56PM -0400, Roy Pledge wrote:
> > >
> > > Updates the QMan and BMan device tree bindings for reserved memory
> > > nodes. This makes the reserved memory allocation compatiable with
> > s/compatiable/compatible/
> >
> > >
> > > the shared-dma-pool usage.
> > This change is not backwards compatible. Please state that and explain
> > why that is okay. If PPC needs to not change, then the old strings and
> > properties should remain, but deprecated.
> I think I can make the old device trees compatible since the
> "compatible" string changed without too much effort or ifdefery in the
> code. However I would like to eventually see all PPC users move to the
> new mode as I do believe it is more in alignment with the spirit of the
> reserved-memory framework that is in the kernel.
How much benefit is there to changing PPC if you have to retain the old method
anyway for compatibility? Whereas if you don't convert, you retain test
coverage for the old device trees, and don't have to worry about
the memblock_end_of_DRAM() questions.
> Do I need to mention the old mode in the binding.txt file?
Yes.
> I'm trying to keep things clean
> so someone reading the binding doesn't get a headache and trying to
> preserve my own sanity as we move forward with adding new features to
> this driver.
If they're sufficiently different then just describe the new and old nodes
separately rather than putting a bunch of if/else clauses in there.
-Scott
--
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: [RFC PATCH 2/5] soc/fsl/qbman: Use shared-dma-pool for QMan private memory allocations
From: Scott Wood @ 2017-04-04 0:24 UTC (permalink / raw)
To: Robin Murphy, Michael Ellerman, roy.pledge-3arQi8VN3Tc,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: Mark Rutland, madalin.bucur-3arQi8VN3Tc
In-Reply-To: <df00c0ab-22b8-1086-def1-69baf648df72-5wv7dgnIgG8@public.gmane.org>
On Mon, 2017-04-03 at 15:52 +0100, Robin Murphy wrote:
> On 01/04/17 08:25, Scott Wood wrote:
> >
> > On Fri, 2017-03-31 at 18:55 +0100, Robin Murphy wrote:
> > >
> > > On 31/03/17 04:27, Michael Ellerman wrote:
> > > >
> > > >
> > > > Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org> writes:
> > > >
> > > > >
> > > > >
> > > > > Hi Roy,
> > > > >
> > > > > On 29/03/17 22:13, Roy Pledge wrote:
> > > > > >
> > > > > >
> > > > > > Use the shared-memory-pool mechanism for frame queue descriptor
> > > > > > and
> > > > > > packed frame descriptor record area allocations.
> > > > > Thanks for persevering with this - in my opinion it's now looking
> > > > > like
> > > > > it was worth the effort :)
> > > > >
> > > > > AFAICS the ioremap_wc() that this leads to does appear to give back
> > > > > something non-cacheable on PPC (assuming "pgprot_noncached_wc" isn't
> > > > > horrendously misnamed), and "no-map" should rule out any cacheable
> > > > > linear map alias existing, so it would seem that this approach
> > > > > should
> > > > > avert Scott's concerns about attribute mismatches.
> > > > How does 'no-map' translate into something being excluded from the
> > > > linear mapping?
> > > Reserved regions marked with "no-map" get memblock_remove()d by
> > > early_init_dt_alloc_reserved_memory_arch(). As I understand things, the
> > > linear map should only cover memblock areas, and it would be explicitly
> > > violating the semantics of "no-map" to still cover such a region.
> > Discontiguous memory isn't supported on these PPC chips. Everything up to
> > memblock_end_of_DRAM() gets mapped -- and if that were to change, the
> > fragmentation would waste TLB1 entries.
> Ah, so the "PPC-specific angles I'm not aware of" category is indeed
> non-empty - I guess the lack of HAVE_GENERIC_DMA_COHERENT might be
> related, then.
>
> That said, though, AFAICS only certain x86 and s390 configurations ever
> call memblock_set_bottom_up(true), so we should be able to assume that
> the reserved region allocations always fall through to
> __memblock_find_range_top_down(). Thus if your DRAM is contiguous, then
> "no-map"-ing the reserved regions will simply end up pushing
> memblock_end_of_DRAM() down in a manner that would appear to still avoid
> overlaps.
Can you guarantee it will be at the end? What if there were other early
memblock allocations (e.g. other reserved-memory regions without no-map) that
came first?
> I can only see that going wrong if the end of DRAM wasn't at
> least 32MB aligned to begin with - is that ever likely to happen in
> practice?
Probably not, unless the user asks for an unusual memory size via mem= or
similar.
-Scott
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH linux v6 2/2] drivers: hwmon: Support for ASPEED PWM/Fan tach
From: Jaghathiswari Rankappagounder Natarajan @ 2017-04-03 23:30 UTC (permalink / raw)
To: joel, jdelvare, linux, linux-hwmon, linux-kernel, openbmc, corbet,
linux-doc, robh+dt, mark.rutland, devicetree
Cc: Jaghathiswari Rankappagounder Natarajan
In-Reply-To: <20170403233025.26952-1-jaghu@google.com>
The ASPEED AST2400/2500 PWM controller supports 8 PWM output ports.
The ASPEED AST2400/2500 Fan tach controller supports 16 tachometer
inputs.
The device driver matches on the device tree node. The configuration
values are read from the device tree and written to the respective registers.
The driver provides a sysfs entries through which the user can
configure the duty-cycle value (ranging from 0 to 100 percent) and read
the fan tach rpm value.
Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
---
v6
- Corrected odd line breaks
- Changed upto to up to
- Dropped unrelated changes
- Removed struct and used regs pointer directly
- Made groups to be null terminated
- Made correction in calculation of val/raw_data
- Removed else after return
- Removed unnecessary continuation lines
v5:
- Changed the driver to suit the changes in the device tree documentation
v4:
- Modified this driver to suit the representation in the devicetree
v3:
- Only sent out device tree documentation; did not send this driver
v2:
- Used BIT()
- Used regmap
- Avoided division when raw data is 0
- Removed empty lines between declaration
- Removed macros; Used two attribute groups and used is_visible callback
- Returned error when properties are undefined
- Removed .owner field
- Used PTR_ERR_OR_ZERO
- Removed explicit of_node_put for child nodes
Documentation/hwmon/aspeed-pwm-tacho | 22 +
drivers/hwmon/Kconfig | 9 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/aspeed-pwm-tacho.c | 846 +++++++++++++++++++++++++++++++++++
4 files changed, 878 insertions(+)
create mode 100644 Documentation/hwmon/aspeed-pwm-tacho
create mode 100644 drivers/hwmon/aspeed-pwm-tacho.c
diff --git a/Documentation/hwmon/aspeed-pwm-tacho b/Documentation/hwmon/aspeed-pwm-tacho
new file mode 100644
index 000000000000..7cfb34977460
--- /dev/null
+++ b/Documentation/hwmon/aspeed-pwm-tacho
@@ -0,0 +1,22 @@
+Kernel driver aspeed-pwm-tacho
+==============================
+
+Supported chips:
+ ASPEED AST2400/2500
+
+Authors:
+ <jaghu@google.com>
+
+Description:
+------------
+This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
+controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
+controller supports up to 16 tachometer inputs.
+
+The driver provides the following sensor accesses in sysfs:
+
+fanX_input ro provide current fan rotation value in RPM as reported
+ by the fan to the device.
+
+pwmX rw get or set PWM fan control value. This is an integer
+ value between 0(off) and 255(full speed).
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 45cef3d2c75c..757b5b0705bf 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -341,6 +341,15 @@ config SENSORS_ASB100
This driver can also be built as a module. If so, the module
will be called asb100.
+config SENSORS_ASPEED
+ tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver"
+ help
+ This driver provides support for ASPEED AST2400/AST2500 PWM
+ and Fan Tacho controllers.
+
+ This driver can also be built as a module. If so, the module
+ will be called aspeed_pwm_tacho.
+
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index aecf4ba17460..83025cc9bb45 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
+obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
new file mode 100644
index 000000000000..29010ad94208
--- /dev/null
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/regmap.h>
+
+/* ASPEED PWM & FAN Tach Register Definition */
+#define ASPEED_PTCR_CTRL 0x00
+#define ASPEED_PTCR_CLK_CTRL 0x04
+#define ASPEED_PTCR_DUTY0_CTRL 0x08
+#define ASPEED_PTCR_DUTY1_CTRL 0x0c
+#define ASPEED_PTCR_TYPEM_CTRL 0x10
+#define ASPEED_PTCR_TYPEM_CTRL1 0x14
+#define ASPEED_PTCR_TYPEN_CTRL 0x18
+#define ASPEED_PTCR_TYPEN_CTRL1 0x1c
+#define ASPEED_PTCR_TACH_SOURCE 0x20
+#define ASPEED_PTCR_TRIGGER 0x28
+#define ASPEED_PTCR_RESULT 0x2c
+#define ASPEED_PTCR_INTR_CTRL 0x30
+#define ASPEED_PTCR_INTR_STS 0x34
+#define ASPEED_PTCR_TYPEM_LIMIT 0x38
+#define ASPEED_PTCR_TYPEN_LIMIT 0x3C
+#define ASPEED_PTCR_CTRL_EXT 0x40
+#define ASPEED_PTCR_CLK_CTRL_EXT 0x44
+#define ASPEED_PTCR_DUTY2_CTRL 0x48
+#define ASPEED_PTCR_DUTY3_CTRL 0x4c
+#define ASPEED_PTCR_TYPEO_CTRL 0x50
+#define ASPEED_PTCR_TYPEO_CTRL1 0x54
+#define ASPEED_PTCR_TACH_SOURCE_EXT 0x60
+#define ASPEED_PTCR_TYPEO_LIMIT 0x78
+
+/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */
+#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15
+#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6
+#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15))
+
+#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14
+#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5
+#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14))
+
+#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13
+#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4
+#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13))
+
+#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12
+#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3
+#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12))
+
+#define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x))
+
+#define ASPEED_PTCR_CTRL_PWMD_EN BIT(11)
+#define ASPEED_PTCR_CTRL_PWMC_EN BIT(10)
+#define ASPEED_PTCR_CTRL_PWMB_EN BIT(9)
+#define ASPEED_PTCR_CTRL_PWMA_EN BIT(8)
+
+#define ASPEED_PTCR_CTRL_CLK_SRC BIT(1)
+#define ASPEED_PTCR_CTRL_CLK_EN BIT(0)
+
+/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */
+/* TYPE N */
+#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16)
+#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24
+#define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20
+#define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16
+/* TYPE M */
+#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0)
+#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8
+#define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4
+#define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0
+
+/*
+ * ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control
+ * 0/1/2/3 register
+ */
+#define DUTY_CTRL_PWM2_FALL_POINT 24
+#define DUTY_CTRL_PWM2_RISE_POINT 16
+#define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16)
+#define DUTY_CTRL_PWM1_FALL_POINT 8
+#define DUTY_CTRL_PWM1_RISE_POINT 0
+#define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0)
+
+/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */
+#define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16))
+#define TYPE_CTRL_FAN1_MASK GENMASK(31, 0)
+#define TYPE_CTRL_FAN_PERIOD 16
+#define TYPE_CTRL_FAN_MODE 4
+#define TYPE_CTRL_FAN_DIVISION 1
+#define TYPE_CTRL_FAN_TYPE_EN 1
+
+/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */
+/* bit [0,1] at 0x20, bit [2] at 0x60 */
+#define TACH_PWM_SOURCE_BIT01(x) ((x) * 2)
+#define TACH_PWM_SOURCE_BIT2(x) ((x) * 2)
+#define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2))
+#define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2)
+
+/* ASPEED_PTCR_RESULT : 0x2c - Result Register */
+#define RESULT_STATUS_MASK BIT(31)
+#define RESULT_VALUE_MASK 0xfffff
+
+/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */
+#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15
+#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6
+#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15))
+
+#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14
+#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5
+#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14))
+
+#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13
+#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4
+#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13))
+
+#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12
+#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3
+#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12))
+
+#define ASPEED_PTCR_CTRL_PWMH_EN BIT(11)
+#define ASPEED_PTCR_CTRL_PWMG_EN BIT(10)
+#define ASPEED_PTCR_CTRL_PWMF_EN BIT(9)
+#define ASPEED_PTCR_CTRL_PWME_EN BIT(8)
+
+/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */
+/* TYPE O */
+#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0)
+#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8
+#define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4
+#define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0
+
+#define PWM_MAX 255
+
+#define M_PWM_DIV_H 0x00
+#define M_PWM_DIV_L 0x05
+#define M_PWM_PERIOD 0x5F
+#define M_TACH_CLK_DIV 0x00
+#define M_TACH_MODE 0x00
+#define M_TACH_UNIT 0x1000
+#define INIT_FAN_CTRL 0xFF
+
+void __iomem *regs;
+
+struct aspeed_pwm_tacho_data {
+ struct regmap *regmap;
+ unsigned long clk_freq;
+ bool pwm_present[8];
+ bool fan_tach_present[16];
+ u8 type_pwm_clock_unit[3];
+ u8 type_pwm_clock_division_h[3];
+ u8 type_pwm_clock_division_l[3];
+ u8 type_fan_tach_clock_division[3];
+ u16 type_fan_tach_unit[3];
+ u8 pwm_port_type[8];
+ u8 pwm_port_fan_ctrl[8];
+ u8 fan_tach_ch_source[16];
+ const struct attribute_group *groups[3];
+};
+
+enum type { TYPEM, TYPEN, TYPEO };
+
+struct type_params {
+ u32 l_value;
+ u32 h_value;
+ u32 unit_value;
+ u32 clk_ctrl_mask;
+ u32 clk_ctrl_reg;
+ u32 ctrl_reg;
+ u32 ctrl_reg1;
+};
+
+static const struct type_params type_params[] = {
+ [TYPEM] = {
+ .l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L,
+ .h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H,
+ .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT,
+ .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK,
+ .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
+ .ctrl_reg = ASPEED_PTCR_TYPEM_CTRL,
+ .ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1,
+ },
+ [TYPEN] = {
+ .l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L,
+ .h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H,
+ .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT,
+ .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK,
+ .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
+ .ctrl_reg = ASPEED_PTCR_TYPEN_CTRL,
+ .ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1,
+ },
+ [TYPEO] = {
+ .l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L,
+ .h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H,
+ .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT,
+ .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK,
+ .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT,
+ .ctrl_reg = ASPEED_PTCR_TYPEO_CTRL,
+ .ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1,
+ }
+};
+
+enum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH };
+
+struct pwm_port_params {
+ u32 pwm_en;
+ u32 ctrl_reg;
+ u32 type_part1;
+ u32 type_part2;
+ u32 type_mask;
+ u32 duty_ctrl_rise_point;
+ u32 duty_ctrl_fall_point;
+ u32 duty_ctrl_reg;
+ u32 duty_ctrl_rise_fall_mask;
+};
+
+static const struct pwm_port_params pwm_port_params[] = {
+ [PWMA] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMA_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
+ },
+ [PWMB] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMB_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
+ },
+ [PWMC] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMC_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
+ },
+ [PWMD] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMD_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
+ },
+ [PWME] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWME_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
+ },
+ [PWMF] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMF_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
+ },
+ [PWMG] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMG_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
+ },
+ [PWMH] = {
+ .pwm_en = ASPEED_PTCR_CTRL_PWMH_EN,
+ .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
+ .type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1,
+ .type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2,
+ .type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK,
+ .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
+ .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
+ .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
+ .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
+ }
+};
+
+static int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ void __iomem *regs = context;
+
+ writel(val, regs + reg);
+ return 0;
+}
+
+static int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ void __iomem *regs = context;
+
+ *val = readl(regs + reg);
+ return 0;
+}
+
+static const struct regmap_config aspeed_pwm_tacho_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = ASPEED_PTCR_TYPEO_LIMIT,
+ .reg_write = regmap_aspeed_pwm_tacho_reg_write,
+ .reg_read = regmap_aspeed_pwm_tacho_reg_read,
+ .fast_io = true,
+};
+
+static void aspeed_set_clock_enable(struct regmap *regmap, bool val)
+{
+ regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
+ ASPEED_PTCR_CTRL_CLK_EN,
+ val ? ASPEED_PTCR_CTRL_CLK_EN : 0);
+}
+
+static void aspeed_set_clock_source(struct regmap *regmap, int val)
+{
+ regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
+ ASPEED_PTCR_CTRL_CLK_SRC,
+ val ? ASPEED_PTCR_CTRL_CLK_SRC : 0);
+}
+
+static void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type,
+ u8 div_high, u8 div_low, u8 unit)
+{
+ u32 reg_value = ((div_high << type_params[type].h_value) |
+ (div_low << type_params[type].l_value) |
+ (unit << type_params[type].unit_value));
+
+ regmap_update_bits(regmap, type_params[type].clk_ctrl_reg,
+ type_params[type].clk_ctrl_mask, reg_value);
+}
+
+static void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port,
+ bool enable)
+{
+ regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
+ pwm_port_params[pwm_port].pwm_en,
+ enable ? pwm_port_params[pwm_port].pwm_en : 0);
+}
+
+static void aspeed_set_pwm_port_type(struct regmap *regmap,
+ u8 pwm_port, u8 type)
+{
+ u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1;
+
+ reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2;
+
+ regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
+ pwm_port_params[pwm_port].type_mask, reg_value);
+}
+
+static void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap,
+ u8 pwm_port, u8 rising,
+ u8 falling)
+{
+ u32 reg_value = (rising <<
+ pwm_port_params[pwm_port].duty_ctrl_rise_point);
+ reg_value |= (falling <<
+ pwm_port_params[pwm_port].duty_ctrl_fall_point);
+
+ regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg,
+ pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask,
+ reg_value);
+}
+
+static void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type,
+ bool enable)
+{
+ regmap_update_bits(regmap, type_params[type].ctrl_reg,
+ TYPE_CTRL_FAN_TYPE_EN,
+ enable ? TYPE_CTRL_FAN_TYPE_EN : 0);
+}
+
+static void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type,
+ u8 mode, u16 unit, u8 division)
+{
+ u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) |
+ (unit << TYPE_CTRL_FAN_PERIOD) |
+ (division << TYPE_CTRL_FAN_DIVISION));
+
+ regmap_update_bits(regmap, type_params[type].ctrl_reg,
+ TYPE_CTRL_FAN_MASK, reg_value);
+ regmap_update_bits(regmap, type_params[type].ctrl_reg1,
+ TYPE_CTRL_FAN1_MASK, unit << 16);
+}
+
+static void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch,
+ bool enable)
+{
+ regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
+ ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch),
+ enable ?
+ ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0);
+}
+
+static void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch,
+ u8 fan_tach_ch_source)
+{
+ u32 reg_value1 = ((fan_tach_ch_source & 0x3) <<
+ TACH_PWM_SOURCE_BIT01(fan_tach_ch));
+ u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) <<
+ TACH_PWM_SOURCE_BIT2(fan_tach_ch));
+
+ regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE,
+ TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch),
+ reg_value1);
+
+ regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT,
+ TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch),
+ reg_value2);
+}
+
+static void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv,
+ u8 index, u8 fan_ctrl)
+{
+ u16 period, dc_time_on;
+
+ period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]];
+ period += 1;
+ dc_time_on = (fan_ctrl * period) / PWM_MAX;
+
+ if (dc_time_on == 0) {
+ aspeed_set_pwm_port_enable(priv->regmap, index, false);
+ } else {
+ if (dc_time_on == period)
+ dc_time_on = 0;
+
+ aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0,
+ dc_time_on);
+ aspeed_set_pwm_port_enable(priv->regmap, index, true);
+ }
+}
+
+static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data
+ *priv, u8 type)
+{
+ u32 clk;
+ u16 tacho_unit;
+ u8 clk_unit, div_h, div_l, tacho_div;
+
+ clk = priv->clk_freq;
+ clk_unit = priv->type_pwm_clock_unit[type];
+ div_h = priv->type_pwm_clock_division_h[type];
+ div_h = 0x1 << div_h;
+ div_l = priv->type_pwm_clock_division_l[type];
+ if (div_l == 0)
+ div_l = 1;
+ else
+ div_l = div_l * 2;
+
+ tacho_unit = priv->type_fan_tach_unit[type];
+ tacho_div = priv->type_fan_tach_clock_division[type];
+
+ tacho_div = 0x4 << (tacho_div * 2);
+ return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit);
+}
+
+static u32 aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
+ u8 fan_tach_ch)
+{
+ u32 raw_data, tach_div, clk_source, timeout = 0, sec, val;
+ u8 fan_tach_ch_source, type;
+
+ regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
+ regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
+
+ fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch];
+ type = priv->pwm_port_type[fan_tach_ch_source];
+
+ sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type));
+
+ msleep(sec);
+
+ while (!(regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val))
+ & !(val & RESULT_STATUS_MASK)) {
+ timeout++;
+ if (timeout > 1)
+ return 0;
+ msleep(sec);
+ }
+
+ raw_data = val & RESULT_VALUE_MASK;
+ tach_div = priv->type_fan_tach_clock_division[type];
+ tach_div = 0x4 << (tach_div * 2);
+ clk_source = priv->clk_freq;
+
+ if (raw_data == 0)
+ return 0;
+
+ return (clk_source * 60) / (2 * raw_data * tach_div);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int index = sensor_attr->index;
+ int ret;
+ struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
+ long fan_ctrl;
+
+ ret = kstrtol(buf, 10, &fan_ctrl);
+ if (ret != 0)
+ return ret;
+
+ if (fan_ctrl < 0 || fan_ctrl > PWM_MAX)
+ return -EINVAL;
+
+ if (priv->pwm_port_fan_ctrl[index] == fan_ctrl)
+ return count;
+
+ priv->pwm_port_fan_ctrl[index] = fan_ctrl;
+ aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl);
+
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int index = sensor_attr->index;
+ struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]);
+}
+
+static ssize_t show_rpm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int index = sensor_attr->index;
+ u32 rpm;
+ struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
+
+ rpm = aspeed_get_fan_tach_ch_rpm(priv, index);
+
+ return sprintf(buf, "%u\n", rpm);
+}
+
+static umode_t pwm_is_visible(struct kobject *kobj,
+ struct attribute *a, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
+
+ if (!priv->pwm_present[index])
+ return 0;
+ return a->mode;
+}
+
+static umode_t fan_dev_is_visible(struct kobject *kobj,
+ struct attribute *a, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
+
+ if (!priv->fan_tach_present[index])
+ return 0;
+ return a->mode;
+}
+
+static SENSOR_DEVICE_ATTR(pwm0, 0644,
+ show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1, 0644,
+ show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2, 0644,
+ show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm3, 0644,
+ show_pwm, set_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm4, 0644,
+ show_pwm, set_pwm, 4);
+static SENSOR_DEVICE_ATTR(pwm5, 0644,
+ show_pwm, set_pwm, 5);
+static SENSOR_DEVICE_ATTR(pwm6, 0644,
+ show_pwm, set_pwm, 6);
+static SENSOR_DEVICE_ATTR(pwm7, 0644,
+ show_pwm, set_pwm, 7);
+static struct attribute *pwm_dev_attrs[] = {
+ &sensor_dev_attr_pwm0.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm5.dev_attr.attr,
+ &sensor_dev_attr_pwm6.dev_attr.attr,
+ &sensor_dev_attr_pwm7.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group pwm_dev_group = {
+ .attrs = pwm_dev_attrs,
+ .is_visible = pwm_is_visible,
+};
+
+static SENSOR_DEVICE_ATTR(fan0_input, 0444,
+ show_rpm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_input, 0444,
+ show_rpm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_input, 0444,
+ show_rpm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_input, 0444,
+ show_rpm, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan4_input, 0444,
+ show_rpm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan5_input, 0444,
+ show_rpm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan6_input, 0444,
+ show_rpm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan7_input, 0444,
+ show_rpm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan8_input, 0444,
+ show_rpm, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan9_input, 0444,
+ show_rpm, NULL, 9);
+static SENSOR_DEVICE_ATTR(fan10_input, 0444,
+ show_rpm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan11_input, 0444,
+ show_rpm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan12_input, 0444,
+ show_rpm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan13_input, 0444,
+ show_rpm, NULL, 13);
+static SENSOR_DEVICE_ATTR(fan14_input, 0444,
+ show_rpm, NULL, 14);
+static SENSOR_DEVICE_ATTR(fan15_input, 0444,
+ show_rpm, NULL, 15);
+static struct attribute *fan_dev_attrs[] = {
+ &sensor_dev_attr_fan0_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan8_input.dev_attr.attr,
+ &sensor_dev_attr_fan9_input.dev_attr.attr,
+ &sensor_dev_attr_fan10_input.dev_attr.attr,
+ &sensor_dev_attr_fan11_input.dev_attr.attr,
+ &sensor_dev_attr_fan12_input.dev_attr.attr,
+ &sensor_dev_attr_fan13_input.dev_attr.attr,
+ &sensor_dev_attr_fan14_input.dev_attr.attr,
+ &sensor_dev_attr_fan15_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group fan_dev_group = {
+ .attrs = fan_dev_attrs,
+ .is_visible = fan_dev_is_visible,
+};
+
+/*
+ * The clock type is type M :
+ * The PWM frequency = 24MHz / (type M clock division L bit *
+ * type M clock division H bit * (type M PWM period bit + 1))
+ */
+static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv)
+{
+ priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H;
+ priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L;
+ priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD;
+ aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H,
+ M_PWM_DIV_L, M_PWM_PERIOD);
+ aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true);
+ priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV;
+ priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT;
+ aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE,
+ M_TACH_UNIT, M_TACH_CLK_DIV);
+}
+
+static void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv,
+ u8 pwm_port)
+{
+ aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true);
+ priv->pwm_present[pwm_port] = true;
+
+ priv->pwm_port_type[pwm_port] = TYPEM;
+ aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM);
+
+ priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL;
+ aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL);
+}
+
+static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv,
+ u8 *fan_tach_ch,
+ int count,
+ u8 pwm_source)
+{
+ u8 val, index;
+
+ for (val = 0; val < count; val++) {
+ index = fan_tach_ch[val];
+ aspeed_set_fan_tach_ch_enable(priv->regmap, index, true);
+ priv->fan_tach_present[index] = true;
+ priv->fan_tach_ch_source[index] = pwm_source;
+ aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source);
+ }
+}
+
+static int aspeed_create_fan(struct device *dev,
+ struct device_node *child,
+ struct aspeed_pwm_tacho_data *priv)
+{
+ u8 *fan_tach_ch;
+ u32 pwm_port;
+ int ret, count;
+
+ ret = of_property_read_u32(child, "reg", &pwm_port);
+ if (ret)
+ return ret;
+ aspeed_create_pwm_port(priv, (u8)pwm_port);
+
+ count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch");
+ if (count < 1)
+ return -EINVAL;
+ fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count,
+ GFP_KERNEL);
+ if (!fan_tach_ch)
+ return -ENOMEM;
+ ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch",
+ fan_tach_ch, count);
+ if (ret)
+ return ret;
+ aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port);
+
+ return 0;
+}
+
+static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np, *child;
+ struct aspeed_pwm_tacho_data *priv;
+ void __iomem *regs;
+ struct resource *res;
+ struct device *hwmon;
+ struct clk *clk;
+ int ret;
+
+ np = dev->of_node;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->regmap = devm_regmap_init(dev, NULL, regs,
+ &aspeed_pwm_tacho_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+ regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0);
+ regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0);
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return -ENODEV;
+ priv->clk_freq = clk_get_rate(clk);
+ aspeed_set_clock_enable(priv->regmap, true);
+ aspeed_set_clock_source(priv->regmap, 0);
+
+ aspeed_create_type(priv);
+
+ for_each_child_of_node(np, child) {
+ ret = aspeed_create_fan(dev, child, priv);
+ of_node_put(child);
+ if (ret)
+ return ret;
+ }
+ of_node_put(np);
+
+ priv->groups[0] = &pwm_dev_group;
+ priv->groups[1] = &fan_dev_group;
+ priv->groups[2] = NULL;
+ hwmon = devm_hwmon_device_register_with_groups(dev,
+ "aspeed_pwm_tacho",
+ priv, priv->groups);
+
+ return PTR_ERR_OR_ZERO(hwmon);
+}
+
+static const struct of_device_id of_pwm_tacho_match_table[] = {
+ { .compatible = "aspeed,ast2400-pwm-tacho", },
+ { .compatible = "aspeed,ast2500-pwm-tacho", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table);
+
+static struct platform_driver aspeed_pwm_tacho_driver = {
+ .probe = aspeed_pwm_tacho_probe,
+ .driver = {
+ .name = "aspeed_pwm_tacho",
+ .of_match_table = of_pwm_tacho_match_table,
+ },
+};
+
+module_platform_driver(aspeed_pwm_tacho_driver);
+
+MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>");
+MODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver");
+MODULE_LICENSE("GPL");
--
2.12.2.715.g7642488e1d-goog
^ permalink raw reply related
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