Devicetree
 help / color / mirror / Atom feed
* [PATCH 06/13] MIPS: jz4780: DTS: Add node for the jz4780-pinctrl driver
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 333 +++++++++++++++++++++++++++++++++
 1 file changed, 333 insertions(+)

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..0135b2b0c6ad 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,339 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gpio-chips {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpa: gpa {
+				reg = <0x10010000 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <17>;
+
+				ingenic,pull-ups = <0x3fffffff>;
+			};
+
+			gpb: gpb {
+				reg = <0x10010100 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <16>;
+
+				ingenic,pull-downs = <0x000f0c03>;
+				ingenic,pull-ups   = <0xfff0030c>;
+			};
+
+			gpc: gpc {
+				reg = <0x10010200 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <15>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpd: gpd {
+				reg = <0x10010300 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <14>;
+
+				ingenic,pull-downs = <0x0000b000>;
+				ingenic,pull-ups   = <0xffff4fff>;
+			};
+
+			gpe: gpe {
+				reg = <0x10010400 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <13>;
+
+				ingenic,pull-downs = <0x00000483>;
+				ingenic,pull-ups   = <0xfffffb7c>;
+			};
+
+			gpf: gpf {
+				reg = <0x10010500 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <12>;
+
+				ingenic,pull-downs = <0x00580ff0>;
+				ingenic,pull-ups   = <0xffa7f00f>;
+			};
+		};
+
+		bias-configs {
+			nobias: nobias {
+				bias-disable;
+			};
+
+			pull_up: pull_up {
+				bias-pull-up;
+			};
+
+			pull_down: pull_down {
+				bias-pull-down;
+			};
+		};
+
+		functions {
+			pinfunc-uart0 {
+				pins_uart0_data: uart0-data {
+					ingenic,pins = <&gpf  0 0 &pull_up  /* rxd */
+							&gpf  3 0 &nobias>; /* txd */
+				};
+
+				pins_uart0_dataplusflow: uart0-dataplusflow {
+					ingenic,pins = <&gpf  0 0 &pull_up  /* rxd */
+							&gpf  1 0 &nobias   /* cts */
+							&gpf  2 0 &nobias   /* rts */
+							&gpf  3 0 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart1 {
+				pins_uart1_data: uart1-data {
+					ingenic,pins = <&gpd  26 0 &pull_up  /* rxd */
+							&gpd  28 0 &nobias>; /* txd */
+				};
+
+				pins_uart1_dataplusflow: uart1-dataplusflow {
+					ingenic,pins = <&gpd  26 0 &pull_up  /* rxd */
+							&gpd  27 0 &nobias   /* cts */
+							&gpd  29 0 &nobias   /* rts */
+							&gpd  28 0 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart2 {
+				pins_uart2_data: uart2-data {
+					ingenic,pins = <&gpd  6 1 &nobias  /* rxd */
+							&gpd  7 1 &nobias>; /* txd */
+				};
+
+				pins_uart2_dataplusflow: uart2-dataplusflow {
+					ingenic,pins = <&gpd  6 1 &nobias  /* rxd */
+							&gpd  5 1 &nobias   /* cts */
+							&gpd  4 1 &nobias   /* rts */
+							&gpd  7 1 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart3 {
+				pins_uart3_data: uart3-data {
+					ingenic,pins = <&gpd 12 0 &pull_down /* rxd */
+							&gpe  5 1 &nobias>;  /* txd */
+				};
+
+				pins_uart3_dataplusflow: uart3-dataplusflow {
+					ingenic,pins = <&gpd 12 0 &pull_down /* rxd */
+							&gpe  5 1 &nobias    /* txd */
+							&gpe  8 0 &nobias    /* cts */
+							&gpe  9 0 &nobias>;  /* rts */
+				};
+			};
+
+			pinfunc-uart4 {
+				pins_uart4_data: uart4-data {
+					ingenic,pins = <&gpc 20 2 &pull_up   /* rxd */
+							&gpc 10 2 &nobias>;  /* txd */
+				};
+			};
+
+			pinfunc-msc0 {
+				pins_msc0_pa: msc0-pa {
+					ingenic,pins = <&gpa  4 1 &nobias   /* d4 */
+							&gpa  5 1 &nobias   /* d5 */
+							&gpa  6 1 &nobias   /* d6 */
+							&gpa  7 1 &nobias   /* d7 */
+							&gpa 18 1 &nobias   /* clk */
+							&gpa 19 1 &nobias   /* cmd */
+							&gpa 20 1 &nobias   /* d0 */
+							&gpa 21 1 &nobias   /* d1 */
+							&gpa 22 1 &nobias   /* d2 */
+							&gpa 23 1 &nobias   /* d3 */
+							&gpa 24 1 &nobias>; /* rst */
+				};
+
+				pins_msc0_pe: msc0-pe {
+					ingenic,pins = <&gpe 20 0 &nobias   /* d0 */
+							&gpe 21 0 &nobias   /* d1 */
+							&gpe 22 0 &nobias   /* d2 */
+							&gpe 23 0 &nobias   /* d3 */
+							&gpe 28 0 &nobias   /* clk */
+							&gpe 29 0 &nobias>; /* cmd */
+				};
+			};
+
+			pinfunc-msc1 {
+				pins_msc1_pd: msc1-pd {
+					ingenic,pins = <&gpd 20 0 &nobias   /* d0 */
+							&gpd 21 0 &nobias   /* d1 */
+							&gpd 22 0 &nobias   /* d2 */
+							&gpd 23 0 &nobias   /* d3 */
+							&gpd 24 0 &nobias   /* clk */
+							&gpd 25 0 &nobias>; /* cmd */
+				};
+
+				pins_msc1_pe: msc1-pe {
+					ingenic,pins = <&gpe 20 1 &nobias   /* d0 */
+							&gpe 21 1 &nobias   /* d1 */
+							&gpe 22 1 &nobias   /* d2 */
+							&gpe 23 1 &nobias   /* d3 */
+							&gpe 28 1 &nobias   /* clk */
+							&gpe 29 1 &nobias>; /* cmd */
+				};
+			};
+
+			pinfunc-nemc {
+				pins_nemc_data: nemc-data {
+					ingenic,pins = <&gpa 0 0 &nobias    /* sd0 */
+							&gpa 1 0 &nobias    /* sd1 */
+							&gpa 2 0 &nobias    /* sd2 */
+							&gpa 3 0 &nobias    /* sd3 */
+							&gpa 4 0 &nobias    /* sd4 */
+							&gpa 5 0 &nobias    /* sd5 */
+							&gpa 6 0 &nobias    /* sd6 */
+							&gpa 7 0 &nobias>;  /* sd7 */
+				};
+
+				pins_nemc_cle_ale: nemc-cle-ale {
+					ingenic,pins = <&gpb 0 0 &nobias    /* sa0_cl */
+							&gpb 1 0 &nobias>;  /* sa1_al */
+				};
+
+				pins_nemc_addr: nemc-addr {
+					ingenic,pins = <&gpb 0 0 &nobias    /* sa0_cl */
+							&gpb 1 0 &nobias    /* sa1_al */
+							&gpb 2 0 &nobias    /* sa2 */
+							&gpb 3 0 &nobias    /* sa3 */
+							&gpb 4 0 &nobias    /* sa4 */
+							&gpb 5 0 &nobias>;  /* sa5 */
+				};
+
+				pins_nemc_rd_we: nemc-rd-we {
+					ingenic,pins = <&gpa 16 0 &nobias   /* rd */
+							&gpa 17 0 &nobias>; /* we */
+				};
+
+				pins_nemc_frd_fwe: nemc-frd-fwe {
+					ingenic,pins = <&gpa 18 0 &nobias   /* rd */
+							&gpa 19 0 &nobias>; /* we */
+				};
+
+				pins_nemc_cs1: nemc-cs1 {
+					ingenic,pins = <&gpa 21 0 &nobias>; /* cs1 */
+				};
+
+				pins_nemc_cs6: nemc-cs6 {
+					ingenic,pins = <&gpa 26 0 &nobias>; /* cs6 */
+				};
+			};
+
+			pinfunc-i2c0 {
+				pins_i2c0_data: i2c0-data{
+					ingenic,pins = <&gpd  30 0 &nobias  /* sda */
+							&gpd  31 0 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c1 {
+				pins_i2c1_data: i2c1-data{
+					ingenic,pins = <&gpe  30 0 &nobias  /* sda */
+							&gpe  31 0 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c2 {
+				pins_i2c2_data: i2c2-data{
+					ingenic,pins = <&gpf  16 2 &nobias  /* sda */
+							&gpf  17 2 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c3 {
+				pins_i2c3_data: i2c3-data{
+					ingenic,pins = <&gpd  10 1 &nobias  /* sda */
+							&gpd  11 1 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c4 {
+				pins_i2c4_data: i2c4-data-pe{
+					ingenic,pins = <&gpe  12 1 &nobias  /* sda */
+							&gpe  13 1 &nobias>; /* sck */
+				};
+
+				pins_i2c4_data_pf: i2c4-data-pf{
+					ingenic,pins = <&gpf 25 1 &nobias /* hdmi_sda */
+							&gpf 24 1 &nobias>; /* hdmi_sck */
+				};
+			};
+
+			pinfunc-cim {
+				pins_cim: cim-pb {
+					ingenic,pins = <&gpb   6 0 &nobias
+							&gpb   7 0 &nobias
+							&gpb   8 0 &nobias
+							&gpb   9 0 &nobias
+							&gpb  10 0 &nobias
+							&gpb  11 0 &nobias
+							&gpb  12 0 &nobias
+							&gpb  13 0 &nobias
+							&gpb  14 0 &nobias
+							&gpb  15 0 &nobias
+							&gpb  16 0 &nobias
+							&gpb  17 0 &nobias>;
+				};
+			};
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 275 +++++++++++++++++++++++++++++++++
 1 file changed, 275 insertions(+)

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..c014a7159a2a 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,281 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gpio-chips {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpa: gpa {
+				reg = <0x10010000 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <28>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpb: gpb {
+				reg = <0x10010100 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <27>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpc: gpc {
+				reg = <0x10010200 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <26>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpd: gpd {
+				reg = <0x10010300 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <25>;
+
+				ingenic,pull-ups = <0xdfffffff>;
+			};
+		};
+
+		bias-configs {
+			nobias: pincfg-nobias {
+				bias-disable;
+			};
+
+			pull_up: pincfg-pull-up {
+				bias-pull-up;
+			};
+
+			pull_down: pincfg-pull-down {
+				bias-pull-down;
+			};
+		};
+
+		functions {
+			pinfunc-msc {
+				pins_msc_4bit: pins-msc-4bit {
+					ingenic,pins = <&gpd 8 0 &nobias
+							&gpa 9 0 &nobias
+							&gpa 10 0 &nobias
+							&gpa 11 0 &nobias
+							&gpa 12 0 &nobias
+							&gpa 13 0 &nobias>;
+				};
+			};
+
+			pinfunc-uart0 {
+				pins_uart0_data: pins-uart0-data {
+					ingenic,pins = <&gpd 26 1 &pull_up  /* rxd */
+							&gpd 25 1 &nobias>; /* txd */
+				};
+
+				pins_uart0_dataplusflow: uart0-dataplusflow {
+					ingenic,pins = <&gpd 26 1 &pull_up  /* rxd */
+							&gpd 25 1 &nobias   /* txd */
+							&gpd 31 0 &nobias   /* rts */
+							&gpd 30 0 &nobias>; /* cts */
+				};
+			};
+
+			pinfunc-uart1 {
+				pins_uart1_data: uart1-data {
+					ingenic,pins = <&gpd 30 2 &pull_up   /* rxd */
+							&gpd 31 2 &nobias>;  /* txd */
+				};
+			};
+
+			pinfunc-lcd {
+				pins_lcd_8bit: pins-lcd-8bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias	/* LCD_DATA7 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias>;	/* VSYNC */
+				};
+
+				pins_lcd_16bit: pins-lcd-16bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias	/* LCD_DATA15 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias>;	/* DE */
+				};
+
+				pins_lcd_18bit: pins-lcd-18bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias
+							&gpc 16 0 &nobias
+							&gpc 17 0 &nobias	/* LCD_DATA17 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias>;	/* DE */
+				};
+
+				pins_lcd_special_tft: pins-lcd-special-tft {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias
+							&gpc 16 0 &nobias
+							&gpc 17 0 &nobias	/* LCD_DATA17 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias	/* DE */
+							&gpc 22 0 &nobias	/* PS */
+							&gpc 23 0 &nobias	/* REV */
+							&gpb 17 0 &nobias	/* CLS */
+							&gpb 18 0 &nobias>;	/* SPL */
+				};
+
+				pinfunc_lcd_nopins: pins-lcd-no-pins {
+					ingenic,pins = <>;
+				};
+			};
+
+			pinfunc-nand {
+				pins_nand: pins-nand {
+					ingenic,pins = <&gpb 25 0 &nobias
+							&gpb 26 0 &nobias
+							&gpb 27 0 &nobias
+							&gpb 28 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm0 {
+				pins_pwm0: pins-pwm0 {
+					ingenic,pins = <&gpd 23 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm1 {
+				pins_pwm1: pins-pwm1 {
+					ingenic,pins = <&gpd 24 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm2 {
+				pins_pwm2: pins-pwm2 {
+					ingenic,pins = <&gpd 25 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm3 {
+				pins_pwm3: pins-pwm3 {
+					ingenic,pins = <&gpd 26 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm4 {
+				pins_pwm4: pins-pwm4 {
+					ingenic,pins = <&gpd 27 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm5 {
+				pins_pwm5: pins-pwm5 {
+					ingenic,pins = <&gpd 28 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm6 {
+				pins_pwm6: pins-pwm6 {
+					ingenic,pins = <&gpd 30 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm7 {
+				pins_pwm7: pins-pwm7 {
+					ingenic,pins = <&gpd 31 0 &nobias>;
+				};
+			};
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 04/13] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b3c5bde43d34..fc720e37661e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -359,6 +359,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply related

* [PATCH 03/13] pinctrl-jz4780: add a pinctrl driver for the Ingenic jz4780 SoC
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

This driver reuses the core of the driver already present in
pinctrl-ingenic.c, and just supplies callbacks to perform the low-level
operations.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/ingenic/Kconfig          |   6 ++
 drivers/pinctrl/ingenic/Makefile         |   1 +
 drivers/pinctrl/ingenic/pinctrl-jz4780.c | 179 +++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-jz4780.c

diff --git a/drivers/pinctrl/ingenic/Kconfig b/drivers/pinctrl/ingenic/Kconfig
index 9923ce127183..15b6514c1948 100644
--- a/drivers/pinctrl/ingenic/Kconfig
+++ b/drivers/pinctrl/ingenic/Kconfig
@@ -12,3 +12,9 @@ config PINCTRL_JZ4740
 	default y
 	depends on MACH_JZ4740 || COMPILE_TEST
 	select PINCTRL_INGENIC
+
+config PINCTRL_JZ4780
+	bool "Pinctrl driver for the Ingenic JZ4780 SoC"
+	default y
+	depends on MACH_JZ4780 || COMPILE_TEST
+	select PINCTRL_INGENIC
diff --git a/drivers/pinctrl/ingenic/Makefile b/drivers/pinctrl/ingenic/Makefile
index 8b2c8b789dc9..ad691f053207 100644
--- a/drivers/pinctrl/ingenic/Makefile
+++ b/drivers/pinctrl/ingenic/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_JZ4740)	+= pinctrl-jz4740.o
+obj-$(CONFIG_PINCTRL_JZ4780)	+= pinctrl-jz4780.o
diff --git a/drivers/pinctrl/ingenic/pinctrl-jz4780.c b/drivers/pinctrl/ingenic/pinctrl-jz4780.c
new file mode 100644
index 000000000000..a191cd1711e7
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-jz4780.c
@@ -0,0 +1,179 @@
+/*
+ * Ingenic jz4780 pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include "pinctrl-ingenic.h"
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* GPIO port register offsets */
+#define GPIO_PIN	0x00
+#define GPIO_INT	0x10
+#define GPIO_INTS	0x14
+#define GPIO_INTC	0x18
+#define GPIO_MSK	0x20
+#define GPIO_MSKS	0x24
+#define GPIO_MSKC	0x28
+#define GPIO_PAT1	0x30
+#define GPIO_PAT1S	0x34
+#define GPIO_PAT1C	0x38
+#define GPIO_PAT0	0x40
+#define GPIO_PAT0S	0x44
+#define GPIO_PAT0C	0x48
+#define GPIO_FLG	0x50
+#define GPIO_FLGC	0x58
+#define GPIO_PEN	0x70
+#define GPIO_PENS	0x74
+#define GPIO_PENC	0x78
+
+static void jz4780_set_gpio(void __iomem *base,
+		unsigned int offset, bool output)
+{
+	writel(1 << offset, base + GPIO_INTC);
+	writel(1 << offset, base + GPIO_MSKS);
+
+	if (output)
+		writel(1 << offset, base + GPIO_PAT1C);
+	else
+		writel(1 << offset, base + GPIO_PAT1S);
+}
+
+static int jz4780_get_bias(void __iomem *base, unsigned int offset)
+{
+	return !((readl(base + GPIO_PEN) >> offset) & 0x1);
+}
+
+static void jz4780_set_bias(void __iomem *base,
+		unsigned int offset, bool enable)
+{
+	if (enable)
+		writel(1 << offset, base + GPIO_PENC);
+	else
+		writel(1 << offset, base + GPIO_PENS);
+}
+
+static void jz4780_gpio_set_value(void __iomem *base,
+		unsigned int offset, int value)
+{
+	if (value)
+		writel(1 << offset, base + GPIO_PAT0S);
+	else
+		writel(1 << offset, base + GPIO_PAT0C);
+}
+
+static int jz4780_gpio_get_value(void __iomem *base, unsigned int offset)
+{
+	return (readl(base + GPIO_PIN) >> offset) & 0x1;
+}
+
+static u32 jz4780_irq_read(void __iomem *base)
+{
+	return readl(base + GPIO_FLG);
+}
+
+static void jz4780_irq_mask(void __iomem *base, unsigned int offset, bool mask)
+{
+	if (mask)
+		writel(1 << offset, base + GPIO_MSKS);
+	else
+		writel(1 << offset, base + GPIO_MSKC);
+}
+
+static void jz4780_irq_ack(void __iomem *base, unsigned int offset)
+{
+	writel(1 << offset, base + GPIO_FLGC);
+}
+
+static void jz4780_irq_set_type(void __iomem *base,
+		unsigned int offset, unsigned int type)
+{
+	enum {
+		PAT_EDGE_RISING		= 0x3,
+		PAT_EDGE_FALLING	= 0x2,
+		PAT_LEVEL_HIGH		= 0x1,
+		PAT_LEVEL_LOW		= 0x0,
+	} pat;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		pat = PAT_EDGE_RISING;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		pat = PAT_EDGE_FALLING;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		pat = PAT_LEVEL_HIGH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		pat = PAT_LEVEL_LOW;
+		break;
+	};
+
+	writel(1 << offset, base + ((pat & 0x2) ? GPIO_PAT1S : GPIO_PAT1C));
+	writel(1 << offset, base + ((pat & 0x1) ? GPIO_PAT0S : GPIO_PAT0C));
+	writel(1 << offset, base + GPIO_INTS);
+}
+
+static void jz4780_set_function(void __iomem *base,
+		unsigned int offset, unsigned int func)
+{
+	writel(1 << offset, base + GPIO_INTC);
+	writel(1 << offset, base + GPIO_MSKC);
+	writel(1 << offset, base + ((func & 0x2) ? GPIO_PAT1S : GPIO_PAT1C));
+	writel(1 << offset, base + ((func & 0x1) ? GPIO_PAT0S : GPIO_PAT0C));
+}
+
+static const struct ingenic_pinctrl_ops jz4780_pinctrl_ops = {
+	.nb_functions	= 4,
+	.set_function	= jz4780_set_function,
+	.set_gpio	= jz4780_set_gpio,
+	.set_bias	= jz4780_set_bias,
+	.get_bias	= jz4780_get_bias,
+	.gpio_set_value	= jz4780_gpio_set_value,
+	.gpio_get_value	= jz4780_gpio_get_value,
+	.irq_read	= jz4780_irq_read,
+	.irq_mask	= jz4780_irq_mask,
+	.irq_ack	= jz4780_irq_ack,
+	.irq_set_type	= jz4780_irq_set_type,
+};
+
+static int jz4780_pinctrl_probe(struct platform_device *pdev)
+{
+	return ingenic_pinctrl_probe(pdev, &jz4780_pinctrl_ops);
+}
+
+static const struct of_device_id jz4780_pinctrl_dt_match[] = {
+	{ .compatible = "ingenic,jz4780-pinctrl", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4780_pinctrl_dt_match);
+
+
+static struct platform_driver jz4780_pinctrl_driver = {
+	.driver = {
+		.name = "jz4780-pinctrl",
+		.of_match_table = of_match_ptr(jz4780_pinctrl_dt_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = jz4780_pinctrl_probe,
+};
+
+static int __init jz4780_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&jz4780_pinctrl_driver);
+}
+postcore_initcall(jz4780_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

From: Paul Burton <paul.burton@imgtec.com>

This driver handles pin configuration, pin muxing, and GPIOs of the
jz4740 SoC from Ingenic.

It is separated into two files:
- pinctrl-ingenic.c, which contains the core functions that can be
  shared across all Ingenic SoCs,
- pinctrl-jz4740.c, which contains the jz4740-pinctrl driver.

The reason behind separating some functions out of the jz4740-pinctrl
driver, is that the pin/GPIO controllers of the Ingenic SoCs are
extremely similar across SoC versions, except that some have the
registers shuffled around. Making a distinct separation will permit the
reuse of large parts of the driver to support the other SoCs from
Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig                   |   1 +
 drivers/pinctrl/Makefile                  |   1 +
 drivers/pinctrl/ingenic/Kconfig           |  14 +
 drivers/pinctrl/ingenic/Makefile          |   2 +
 drivers/pinctrl/ingenic/pinctrl-ingenic.c | 847 ++++++++++++++++++++++++++++++
 drivers/pinctrl/ingenic/pinctrl-ingenic.h |  42 ++
 drivers/pinctrl/ingenic/pinctrl-jz4740.c  | 190 +++++++
 include/dt-bindings/pinctrl/ingenic.h     |  11 +
 8 files changed, 1108 insertions(+)
 create mode 100644 drivers/pinctrl/ingenic/Kconfig
 create mode 100644 drivers/pinctrl/ingenic/Makefile
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-ingenic.c
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-ingenic.h
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-jz4740.c
 create mode 100644 include/dt-bindings/pinctrl/ingenic.h

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 54044a8ecbd7..e13ca8cc1cde 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -282,6 +282,7 @@ source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
 source "drivers/pinctrl/freescale/Kconfig"
+source "drivers/pinctrl/ingenic/Kconfig"
 source "drivers/pinctrl/intel/Kconfig"
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/nomadik/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 25d50a86981d..93b6837af7bb 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)	+= berlin/
 obj-y				+= freescale/
+obj-$(CONFIG_PINCTRL_INGENIC)	+= ingenic/
 obj-$(CONFIG_X86)		+= intel/
 obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
 obj-y				+= nomadik/
diff --git a/drivers/pinctrl/ingenic/Kconfig b/drivers/pinctrl/ingenic/Kconfig
new file mode 100644
index 000000000000..9923ce127183
--- /dev/null
+++ b/drivers/pinctrl/ingenic/Kconfig
@@ -0,0 +1,14 @@
+#
+# Ingenic SoCs pin control drivers
+#
+config PINCTRL_INGENIC
+	bool
+	select PINMUX
+	select GPIOLIB_IRQCHIP
+	select GENERIC_PINCONF
+
+config PINCTRL_JZ4740
+	bool "Pinctrl driver for the Ingenic JZ4740 SoC"
+	default y
+	depends on MACH_JZ4740 || COMPILE_TEST
+	select PINCTRL_INGENIC
diff --git a/drivers/pinctrl/ingenic/Makefile b/drivers/pinctrl/ingenic/Makefile
new file mode 100644
index 000000000000..8b2c8b789dc9
--- /dev/null
+++ b/drivers/pinctrl/ingenic/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
+obj-$(CONFIG_PINCTRL_JZ4740)	+= pinctrl-jz4740.o
diff --git a/drivers/pinctrl/ingenic/pinctrl-ingenic.c b/drivers/pinctrl/ingenic/pinctrl-ingenic.c
new file mode 100644
index 000000000000..22a2be6d72f1
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-ingenic.c
@@ -0,0 +1,847 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/pinctrl/ingenic.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "pinctrl-ingenic.h"
+
+struct ingenic_pinctrl;
+
+struct ingenic_pinctrl_pin {
+	struct ingenic_gpio_chip *gpio_chip;
+	unsigned int idx;
+	unsigned int func;
+	unsigned long *configs;
+	unsigned int num_configs;
+};
+
+struct ingenic_pinctrl_group {
+	const char *name;
+	struct device_node *of_node;
+
+	unsigned int num_pins;
+	struct ingenic_pinctrl_pin *pins;
+	unsigned int *pin_indices;
+};
+
+struct ingenic_pinctrl_func {
+	const char *name;
+	struct device_node *of_node;
+
+	unsigned int num_groups;
+	struct ingenic_pinctrl_group **groups;
+	const char **group_names;
+};
+
+struct ingenic_gpio_chip {
+	char name[3];
+	unsigned int idx;
+	void __iomem *base;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	struct ingenic_pinctrl *pinctrl;
+	const struct ingenic_pinctrl_ops *ops;
+	uint32_t pull_ups;
+	uint32_t pull_downs;
+	unsigned int irq;
+	struct pinctrl_gpio_range grange;
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	uint32_t base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+
+	unsigned int num_gpio_chips;
+	struct ingenic_gpio_chip *gpio_chips;
+
+	unsigned int num_groups;
+	struct ingenic_pinctrl_group *groups;
+
+	unsigned int num_funcs;
+	struct ingenic_pinctrl_func *funcs;
+};
+
+#define gc_to_jzgc(gpiochip) \
+	container_of(gpiochip, struct ingenic_gpio_chip, gc)
+
+#define PINS_PER_GPIO_PORT 32
+
+static struct ingenic_pinctrl_group *find_group_by_of_node(
+		struct ingenic_pinctrl *jzpc, struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < jzpc->num_groups; i++)
+		if (jzpc->groups[i].of_node == np)
+			return &jzpc->groups[i];
+
+	return NULL;
+}
+
+static struct ingenic_pinctrl_func *find_func_by_of_node(
+		struct ingenic_pinctrl *jzpc, struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < jzpc->num_funcs; i++)
+		if (jzpc->funcs[i].of_node == np)
+			return &jzpc->funcs[i];
+
+	return NULL;
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->gpio_set_value(jzgc->base, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	return jzgc->ops->gpio_get_value(jzgc->base, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->irq_mask(jzgc->base, irqd->hwirq, true);
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->irq_mask(jzgc->base, irqd->hwirq, false);
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+	unsigned int high;
+	int irq = irqd->hwirq;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = jzgc->ops->gpio_get_value(jzgc->base, irq);
+		if (high)
+			jzgc->ops->irq_set_type(jzgc->base, irq,
+					IRQ_TYPE_EDGE_FALLING);
+		else
+			jzgc->ops->irq_set_type(jzgc->base, irq,
+					IRQ_TYPE_EDGE_RISING);
+	}
+
+	jzgc->ops->irq_ack(jzgc->base, irq);
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		break;
+	default:
+		pr_err("unsupported external interrupt type\n");
+		return -EINVAL;
+	}
+
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		irq_set_handler_locked(irqd, handle_edge_irq);
+	else
+		irq_set_handler_locked(irqd, handle_level_irq);
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		int value = jzgc->ops->gpio_get_value(jzgc->base, irqd->hwirq);
+
+		type = value ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	jzgc->ops->irq_set_type(jzgc->base, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+	flag = jzgc->ops->irq_read(jzgc->base);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static int ingenic_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->num_groups;
+}
+
+static const char *ingenic_pinctrl_get_group_name(
+		struct pinctrl_dev *pctldev, unsigned int selector)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->groups[selector].name;
+}
+
+static int ingenic_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned int selector, const unsigned int **pins,
+		unsigned int *num_pins)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= jzpc->num_groups)
+		return -EINVAL;
+
+	*pins = jzpc->groups[selector].pin_indices;
+	*num_pins = jzpc->groups[selector].num_pins;
+	return 0;
+}
+
+static int ingenic_pinctrl_dt_node_to_map(
+		struct pinctrl_dev *pctldev, struct device_node *np,
+		struct pinctrl_map **map, unsigned int *num_maps)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_pinctrl_func *func;
+	struct ingenic_pinctrl_group *group;
+	struct pinctrl_map *new_map;
+	unsigned int map_num, i;
+
+	group = find_group_by_of_node(jzpc, np);
+	if (!group)
+		return -EINVAL;
+
+	func = find_func_by_of_node(jzpc, of_get_parent(np));
+	if (!func)
+		return -EINVAL;
+
+	map_num = 1 + group->num_pins;
+	new_map = devm_kzalloc(jzpc->dev,
+				sizeof(*new_map) * map_num, GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map[0].data.mux.function = func->name;
+	new_map[0].data.mux.group = group->name;
+
+	for (i = 0; i < group->num_pins; i++) {
+		new_map[i + 1].type = PIN_MAP_TYPE_CONFIGS_PIN;
+		new_map[i + 1].data.configs.group_or_pin =
+			jzpc->pdesc[group->pins[i].idx].name;
+		new_map[i + 1].data.configs.configs = group->pins[i].configs;
+		new_map[i + 1].data.configs.num_configs =
+			group->pins[i].num_configs;
+	}
+
+	*map = new_map;
+	*num_maps = map_num;
+	return 0;
+}
+
+static void ingenic_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map *map, unsigned int num_maps)
+{
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = ingenic_pinctrl_get_groups_count,
+	.get_group_name = ingenic_pinctrl_get_group_name,
+	.get_group_pins = ingenic_pinctrl_get_group_pins,
+	.dt_node_to_map = ingenic_pinctrl_dt_node_to_map,
+	.dt_free_map = ingenic_pinctrl_dt_free_map,
+};
+
+static int ingenic_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->num_funcs;
+}
+
+static const char *ingenic_pinmux_get_function_name(
+		struct pinctrl_dev *pctldev, unsigned int selector)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->funcs[selector].name;
+}
+
+static int ingenic_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+		unsigned int selector, const char * const **groups,
+		unsigned int * const num_groups)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= jzpc->num_funcs)
+		return -EINVAL;
+
+	*groups = jzpc->funcs[selector].group_names;
+	*num_groups = jzpc->funcs[selector].num_groups;
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		struct ingenic_pinctrl_pin *pin)
+{
+	struct ingenic_gpio_chip *jzgc = &jzpc->gpio_chips[
+		pin->idx / PINS_PER_GPIO_PORT];
+	unsigned int idx = pin->idx % PINS_PER_GPIO_PORT;
+
+	if (pin->func == JZ_PIN_MODE_GPIO) {
+		dev_dbg(jzpc->dev, "set pin P%c%u to GPIO\n",
+				'A' + pin->gpio_chip->idx, idx);
+
+		jzgc->ops->set_gpio(jzgc->base, idx, false);
+	} else if (pin->func < jzgc->ops->nb_functions) {
+		dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+				'A' + pin->gpio_chip->idx, idx, pin->func);
+
+		jzgc->ops->set_function(jzgc->base, idx, pin->func);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_pinctrl_group *grp = &jzpc->groups[group];
+	unsigned int i;
+	int err = 0;
+
+	if (selector >= jzpc->num_funcs || group >= jzpc->num_groups)
+		return -EINVAL;
+
+	for (i = 0; i < grp->num_pins; i++) {
+		err = ingenic_pinmux_set_pin_fn(jzpc, &grp->pins[i]);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int offset, bool input)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(range->gc);
+	unsigned int idx;
+
+	idx = offset - (jzgc->idx * PINS_PER_GPIO_PORT);
+
+	jzgc->ops->set_gpio(jzgc->base, idx, !input);
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = ingenic_pinmux_get_functions_count,
+	.get_function_name = ingenic_pinmux_get_function_name,
+	.get_function_groups = ingenic_pinmux_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_gpio_chip *jzgc;
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx, pull;
+
+	if (pin >= (jzpc->num_gpio_chips * PINS_PER_GPIO_PORT))
+		return -EINVAL;
+	jzgc = &jzpc->gpio_chips[pin / PINS_PER_GPIO_PORT];
+	idx = pin % PINS_PER_GPIO_PORT;
+
+	pull = jzgc->ops->get_bias(jzgc->base, idx);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzgc->pull_ups & (1 << idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzgc->pull_downs & (1 << idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_gpio_chip *jzgc;
+	unsigned int idx, cfg;
+
+	if (pin >= (jzpc->num_gpio_chips * PINS_PER_GPIO_PORT))
+		return -EINVAL;
+
+	jzgc = &jzpc->gpio_chips[pin / PINS_PER_GPIO_PORT];
+	idx = pin % PINS_PER_GPIO_PORT;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			jzgc->ops->set_bias(jzgc->base, idx, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzgc->pull_ups & (1 << idx)))
+				return -EINVAL;
+			jzgc->ops->set_bias(jzgc->base, idx, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzgc->pull_downs & (1 << idx)))
+				return -EINVAL;
+			jzgc->ops->set_bias(jzgc->base, idx, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+};
+
+static int ingenic_pinctrl_parse_dt_gpio(struct ingenic_pinctrl *jzpc,
+		struct ingenic_gpio_chip *jzgc, struct device_node *np)
+{
+	int err;
+
+	jzgc->pinctrl = jzpc;
+	snprintf(jzgc->name, sizeof(jzgc->name), "P%c", 'A' + jzgc->idx);
+
+	jzgc->base = of_iomap(np, 0);
+	if (!jzgc->base) {
+		dev_err(jzpc->dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzgc->gc.base = jzpc->base + (jzgc->idx * PINS_PER_GPIO_PORT);
+	jzgc->gc.ngpio = PINS_PER_GPIO_PORT;
+	jzgc->gc.parent = jzpc->dev;
+	jzgc->gc.of_node = np;
+	jzgc->gc.label = np->name;
+	jzgc->gc.owner = THIS_MODULE;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_u32_index(np, "ingenic,pull-ups", 0,
+				&jzgc->pull_ups))
+		jzgc->pull_ups = 0;
+	if (of_property_read_u32_index(np, "ingenic,pull-downs", 0,
+				&jzgc->pull_downs))
+		jzgc->pull_downs = 0;
+
+	if (jzgc->pull_ups & jzgc->pull_downs) {
+		dev_err(jzpc->dev, "GPIO port %c has overlapping pull ups & pull downs\n",
+			'A' + jzgc->idx);
+		return -EINVAL;
+	}
+
+	err = devm_gpiochip_add_data(jzpc->dev, &jzgc->gc, NULL);
+	if (err)
+		return err;
+
+	if (!of_find_property(np, "interrupt-controller", NULL))
+		return 0;
+
+	jzgc->irq = irq_of_parse_and_map(np, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = jzgc->name;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int find_gpio_chip_by_of_node(struct gpio_chip *chip, void *data)
+{
+	return chip->of_node == data;
+}
+
+static int ingenic_pinctrl_parse_dt_pincfg(struct ingenic_pinctrl *jzpc,
+		struct ingenic_pinctrl_pin *pin, phandle cfg_handle)
+{
+	struct device_node *cfg_node;
+	int err;
+
+	cfg_node = of_find_node_by_phandle(cfg_handle);
+	if (!cfg_node)
+		return -EINVAL;
+
+	err = pinconf_generic_parse_dt_config(cfg_node, NULL,
+			&pin->configs, &pin->num_configs);
+	if (err)
+		return err;
+
+	err = devm_add_action(jzpc->dev, (void (*)(void *))kfree, pin->configs);
+	if (err) {
+		kfree(pin->configs);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
+		struct device_node *np, unsigned int *ifunc,
+		unsigned int *igroup)
+{
+	struct ingenic_pinctrl_func *func;
+	struct ingenic_pinctrl_group *grp;
+	struct device_node *group_node, *gpio_node;
+	struct gpio_chip *gpio_chip;
+	phandle gpio_handle, cfg_handle;
+	struct property *pp;
+	__be32 *plist;
+	unsigned int i, j;
+	int err;
+	const unsigned int vals_per_pin = 4;
+
+	func = &jzpc->funcs[(*ifunc)++];
+	func->of_node = np;
+	func->name = np->name;
+
+	func->num_groups = of_get_child_count(np);
+	func->groups = devm_kzalloc(jzpc->dev, sizeof(*func->groups) *
+			func->num_groups, GFP_KERNEL);
+	func->group_names = devm_kzalloc(jzpc->dev,
+			sizeof(*func->group_names) * func->num_groups,
+			GFP_KERNEL);
+	if (!func->groups || !func->group_names)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, group_node) {
+		pp = of_find_property(group_node, "ingenic,pins", NULL);
+		if (!pp)
+			return -EINVAL;
+		if ((pp->length / sizeof(__be32)) % vals_per_pin)
+			return -EINVAL;
+
+		grp = &jzpc->groups[(*igroup)++];
+		grp->of_node = group_node;
+		grp->name = group_node->name;
+		grp->num_pins = (pp->length / sizeof(__be32)) / vals_per_pin;
+		grp->pins = devm_kzalloc(jzpc->dev, sizeof(*grp->pins) *
+				grp->num_pins, GFP_KERNEL);
+		grp->pin_indices = devm_kzalloc(jzpc->dev,
+				sizeof(*grp->pin_indices) * grp->num_pins,
+				GFP_KERNEL);
+		if (!grp->pins)
+			return -EINVAL;
+
+		plist = pp->value;
+		for (j = 0; j < grp->num_pins; j++) {
+			gpio_handle = be32_to_cpup(plist++);
+			grp->pins[j].idx = be32_to_cpup(plist++);
+			grp->pins[j].func = be32_to_cpup(plist++);
+			cfg_handle = be32_to_cpup(plist++);
+
+			gpio_node = of_find_node_by_phandle(gpio_handle);
+			if (!gpio_node)
+				return -EINVAL;
+
+			gpio_chip = gpiochip_find(gpio_node,
+					find_gpio_chip_by_of_node);
+			if (!gpio_chip)
+				return -EINVAL;
+
+			grp->pins[j].gpio_chip = gc_to_jzgc(gpio_chip);
+
+			err = ingenic_pinctrl_parse_dt_pincfg(jzpc,
+					&grp->pins[j], cfg_handle);
+			if (err)
+				return err;
+
+			grp->pins[j].idx += grp->pins[j].gpio_chip->idx *
+				PINS_PER_GPIO_PORT;
+			grp->pin_indices[j] = grp->pins[j].idx;
+		}
+
+		func->groups[i] = grp;
+		func->group_names[i] = grp->name;
+		i++;
+	}
+
+	return 0;
+}
+
+int ingenic_pinctrl_probe(struct platform_device *pdev,
+		const struct ingenic_pinctrl_ops *ops)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct ingenic_gpio_chip *jzgc;
+	struct pinctrl_desc *pctl_desc;
+	struct device_node *np, *chips_node, *functions_node;
+	unsigned int i, j;
+	int err;
+
+	if (!dev->of_node) {
+		dev_err(dev, "device tree node not found\n");
+		return -ENODEV;
+	}
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	jzpc->dev = dev;
+	platform_set_drvdata(pdev, jzpc);
+
+	jzpc->base = 0;
+	of_property_read_u32(dev->of_node, "base", &jzpc->base);
+
+	chips_node = of_find_node_by_name(dev->of_node, "gpio-chips");
+	if (!chips_node) {
+		dev_err(dev, "Missing \"chips\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	jzpc->num_gpio_chips = of_get_available_child_count(chips_node);
+	if (!jzpc->num_gpio_chips) {
+		dev_err(dev, "No GPIO chips found\n");
+		return -EINVAL;
+	}
+
+	functions_node = of_find_node_by_name(dev->of_node, "functions");
+	if (!functions_node) {
+		dev_err(dev, "Missing \"functions\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	jzpc->num_funcs = of_get_available_child_count(functions_node);
+	if (!jzpc->num_funcs) {
+		dev_err(dev, "No functions found\n");
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(functions_node, np) {
+		jzpc->num_groups += of_get_available_child_count(np);
+	}
+
+	if (!jzpc->num_groups) {
+		dev_err(dev, "No groups found\n");
+		return -EINVAL;
+	}
+
+	/* allocate memory for GPIO chips, pin groups & functions */
+	jzpc->gpio_chips = devm_kzalloc(jzpc->dev, sizeof(*jzpc->gpio_chips) *
+			jzpc->num_gpio_chips, GFP_KERNEL);
+	jzpc->groups = devm_kzalloc(jzpc->dev, sizeof(*jzpc->groups) *
+			jzpc->num_groups, GFP_KERNEL);
+	jzpc->funcs = devm_kzalloc(jzpc->dev, sizeof(*jzpc->funcs) *
+			jzpc->num_funcs, GFP_KERNEL);
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!jzpc->gpio_chips || !jzpc->groups || !jzpc->funcs || !pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = jzpc->num_gpio_chips * PINS_PER_GPIO_PORT;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_PORT),
+						i % PINS_PER_GPIO_PORT);
+	}
+
+	/* Register GPIO chips */
+
+	i = 0;
+	for_each_child_of_node(chips_node, np) {
+		if (!of_find_property(np, "gpio-controller", NULL)) {
+			dev_err(dev, "GPIO chip missing \"gpio-controller\" flag\n");
+			return -EINVAL;
+		}
+
+		jzpc->gpio_chips[i].idx = i;
+		jzpc->gpio_chips[i].ops = ops;
+
+		err = ingenic_pinctrl_parse_dt_gpio(jzpc,
+				&jzpc->gpio_chips[i++], np);
+		if (err) {
+			dev_err(dev, "failed to register GPIO chip: %d\n", err);
+			return err;
+		}
+	}
+
+	i = 0;
+	j = 0;
+	for_each_child_of_node(functions_node, np) {
+		err = ingenic_pinctrl_parse_dt_func(jzpc, np, &i, &j);
+		if (err) {
+			dev_err(dev, "failed to parse function %s\n",
+					np->full_name);
+			return err;
+		}
+	}
+
+	for (i = 0; i < jzpc->num_groups; i++)
+		dev_dbg(dev, "group '%s'\n", jzpc->groups[i].name);
+	for (i = 0; i < jzpc->num_funcs; i++)
+		dev_dbg(dev, "func '%s'\n", jzpc->funcs[i].name);
+
+	jzpc->pctl = pinctrl_register(pctl_desc, dev, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed pinctrl registration\n");
+		return -EINVAL;
+	}
+
+	/* register pinctrl GPIO ranges */
+	for (i = 0; i < jzpc->num_gpio_chips; i++) {
+		jzgc = &jzpc->gpio_chips[i];
+
+		jzgc->grange.name = jzgc->name;
+		jzgc->grange.id = jzgc->idx;
+		jzgc->grange.pin_base = jzgc->idx * PINS_PER_GPIO_PORT;
+		jzgc->grange.base = jzgc->gc.base;
+		jzgc->grange.npins = jzgc->gc.ngpio;
+		jzgc->grange.gc = &jzgc->gc;
+		pinctrl_add_gpio_range(jzpc->pctl, &jzgc->grange);
+	}
+
+	return 0;
+}
diff --git a/drivers/pinctrl/ingenic/pinctrl-ingenic.h b/drivers/pinctrl/ingenic/pinctrl-ingenic.h
new file mode 100644
index 000000000000..76cb7ffa68e5
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-ingenic.h
@@ -0,0 +1,42 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef PINCTRL_INGENIC_H
+#define PINCTRL_INGENIC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+struct platform_device;
+
+struct ingenic_pinctrl_ops {
+	unsigned int nb_functions;
+
+	void (*set_function)(void __iomem *base,
+			unsigned int offset, unsigned int function);
+	void (*set_gpio)(void __iomem *base, unsigned int offset, bool output);
+	int  (*get_bias)(void __iomem *base, unsigned int offset);
+	void (*set_bias)(void __iomem *base, unsigned int offset, bool enable);
+	void (*gpio_set_value)(void __iomem *base,
+			unsigned int offset, int value);
+	int  (*gpio_get_value)(void __iomem *base, unsigned int offset);
+	u32  (*irq_read)(void __iomem *base);
+	void (*irq_mask)(void __iomem *base, unsigned int irq, bool mask);
+	void (*irq_ack)(void __iomem *base, unsigned int irq);
+	void (*irq_set_type)(void __iomem *base,
+			unsigned int irq, unsigned int type);
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev,
+		const struct ingenic_pinctrl_ops *ops);
+
+#endif /* PINCTRL_INGENIC_H */
diff --git a/drivers/pinctrl/ingenic/pinctrl-jz4740.c b/drivers/pinctrl/ingenic/pinctrl-jz4740.c
new file mode 100644
index 000000000000..ae0b9d903258
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-jz4740.c
@@ -0,0 +1,190 @@
+/*
+ * Ingenic jz4740 pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include "pinctrl-ingenic.h"
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* GPIO port register offsets */
+#define GPIO_PIN	0x00
+#define GPIO_DATA	0x10
+#define GPIO_DATAS	0x14
+#define GPIO_DATAC	0x18
+#define GPIO_MASK	0x20
+#define GPIO_MASKS	0x24
+#define GPIO_MASKC	0x28
+#define GPIO_PULL_DIS	0x30
+#define GPIO_PULL_DISS	0x34
+#define GPIO_PULL_DISC	0x38
+#define GPIO_FUNC	0x40
+#define GPIO_FUNCS	0x44
+#define GPIO_FUNCC	0x48
+#define GPIO_SELECT	0x50
+#define GPIO_SELECTS	0x54
+#define GPIO_SELECTC	0x58
+#define GPIO_DIR	0x60
+#define GPIO_DIRS	0x64
+#define GPIO_DIRC	0x68
+#define GPIO_TRIG	0x70
+#define GPIO_TRIGS	0x74
+#define GPIO_TRIGC	0x78
+#define GPIO_FLAG	0x80
+#define GPIO_FLAGC	0x14
+#define GPIO_REGS_SIZE	0x100
+
+static void jz4740_set_gpio(void __iomem *base,
+		unsigned int offset, bool output)
+{
+	writel(1 << offset, base + GPIO_FUNCC);
+	writel(1 << offset, base + GPIO_SELECTC);
+	writel(1 << offset, base + GPIO_TRIGC);
+
+	if (output)
+		writel(1 << offset, base + GPIO_DIRS);
+	else
+		writel(1 << offset, base + GPIO_DIRC);
+}
+
+static int jz4740_get_bias(void __iomem *base, unsigned int offset)
+{
+	return !((readl(base + GPIO_PULL_DIS) >> offset) & 0x1);
+}
+
+static void jz4740_set_bias(void __iomem *base,
+		unsigned int offset, bool enable)
+{
+	if (enable)
+		writel(1 << offset, base + GPIO_PULL_DISC);
+	else
+		writel(1 << offset, base + GPIO_PULL_DISS);
+}
+
+static void jz4740_gpio_set_value(void __iomem *base,
+		unsigned int offset, int value)
+{
+	if (value)
+		writel(1 << offset, base + GPIO_DATAS);
+	else
+		writel(1 << offset, base + GPIO_DATAC);
+}
+
+static int jz4740_gpio_get_value(void __iomem *base, unsigned int offset)
+{
+	return (readl(base + GPIO_DATA) >> offset) & 0x1;
+}
+
+static u32 jz4740_irq_read(void __iomem *base)
+{
+	return readl(base + GPIO_FLAG);
+}
+
+static void jz4740_irq_mask(void __iomem *base, unsigned int irq, bool mask)
+{
+	if (mask)
+		writel(1 << irq, base + GPIO_MASKS);
+	else
+		writel(1 << irq, base + GPIO_MASKC);
+}
+
+static void jz4740_irq_ack(void __iomem *base, unsigned int irq)
+{
+	writel(1 << irq, base + GPIO_FLAGC);
+}
+
+static void jz4740_irq_set_type(void __iomem *base,
+		unsigned int offset, unsigned int type)
+{
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		writel(1 << offset, base + GPIO_DIRS);
+		writel(1 << offset, base + GPIO_TRIGS);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		writel(1 << offset, base + GPIO_DIRC);
+		writel(1 << offset, base + GPIO_TRIGS);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		writel(1 << offset, base + GPIO_DIRS);
+		writel(1 << offset, base + GPIO_TRIGC);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		writel(1 << offset, base + GPIO_DIRC);
+		writel(1 << offset, base + GPIO_TRIGC);
+		break;
+	}
+}
+
+static void jz4740_set_function(void __iomem *base,
+		unsigned int offset, unsigned int func)
+{
+	writel(1 << offset, base + GPIO_FUNCS);
+	writel(1 << offset, base + GPIO_TRIGC);
+
+	switch (func) {
+	case 2:
+		writel(1 << offset, base + GPIO_TRIGS);
+	case 1: /* fallthrough */
+		writel(1 << offset, base + GPIO_SELECTS);
+		break;
+	case 0:
+	default:
+		writel(1 << offset, base + GPIO_SELECTC);
+		break;
+	}
+}
+
+static const struct ingenic_pinctrl_ops jz4740_pinctrl_ops = {
+	.nb_functions	= 3,
+	.set_function	= jz4740_set_function,
+	.set_gpio	= jz4740_set_gpio,
+	.set_bias	= jz4740_set_bias,
+	.get_bias	= jz4740_get_bias,
+	.gpio_set_value	= jz4740_gpio_set_value,
+	.gpio_get_value	= jz4740_gpio_get_value,
+	.irq_read	= jz4740_irq_read,
+	.irq_mask	= jz4740_irq_mask,
+	.irq_ack	= jz4740_irq_ack,
+	.irq_set_type	= jz4740_irq_set_type,
+};
+
+static int jz4740_pinctrl_probe(struct platform_device *pdev)
+{
+	return ingenic_pinctrl_probe(pdev, &jz4740_pinctrl_ops);
+}
+
+static const struct of_device_id jz4740_pinctrl_dt_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4740_pinctrl_dt_match);
+
+
+static struct platform_driver jz4740_pinctrl_driver = {
+	.driver = {
+		.name = "jz4740-pinctrl",
+		.of_match_table = of_match_ptr(jz4740_pinctrl_dt_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = jz4740_pinctrl_probe,
+};
+
+static int __init jz4740_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&jz4740_pinctrl_driver);
+}
+postcore_initcall(jz4740_pinctrl_drv_register);
diff --git a/include/dt-bindings/pinctrl/ingenic.h b/include/dt-bindings/pinctrl/ingenic.h
new file mode 100644
index 000000000000..19eb173844b1
--- /dev/null
+++ b/include/dt-bindings/pinctrl/ingenic.h
@@ -0,0 +1,11 @@
+#ifndef DT_BINDINGS_PINCTRL_INGENIC_H
+#define DT_BINDINGS_PINCTRL_INGENIC_H
+
+#define JZ_PIN_MODE_FUNCTION_0	0
+#define JZ_PIN_MODE_FUNCTION_1	1
+#define JZ_PIN_MODE_FUNCTION_2	2
+#define JZ_PIN_MODE_FUNCTION_3	3
+
+#define JZ_PIN_MODE_GPIO	255
+
+#endif /* DT_BINDINGS_PINCTRL_INGENIC_H */
-- 
2.11.0

^ permalink raw reply related

* [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil
In-Reply-To: <20170117231421.16310-1-paul@crapouillou.net>

From: Paul Burton <paul.burton@imgtec.com>

This commit adds documentation for the devicetree bidings of the
pinctrl-ingenic driver, which handles pin configuration, pin muxing
and GPIOs of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 173 +++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..e59f7e7b6a49
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,173 @@
+Ingenic jz47xx pin controller
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+##### Pin controller node #####
+
+Required properties:
+- compatible: One of:
+  - "ingenic,jz4740-pinctrl"
+  - "ingenic,jz4780-pinctrl"
+- #address-cells: Should contain the integer 1.
+- #size-cells: Should contain the integer 1.
+- ranges: Should be empty.
+
+Required sub-nodes:
+  - gpio-chips (see below)
+  - functions (see below)
+
+The pin controller node must have two sub-nodes, 'gpio-chips' and 'functions'.
+
+
+##### 'gpio-chips' sub-node #####
+
+The gpio-chips node will contain sub-nodes that correspond to GPIO controllers
+(one sub-node per GPIO controller).
+
+Required properties:
+- #address-cells: Should contain the integer 1.
+- #size-cells: Should contain the integer 1.
+- ranges: Should be empty.
+
+
+##### 'functions' sub-node #####
+
+The "functions" node will contain sub-nodes that correspond to pin function
+nodes.
+
+Required properties:
+- None.
+
+
+##### GPIO controller node #####
+
+Each subnode of the 'gpio-chips' node is a GPIO controller node.
+
+Required properties:
+- gpio-controller: Identifies this node as a GPIO controller.
+- #gpio-cells: Should contain the integer 2.
+- reg: Should contain the physical address and length of the GPIO controller's
+  configuration registers.
+
+Optional properties:
+- interrupt-controller: The GPIO controllers can optionally configure the
+  GPIOs as interrupt sources. In this case, the 'interrupt-controller'
+  standalone property should be supplied.
+- #interrupt-cells: Required if 'interrupt-controller' is also specified.
+  In that case, it should contain the integer 2.
+- interrupts: Required if 'interrupt-controller' is also specified.
+  In that case, it should contain the IRQ number of this GPIO controller.
+- ingenic,pull-ups: A bit mask identifying the pins associated with this GPIO
+  port which feature a pull-up resistor. The default mask is 0x0.
+- ingenic,pull-downs: A bit mask identifying the pins associated with this GPIO
+  port which feature a pull-down resistor. The default mask is 0x0.
+  Each pin of the jz47xx SoCs may feature a single bias resistor, thus there
+  should be no bits which are set in both ingenic,pull-ups & ingenic,pull-downs.
+
+
+##### Pin function node #####
+
+Each subnode of the 'functions' node is a pin function node.
+
+These subnodes represent a functionality of the SoC which may be exposed
+through one or more groups of pins, represented as subnodes of the pin
+function node. For example a function may be uart0, which may be exposed
+through the group of pins PF0 to PF3.
+
+Required pin function node properties:
+- None.
+
+
+##### Pin group node #####
+
+Each subnode of a pin function node is a pin group node.
+
+Required pin group node properties:
+- ingenic,pins: A set of values representing the pins within this pin group and
+  their configuration. Four values should be provided for each pin:
+  - The phandle of the GPIO controller node for the GPIO port within which the
+    pin is found.
+  - The index of the pin within its GPIO port (an integer in the range 0 to 31
+    inclusive).
+  - The index of the shared function port to be programmed in the GPIO port
+    registers for this pin.
+    Tables of these may be found in the jz4740 and jz4780 programming
+    manuals within the "General-Purpose I/O Ports" -> "Overview" section.
+    The value can either be supplied directly (0 for function 0, 1 for
+    function 1, etc.) or using the macros present in
+    <dt-bindings/pinctrl/ingenic.h>.
+    The special macro JZ_PIN_MODE_GPIO can be used to specify that the pin is
+    to be used as a GPIO. This is useful, for instance, when you just want to
+    set the electrical configuration of a pin used as GPIO.
+  - The phandle of a pin configuration node specifying the electrical
+    configuration that should be applied to the pin.
+
+For example the function 'msc0' may be exposed through 2 different pin groups,
+one in GPIO port A and one in GPIO port E:
+
+  bias-configs {
+    nobias: nobias {
+      bias-disable;
+    };
+  };
+
+  functions {
+    pinfunc_msc0: msc0 {
+      pins_msc0_pa: msc0-pa {
+        ingenic,pins = <&gpa  4 1 &nobias   /* d4 */
+                        &gpa  5 1 &nobias   /* d5 */
+                        &gpa  6 1 &nobias   /* d6 */
+                        &gpa  7 1 &nobias   /* d7 */
+                        &gpa 18 1 &nobias   /* clk */
+                        &gpa 19 1 &nobias   /* cmd */
+                        &gpa 20 1 &nobias   /* d0 */
+                        &gpa 21 1 &nobias   /* d1 */
+                        &gpa 22 1 &nobias   /* d2 */
+                        &gpa 23 1 &nobias   /* d3 */
+                        &gpa 24 1 &nobias>; /* rst */
+      };
+
+      pins_msc0_pe: msc0-pe {
+        ingenic,pins = <&gpe 20 0 &nobias   /* d0 */
+                        &gpe 21 0 &nobias   /* d1 */
+                        &gpe 22 0 &nobias   /* d2 */
+                        &gpe 23 0 &nobias   /* d3 */
+                        &gpe 28 0 &nobias   /* clk */
+                        &gpe 29 0 &nobias>; /* cmd */
+      };
+    };
+  };
+
+
+##### Pin configuration node #####
+
+The pin configuration nodes are referenced by phandle, and can be placed
+anywhere in the device tree (including in the pin controller node, or in a
+sub-node that is not 'gpio-chips' or 'functions').
+
+Pin configuration nodes use generic pinconf properties to specify an electrical
+configuration of a pin. The only configurable property for a pin of the jz47xx
+SoCs is whether to enable its bias resistor. Thus the only supported pinconf
+properties are:
+
+- bias-disable
+- bias-pull-up
+- bias-pull-down
+
+No arguments are supported for any of these properties.
+
+For more information about generic pinconfig properties, see
+Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
-- 
2.11.0

^ permalink raw reply related

* [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne, Lars-Peter Clausen,
	Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan

Hi,

This set of patches introduces a new pinctrl driver for the Ingenic
JZ4740 and JZ4780, which handles pin configuration, pin muxing and
GPIO config for those MIPS SoCs.

The initial driver was developed by to Paul Burton, so I'll expect his
Signed-Off-By to be added to each patch. It has been severely modified
and improved by myself, notably to add support for the JZ4740 (the
initial non-upstream driver only handled the JZ4780).

I successfully tested it on Imagination Technologies' CI20 board (JZ4780),
as well as on the Dingoo A320 chinese handheld console (JZ4740).

One patch in this series add a pinctrl configuration for some drivers
instanciated in the QI LB60 devicetree. Since I don't own this device,
this one patch was not tested.

Some words about the driver itself:
- pinctrl-ingenic.c contains the core functions that can be shared
  across all Ingenic SoCs,
- pinctrl-jz4740.c contains the JZ4740-specific low-level functions and
  the jz4740-pinctrl driver,
- pinctrl-jz4780.c contains the JZ4780-specific low-level functions and
  the jz4780-pinctrl driver.

The reason behind using a common file sharing core functions and backend
ops for each SoC version, is that the pin/GPIO controllers of the Ingenic
SoCs are extremely similar across SoC versions, except that some have the
registers shuffled around. Making a distinct separation permits the reuse
of large parts of the driver to support the two SoC versions.

One problem still unresolved: the pinctrl framework does not allow us to
configure each pin on demand (someone please prove me wrong), when the
various PWM channels are requested or released. For instance, the PWM
channels can be configured from sysfs, which would require all PWM pins
to be configured properly beforehand for the PWM function, eventually
causing conflicts with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) could configure all of its connected PWM pins in PWM function
mode, if those are not used by other drivers nor by GPIOs on the
board. The only jz4780 board upstream (CI20) does not yet support the
PWM driver.

^ permalink raw reply

* Re: [PATCH 1/2] ARM64: dts: meson-gxm: Add R-Box Pro
From: Andreas Färber @ 2017-01-17 23:06 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Mark Rutland, devicetree, Kevin Hilman, Will Deacon, linux-kernel,
	Rob Herring, Catalin Marinas, Carlo Caione, linux-arm-kernel
In-Reply-To: <20170117030611.23827-2-afaerber@suse.de>

Am 17.01.2017 um 04:06 schrieb Andreas Färber:
> diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
> index 0d7bfbf7d922..66bc809a5eae 100644
> --- a/arch/arm64/boot/dts/amlogic/Makefile
> +++ b/arch/arm64/boot/dts/amlogic/Makefile
> @@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-nexbox-a95x.dtb
>  dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-q200.dtb
>  dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-q201.dtb
>  dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb

What is the logic behind meson-gxm-s912-q201 vs. meson-gxm-nexbox-a1?
Should it be renamed to include -s912 for consistency?

> +dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb

Should this new board use meson-gxm-s912-?

>  
>  always		:= $(dtb-y)
>  subdir-y	:= $(dts-dirs)

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 3/3] ARM64: dts: meson-gxm-rbox-pro: Add board compatible string
From: Andreas Färber @ 2017-01-17 22:54 UTC (permalink / raw)
  To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Carlo Caione, Kevin Hilman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andreas Färber,
	ada-MUr+2Ic57fgS+FvcfC7Uqw, Rob Herring, Mark Rutland,
	Catalin Marinas, Will Deacon, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170117225459.4438-1-afaerber-l3A5Bk7waGM@public.gmane.org>

Cc: ada-MUr+2Ic57fgS+FvcfC7Uqw@public.gmane.org
Signed-off-by: Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org>
---
 To be squashed in v2.
 
 arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
index 6ea225f584bd..7ff02754cfde 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
@@ -53,7 +53,7 @@
 #include "meson-gxm.dtsi"
 
 / {
-	compatible = "amlogic,s912", "amlogic,meson-gxm";
+	compatible = "kingnovel,r-box-pro", "amlogic,s912", "amlogic,meson-gxm";
 	model = "R-Box Pro";
 
 	aliases {
-- 
2.10.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 related

* [PATCH 2/3] Documentation: devicetree: amlogic: Add R-Box Pro
From: Andreas Färber @ 2017-01-17 22:54 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Carlo Caione, Kevin Hilman, linux-arm-kernel, linux-kernel,
	Andreas Färber, ada, Rob Herring, Mark Rutland, devicetree
In-Reply-To: <20170117225459.4438-1-afaerber@suse.de>

Cc: ada@kingnoval.com
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 Originally I thought we would group by SoC (6, 8, 8b, gxbb, gxl, gmx, etc.)
 but this got out of order with nexbox,a95x - so inserting kingnovel between
 amlogic and nexbox here. If that's what we want going forward, we should move
 the old entries to make the scheme clearer. The alternative would be to
 reorder alphabetically within each SoC group, but nexbox,a95x with two SoCs
 makes it difficult to categorize, we could choose gxbb as the earlier one.
 
 Documentation/devicetree/bindings/arm/amlogic.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
index 9b2b41ab6817..fb0ee7d9a921 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.txt
+++ b/Documentation/devicetree/bindings/arm/amlogic.txt
@@ -45,5 +45,6 @@ Board compatible values:
   - "amlogic,p231" (Meson gxl s905d)
   - "amlogic,q200" (Meson gxm s912)
   - "amlogic,q201" (Meson gxm s912)
+  - "kingnovel,r-box-pro" (Meson gxm S912)
   - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
   - "nexbox,a1" (Meson gxm s912)
-- 
2.10.2

^ permalink raw reply related

* [PATCH 1/3] Documentation: devicetree: Add Kingnovel vendor prefix
From: Andreas Färber @ 2017-01-17 22:54 UTC (permalink / raw)
  To: linux-amlogic
  Cc: Mark Rutland, devicetree, Kevin Hilman, linux-kernel, Rob Herring,
	Carlo Caione, ada, Andreas Färber, linux-arm-kernel
In-Reply-To: <20170117030611.23827-2-afaerber@suse.de>

Their domain name is spelled kingnoval, but textually Kingnovel.

Cc: ada@kingnoval.com
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 14fd1c24e1f0..b38301c4f3f0 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -156,6 +156,7 @@ karo	Ka-Ro electronics GmbH
 keithkoep	Keith & Koep GmbH
 keymile	Keymile GmbH
 kinetic Kinetic Technologies
+kingnovel	Kingnovel Technology Co., Ltd.
 kosagi	Sutajio Ko-Usagi PTE Ltd.
 kyo	Kyocera Corporation
 lacie	LaCie
-- 
2.10.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCHv2] Documentation: dt-bindings: Add binding documentation for TI clkctrl clocks
From: Tony Lindgren @ 2017-01-17 22:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Tero Kristo
  Cc: devicetree, linux-clk, linux-omap, Paul Walmsley, Rob Herring

Texas Instruments omap variant SoCs starting with omap4 have a clkctrl
clock controller instance for each interconnect target module. The clkctrl
controls functional and interface clocks for the module.

The clkctrl clocks are currently handled by arch/arm/mach-omap2 hwmod code.
With this binding and a related clock device driver we can start moving the
clkctrl clock handling to live in drivers/clk/ti.

Note that this binding allows keeping the clockdomain related parts out of
drivers/clock. The CLKCTCTRL and DYNAMICDEP registers can be handled by
a separate driver in drivers/soc/ti and genpd. If the clockdomain driver
needs to know it's clocks, we can just set the the clkctrl device
instances to be children of the related clockdomain device.

Each clkctrl clock can have multiple optional gate clocks, and multiple
optional mux clocks. To represent this in device tree, it seems that
it is best done using four clock cells #clock-cells = <4> property.

The reasons for using #clock-cells = <4> are:

1. We need to specify the clkctrl offset from the instance base. Otherwise
   we end up with a large number of device tree nodes that need to be
   patched when new clocks are discovered in a clkctrl clock with minor
   hardware revision changes for example

2. On omap5 CM_L3INIT_USB_HOST_HS_CLKCTRL has ten OPTFCLKEN bits. So we
   need to use a separate cell for optional gate clocks to avoid address
   space conflicts

3. Some clkctrl instances can also also optional mux clocks. To address
   them properly we need also a separate cell for the optional mux
   clock index

4. The modulemode clock needs a flag passed to it for hardware or
   software controlled mode

There is probably no need to list input clocks for each clkctrl clock
instance in the binding. If we want to add them, the standard clocks
binding can be used for that.

For hardware reference, see omap4430 TRM "Table 3-1312. L4PER_CM2 Registers
Mapping Summary" for example. It shows one instance of a clkctrl clock
controller with multiple clkctrl registers.

Cc: Paul Walmsley <paul@pwsan.com>
Cc: Rob Herring <robh@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---

Changes from v1:

- Use #clock-cells to avoid address space conflicts

- Consider also optional mux clocks as pointed out by Tero

---
 .../devicetree/bindings/clock/ti-clkctrl.txt       | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/ti-clkctrl.txt

diff --git a/Documentation/devicetree/bindings/clock/ti-clkctrl.txt b/Documentation/devicetree/bindings/clock/ti-clkctrl.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ti-clkctrl.txt
@@ -0,0 +1,57 @@
+Texas Instruments clkctrl clock binding
+
+Texas Instruments SoCs can have a clkctrl clock controller for each
+interconnect target module. The clkctrl clock controller manages functional
+and interface clocks for each module. Each clkctrl controller can also
+gate one or more optional functional clocks for a module, and can have one
+or more clock muxes. There is a clkctrl clock controller typically for each
+interconnect target module on omap4 and later variants.
+
+The clock consumers can specify the index of the clkctrl clock using
+the hardware offset from the clkctrl instance register space. The optional
+clocks can be specified by clkctrl hardware offset and the index of the
+optional clock.
+
+For more information, please see the Linux clock framework binding at
+Documentation/devicetree/bindings/clock/clock-bindings.txt.
+
+Required properties :
+- compatible : shall be "ti,clkctrl"
+- #clock-cells : shall contain 4 with the first entry being the instance
+		 offset from the clock domain base, the second being the
+		 clock index, the third being the optional clock mux index,
+		 and fourth being the clock flags
+
+Example: Clock controller node on omap 4430:
+
+&cm2 {
+	l4per: cm@1400 {
+		cm_l4per@0 {
+			cm_l4per_clkctrl: clk@20 {
+				compatible = "ti,clkctrl";
+				reg = <0x20 0x1b0>;
+				#clock-cells = <4>;
+			};
+		};
+	};
+};
+
+Example: Preprocessor helper macros in dt-bindings/clock/ti-clkctrl.h
+
+#define OMAP4_CLKCTRL_OFFSET		0x20
+#define OMAP4_CLKCTRL_INDEX(offset)	((offset) - OMAP4_CLKCTRL_OFFSET)
+#define MODULEMODE_HWCTRL		1
+#define MODULEMODE_SWCTRL		2
+
+#define OMAP4_GPTIMER10_CLKTRL		OMAP4_CLKCTRL_INDEX(0x28)
+#define OMAP4_GPTIMER11_CLKTRL		OMAP4_CLKCTRL_INDEX(0x30)
+#define OMAP4_GPTIMER2_CLKTRL		OMAP4_CLKCTRL_INDEX(0x38)
+...
+#define OMAP4_GPIO2_CLKCTRL		OMAP_CLKCTRL_INDEX(0x60)
+
+Example: Clock consumer node for GPIO2:
+
+&gpio2 {
+       clocks = <&cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 0 0 MODULEMODE_HWCTRL
+		 &cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 8 0 0>;
+};
-- 
2.11.0

^ permalink raw reply

* Re: [PATCH 0/5] meson-gx: reset RGMII PHYs and configure TX delay
From: Martin Blumenstingl @ 2017-01-17 22:44 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, will.deacon-5wv7dgnIgG8,
	catalin.marinas-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <1484691981.26620.55.camel-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>

On Tue, Jan 17, 2017 at 11:26 PM, Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> On Tue, 2017-01-17 at 22:09 +0100, Martin Blumenstingl wrote:
>> On Tue, Jan 17, 2017 at 8:23 PM, Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> wrote:
>> >
>> > On Sat, 2016-12-03 at 00:47 +0100, Martin Blumenstingl wrote:
>> > >
>> > > This partially fixes the 1000Mbit/s ethernet TX throughput issues
>> > > (on
>> > > networks which are not affected by the EEE problem, as reported
>> > > here:
>> > > [1]).
>> > > The actual problem for the TX throughput issues was that the TX
>> > > delay
>> > > was applied twice:
>> > > - once "accidentally" by the PHY (this was fixed with [2])
>> > > - once by the MAC because there was a hardcoded TX delay (of
>> > > 2ns),
>> > >   this will be configurable with the changes from [0]
>> > >
>> > > These are the dts changes which belong to my other series (in v2
>> > > these patches were part of the other series, upon request of the
>> > > net maintainers I have split the .dts changes into their own
>> > > series
>> > > so
>> > > we are able to take both through different trees):
>> > > "[PATCH net-next v3 0/2] stmmac: dwmac-meson8b: configurable
>> > > RGMII TX delay": [0].
>> > > Thus this series depends on the ACK for the binding changes in
>> > > the
>> > > other series!
>> > >
>> > > I based these changes on my other series "[PATCH v2 0/2] GXL and
>> > > GXM
>> > > SCPI improvements": [3]
>> > >
>> > >
>> > > [0] http://lists.infradead.org/pipermail/linux-amlogic/2016-Decem
>> > > ber/
>> > > 001834.html
>> > > [1] http://lists.infradead.org/pipermail/linux-amlogic/2016-Novem
>> > > ber/
>> > > 001607.html
>> > > [2] http://lists.infradead.org/pipermail/linux-amlogic/2016-Novem
>> > > ber/
>> > > 001707.html
>> > > [3] http://lists.infradead.org/pipermail/linux-amlogic/2016-Decem
>> > > ber/
>> > > 001831.html
>> > >
>> > > Martin Blumenstingl (5):
>> > >   ARM64: dts: meson-gx: move the MDIO node to meson-gx
>> >
>> > Sorry for the late reply, I've only been able to test this
>> > yesterday.
>> >
>> > With "snps,dwmac-mdio" provided in meson-gx.dtsi, the mdio_node is
>> > defined in stmmac_mdio_register and auto-detection of the PHY is
>> > disabled for all meson-gx boards.
>> >
>> > I wonder if this is desirable ? or maybe this something we could
>> > fix in
>> > stmmac ? (perform auto-detect the mdio bus is provided without a
>> > PHY)
>> actually it's only a "problem" when introducing support for new
>> devices. can you please forward this question to the stmmac
>> maintainers, as I think your idea of enabling auto-detection when
>> there are no children in the MDIO-bus makes sense
>
> That's one way to address the issue, sure. I just wonder if we should
> keep the declaration of the mdio bus with "snps,dwmac-mdio" in the dts
> using it, with the phy explicitly declared ...
>
> Otherwise, we have to make clear that you must always explicitly
> declare your PHY in amlogic's dts so there is no surprise.
>
> As you mentioned, we missed the gxbb-nexbox-a95. No phy declared in
> that dts, but it still get the mdio bus from meson-gx.dtsi. So as of
> "ARM64: dts: meson-gx: move the MDIO node to meson-gx" the PHY is not
> detected on this board.
indeed, however I'd like to point out that this was already a
restriction for GXL and GXM based boards before.
I'm open to any solution though as breaking things is always bad

>>
>> >
>> > Also, I think bisect is broken between patch 1 and patch 4: The PHY
>> > of
>> > some boards won't be detected between these patches. Should we
>> > squash
>> > them ?
>> what do you mean exactly? currently the TX-delay is hardcoded in
>> dwmac-meson8b. patch 4 moves the hardcoded value from the
>> dwmac-meson8b to the .dts-files.
>> unfortunately the corresponding dwmac-meson8b patch was not accepted
>> yet, so at the moment patch 4 should be a no-op.
>
> Nothing related to the tx-delay ... I'm all for it ;) Thx for your work
> by the way
>
> What I meant is that as of "ARM64: dts: meson-gx: move the MDIO node to
> meson-gx" all boards not declaring the PHY explicitly can't detect it
> anymore. that's more or less all gxbb boards
>
> With "ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY"
> the odroid gets fixed ... but the p200 and vega-s95 are still broken
>
> With the next patch, the p200 is/should have been fixed, then the vega-
> s95 is fixed
>
> In the end the gxbb-nexbox is still broken. To be honest I did not
> verify if there any other board in that case.
>
> My point is that I think the declaration of the mdio bus in meson-
> gx.dtsi and the declaration of each PHY in the board dtss should be
> done in single commit to avoid having a (very) short part of the
> history with regressions
now I see the dependency, thanks for pointing this out!
Depending on the decision for above problem (MDIO-bus in meson-gx.dtsi
or not) I can provide a v2 with all issues addressed.


>>
>> >
>> > >
>> > >   ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY
>> > >   ARM64: dts: meson-gxbb-p20x: add reset for the ethernet PHY
>> > >   ARM64: dts: meson-gxbb-vega-s95: add reset for the ethernet PHY
>> > >   ARM64: dts: amlogic: add the ethernet TX delay configuration
>> > >
>> >
>> > Last remark, about the use of ethernet-phy-idXXXX.XXXX in the
>> > odroid
>> > and the vega: Isn't it better to let phylib do the autodetection of
>> > the
>> > phy id ?
>> >
>> > If we want to specify the id in DT, we should probably add it for
>> > the
>> > Micrel PHY of the p200 as well, for consistency.
>> this seems to be a "best practice" when the PHY ID is known, see [0]
>> If you know the PHY ID of the Micrel PHY then please let me know,
>> then
>> we can include this in the fix for the p20x boards
>
> OK
>
>>
>> >
>> > >
>> > >  arch/arm64/boot/dts/amlogic/meson-gx.dtsi            |  6 ++++++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts  | 17
>> > > +++++++++++++++++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi     | 17
>> > > +++++++++++++++++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 17
>> > > +++++++++++++++++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts |  2 ++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi           |  6 ------
>> > >  arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts  |  2 ++
>> > >  arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts  |  2 ++
>> > >  8 files changed, 63 insertions(+), 6 deletions(-)
>> > >
>>
>> [0] http://lxr.free-electrons.com/source/Documentation/devicetree/bin
>> dings/net/phy.txt#L22
--
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 0/5] meson-gx: reset RGMII PHYs and configure TX delay
From: Jerome Brunet @ 2017-01-17 22:26 UTC (permalink / raw)
  To: Martin Blumenstingl
  Cc: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, will.deacon-5wv7dgnIgG8,
	catalin.marinas-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <CAFBinCDvtufXUxe+cRCzOKFtbOqS-xEr0Vp=_0S4Pn+sTPHOmg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue, 2017-01-17 at 22:09 +0100, Martin Blumenstingl wrote:
> On Tue, Jan 17, 2017 at 8:23 PM, Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> wrote:
> > 
> > On Sat, 2016-12-03 at 00:47 +0100, Martin Blumenstingl wrote:
> > > 
> > > This partially fixes the 1000Mbit/s ethernet TX throughput issues
> > > (on
> > > networks which are not affected by the EEE problem, as reported
> > > here:
> > > [1]).
> > > The actual problem for the TX throughput issues was that the TX
> > > delay
> > > was applied twice:
> > > - once "accidentally" by the PHY (this was fixed with [2])
> > > - once by the MAC because there was a hardcoded TX delay (of
> > > 2ns),
> > >   this will be configurable with the changes from [0]
> > > 
> > > These are the dts changes which belong to my other series (in v2
> > > these patches were part of the other series, upon request of the
> > > net maintainers I have split the .dts changes into their own
> > > series
> > > so
> > > we are able to take both through different trees):
> > > "[PATCH net-next v3 0/2] stmmac: dwmac-meson8b: configurable
> > > RGMII TX delay": [0].
> > > Thus this series depends on the ACK for the binding changes in
> > > the
> > > other series!
> > > 
> > > I based these changes on my other series "[PATCH v2 0/2] GXL and
> > > GXM
> > > SCPI improvements": [3]
> > > 
> > > 
> > > [0] http://lists.infradead.org/pipermail/linux-amlogic/2016-Decem
> > > ber/
> > > 001834.html
> > > [1] http://lists.infradead.org/pipermail/linux-amlogic/2016-Novem
> > > ber/
> > > 001607.html
> > > [2] http://lists.infradead.org/pipermail/linux-amlogic/2016-Novem
> > > ber/
> > > 001707.html
> > > [3] http://lists.infradead.org/pipermail/linux-amlogic/2016-Decem
> > > ber/
> > > 001831.html
> > > 
> > > Martin Blumenstingl (5):
> > >   ARM64: dts: meson-gx: move the MDIO node to meson-gx
> > 
> > Sorry for the late reply, I've only been able to test this
> > yesterday.
> > 
> > With "snps,dwmac-mdio" provided in meson-gx.dtsi, the mdio_node is
> > defined in stmmac_mdio_register and auto-detection of the PHY is
> > disabled for all meson-gx boards.
> > 
> > I wonder if this is desirable ? or maybe this something we could
> > fix in
> > stmmac ? (perform auto-detect the mdio bus is provided without a
> > PHY)
> actually it's only a "problem" when introducing support for new
> devices. can you please forward this question to the stmmac
> maintainers, as I think your idea of enabling auto-detection when
> there are no children in the MDIO-bus makes sense

That's one way to address the issue, sure. I just wonder if we should
keep the declaration of the mdio bus with "snps,dwmac-mdio" in the dts
using it, with the phy explicitly declared ...

Otherwise, we have to make clear that you must always explicitly
declare your PHY in amlogic's dts so there is no surprise.

As you mentioned, we missed the gxbb-nexbox-a95. No phy declared in
that dts, but it still get the mdio bus from meson-gx.dtsi. So as of
"ARM64: dts: meson-gx: move the MDIO node to meson-gx" the PHY is not
detected on this board.

> 
> > 
> > Also, I think bisect is broken between patch 1 and patch 4: The PHY
> > of
> > some boards won't be detected between these patches. Should we
> > squash
> > them ?
> what do you mean exactly? currently the TX-delay is hardcoded in
> dwmac-meson8b. patch 4 moves the hardcoded value from the
> dwmac-meson8b to the .dts-files.
> unfortunately the corresponding dwmac-meson8b patch was not accepted
> yet, so at the moment patch 4 should be a no-op.

Nothing related to the tx-delay ... I'm all for it ;) Thx for your work
by the way

What I meant is that as of "ARM64: dts: meson-gx: move the MDIO node to
meson-gx" all boards not declaring the PHY explicitly can't detect it
anymore. that's more or less all gxbb boards

With "ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY"
the odroid gets fixed ... but the p200 and vega-s95 are still broken 

With the next patch, the p200 is/should have been fixed, then the vega-
s95 is fixed 

In the end the gxbb-nexbox is still broken. To be honest I did not
verify if there any other board in that case.

My point is that I think the declaration of the mdio bus in meson-
gx.dtsi and the declaration of each PHY in the board dtss should be
done in single commit to avoid having a (very) short part of the
history with regressions

> 
> > 
> > > 
> > >   ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY
> > >   ARM64: dts: meson-gxbb-p20x: add reset for the ethernet PHY
> > >   ARM64: dts: meson-gxbb-vega-s95: add reset for the ethernet PHY
> > >   ARM64: dts: amlogic: add the ethernet TX delay configuration
> > > 
> > 
> > Last remark, about the use of ethernet-phy-idXXXX.XXXX in the
> > odroid
> > and the vega: Isn't it better to let phylib do the autodetection of
> > the
> > phy id ?
> > 
> > If we want to specify the id in DT, we should probably add it for
> > the
> > Micrel PHY of the p200 as well, for consistency.
> this seems to be a "best practice" when the PHY ID is known, see [0]
> If you know the PHY ID of the Micrel PHY then please let me know,
> then
> we can include this in the fix for the p20x boards

OK

> 
> > 
> > > 
> > >  arch/arm64/boot/dts/amlogic/meson-gx.dtsi            |  6 ++++++
> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts  | 17
> > > +++++++++++++++++
> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi     | 17
> > > +++++++++++++++++
> > >  arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 17
> > > +++++++++++++++++
> > >  arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts |  2 ++
> > >  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi           |  6 ------
> > >  arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts  |  2 ++
> > >  arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts  |  2 ++
> > >  8 files changed, 63 insertions(+), 6 deletions(-)
> > > 
> 
> [0] http://lxr.free-electrons.com/source/Documentation/devicetree/bin
> dings/net/phy.txt#L22
--
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 v3 00/18] FSI device driver introduction
From: christopher.lee.bostic @ 2017-01-17 22:02 UTC (permalink / raw)
  To: robh+dt, mark.rutland, linux, gregkh, mturquette, geert+renesas,
	devicetree, linux-arm-kernel, joel, jk, linux-kernel, andrew,
	alistair, benh
  Cc: Chris Bostic

From: Chris Bostic <cbostic@us.ibm.com>

Introduction of the IBM 'Flexible Support Interface' (FSI) bus device
driver. FSI is a high fan out serial bus consisting of a clock and a serial
data line capable of running at speeds up to 166 MHz.

This set provides the basic framework to add FSI extensions to the
Linux bus and device models. Master specific implementations are
defined to utilize the core FSI function.

In Linux, we have a core FSI "bus type", along with drivers for FSI
masters and engines.

The FSI master drivers expose a read/write interface to the bus address
space. The master drivers are under drivers/fsi/fsi-master-*.c.

The core handles probing and discovery of slaves and slave
engines, using those read/write interfaces. It is responsible for
creating the endpoint Linux devices corresponding to the discovered
engines on each slave.

Slave engines are identified by an 'engine' type, and an optional
version. Engine, a.k.a. client, drivers are matched and bound to these
engines during discovery.

This patch set does not include extended FSI function such as:
    *  Hub master support
    *  Cascaded master support
    *  Application layer hot plug notification
    *  Application layer FSI bus status interface

Common FSI terminology:

* Master
    Controller of the FSI bus.  Only the master is allowed to control the
    clock line and is the initiator of all transactions on a bus.

* Slave
    The receiver or target of a master initiated transaction.  The slave
    cannot initiate communications on a bus and must respond to any
    master requests for data.

* CFAM
    Stands for Common Field replaceable unit Access Macro.  A CFAM is an
    ASIC residing in any device requiring FSI communications. CFAMs
    consist of an array of hardware 'engines' used for various purposes.
    I2C masters, UARTs, General Purpose IO hardware are common types of
    these engines.

* Configuration Space / Table
    A table contained at the beginning of each CFAM address space.
    This table lists information such as the CFAM's ID, which engine types
    and versions it has available, as well as its addressing range.

* FSI Engine driver
    A device driver that registers with the FSI core so that it can access
    devices it owns on an FSI bus.

Chris Bostic (8):
  drivers/fsi: Kick off master scan via sysfs
  drivers/fsi: Set up links for slave communication
  drivers/fsi: Set slave SMODE to init communication
  drivers/fsi: Remove all scanned devices during master unregister
  drivers/fsi: Add FSI bus documentation
  drivers/fsi: Add documentation for GPIO based FSI master
  drivers/fsi: Document FSI master sysfs files in ABI
  drivers/fsi: Add GPIO based FSI master

Jeremy Kerr (10):
  drivers/fsi: Add empty fsi bus definitions
  drivers/fsi: Add device & driver definitions
  drivers/fsi: add driver to device matches
  drivers/fsi: Add fsi master definition
  drivers/fsi: Add slave definition
  drivers/fsi: Add empty master scan
  drivers/fsi: Add FSI crc calculators to library
  drivers/fsi: Implement slave initialisation
  drivers/fsi: scan slaves & register devices
  drivers/fsi: Add device read/write/peek functions

Changes for v3:
    - Patch set contained an invalid 18/18 test patch not
      meant for community review, corrected.

Changes for v2:
    - Change from atomic global for master number to ida simple
      interface.
    - Add valid pointer checks on register and unregister utils.
    - Move CRC calculation utilities out of driver to lib path.
    - Clean up white space issues.
    - Remove added list management of master devices and use
      instead the device_for_each_child method available in the
      bus.
    - Add new patch to document FSI bus functionality.
    - Add new patch documenting FSI gpio master.
    - Rearrage patch set to have documentation earlier than code
      implementing it.
    - Document all comptible strings used in device tree bindings.
    - Elaborate documentation definition of FSI GPIO master.
    - Describe in more detail what each GPIO FSI master pin is for.
    - Re-order compatible strings in example binding so that most
      specific device comes first.
    - Indicate proper activation order of all FSI GPIO master pins.
    - Fix an unmatched '>' bracket in the example for binding.
    - Bracket each element of the example bindings individually.
    - Add new patch documenting sysfs-bus-fsi attributes.
    - Merge FSI GPIO master init into probe function.
    - Set pin initial values at time of pin request.
    - Assign value of master->master.dev at probe time.
    - Use get_optional interfac for all optional GPIO pins.


 Documentation/ABI/testing/sysfs-bus-fsi            |   6 +
 .../devicetree/bindings/fsi/fsi-master-gpio.txt    |  71 +++
 Documentation/devicetree/bindings/fsi/fsi.txt      |  54 +++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/fsi/Kconfig                                |  23 +
 drivers/fsi/Makefile                               |   3 +
 drivers/fsi/fsi-core.c                             | 494 +++++++++++++++++++
 drivers/fsi/fsi-master-gpio.c                      | 530 +++++++++++++++++++++
 drivers/fsi/fsi-master.h                           |  39 ++
 include/linux/crc-fsi.h                            |  29 ++
 include/linux/fsi.h                                |  60 +++
 lib/Makefile                                       |   1 +
 lib/crc-fsi.c                                      |  39 ++
 14 files changed, 1352 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-fsi
 create mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
 create mode 100644 Documentation/devicetree/bindings/fsi/fsi.txt
 create mode 100644 drivers/fsi/Kconfig
 create mode 100644 drivers/fsi/Makefile
 create mode 100644 drivers/fsi/fsi-core.c
 create mode 100644 drivers/fsi/fsi-master-gpio.c
 create mode 100644 drivers/fsi/fsi-master.h
 create mode 100644 include/linux/crc-fsi.h
 create mode 100644 include/linux/fsi.h
 create mode 100644 lib/crc-fsi.c

-- 
1.8.2.2

^ permalink raw reply

* Re: [PATCH v3 00/18] FSI device driver introduction
From: Christopher Bostic @ 2017-01-17 22:00 UTC (permalink / raw)
  To: Greg KH
  Cc: Mark Rutland, Open List OF Flattened dev tree bindings,
	geert+renesas, Andrew Jeffery, Alistair Popple, Michael Turquette,
	linux, Chris Bostic, Linux open list, Rob Herring, Joel Stanley,
	Benjamin Herrenschmidt, Moderated list: ARM PORT, Jeremy Kerr
In-Reply-To: <20170117074243.GA20818@kroah.com>

On Tue, Jan 17, 2017 at 1:42 AM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Jan 16, 2017 at 03:22:48PM -0600, christopher.lee.bostic@gmail.com wrote:
>> From: Chris Bostic <cbostic@us.ibm.com>
>
> <snip>
>
> Only this, and patch 02/18 came through, did something get stuck on your
> end?
>

Hi Greg,

Yes had an issue with the server blocking send, investigating why.

> greg k-h

^ permalink raw reply

* Re: [PATCH 3/5] ARM64: dts: meson-gxbb-p20x: add reset for the ethernet PHY
From: Martin Blumenstingl @ 2017-01-17 21:26 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: mark.rutland, devicetree, khilman, will.deacon, robh+dt,
	catalin.marinas, carlo, linux-amlogic, linux-arm-kernel
In-Reply-To: <1484680941.26620.28.camel@baylibre.com>

On Tue, Jan 17, 2017 at 8:22 PM, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On Sat, 2016-12-03 at 00:47 +0100, Martin Blumenstingl wrote:
>> This resets the ethernet PHY during boot to get the PHY into a
>> "clean"
>> state. While here also specify the phy-handle of the ethmac node to
>> make the PHY configuration similar to the one we have on GXL devices.
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.co
>> m>
>> Tested-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 15
>> +++++++++++++++
>>  1 file changed, 15 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
>> b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
>> index 203be28..2abc553 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
>> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
>> @@ -134,10 +134,25 @@
>>       pinctrl-names = "default";
>>  };
>>
>> +&mdio0 {
>> +     ethernet_phy0: ethernet-phy@0 {
>> +             compatible = "ethernet-phy-ieee802.3-c22";
>> +             reg = <0>;
>
> Sorry for the late reply.
> I just tried on the p200 and this patch (serie) breaks the network on
> it. The PHY is not detected anymore.
>
> From the KSZ9031 Datasheet : "PHY Address 0h is supported as the unique
> PHY address only; it is not supported as the broadcast PHY address
> [...]"
>
> So we can't just use the broadcast address here:
> reg should be <3>.
OK, I'll fix that in a follow-up. as mentioned in the other thread:
can you confirm that the PHY ID is 0x00221620?
It seems that I also broke meson-gxbb-nexbox-a95x.dts with that series
(no idea why that slipped through): according to the photos from
Neil's wiki [0] this seems to use an IC+ 10/100 ethernet PHY (probably
an IP101A)

>> +     };
>> +};
>> +
>>  &ethmac {
>>       status = "okay";
>>       pinctrl-0 = <&eth_rgmii_pins>;
>>       pinctrl-names = "default";
>> +
>> +     phy-handle = <&ethernet_phy0>;
>> +
>> +     snps,reset-gpio = <&gpio GPIOZ_14 0>;
>> +     snps,reset-delays-us = <0 10000 1000000>;
>> +     snps,reset-active-low;
>> +
>> +     phy-mode = "rgmii";
>
> We can't define this in p20x. actually the p201 uses an rmii.
> I have not idea about gpio reset, or the phy address for the p201.
>
> I suppose it would be better to move this to meson-gxbb_p200.dts
>
> I don't know if anybody has a p201, but until we can confirm a working
> Ethernet configuration, we should probably drop it for the p201
>
> Of course the problem was already there before this patch ...
indeed, that seems to be a problem.
the GXBB Nexbox A95x I mentioned above is based on the p201 board.
Amlogic's .dts also toggles GPIOZ_14 for it: [1]
chances are high that it also features an IP101A PHY (this is pure
speculation though).

I propose four patches to fix all this situation:
- add the GPIOZ_14 reset and an ethernet_phy0 (with reg = <0>) to
meson-gxbb-nexbox-a95x.dts
- add the ethernet_phy0 node with reg = <0> (and ideally I also want
to include the KSZ9031 PHY ID) to meson-gxbb-p200.dtsi along with
phy-mode = "rgmii"
- add the ethernet_phy0 node with reg = <0> (without any PHY ID as we
don't know which one is used) to meson-gxbb-p201.dtsi along with
phy-mode = "rgmii"
- remove "phy-mode" and ethernet_phy0 from meson-gxbb-p20x.dtsi and
add a comment that both, the RGMII and the RMII PHY have GPIOZ_14
connected to their reset line

does that make sense?


Regards,
Martin


[0] https://github.com/superna9999/linux/wiki/Boards#nexbox-a95x-s905
[1] https://github.com/khadas/linux/blob/Vim/arch/arm64/boot/dts/amlogic/gxbb_p201.dts#L186

^ permalink raw reply

* Re: [PATCH 2/3] Input: add support for the STMicroelectronics FingerTip touchscreen
From: Dmitry Torokhov @ 2017-01-17 21:21 UTC (permalink / raw)
  To: Andi Shyti
  Cc: Krzysztof Kozlowski, Rob Herring, Chanwoo Choi,
	Javier Martinez Canillas, linux-input, devicetree, linux-kernel,
	linux-samsung-soc, Andi Shyti
In-Reply-To: <20170117135441.31450-3-andi.shyti@samsung.com>

Hi Andi.

On Tue, Jan 17, 2017 at 10:54:40PM +0900, Andi Shyti wrote:
> The stmfts (ST-Microelectronics FingerTip S) touchscreen device
> is a capacitive multi-touch controller mainly for mobile use.
> 
> It's connected through i2c bus at the address 0x49 and it
> interfaces with userspace through input event interface.
> 
> At the current state it provides a touchscreen multitouch
> functionality up to 10 fingers. Each finger is enumerated with a
> distinctive id (from 0 to 9).
> 
> If enabled the device can support single "touch" hovering, by
> providing three coordinates, x, y, z. The z coordinate is
> related to the distance between the finger and the touchscreen
> itself.

No, we have dedicated ABS_DISTANCE event code for this, not ABS_Z.

> 
> It is possible to select the touchkey functionality which
> provides a basic two keys interface for "home" and "back" menu,
> typical in mobile phones.
> 
> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
> ---
>  drivers/input/touchscreen/Kconfig  |  12 +
>  drivers/input/touchscreen/Makefile |   1 +
>  drivers/input/touchscreen/stmfts.c | 759 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 772 insertions(+)
>  create mode 100644 drivers/input/touchscreen/stmfts.c
> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 8650c94e29d0..18c2f919eb79 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -1092,6 +1092,18 @@ config TOUCHSCREEN_ST1232
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called st1232_ts.
>  
> +config TOUCHSCREEN_STMFTS
> +	tristate "STMicroelectronics STMFTS touchscreen"
> +	depends on I2C
> +	depends on INPUT
> +	depends on LEDS_CLASS
> +	help
> +	  Say Y here if you want support for STMicroelectronics
> +	  STMFTS touchscreen.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called stmfts.
> +
>  config TOUCHSCREEN_STMPE
>  	tristate "STMicroelectronics STMPE touchscreens"
>  	depends on MFD_STMPE
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index e41e3c7aa427..be7673f9c71a 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -66,6 +66,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_SILEAD)	+= silead.o
>  obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)	+= sis_i2c.o
>  obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
> +obj-$(CONFIG_TOUCHSCREEN_STMFTS)	+= stmfts.o
>  obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_SUN4I)		+= sun4i-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_SUR40)		+= sur40.o
> diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
> new file mode 100644
> index 000000000000..abccc14d06d2
> --- /dev/null
> +++ b/drivers/input/touchscreen/stmfts.c
> @@ -0,0 +1,759 @@
> +/*
> + * Copyright (c) 2017 Samsung Electronics Co., Ltd.
> + * Author: Andi Shyti <andi.shyti@samsung.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.
> + *
> + * STMicroelectronics FTS Touchscreen device driver
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/input/mt.h>
> +#include <linux/interrupt.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/regulator/consumer.h>
> +
> +/* I2C commands */
> +#define STMFTS_READ_INFO			0x80
> +#define STMFTS_READ_STATUS			0x84
> +#define STMFTS_READ_ONE_EVENT			0x85
> +#define STMFTS_SLEEP_IN				0x91
> +#define STMFTS_SLEEP_OUT			0x91
> +#define STMFTS_MS_MT_SENSE_OFF			0x92
> +#define STMFTS_MS_MT_SENSE_ON			0x93
> +#define STMFTS_SS_HOVER_SENSE_OFF		0x94
> +#define STMFTS_SS_HOVER_SENSE_ON		0x95
> +#define STMFTS_MS_KEY_SENSE_OFF			0x9a
> +#define STMFTS_MS_KEY_SENSE_ON			0x9b
> +#define STMFTS_SYSTEM_RESET			0xa0
> +#define STMFTS_CLEAR_EVENT_STACK		0xa1
> +#define STMFTS_FULL_FORCE_CALIBRATION		0xa2
> +#define STMFTS_MS_CX_TUNING			0xa3
> +#define STMFTS_SS_CX_TUNING			0xa4
> +
> +/* events */
> +#define STMFTS_EV_NO_EVENT			0x00
> +#define STMFTS_EV_MULTI_TOUCH_DETECTED		0x02
> +#define STMFTS_EV_MULTI_TOUCH_ENTER		0x03
> +#define STMFTS_EV_MULTI_TOUCH_LEAVE		0x04
> +#define STMFTS_EV_MULTI_TOUCH_MOTION		0x05
> +#define STMFTS_EV_HOVER_ENTER			0x07
> +#define STMFTS_EV_HOVER_LEAVE			0x08
> +#define STMFTS_EV_HOVER_MOTION			0x09
> +#define STMFTS_EV_KEY_STATUS			0x0e
> +#define STMFTS_EV_ERROR				0x0f
> +#define STMFTS_EV_CONTROLLER_READY		0x10
> +#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY	0x11
> +#define STMFTS_EV_STATUS			0x16
> +
> +/* multi touch related event masks */
> +#define STMFTS_MASK_EVENT_ID			0x0f
> +#define STMFTS_MASK_TOUCH_ID			0xf0
> +#define STMFTS_MASK_LEFT_EVENT			0x0f
> +#define STMFTS_MASK_X_MSB			0x0f
> +#define STMFTS_MASK_Y_LSB			0xf0
> +
> +/* key related event masks */
> +#define STMFTS_MASK_KEY_NO_TOUCH		0x00
> +#define STMFTS_MASK_KEY_BACK			0x01
> +#define STMFTS_MASK_KEY_MENU			0x02
> +
> +#define STMFTS_EVENT_SIZE	8
> +#define STMFTS_MAX_FINGERS	10
> +#define STMFTS_DEV_NAME		"stmfts"
> +
> +enum stmfts_regulators {
> +	STMFTS_REGULATOR_VDD,
> +	STMFTS_REGULATOR_AVDD,
> +};
> +
> +struct stmfts_data {
> +	struct i2c_client *client;
> +	struct input_dev *input_touch;
> +	struct input_dev *input_key;
> +	struct led_classdev led_cdev;
> +	struct mutex mutex;
> +	u32 x_size;
> +	u32 y_size;
> +
> +	struct regulator_bulk_data regulators[2];
> +
> +	/* ledvdd will be used also to check
> +	 * whether the LED is supported
> +	 */
> +	struct regulator *ledvdd;
> +
> +	bool use_key;
> +	bool signal;
> +	bool led_status;
> +	u8 users;
> +
> +	u16 chip_id;
> +	u8 chip_ver;
> +	u16 fw_ver;
> +	u8 config_id;
> +	u8 config_ver;
> +	u8 in_touch;
> +
> +	wait_queue_head_t wq;
> +
> +	bool hover_enabled;
> +};
> +
> +static void stmfts_brightness_set(struct led_classdev *led_cdev,
> +					enum led_brightness value)
> +{
> +	struct stmfts_data *sdata = container_of(led_cdev,
> +					struct stmfts_data, led_cdev);
> +
> +	if (value == sdata->led_status)
> +		return;
> +
> +	if (!value) {
> +		regulator_disable(sdata->ledvdd);
> +	} else {
> +		int err = regulator_enable(sdata->ledvdd);
> +
> +		if (err)
> +			dev_warn(&sdata->client->dev,
> +				"failed to disable ledvdd regulator\n");
> +	}
> +
> +	sdata->led_status = value;
> +}
> +
> +static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
> +{
> +	struct stmfts_data *sdata = container_of(led_cdev,
> +						struct stmfts_data, led_cdev);
> +
> +	return !!regulator_is_enabled(sdata->ledvdd);
> +}
> +
> +static void stmfts_parse_event(struct stmfts_data *sdata, u8 event[])
> +{
> +	int ret;
> +	u8 id, t_id = 0;
> +	u16 x, y, z, maj, min, orientation, area;
> +
> +	id = event[0];
> +
> +	do {
> +		mutex_lock(&sdata->mutex);
> +		if (sdata->in_touch) {
> +			id = event[0] & STMFTS_MASK_EVENT_ID;
> +			t_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
> +		} else {
> +			id = event[0];
> +			t_id = 0;
> +		}
> +
> +		switch (id) {
> +		case STMFTS_EV_NO_EVENT:
> +			break;
> +
> +		case STMFTS_EV_MULTI_TOUCH_ENTER:
> +		case STMFTS_EV_MULTI_TOUCH_LEAVE:
> +		case STMFTS_EV_MULTI_TOUCH_MOTION:
> +			if (id == STMFTS_EV_MULTI_TOUCH_ENTER) {
> +				if (!(sdata->in_touch++))
> +					input_mt_report_slot_state(
> +							sdata->input_touch,
> +							MT_TOOL_FINGER, true);
> +			} else if (id == STMFTS_EV_MULTI_TOUCH_LEAVE) {
> +				if (!(--sdata->in_touch))
> +					input_mt_report_slot_state(
> +							sdata->input_touch,
> +							MT_TOOL_FINGER, false);
> +			}
> +
> +			x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
> +			y = (event[2] >> 4) | (event[3] << 4);
> +
> +			maj = event[4];
> +			min = event[5];
> +			orientation = event[6];
> +			area = event[7];
> +
> +			input_mt_slot(sdata->input_touch, t_id);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_POSITION_X, x);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_POSITION_Y, y);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_TOUCH_MAJOR, maj);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_TOUCH_MINOR, min);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_PRESSURE, area);
> +			input_report_abs(sdata->input_touch,
> +					ABS_MT_ORIENTATION, orientation);
> +			input_sync(sdata->input_touch);
> +
> +			break;
> +
> +		case STMFTS_EV_HOVER_ENTER:
> +		case STMFTS_EV_HOVER_LEAVE:
> +		case STMFTS_EV_HOVER_MOTION:
> +			x = (event[2] << 4) | (event[4] >> 4);
> +			y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB);
> +			z = event[5];
> +			orientation = event[6] & STMFTS_MASK_Y_LSB;
> +
> +			input_report_abs(sdata->input_touch, ABS_X, x);
> +			input_report_abs(sdata->input_touch, ABS_Y, y);
> +			input_report_abs(sdata->input_touch, ABS_Z, z);
> +			input_sync(sdata->input_touch);
> +
> +			break;
> +
> +		case STMFTS_EV_KEY_STATUS:

Please use:
			switch (event[2]) {
			case 0:
				...

			case STMFTS_MASK_KEY_BACK:
				...

			case STMFTS_MASK_KEY_MENU:
				...

			default:
				dev_warn(...);
				break;
			}

> +			if (!event[2]) {
> +				input_report_key(sdata->input_key, KEY_BACK, 0);
> +				input_report_key(sdata->input_key, KEY_MENU, 0);
> +			} else {
> +				if (event[2] == STMFTS_MASK_KEY_BACK)
> +					input_report_key(sdata->input_key,
> +								KEY_BACK, 1);
> +				else if (event[2] == STMFTS_MASK_KEY_MENU)
> +					input_report_key(sdata->input_key,
> +								KEY_MENU, 1);
> +				else /* quite impossible */
> +					break;
> +			}
> +			input_sync(sdata->input_key);
> +			break;
> +
> +		case STMFTS_EV_STATUS:
> +			sdata->signal = true;
> +			wake_up_interruptible(&sdata->wq);
> +			break;
> +
> +		case STMFTS_EV_ERROR:
> +			dev_err(&sdata->client->dev,
> +				"error code: 0x%x%x%x%x%x%x",
> +				event[6], event[5], event[4],
> +				event[3], event[2], event[1]);
> +			break;
> +
> +		default:
> +			dev_err(&sdata->client->dev,
> +				"unknown event 0x%x\n", event[0]);
> +		}
> +		mutex_unlock(&sdata->mutex);
> +
> +		ret = i2c_smbus_read_i2c_block_data(sdata->client,
> +						STMFTS_READ_ONE_EVENT,
> +						STMFTS_EVENT_SIZE, event);
> +		if (ret) {
> +			i2c_smbus_write_byte(sdata->client,
> +						STMFTS_CLEAR_EVENT_STACK);
> +			break;
> +		}
> +
> +	} while (event[0]);
> +}
> +
> +static irqreturn_t stmfts_irq_handler(int irq, void *dev)
> +{
> +	struct stmfts_data *sdata = dev;
> +	int ret;
> +	u8 event[STMFTS_EVENT_SIZE];
> +
> +	ret = i2c_smbus_read_i2c_block_data(sdata->client,
> +					STMFTS_READ_ONE_EVENT,
> +					STMFTS_EVENT_SIZE, event);
> +
> +	switch (event[0]) {
> +	case STMFTS_EV_CONTROLLER_READY:
> +	case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
> +		sdata->signal = true;
> +		wake_up_interruptible(&sdata->wq);
> +		break;
> +	default:
> +		stmfts_parse_event(sdata, event);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int stmfts_write_and_wait(struct stmfts_data *sdata, const u8 cmd)
> +{
> +	int err;
> +
> +	err = i2c_smbus_write_byte(sdata->client, cmd);
> +	if (err)
> +		return err;
> +
> +	sdata->signal = false;

This is racy, interrupt may run before you get chance to set signal to
false. Also, please use wait_for_completion*() API.

> +	err = wait_event_interruptible_timeout(sdata->wq, sdata->signal,
> +						msecs_to_jiffies(1000));
> +
> +	return !err ? -ETIMEDOUT : 0;
> +}
> +
> +static void stmfts_sleep_in(struct stmfts_data *sdata)
> +{
> +	mutex_lock(&sdata->mutex);
> +
> +	sdata->users--;
> +	if (!sdata->users)
> +		i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);

This looks like somewhat homegrown runtime PM, please replace.

> +
> +	mutex_unlock(&sdata->mutex);
> +}
> +
> +static int stmfts_sleep_out(struct stmfts_data *sdata, u8 cmd)
> +{
> +	int ret = 0;
> +
> +	mutex_lock(&sdata->mutex);
> +
> +	if (!sdata->users)
> +		ret = stmfts_write_and_wait(sdata, STMFTS_SLEEP_OUT);
> +
> +	/* if sleep out succeeds users increments, otherwise not */
> +	sdata->users += !ret;
> +
> +	mutex_unlock(&sdata->mutex);
> +
> +	ret = i2c_smbus_write_byte(sdata->client, cmd);
> +	if (ret)
> +		stmfts_sleep_in(sdata);
> +
> +	return ret;
> +}
> +
> +static int stmfts_input_touch_open(struct input_dev *dev)
> +{
> +	struct stmfts_data *sdata = input_get_drvdata(dev);
> +
> +	return stmfts_sleep_out(sdata, STMFTS_MS_MT_SENSE_ON);
> +}
> +
> +static void stmfts_input_touch_close(struct input_dev *dev)
> +{
> +	struct stmfts_data *sdata = input_get_drvdata(dev);
> +
> +	i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF);
> +
> +	stmfts_sleep_in(sdata);
> +}
> +
> +static int stmfts_input_key_open(struct input_dev *dev)
> +{
> +	struct stmfts_data *sdata = input_get_drvdata(dev);
> +
> +	return stmfts_sleep_out(sdata, STMFTS_MS_KEY_SENSE_ON);
> +}
> +
> +static void stmfts_input_key_close(struct input_dev *dev)
> +{
> +	struct stmfts_data *sdata = input_get_drvdata(dev);
> +
> +	i2c_smbus_write_byte(sdata->client, STMFTS_MS_KEY_SENSE_OFF);
> +	stmfts_sleep_in(sdata);
> +}
> +
> +static ssize_t stmfts_sysfs_hwid(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "ST-Microelectronics FTS 0x%x version %u\n",
> +					sdata->chip_id, sdata->chip_ver);

sysfs attributes should have only 1 value. Please split into chip ID and
chip version and drop static strings.

> +}
> +
> +static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%u\n", sdata->fw_ver);
> +}
> +
> +static ssize_t stmfts_sysfs_config_id(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "0x%x version %u\n",
> +			sdata->config_id, sdata->config_ver);

Please split in 2.

> +}
> +
> +static ssize_t stmfts_sysfs_read_status(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +	u8 status[4];
> +	int ret;
> +
> +	ret = i2c_smbus_read_i2c_block_data(sdata->client,
> +					STMFTS_READ_STATUS, 4, status);
> +
> +	return sprintf(buf, "0x%x\n", status[0]);
> +}
> +
> +static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%u\n", sdata->hover_enabled);
> +}
> +
> +static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t len)
> +{
> +	unsigned long value;
> +	int err;
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	if (kstrtoul(buf, 0, &value))
> +		return -EINVAL;
> +
> +	if (value & sdata->hover_enabled)
> +		return len;
> +
> +	if (value) {
> +		err = stmfts_sleep_out(sdata, STMFTS_SS_HOVER_SENSE_ON);

Why setting hover explicitly wakes up controller? You shuld put it back
into sleep if nobody is listening, or postpone programming until there
are users.

> +		sdata->hover_enabled = !err;
> +	} else {
> +		err = i2c_smbus_write_byte(sdata->client,
> +					STMFTS_SS_HOVER_SENSE_OFF);
> +		stmfts_sleep_in(sdata);
> +		sdata->hover_enabled = !!err;
> +	}
> +
> +	return len;
> +}
> +
> +static DEVICE_ATTR(hwid, 0444, stmfts_sysfs_hwid, NULL);
> +static DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL);
> +static DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL);
> +static DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL);
> +static DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read,
> +					stmfts_sysfs_hover_enable_write);
> +
> +static struct attribute *stmfts_sysfs_attrs[] = {
> +	&dev_attr_hwid.attr,
> +	&dev_attr_fw_ver.attr,
> +	&dev_attr_config_id.attr,
> +	&dev_attr_status.attr,
> +	&dev_attr_hover_enable.attr,
> +	NULL
> +};
> +
> +static struct attribute_group stmfts_attribute_group = {
> +	.attrs = stmfts_sysfs_attrs
> +};
> +
> +static int stmfts_parse_dt(struct stmfts_data *sdata)
> +{
> +	int ret;
> +	struct device_node *np = sdata->client->dev.of_node;
> +
> +	if (!np)
> +		return -ENOENT;
> +
> +	ret = of_property_read_u32(np, "touchscreen-size-x", &sdata->x_size);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_property_read_u32(np, "touchscreen-size-y", &sdata->y_size);
> +	if (ret)
> +		return ret;

Please use touchscreen_parse_properties().

> +
> +	sdata->use_key = of_property_read_bool(np, "touch-key-connected");
> +
> +	return 0;
> +}
> +
> +static int stmfts_power_on(struct stmfts_data *sdata)
> +{
> +	int err;
> +	u8 reg[8];
> +
> +	err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
> +							sdata->regulators);
> +	if (err)
> +		return err;
> +
> +	/*
> +	 * the datasheet does not specify the power on time, but considering
> +	 * that the reset time is < 10ms, I sleep 20ms to be sure
> +	 */
> +	msleep(20);
> +
> +	err = i2c_smbus_read_i2c_block_data(sdata->client,
> +					STMFTS_READ_INFO, 8, reg);
> +	if (err < 0)
> +		return err;
> +	if (err != 8)
> +		return -EIO;
> +
> +	sdata->chip_id = (reg[6] << 8) | reg[7];
> +	sdata->chip_ver = reg[0];
> +	sdata->fw_ver = (reg[2] << 8) | reg[3];
> +	sdata->config_id = reg[4];
> +	sdata->config_ver = reg[5];
> +
> +	enable_irq(sdata->client->irq);
> +	err = stmfts_write_and_wait(sdata, STMFTS_SYSTEM_RESET);
> +	if (err)
> +		return err;
> +
> +	err = stmfts_write_and_wait(sdata, STMFTS_SLEEP_OUT);
> +	if (err)
> +		return err;
> +
> +	/* optional tuning */
> +	err = stmfts_write_and_wait(sdata, STMFTS_MS_CX_TUNING);
> +	if (err)
> +		dev_warn(&sdata->client->dev, "failed to perform mutual auto tune\n");
> +
> +	/* optional tuning */
> +	err = stmfts_write_and_wait(sdata, STMFTS_SS_CX_TUNING);
> +	if (err)
> +		dev_warn(&sdata->client->dev, "failed to perform self auto tune\n");
> +
> +	err = stmfts_write_and_wait(sdata, STMFTS_FULL_FORCE_CALIBRATION);
> +	if (err)
> +		return err;

Hmm, do you need to calibrate on boot, or maybe wait for the device to
be opened first?

> +
> +	/* at this point no one is using the touchscreen
> +	 * and I don't really care about the return value
> +	 */
> +	i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
> +
> +	return 0;
> +}
> +
> +static void stmfts_power_off(void *data)
> +{
> +	struct stmfts_data *sdata = data;
> +
> +	disable_irq(sdata->client->irq);
> +	regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
> +						sdata->regulators);
> +}
> +
> +static int stmfts_enable_key(struct stmfts_data *sdata)
> +{
> +	int err;
> +
> +	sdata->input_key = devm_input_allocate_device(&sdata->client->dev);
> +	if (!sdata->input_key)
> +		return -ENOMEM;
> +
> +	sdata->input_key->name = "stmfts_key";
> +	sdata->input_key->id.bustype = BUS_I2C;
> +	sdata->input_key->open = stmfts_input_key_open;
> +	sdata->input_key->close = stmfts_input_key_close;

If you want separate input device for keys I'd recommend setting ->phys
on them. Another option is to add keys to teh touchscreen device. Do you
expect different actors listening to these devices? Even with different
actors you can program event masks so that if process is not interested
in some events (like ABS_MT_* events) it is not woken up when dveice
generates them.

> +
> +	input_set_capability(sdata->input_key, EV_KEY, KEY_MENU);
> +	input_set_capability(sdata->input_key, EV_KEY, KEY_BACK);
> +
> +	input_set_drvdata(sdata->input_key, sdata);
> +	err = input_register_device(sdata->input_key);
> +	if (err)
> +		return err;
> +
> +	/* get the regulator for powering the leds on */
> +	sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd");
> +	if (IS_ERR(sdata->ledvdd))
> +		/* there is no LED connected to the touch key */
> +		sdata->ledvdd = NULL;

As I mentioned, is it truly regulator, or just a GPIO?

> +
> +	sdata->led_cdev.name = STMFTS_DEV_NAME;
> +	sdata->led_cdev.max_brightness = LED_ON;
> +	sdata->led_cdev.brightness = LED_OFF;
> +	sdata->led_cdev.brightness_set = stmfts_brightness_set;
> +	sdata->led_cdev.brightness_get = stmfts_brightness_get;
> +
> +	err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
> +	if (err) {
> +		dev_warn(&sdata->client->dev, "unable to register led, led might not work\n");
> +		sdata->ledvdd = NULL;
> +
> +		/* I don't want to prevent using the touch key
> +		 * only because the LEDs don't get registered
> +		 */
> +		err = 0;
> +	}
> +
> +	return err;
> +}
> +
> +static int stmfts_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id)
> +{
> +	int err;
> +	struct stmfts_data *sdata;
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
> +						I2C_FUNC_SMBUS_BYTE_DATA |
> +						I2C_FUNC_SMBUS_I2C_BLOCK))
> +		return -ENODEV;
> +
> +	sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
> +	if (!sdata)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(client, sdata);
> +
> +	mutex_init(&sdata->mutex);
> +
> +	sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
> +	sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
> +	err = devm_regulator_bulk_get(&client->dev,
> +			ARRAY_SIZE(sdata->regulators), sdata->regulators);
> +	if (err)
> +		return err;
> +
> +	err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
> +	if (err)
> +		return err;
> +
> +	sdata->client = client;
> +
> +	err = stmfts_parse_dt(sdata);
> +	if (err)
> +		return err;
> +
> +	init_waitqueue_head(&sdata->wq);
> +
> +	err = sysfs_create_group(&sdata->client->dev.kobj,
> +					&stmfts_attribute_group);

I do not see it being removed on errors.

> +	if (err)
> +		return err;
> +
> +	err = devm_request_threaded_irq(&client->dev, client->irq,
> +					NULL, stmfts_irq_handler,
> +					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> +					"stmfts_irq", sdata);
> +	if (err)
> +		return err;

What happens if interrupt is raised here?

> +
> +	disable_irq(sdata->client->irq);
> +
> +	dev_info(&client->dev, "initializing ST-Microelectronics FTS...\n");
> +	err = stmfts_power_on(sdata);
> +	if (err)
> +		return err;
> +
> +	sdata->input_touch = devm_input_allocate_device(&client->dev);
> +	if (!sdata->input_touch)
> +		return -ENOMEM;
> +
> +	sdata->input_touch->name = STMFTS_DEV_NAME;
> +	sdata->input_touch->id.bustype = BUS_I2C;
> +	sdata->input_touch->open = stmfts_input_touch_open;
> +	sdata->input_touch->close = stmfts_input_touch_close;
> +
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_Y);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_X);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_TOUCH_MAJOR);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_TOUCH_MINOR);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_ORIENTATION);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_PRESSURE);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_X);
> +
> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_POSITION_X, 0, sdata->x_size, 0, 0);

input_set_abs_params() implies input_set_capability(), you can drop the
calls above.

> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_POSITION_Y, 0, sdata->y_size, 0, 0);
> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_ORIENTATION, 0, 255, 0, 0);
> +	input_set_abs_params(sdata->input_touch,
> +				ABS_MT_PRESSURE, 0, 255, 0, 0);
> +	input_mt_init_slots(sdata->input_touch,
> +				STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);

Error handling please.

> +
> +	/* for hover features */
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_X);
> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_Y);

Not needed, input_mt_init_slots() will copy MT axis setup into ST axis
for INPUT_MT_DIRECT devices.

> +	input_set_capability(sdata->input_touch, EV_ABS, ABS_Z);

ABS_DISTANCE

> +	input_set_abs_params(sdata->input_touch, ABS_X, 0, sdata->x_size, 0, 0);
> +	input_set_abs_params(sdata->input_touch, ABS_Y, 0, sdata->y_size, 0, 0);
> +	input_set_abs_params(sdata->input_touch, ABS_Z, 0, 255, 0, 0);
> +
> +	input_set_drvdata(sdata->input_touch, sdata);
> +	err = input_register_device(sdata->input_touch);
> +	if (err)
> +		return err;
> +
> +	if (sdata->use_key) {
> +		err = stmfts_enable_key(sdata);
> +		if (err)
> +			dev_warn(&client->dev, "failed to enable touchkey\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int stmfts_remove(struct i2c_client *client)
> +{
> +	struct stmfts_data *sdata = i2c_get_clientdata(client);
> +
> +	sysfs_remove_group(&sdata->client->dev.kobj, &stmfts_attribute_group);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused stmfts_suspend(struct device *dev)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	stmfts_power_off(sdata);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused stmfts_resume(struct device *dev)
> +{
> +	struct stmfts_data *sdata = dev_get_drvdata(dev);
> +
> +	return stmfts_power_on(sdata);
> +}
> +
> +static SIMPLE_DEV_PM_OPS(stmfts_pm_ops, stmfts_suspend, stmfts_resume);
> +
> +static const struct of_device_id stmfts_of_match[] = {
> +	{ .compatible = "st,stmfts", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, stmfts_of_match);
> +
> +static const struct i2c_device_id stmfts_id[] = {
> +	{ "stmfts", 0 },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(i2c, stmfts_id);
> +
> +static struct i2c_driver stmfts_driver = {
> +	.driver = {
> +		.name = STMFTS_DEV_NAME,
> +		.of_match_table = of_match_ptr(stmfts_of_match),
> +		.pm = &stmfts_pm_ops,
> +	},
> +	.probe = stmfts_probe,
> +	.remove = stmfts_remove,
> +	.id_table = stmfts_id,
> +};
> +
> +module_i2c_driver(stmfts_driver);
> +
> +MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
> +MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.11.0
> 

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2 03/10] dt-bindings: sound: Add new reset compatible for sun4i-i2s
From: Thomas Petazzoni @ 2017-01-17 21:20 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: mark.rutland, devicetree, alsa-devel, wens, linux-kernel,
	mturquette, tiwai, sboyd, lgirdwood, robh+dt, perex, linux-sunxi,
	broonie, alexandre.belloni, maxime.ripard, Mylène Josserand,
	linux-clk, linux-arm-kernel
In-Reply-To: <20170117201016.A5fiHT0P@smtp2p.mail.yandex.net>

Hello,

On Wed, 18 Jan 2017 01:10:00 +0800, Icenowy Zheng wrote:

> > Add a new compatible for sun4i-i2s driver to handle some
> > SoCs that have a reset line that must be asserted/deasserted.
> >
> > This new compatible, "allwinner,sun6i-a31-i2s", requires two
> > properties:
> > - resets: phandle to the reset line
> > - reset-names: the name of the reset line ("rst").
> > Except these differences, the compatible is identical to previous one
> > which will not handle a reset line.  
> 
> But I think the IP block is identical, right?
> 
> Should a new compatible be added only for reset-line?

Having a different compatible in this case allows to make some stricter
error checking: the driver can make sure that if the compatible string
is sun6i-a31-i2s there *IS* a reset line specified in the DT. Without a
separate compatible value, such a check is not possible, and the reset
line is just optional. This can lead to people being confused if they
forget to specify the reset line.

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* Re: [PATCH 0/5] meson-gx: reset RGMII PHYs and configure TX delay
From: Martin Blumenstingl @ 2017-01-17 21:09 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: mark.rutland, devicetree, khilman, will.deacon, robh+dt,
	catalin.marinas, carlo, linux-amlogic, linux-arm-kernel
In-Reply-To: <1484680984.26620.29.camel@baylibre.com>

On Tue, Jan 17, 2017 at 8:23 PM, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On Sat, 2016-12-03 at 00:47 +0100, Martin Blumenstingl wrote:
>> This partially fixes the 1000Mbit/s ethernet TX throughput issues (on
>> networks which are not affected by the EEE problem, as reported here:
>> [1]).
>> The actual problem for the TX throughput issues was that the TX delay
>> was applied twice:
>> - once "accidentally" by the PHY (this was fixed with [2])
>> - once by the MAC because there was a hardcoded TX delay (of 2ns),
>>   this will be configurable with the changes from [0]
>>
>> These are the dts changes which belong to my other series (in v2
>> these patches were part of the other series, upon request of the
>> net maintainers I have split the .dts changes into their own series
>> so
>> we are able to take both through different trees):
>> "[PATCH net-next v3 0/2] stmmac: dwmac-meson8b: configurable
>> RGMII TX delay": [0].
>> Thus this series depends on the ACK for the binding changes in the
>> other series!
>>
>> I based these changes on my other series "[PATCH v2 0/2] GXL and GXM
>> SCPI improvements": [3]
>>
>>
>> [0] http://lists.infradead.org/pipermail/linux-amlogic/2016-December/
>> 001834.html
>> [1] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/
>> 001607.html
>> [2] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/
>> 001707.html
>> [3] http://lists.infradead.org/pipermail/linux-amlogic/2016-December/
>> 001831.html
>>
>> Martin Blumenstingl (5):
>>   ARM64: dts: meson-gx: move the MDIO node to meson-gx
>
> Sorry for the late reply, I've only been able to test this yesterday.
>
> With "snps,dwmac-mdio" provided in meson-gx.dtsi, the mdio_node is
> defined in stmmac_mdio_register and auto-detection of the PHY is
> disabled for all meson-gx boards.
>
> I wonder if this is desirable ? or maybe this something we could fix in
> stmmac ? (perform auto-detect the mdio bus is provided without a PHY)
actually it's only a "problem" when introducing support for new
devices. can you please forward this question to the stmmac
maintainers, as I think your idea of enabling auto-detection when
there are no children in the MDIO-bus makes sense

> Also, I think bisect is broken between patch 1 and patch 4: The PHY of
> some boards won't be detected between these patches. Should we squash
> them ?
what do you mean exactly? currently the TX-delay is hardcoded in
dwmac-meson8b. patch 4 moves the hardcoded value from the
dwmac-meson8b to the .dts-files.
unfortunately the corresponding dwmac-meson8b patch was not accepted
yet, so at the moment patch 4 should be a no-op.

>>   ARM64: dts: meson-gxbb-odroidc2: add reset for the ethernet PHY
>>   ARM64: dts: meson-gxbb-p20x: add reset for the ethernet PHY
>>   ARM64: dts: meson-gxbb-vega-s95: add reset for the ethernet PHY
>>   ARM64: dts: amlogic: add the ethernet TX delay configuration
>>
>
> Last remark, about the use of ethernet-phy-idXXXX.XXXX in the odroid
> and the vega: Isn't it better to let phylib do the autodetection of the
> phy id ?
>
> If we want to specify the id in DT, we should probably add it for the
> Micrel PHY of the p200 as well, for consistency.
this seems to be a "best practice" when the PHY ID is known, see [0]
If you know the PHY ID of the Micrel PHY then please let me know, then
we can include this in the fix for the p20x boards

>>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi            |  6 ++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts  | 17
>> +++++++++++++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi     | 17
>> +++++++++++++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 17
>> +++++++++++++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts |  2 ++
>>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi           |  6 ------
>>  arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts  |  2 ++
>>  arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts  |  2 ++
>>  8 files changed, 63 insertions(+), 6 deletions(-)
>>

[0] http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/net/phy.txt#L22

^ permalink raw reply

* Re: [PATCH v4 2/2] dt-bindings: iio: document MAX11100 ADC
From: Wolfram Sang @ 2017-01-17 21:03 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: wsa+renesas-jBu1N2QxHDJrcw3mvpCnnVaTQe2KTcn/,
	magnus.damm-Re5JQEeQqe8AvxtiuMwx3w, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484301038-16386-3-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>

On Fri, Jan 13, 2017 at 10:50:38AM +0100, Jacopo Mondi wrote:
> Add device tree bindings documentation for Maxim MAX11100 single-channel
> ADC
> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>

Acked-by: Wolfram Sang <wsa+renesas-jBu1N2QxHDJrcw3mvpCnnVaTQe2KTcn/@public.gmane.org>

^ permalink raw reply

* Re: [PATCH v4 1/2] iio: adc: Add Maxim MAX11100 driver
From: Wolfram Sang @ 2017-01-17 21:02 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: wsa+renesas-jBu1N2QxHDJrcw3mvpCnnVaTQe2KTcn/,
	magnus.damm-Re5JQEeQqe8AvxtiuMwx3w, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484301038-16386-2-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>


> + * Copyright (C) 2016 Renesas Electronics Corporation
> + * Copyright (C) 2016 Jacopo Mondi

In case you need to resend: 2016-17?

--
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/2] dt-bindings: gpu: Add Mali Utgard bindings
From: Maxime Ripard @ 2017-01-17 20:51 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Rutland, devicetree, Heiko Stuebner,
	Javier Martinez Canillas, Kevin Hilman, Linus Walleij,
	Boris Brezillon, Matthias Brugger, Chen-Yu Tsai, Rob Herring,
	Alexandre Belloni, Kukjin Kim, Antoine Ténart, Carlo Caione,
	Thomas Petazzoni, linux-arm-kernel
In-Reply-To: <CAJKOXPdbbzoqNLg=iRGC8ijVPdpLD5+CFyqysfM49vkx6o3rRQ@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 1671 bytes --]

On Tue, Jan 17, 2017 at 01:31:19PM +0200, Krzysztof Kozlowski wrote:
> On Tue, Jan 17, 2017 at 11:38 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Mon, Jan 16, 2017 at 08:49:06PM +0200, Krzysztof Kozlowski wrote:
> >> On Mon, Jan 16, 2017 at 02:24:23PM +0100, Maxime Ripard wrote:
> >> > The ARM Mali Utgard GPU family is embedded into a number of SoCs from
> >> > Allwinner, Amlogic, Mediatek or Rockchip.
> >> >
> >> > Add a binding for the GPU of that family.
> >> >
> >> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >> > ---
> >> >  .../devicetree/bindings/gpu/arm,mali-utgard.txt    | 76 ++++++++++++++++++++++
> >> >  1 file changed, 76 insertions(+)
> >> >  create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
> >>
> >> Do you have a driver in kernel which will implement these bindings?
> >
> > No, but we have bindings for out-of-tree drivers already.
> >
> >> Defining them for out-of-tree driver does not bring any benefits
> >> (3rd party driver will not respect them anyway).
> >
> > You could see it the other way around too. The out-of-tree drivers
> > don't respect it at the moment because there's no binding to respect.
> 
> Indeed, that's a point. However valid only when the out-of-tree driver
> will respect them, for example do not break them on next release.

If you're talking about the default platform provided by ARM, you also
have the option of creating your own. That's what we did, and it
worked like a charm.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: gpu: Add Mali Utgard bindings
From: Maxime Ripard @ 2017-01-17 20:50 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Rutland, devicetree, Heiko Stuebner, Neil Armstrong,
	Kevin Hilman, Linus Walleij, Javier Martinez Canillas,
	Chen-Yu Tsai, Rob Herring, Boris Brezillon, Kukjin Kim,
	Matthias Brugger, Alexandre Belloni, Thomas Petazzoni,
	Carlo Caione, Antoine Ténart, linux-arm-kernel
In-Reply-To: <CAJKOXPe5AWTK+NuVpiObzjEG+CFWB5_AeYncNkbkSXRr+4RQUQ@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 3066 bytes --]

On Tue, Jan 17, 2017 at 01:33:57PM +0200, Krzysztof Kozlowski wrote:
> On Tue, Jan 17, 2017 at 12:22 PM, Neil Armstrong
> <narmstrong@baylibre.com> wrote:
> > On 01/17/2017 10:38 AM, Maxime Ripard wrote:
> >> Hi,
> >>
> >> On Mon, Jan 16, 2017 at 08:49:06PM +0200, Krzysztof Kozlowski wrote:
> >>> On Mon, Jan 16, 2017 at 02:24:23PM +0100, Maxime Ripard wrote:
> >>>> The ARM Mali Utgard GPU family is embedded into a number of SoCs from
> >>>> Allwinner, Amlogic, Mediatek or Rockchip.
> >>>>
> >>>> Add a binding for the GPU of that family.
> >>>>
> >>>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >>>> ---
> >>>>  .../devicetree/bindings/gpu/arm,mali-utgard.txt    | 76 ++++++++++++++++++++++
> >>>>  1 file changed, 76 insertions(+)
> >>>>  create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
> >>>
> >>> Do you have a driver in kernel which will implement these bindings?
> >>
> >> No, but we have bindings for out-of-tree drivers already.
> >>
> >>> Defining them for out-of-tree driver does not bring any benefits
> >>> (3rd party driver will not respect them anyway).
> >>
> >> You could see it the other way around too. The out-of-tree drivers
> >> don't respect it at the moment because there's no binding to respect.
> >>
> >> And at least for us, we definitely plan on doing that.
> >>
> >> Maxime
> >
> > Hi Maxime, Krzysztof,
> >
> > We hope this will be accepted so it will solve the same issue we have on Amlogic SoCs
> > and all the other mali powered SoCs.
> 
> It will be helpful also for other SoCs using Mali 400 (e.g.
> Exynos3250, Exynos4412).

Yep, hence why you were in Cc :)

> > Having mainline bindings will forcre out-of-tree driver to respect those bindings
> > and remove a dts out-of-tree patch aswell.
> 
> I would argue here over the word "force". Having bindings defined here
> does not force anyone into anything. The out-of-tree can do whatever
> they want. It is a wish from kernel side - it might be respected but
> it might not.

Well, that statement can be made for each line of the kernel itself,
nothing forces you to use the code as is, or to make any kind of
modifications, including to its ABI. You just have an incentive to
respect the various frameworks and ABI because it's the path of least
resistance and all the tools, libraries and applications already know
how to use those interfaces.

But that's just it, an incentive, that anyone is free or not to comply
to.

> Just to be sure - I am not opposed against. Some time ago I wanted
> Mali400 to be upstreamed but with current policy about user-space side
> it is not possible.

While I would also very much like to see the kernel driver upstreamed,
this is unreasonable at this point. But this patch is here only to add
a binding to it, so that the out-of-tree drivers can comply to it, and
this is something we already have done.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/3] Input: add STMicroelectronics FingerTip touchscreen driver
From: Dmitry Torokhov @ 2017-01-17 20:47 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Andi Shyti, Rob Herring, Chanwoo Choi, Javier Martinez Canillas,
	linux-input, devicetree, linux-kernel, linux-samsung-soc,
	Andi Shyti
In-Reply-To: <20170117184332.6ne4ercemll6qrbm@kozik-lap>

On Tue, Jan 17, 2017 at 08:43:32PM +0200, Krzysztof Kozlowski wrote:
> On Tue, Jan 17, 2017 at 10:54:39PM +0900, Andi Shyti wrote:
> > Add binding for the STMicroelectronics FingerTip (stmfts)
> > touchscreen driver.
> > 
> > Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
> > ---
> >  .../bindings/input/touchscreen/st,stmfts.txt       | 43 ++++++++++++++++++++++
> >  1 file changed, 43 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
> > new file mode 100644
> > index 000000000000..788f4ba744db
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
> > @@ -0,0 +1,43 @@
> > +* ST-Microelectronics FingerTip touchscreen controller
> > +
> > +The ST-Microelectronics FingerTip device provides a basic touchscreen
> > +functionality. Along with it the user can enable the touchkey which can work as
> > +a basic HOME and BACK key for phones.
> > +
> > +The driver supports also hovering as an absolute single touch event with x, y, z
> > +coordinates.
> > +
> > +Required properties:
> > +- compatible		: must be "st,stmfts"
> > +- reg			: I2C slave address, (e.g. 0x49)
> > +- interrupt-parent	: the phandle to the interrupt controller which provides
> > +			  the interrupt
> > +- interrupts		: interrupt specification
> > +- avdd-supply		: analogic power supply
> > +- vdd-supply		: power supply
> > +- touchscreen-size-x	: see touchscreen.txt
> > +- touchscreen-size-y	: see touchscreen.txt
> > +
> > +Optional properties:
> > +- touch-key-connected	: specifies whether the touchkey feature is connected
> 
> You are making it a generic property but it is specific to this device,
> so:
> 	st,touch-key-connected
> ?
> 
> > +- ledvdd-supply		: power supply to the touch key leds
> 
> Is this really optional? If yes... how it gets the power when not
> provided?

Also, is this really a regulator? Given you are testing whether it is on
or off to report LED state it feels to me it might be a GPIO pin, not
regulator...

Thanks.

-- 
Dmitry

^ permalink raw reply


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