All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller
@ 2015-01-16 14:03 ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

This adds support for Allwinner A0, A20 PS2 controller. 

I've tested PS2 keyboard on A20 Olimex-Lime2 board. 
Hans had tested previous patch on A10 as well.

v3 --> v4
1. Reported errors(SERIO_FRAME,SERIO_TIMEOUT, SERIO_PARITY) to consumer.
2. Handled the transmit timeout in sun4i_ps2_write.
3. Removed the resetting the ps2 controller in case of errors.
4. Added synchronize_irq() in sun4i_ps2_close to make sure pending interrupts are handled.
5. Explicitly disabled interrupt in probe to avoid spurious interrupts.
6. Removed disable_irq from sun4i_ps2_remove as serio_close will take care of it.
7. Removed the obvious comments.
3. Corrected the style errors.
4. As there is not conflict with ps2 pins, enabled ps2 pins in lime2 dts by default.

v2 --> v3
1. changed config to SERIO_SUN4I_PS2 from SERIO_SUNXI_PS2
2. changed driver name to sun4i-ps2 from sunxi-ps2.
3. changed the function names to sun4i_ps2_*.
4. added locking in sun4i_ps2_open.
5. kept compatible "sun4i-a10-ps2" for A10 and A20, as A10 is earlier SOC.
6. corrected the style errors.
7. separated the dts patches.
8. removed commented ps2 notes from lime2 dts.
9. added note that ps2 pins confilt with hdmi.
10. corrected the interrupt property for A10.
11. moved dt-bindings to Documentation/devicetree/bindings/serio

v1 --> v2:
1. added default n depends on ARCH_SUNXI || COMPILE_TEST in Kconfig.
2. handled errors and free resources on errors.
3. used BIT(x), DIV_ROUND_UP macros.
4. corrected style errors.
5. added support for A10 also, A10 and A2 have same properties of PS2 controller.
6. by default commented ps20 and ps21 nodes,as ps20 pins conflict with HDMI.
7. added compatible as allwinner,sun4i-a10-ps2.
8. corrected the possible race condition.

Vishnu Patekar (5):
  sunxi:dts-bindings:input: bindings for A10/A20 ps2
  ARM:sunxi:drivers:input Add support for A10/A20 PS2
  ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
  ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
  ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board

 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++
 arch/arm/boot/dts/sun4i-a10.dtsi                   |   30 ++
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts    |   12 +
 arch/arm/boot/dts/sun7i-a20.dtsi                   |   30 ++
 drivers/input/serio/Kconfig                        |   11 +
 drivers/input/serio/Makefile                       |    1 +
 drivers/input/serio/sun4i-ps2.c                    |  330 ++++++++++++++++++++
 7 files changed, 437 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
 create mode 100644 drivers/input/serio/sun4i-ps2.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller
@ 2015-01-16 14:03 ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

This adds support for Allwinner A0, A20 PS2 controller. 

I've tested PS2 keyboard on A20 Olimex-Lime2 board. 
Hans had tested previous patch on A10 as well.

v3 --> v4
1. Reported errors(SERIO_FRAME,SERIO_TIMEOUT, SERIO_PARITY) to consumer.
2. Handled the transmit timeout in sun4i_ps2_write.
3. Removed the resetting the ps2 controller in case of errors.
4. Added synchronize_irq() in sun4i_ps2_close to make sure pending interrupts are handled.
5. Explicitly disabled interrupt in probe to avoid spurious interrupts.
6. Removed disable_irq from sun4i_ps2_remove as serio_close will take care of it.
7. Removed the obvious comments.
3. Corrected the style errors.
4. As there is not conflict with ps2 pins, enabled ps2 pins in lime2 dts by default.

v2 --> v3
1. changed config to SERIO_SUN4I_PS2 from SERIO_SUNXI_PS2
2. changed driver name to sun4i-ps2 from sunxi-ps2.
3. changed the function names to sun4i_ps2_*.
4. added locking in sun4i_ps2_open.
5. kept compatible "sun4i-a10-ps2" for A10 and A20, as A10 is earlier SOC.
6. corrected the style errors.
7. separated the dts patches.
8. removed commented ps2 notes from lime2 dts.
9. added note that ps2 pins confilt with hdmi.
10. corrected the interrupt property for A10.
11. moved dt-bindings to Documentation/devicetree/bindings/serio

v1 --> v2:
1. added default n depends on ARCH_SUNXI || COMPILE_TEST in Kconfig.
2. handled errors and free resources on errors.
3. used BIT(x), DIV_ROUND_UP macros.
4. corrected style errors.
5. added support for A10 also, A10 and A2 have same properties of PS2 controller.
6. by default commented ps20 and ps21 nodes,as ps20 pins conflict with HDMI.
7. added compatible as allwinner,sun4i-a10-ps2.
8. corrected the possible race condition.

Vishnu Patekar (5):
  sunxi:dts-bindings:input: bindings for A10/A20 ps2
  ARM:sunxi:drivers:input Add support for A10/A20 PS2
  ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
  ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
  ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board

 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++
 arch/arm/boot/dts/sun4i-a10.dtsi                   |   30 ++
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts    |   12 +
 arch/arm/boot/dts/sun7i-a20.dtsi                   |   30 ++
 drivers/input/serio/Kconfig                        |   11 +
 drivers/input/serio/Makefile                       |    1 +
 drivers/input/serio/sun4i-ps2.c                    |  330 ++++++++++++++++++++
 7 files changed, 437 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
 create mode 100644 drivers/input/serio/sun4i-ps2.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller
@ 2015-01-16 14:03 ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

This adds support for Allwinner A0, A20 PS2 controller. 

I've tested PS2 keyboard on A20 Olimex-Lime2 board. 
Hans had tested previous patch on A10 as well.

v3 --> v4
1. Reported errors(SERIO_FRAME,SERIO_TIMEOUT, SERIO_PARITY) to consumer.
2. Handled the transmit timeout in sun4i_ps2_write.
3. Removed the resetting the ps2 controller in case of errors.
4. Added synchronize_irq() in sun4i_ps2_close to make sure pending interrupts are handled.
5. Explicitly disabled interrupt in probe to avoid spurious interrupts.
6. Removed disable_irq from sun4i_ps2_remove as serio_close will take care of it.
7. Removed the obvious comments.
3. Corrected the style errors.
4. As there is not conflict with ps2 pins, enabled ps2 pins in lime2 dts by default.

v2 --> v3
1. changed config to SERIO_SUN4I_PS2 from SERIO_SUNXI_PS2
2. changed driver name to sun4i-ps2 from sunxi-ps2.
3. changed the function names to sun4i_ps2_*.
4. added locking in sun4i_ps2_open.
5. kept compatible "sun4i-a10-ps2" for A10 and A20, as A10 is earlier SOC.
6. corrected the style errors.
7. separated the dts patches.
8. removed commented ps2 notes from lime2 dts.
9. added note that ps2 pins confilt with hdmi.
10. corrected the interrupt property for A10.
11. moved dt-bindings to Documentation/devicetree/bindings/serio

v1 --> v2:
1. added default n depends on ARCH_SUNXI || COMPILE_TEST in Kconfig.
2. handled errors and free resources on errors.
3. used BIT(x), DIV_ROUND_UP macros.
4. corrected style errors.
5. added support for A10 also, A10 and A2 have same properties of PS2 controller.
6. by default commented ps20 and ps21 nodes,as ps20 pins conflict with HDMI.
7. added compatible as allwinner,sun4i-a10-ps2.
8. corrected the possible race condition.

Vishnu Patekar (5):
  sunxi:dts-bindings:input: bindings for A10/A20 ps2
  ARM:sunxi:drivers:input Add support for A10/A20 PS2
  ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
  ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
  ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board

 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++
 arch/arm/boot/dts/sun4i-a10.dtsi                   |   30 ++
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts    |   12 +
 arch/arm/boot/dts/sun7i-a20.dtsi                   |   30 ++
 drivers/input/serio/Kconfig                        |   11 +
 drivers/input/serio/Makefile                       |    1 +
 drivers/input/serio/sun4i-ps2.c                    |  330 ++++++++++++++++++++
 7 files changed, 437 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
 create mode 100644 drivers/input/serio/sun4i-ps2.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 1/5] sunxi:dts-bindings:input: bindings for A10/A20 ps2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt

diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
new file mode 100644
index 0000000..0c30440
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
@@ -0,0 +1,23 @@
+* Device tree bindings for Allwinner A10, A20 PS2 host controller
+
+A20 PS2 is dual role controller(PS2 host and PS2 device). These bindings are
+for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard
+and mouse can be connected.
+
+Required properties:
+
+ - reg             : Offset and length of the register set for the device.
+ - compatible      : Should be as of the following:
+                     - "allwinner,sun4i-a10-ps2"
+ - interrupts      : The interrupt line connected to the PS2.
+ - clocks          : The gate clk connected to the PS2.
+
+
+Example:
+	ps20: ps2@0x01c2a000 {
+		compatible = "allwinner,sun4i-a10-ps2";
+		reg = <0x01c2a000 0x400>;
+		interrupts = <0 62 4>;
+		clocks = <&apb1_gates 6>;
+		status = "disabled";
+	};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 1/5] sunxi:dts-bindings:input: bindings for A10/A20 ps2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt

diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
new file mode 100644
index 0000000..0c30440
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
@@ -0,0 +1,23 @@
+* Device tree bindings for Allwinner A10, A20 PS2 host controller
+
+A20 PS2 is dual role controller(PS2 host and PS2 device). These bindings are
+for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard
+and mouse can be connected.
+
+Required properties:
+
+ - reg             : Offset and length of the register set for the device.
+ - compatible      : Should be as of the following:
+                     - "allwinner,sun4i-a10-ps2"
+ - interrupts      : The interrupt line connected to the PS2.
+ - clocks          : The gate clk connected to the PS2.
+
+
+Example:
+	ps20: ps2@0x01c2a000 {
+		compatible = "allwinner,sun4i-a10-ps2";
+		reg = <0x01c2a000 0x400>;
+		interrupts = <0 62 4>;
+		clocks = <&apb1_gates 6>;
+		status = "disabled";
+	};
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 1/5] sunxi:dts-bindings:input: bindings for A10/A20 ps2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 .../bindings/serio/allwinner,sun4i-ps2.txt         |   23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt

diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
new file mode 100644
index 0000000..0c30440
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
@@ -0,0 +1,23 @@
+* Device tree bindings for Allwinner A10, A20 PS2 host controller
+
+A20 PS2 is dual role controller(PS2 host and PS2 device). These bindings are
+for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard
+and mouse can be connected.
+
+Required properties:
+
+ - reg             : Offset and length of the register set for the device.
+ - compatible      : Should be as of the following:
+                     - "allwinner,sun4i-a10-ps2"
+ - interrupts      : The interrupt line connected to the PS2.
+ - clocks          : The gate clk connected to the PS2.
+
+
+Example:
+	ps20: ps2 at 0x01c2a000 {
+		compatible = "allwinner,sun4i-a10-ps2";
+		reg = <0x01c2a000 0x400>;
+		interrupts = <0 62 4>;
+		clocks = <&apb1_gates 6>;
+		status = "disabled";
+	};
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 drivers/input/serio/Kconfig     |   11 ++
 drivers/input/serio/Makefile    |    1 +
 drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+)
 create mode 100644 drivers/input/serio/sun4i-ps2.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bc2d474..964afc5 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
 	  To compile this driver as a module, choose M here: the module will
 	  be called hyperv_keyboard.
 
+config SERIO_SUN4I_PS2
+	tristate "Allwinner A10 PS/2 controller support"
+	default n
+	depends on ARCH_SUNXI || COMPILE_TEST
+	help
+	  This selects support for the PS/2 Host Controller on
+	  Allwinner A10.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sun4i-ps2.
+
 endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 815d874..c600089 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
 obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
 obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
 obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
+obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
new file mode 100644
index 0000000..06b3fef
--- /dev/null
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -0,0 +1,330 @@
+/*
+ *	Driver for Allwinner A10 PS2 host controller
+ *
+ *	Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
+ *		Aaron.maoye <leafy.myeh@newbietech.com>
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME		"sun4i-ps2"
+
+/* register offset definitions */
+#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
+#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
+#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
+#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
+#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
+#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
+#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
+
+/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
+#define PS2_GCTL_INTFLAG	BIT(4)
+#define PS2_GCTL_INTEN		BIT(3)
+#define PS2_GCTL_RESET		BIT(2)
+#define PS2_GCTL_MASTER		BIT(1)
+#define PS2_GCTL_BUSEN		BIT(0)
+
+/* PS2 LINE CONTROL REGISTER */
+#define PS2_LCTL_NOACK		BIT(18)
+#define PS2_LCTL_TXDTOEN	BIT(8)
+#define PS2_LCTL_STOPERREN	BIT(3)
+#define PS2_LCTL_ACKERREN	BIT(2)
+#define PS2_LCTL_PARERREN	BIT(1)
+#define PS2_LCTL_RXDTOEN	BIT(0)
+
+/* PS2 LINE STATUS REGISTER */
+#define PS2_LSTS_TXTDO		BIT(8)
+#define PS2_LSTS_STOPERR	BIT(3)
+#define PS2_LSTS_ACKERR		BIT(2)
+#define PS2_LSTS_PARERR		BIT(1)
+#define PS2_LSTS_RXTDO		BIT(0)
+
+#define PS2_LINE_ERROR_BIT \
+	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
+	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
+
+/* PS2 FIFO CONTROL REGISTER */
+#define PS2_FCTL_TXRST		BIT(17)
+#define PS2_FCTL_RXRST		BIT(16)
+#define PS2_FCTL_TXUFIEN	BIT(10)
+#define PS2_FCTL_TXOFIEN	BIT(9)
+#define PS2_FCTL_TXRDYIEN	BIT(8)
+#define PS2_FCTL_RXUFIEN	BIT(2)
+#define PS2_FCTL_RXOFIEN	BIT(1)
+#define PS2_FCTL_RXRDYIEN	BIT(0)
+
+/* PS2 FIFO STATUS REGISTER */
+#define PS2_FSTS_TXUF		BIT(10)
+#define PS2_FSTS_TXOF		BIT(9)
+#define PS2_FSTS_TXRDY		BIT(8)
+#define PS2_FSTS_RXUF		BIT(2)
+#define PS2_FSTS_RXOF		BIT(1)
+#define PS2_FSTS_RXRDY		BIT(0)
+
+#define PS2_FIFO_ERROR_BIT \
+	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
+
+#define PS2_SAMPLE_CLK		1000000
+#define PS2_SCLK		125000
+
+struct sun4i_ps2data {
+	struct serio *serio;
+	struct device *dev;
+
+	/* IO mapping base */
+	void __iomem	*reg_base;
+
+	/* clock management */
+	struct clk	*clk;
+
+	/* irq */
+	spinlock_t	lock;
+	int		irq;
+};
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
+{
+	struct sun4i_ps2data *drvdata = dev_id;
+	u32 intr_status;
+	u32 fifo_status;
+	unsigned char byte;
+	unsigned int rxflags = 0;
+	u32 rval;
+
+	spin_lock(&drvdata->lock);
+
+	/* Get the PS/2 interrupts and clear them */
+	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
+	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
+
+	/*Check Line Status Register*/
+	if (intr_status & PS2_LINE_ERROR_BIT) {
+		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
+
+		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
+			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
+		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
+	}
+
+	/*Check FIFO Status Register*/
+	if (fifo_status & PS2_FIFO_ERROR_BIT) {
+		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
+			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
+		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
+	}
+
+	rval = (fifo_status >> 16) & 0x3;
+	while (rval--) {
+		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
+		serio_interrupt(drvdata->serio, byte, rxflags);
+	}
+
+	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
+	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
+
+	spin_unlock(&drvdata->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static int sun4i_ps2_open(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+	u32 src_clk = 0;
+	u32 clk_scdf;
+	u32 clk_pcdf;
+	u32 rval;
+	unsigned long flags;
+
+	/*Set Line Control And Enable Interrupt*/
+	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
+		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
+	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
+
+	/*Reset FIFO*/
+	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
+		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
+		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
+
+	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
+
+	src_clk = clk_get_rate(drvdata->clk);
+	/*Set Clock Divider Register*/
+	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
+	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
+	rval = (clk_scdf<<8) | clk_pcdf;
+	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
+
+
+	/*Set Global Control Register*/
+	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
+		| PS2_GCTL_BUSEN;
+
+	spin_lock_irqsave(&drvdata->lock, flags);
+	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
+	spin_unlock_irqrestore(&drvdata->lock, flags);
+
+	return 0;
+}
+
+static void sun4i_ps2_close(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+
+	synchronize_irq(drvdata->irq);
+}
+
+static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
+{
+	unsigned long expire = jiffies + msecs_to_jiffies(10000);
+	struct sun4i_ps2data *drvdata;
+
+	drvdata = (struct sun4i_ps2data *)pserio->port_data;
+
+	do {
+		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
+			writel(val, drvdata->reg_base + PS2_REG_DATA);
+			return 0;
+		}
+	} while (time_before(jiffies, expire));
+
+	return SERIO_TIMEOUT;
+}
+
+static int sun4i_ps2_probe(struct platform_device *pdev)
+{
+	struct resource *res; /* IO mem resources */
+	struct sun4i_ps2data *drvdata;
+	struct serio *serio;
+	struct device *dev = &pdev->dev;
+	unsigned int irq;
+	int error;
+
+	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!drvdata || !serio) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	spin_lock_init(&drvdata->lock);
+
+	/* IO */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drvdata->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(drvdata->reg_base)) {
+		dev_err(dev, "failed to map registers\n");
+		error = PTR_ERR(drvdata->reg_base);
+		goto err_free_mem;
+	}
+
+	drvdata->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(drvdata->clk)) {
+		error = PTR_ERR(drvdata->clk);
+		dev_err(dev, "couldn't get clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	error = clk_prepare_enable(drvdata->clk);
+	if (error) {
+		dev_err(dev, "failed to enable clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	serio->id.type = SERIO_8042;
+	serio->write = sun4i_ps2_write;
+	serio->open = sun4i_ps2_open;
+	serio->close = sun4i_ps2_close;
+	serio->port_data = drvdata;
+	serio->dev.parent = dev;
+	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
+	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
+
+	/* Get IRQ for the device */
+	irq = platform_get_irq(pdev, 0);
+	if (!irq) {
+		dev_err(dev, "no IRQ found\n");
+		error = -ENXIO;
+		goto error_disable_clk;
+	}
+
+	drvdata->irq = irq;
+	drvdata->serio = serio;
+	drvdata->dev = dev;
+	error = devm_request_threaded_irq(dev, drvdata->irq,
+		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
+
+	if (error) {
+		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
+			drvdata->irq, error);
+		goto error_disable_clk;
+	}
+
+	serio_register_port(serio);
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;	/* success */
+
+error_disable_clk:
+	clk_disable_unprepare(drvdata->clk);
+
+err_free_mem:
+	kfree(serio);
+	return error;
+}
+
+static int sun4i_ps2_remove(struct platform_device *pdev)
+{
+	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
+
+	serio_unregister_port(drvdata->serio);
+
+	if (!IS_ERR(drvdata->clk))
+		clk_disable_unprepare(drvdata->clk);
+	kfree(drvdata->serio);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_ps2_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-ps2", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
+
+static struct platform_driver sun4i_ps2_driver = {
+	.probe		= sun4i_ps2_probe,
+	.remove		= sun4i_ps2_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = sun4i_ps2_match,
+	},
+};
+module_platform_driver(sun4i_ps2_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
+MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
+MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/input/serio/Kconfig     |   11 ++
 drivers/input/serio/Makefile    |    1 +
 drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+)
 create mode 100644 drivers/input/serio/sun4i-ps2.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bc2d474..964afc5 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
 	  To compile this driver as a module, choose M here: the module will
 	  be called hyperv_keyboard.
 
+config SERIO_SUN4I_PS2
+	tristate "Allwinner A10 PS/2 controller support"
+	default n
+	depends on ARCH_SUNXI || COMPILE_TEST
+	help
+	  This selects support for the PS/2 Host Controller on
+	  Allwinner A10.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sun4i-ps2.
+
 endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 815d874..c600089 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
 obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
 obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
 obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
+obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
new file mode 100644
index 0000000..06b3fef
--- /dev/null
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -0,0 +1,330 @@
+/*
+ *	Driver for Allwinner A10 PS2 host controller
+ *
+ *	Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *		Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME		"sun4i-ps2"
+
+/* register offset definitions */
+#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
+#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
+#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
+#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
+#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
+#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
+#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
+
+/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
+#define PS2_GCTL_INTFLAG	BIT(4)
+#define PS2_GCTL_INTEN		BIT(3)
+#define PS2_GCTL_RESET		BIT(2)
+#define PS2_GCTL_MASTER		BIT(1)
+#define PS2_GCTL_BUSEN		BIT(0)
+
+/* PS2 LINE CONTROL REGISTER */
+#define PS2_LCTL_NOACK		BIT(18)
+#define PS2_LCTL_TXDTOEN	BIT(8)
+#define PS2_LCTL_STOPERREN	BIT(3)
+#define PS2_LCTL_ACKERREN	BIT(2)
+#define PS2_LCTL_PARERREN	BIT(1)
+#define PS2_LCTL_RXDTOEN	BIT(0)
+
+/* PS2 LINE STATUS REGISTER */
+#define PS2_LSTS_TXTDO		BIT(8)
+#define PS2_LSTS_STOPERR	BIT(3)
+#define PS2_LSTS_ACKERR		BIT(2)
+#define PS2_LSTS_PARERR		BIT(1)
+#define PS2_LSTS_RXTDO		BIT(0)
+
+#define PS2_LINE_ERROR_BIT \
+	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
+	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
+
+/* PS2 FIFO CONTROL REGISTER */
+#define PS2_FCTL_TXRST		BIT(17)
+#define PS2_FCTL_RXRST		BIT(16)
+#define PS2_FCTL_TXUFIEN	BIT(10)
+#define PS2_FCTL_TXOFIEN	BIT(9)
+#define PS2_FCTL_TXRDYIEN	BIT(8)
+#define PS2_FCTL_RXUFIEN	BIT(2)
+#define PS2_FCTL_RXOFIEN	BIT(1)
+#define PS2_FCTL_RXRDYIEN	BIT(0)
+
+/* PS2 FIFO STATUS REGISTER */
+#define PS2_FSTS_TXUF		BIT(10)
+#define PS2_FSTS_TXOF		BIT(9)
+#define PS2_FSTS_TXRDY		BIT(8)
+#define PS2_FSTS_RXUF		BIT(2)
+#define PS2_FSTS_RXOF		BIT(1)
+#define PS2_FSTS_RXRDY		BIT(0)
+
+#define PS2_FIFO_ERROR_BIT \
+	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
+
+#define PS2_SAMPLE_CLK		1000000
+#define PS2_SCLK		125000
+
+struct sun4i_ps2data {
+	struct serio *serio;
+	struct device *dev;
+
+	/* IO mapping base */
+	void __iomem	*reg_base;
+
+	/* clock management */
+	struct clk	*clk;
+
+	/* irq */
+	spinlock_t	lock;
+	int		irq;
+};
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
+{
+	struct sun4i_ps2data *drvdata = dev_id;
+	u32 intr_status;
+	u32 fifo_status;
+	unsigned char byte;
+	unsigned int rxflags = 0;
+	u32 rval;
+
+	spin_lock(&drvdata->lock);
+
+	/* Get the PS/2 interrupts and clear them */
+	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
+	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
+
+	/*Check Line Status Register*/
+	if (intr_status & PS2_LINE_ERROR_BIT) {
+		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
+
+		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
+			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
+		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
+	}
+
+	/*Check FIFO Status Register*/
+	if (fifo_status & PS2_FIFO_ERROR_BIT) {
+		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
+			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
+		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
+	}
+
+	rval = (fifo_status >> 16) & 0x3;
+	while (rval--) {
+		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
+		serio_interrupt(drvdata->serio, byte, rxflags);
+	}
+
+	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
+	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
+
+	spin_unlock(&drvdata->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static int sun4i_ps2_open(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+	u32 src_clk = 0;
+	u32 clk_scdf;
+	u32 clk_pcdf;
+	u32 rval;
+	unsigned long flags;
+
+	/*Set Line Control And Enable Interrupt*/
+	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
+		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
+	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
+
+	/*Reset FIFO*/
+	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
+		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
+		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
+
+	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
+
+	src_clk = clk_get_rate(drvdata->clk);
+	/*Set Clock Divider Register*/
+	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
+	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
+	rval = (clk_scdf<<8) | clk_pcdf;
+	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
+
+
+	/*Set Global Control Register*/
+	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
+		| PS2_GCTL_BUSEN;
+
+	spin_lock_irqsave(&drvdata->lock, flags);
+	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
+	spin_unlock_irqrestore(&drvdata->lock, flags);
+
+	return 0;
+}
+
+static void sun4i_ps2_close(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+
+	synchronize_irq(drvdata->irq);
+}
+
+static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
+{
+	unsigned long expire = jiffies + msecs_to_jiffies(10000);
+	struct sun4i_ps2data *drvdata;
+
+	drvdata = (struct sun4i_ps2data *)pserio->port_data;
+
+	do {
+		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
+			writel(val, drvdata->reg_base + PS2_REG_DATA);
+			return 0;
+		}
+	} while (time_before(jiffies, expire));
+
+	return SERIO_TIMEOUT;
+}
+
+static int sun4i_ps2_probe(struct platform_device *pdev)
+{
+	struct resource *res; /* IO mem resources */
+	struct sun4i_ps2data *drvdata;
+	struct serio *serio;
+	struct device *dev = &pdev->dev;
+	unsigned int irq;
+	int error;
+
+	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!drvdata || !serio) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	spin_lock_init(&drvdata->lock);
+
+	/* IO */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drvdata->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(drvdata->reg_base)) {
+		dev_err(dev, "failed to map registers\n");
+		error = PTR_ERR(drvdata->reg_base);
+		goto err_free_mem;
+	}
+
+	drvdata->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(drvdata->clk)) {
+		error = PTR_ERR(drvdata->clk);
+		dev_err(dev, "couldn't get clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	error = clk_prepare_enable(drvdata->clk);
+	if (error) {
+		dev_err(dev, "failed to enable clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	serio->id.type = SERIO_8042;
+	serio->write = sun4i_ps2_write;
+	serio->open = sun4i_ps2_open;
+	serio->close = sun4i_ps2_close;
+	serio->port_data = drvdata;
+	serio->dev.parent = dev;
+	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
+	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
+
+	/* Get IRQ for the device */
+	irq = platform_get_irq(pdev, 0);
+	if (!irq) {
+		dev_err(dev, "no IRQ found\n");
+		error = -ENXIO;
+		goto error_disable_clk;
+	}
+
+	drvdata->irq = irq;
+	drvdata->serio = serio;
+	drvdata->dev = dev;
+	error = devm_request_threaded_irq(dev, drvdata->irq,
+		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
+
+	if (error) {
+		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
+			drvdata->irq, error);
+		goto error_disable_clk;
+	}
+
+	serio_register_port(serio);
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;	/* success */
+
+error_disable_clk:
+	clk_disable_unprepare(drvdata->clk);
+
+err_free_mem:
+	kfree(serio);
+	return error;
+}
+
+static int sun4i_ps2_remove(struct platform_device *pdev)
+{
+	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
+
+	serio_unregister_port(drvdata->serio);
+
+	if (!IS_ERR(drvdata->clk))
+		clk_disable_unprepare(drvdata->clk);
+	kfree(drvdata->serio);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_ps2_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-ps2", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
+
+static struct platform_driver sun4i_ps2_driver = {
+	.probe		= sun4i_ps2_probe,
+	.remove		= sun4i_ps2_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = sun4i_ps2_match,
+	},
+};
+module_platform_driver(sun4i_ps2_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_AUTHOR("Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>");
+MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 drivers/input/serio/Kconfig     |   11 ++
 drivers/input/serio/Makefile    |    1 +
 drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+)
 create mode 100644 drivers/input/serio/sun4i-ps2.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bc2d474..964afc5 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
 	  To compile this driver as a module, choose M here: the module will
 	  be called hyperv_keyboard.
 
+config SERIO_SUN4I_PS2
+	tristate "Allwinner A10 PS/2 controller support"
+	default n
+	depends on ARCH_SUNXI || COMPILE_TEST
+	help
+	  This selects support for the PS/2 Host Controller on
+	  Allwinner A10.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sun4i-ps2.
+
 endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 815d874..c600089 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
 obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
 obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
 obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
+obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
new file mode 100644
index 0000000..06b3fef
--- /dev/null
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -0,0 +1,330 @@
+/*
+ *	Driver for Allwinner A10 PS2 host controller
+ *
+ *	Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
+ *		Aaron.maoye <leafy.myeh@newbietech.com>
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME		"sun4i-ps2"
+
+/* register offset definitions */
+#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
+#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
+#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
+#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
+#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
+#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
+#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
+
+/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
+#define PS2_GCTL_INTFLAG	BIT(4)
+#define PS2_GCTL_INTEN		BIT(3)
+#define PS2_GCTL_RESET		BIT(2)
+#define PS2_GCTL_MASTER		BIT(1)
+#define PS2_GCTL_BUSEN		BIT(0)
+
+/* PS2 LINE CONTROL REGISTER */
+#define PS2_LCTL_NOACK		BIT(18)
+#define PS2_LCTL_TXDTOEN	BIT(8)
+#define PS2_LCTL_STOPERREN	BIT(3)
+#define PS2_LCTL_ACKERREN	BIT(2)
+#define PS2_LCTL_PARERREN	BIT(1)
+#define PS2_LCTL_RXDTOEN	BIT(0)
+
+/* PS2 LINE STATUS REGISTER */
+#define PS2_LSTS_TXTDO		BIT(8)
+#define PS2_LSTS_STOPERR	BIT(3)
+#define PS2_LSTS_ACKERR		BIT(2)
+#define PS2_LSTS_PARERR		BIT(1)
+#define PS2_LSTS_RXTDO		BIT(0)
+
+#define PS2_LINE_ERROR_BIT \
+	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
+	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
+
+/* PS2 FIFO CONTROL REGISTER */
+#define PS2_FCTL_TXRST		BIT(17)
+#define PS2_FCTL_RXRST		BIT(16)
+#define PS2_FCTL_TXUFIEN	BIT(10)
+#define PS2_FCTL_TXOFIEN	BIT(9)
+#define PS2_FCTL_TXRDYIEN	BIT(8)
+#define PS2_FCTL_RXUFIEN	BIT(2)
+#define PS2_FCTL_RXOFIEN	BIT(1)
+#define PS2_FCTL_RXRDYIEN	BIT(0)
+
+/* PS2 FIFO STATUS REGISTER */
+#define PS2_FSTS_TXUF		BIT(10)
+#define PS2_FSTS_TXOF		BIT(9)
+#define PS2_FSTS_TXRDY		BIT(8)
+#define PS2_FSTS_RXUF		BIT(2)
+#define PS2_FSTS_RXOF		BIT(1)
+#define PS2_FSTS_RXRDY		BIT(0)
+
+#define PS2_FIFO_ERROR_BIT \
+	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
+
+#define PS2_SAMPLE_CLK		1000000
+#define PS2_SCLK		125000
+
+struct sun4i_ps2data {
+	struct serio *serio;
+	struct device *dev;
+
+	/* IO mapping base */
+	void __iomem	*reg_base;
+
+	/* clock management */
+	struct clk	*clk;
+
+	/* irq */
+	spinlock_t	lock;
+	int		irq;
+};
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
+{
+	struct sun4i_ps2data *drvdata = dev_id;
+	u32 intr_status;
+	u32 fifo_status;
+	unsigned char byte;
+	unsigned int rxflags = 0;
+	u32 rval;
+
+	spin_lock(&drvdata->lock);
+
+	/* Get the PS/2 interrupts and clear them */
+	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
+	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
+
+	/*Check Line Status Register*/
+	if (intr_status & PS2_LINE_ERROR_BIT) {
+		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
+		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
+
+		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
+			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
+		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
+	}
+
+	/*Check FIFO Status Register*/
+	if (fifo_status & PS2_FIFO_ERROR_BIT) {
+		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
+			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
+		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
+	}
+
+	rval = (fifo_status >> 16) & 0x3;
+	while (rval--) {
+		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
+		serio_interrupt(drvdata->serio, byte, rxflags);
+	}
+
+	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
+	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
+
+	spin_unlock(&drvdata->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static int sun4i_ps2_open(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+	u32 src_clk = 0;
+	u32 clk_scdf;
+	u32 clk_pcdf;
+	u32 rval;
+	unsigned long flags;
+
+	/*Set Line Control And Enable Interrupt*/
+	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
+		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
+	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
+
+	/*Reset FIFO*/
+	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
+		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
+		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
+
+	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
+
+	src_clk = clk_get_rate(drvdata->clk);
+	/*Set Clock Divider Register*/
+	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
+	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
+	rval = (clk_scdf<<8) | clk_pcdf;
+	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
+
+
+	/*Set Global Control Register*/
+	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
+		| PS2_GCTL_BUSEN;
+
+	spin_lock_irqsave(&drvdata->lock, flags);
+	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
+	spin_unlock_irqrestore(&drvdata->lock, flags);
+
+	return 0;
+}
+
+static void sun4i_ps2_close(struct serio *pserio)
+{
+	struct sun4i_ps2data *drvdata = pserio->port_data;
+
+	synchronize_irq(drvdata->irq);
+}
+
+static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
+{
+	unsigned long expire = jiffies + msecs_to_jiffies(10000);
+	struct sun4i_ps2data *drvdata;
+
+	drvdata = (struct sun4i_ps2data *)pserio->port_data;
+
+	do {
+		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
+			writel(val, drvdata->reg_base + PS2_REG_DATA);
+			return 0;
+		}
+	} while (time_before(jiffies, expire));
+
+	return SERIO_TIMEOUT;
+}
+
+static int sun4i_ps2_probe(struct platform_device *pdev)
+{
+	struct resource *res; /* IO mem resources */
+	struct sun4i_ps2data *drvdata;
+	struct serio *serio;
+	struct device *dev = &pdev->dev;
+	unsigned int irq;
+	int error;
+
+	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!drvdata || !serio) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	spin_lock_init(&drvdata->lock);
+
+	/* IO */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drvdata->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(drvdata->reg_base)) {
+		dev_err(dev, "failed to map registers\n");
+		error = PTR_ERR(drvdata->reg_base);
+		goto err_free_mem;
+	}
+
+	drvdata->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(drvdata->clk)) {
+		error = PTR_ERR(drvdata->clk);
+		dev_err(dev, "couldn't get clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	error = clk_prepare_enable(drvdata->clk);
+	if (error) {
+		dev_err(dev, "failed to enable clock %d\n", error);
+		goto err_free_mem;
+	}
+
+	serio->id.type = SERIO_8042;
+	serio->write = sun4i_ps2_write;
+	serio->open = sun4i_ps2_open;
+	serio->close = sun4i_ps2_close;
+	serio->port_data = drvdata;
+	serio->dev.parent = dev;
+	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
+	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
+
+	/* Get IRQ for the device */
+	irq = platform_get_irq(pdev, 0);
+	if (!irq) {
+		dev_err(dev, "no IRQ found\n");
+		error = -ENXIO;
+		goto error_disable_clk;
+	}
+
+	drvdata->irq = irq;
+	drvdata->serio = serio;
+	drvdata->dev = dev;
+	error = devm_request_threaded_irq(dev, drvdata->irq,
+		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
+
+	if (error) {
+		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
+			drvdata->irq, error);
+		goto error_disable_clk;
+	}
+
+	serio_register_port(serio);
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;	/* success */
+
+error_disable_clk:
+	clk_disable_unprepare(drvdata->clk);
+
+err_free_mem:
+	kfree(serio);
+	return error;
+}
+
+static int sun4i_ps2_remove(struct platform_device *pdev)
+{
+	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
+
+	serio_unregister_port(drvdata->serio);
+
+	if (!IS_ERR(drvdata->clk))
+		clk_disable_unprepare(drvdata->clk);
+	kfree(drvdata->serio);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_ps2_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-ps2", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
+
+static struct platform_driver sun4i_ps2_driver = {
+	.probe		= sun4i_ps2_probe,
+	.remove		= sun4i_ps2_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = sun4i_ps2_match,
+	},
+};
+module_platform_driver(sun4i_ps2_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
+MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
+MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 7b4099f..2c31242 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -795,5 +795,21 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <62>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <63>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e21ce59..f35c691 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1093,5 +1093,21 @@
 			#interrupt-cells = <3>;
 			interrupts = <1 9 0xf04>;
 		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <0 62 4>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <0 63 4>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 7b4099f..2c31242 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -795,5 +795,21 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <62>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <63>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e21ce59..f35c691 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1093,5 +1093,21 @@
 			#interrupt-cells = <3>;
 			interrupts = <1 9 0xf04>;
 		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <0 62 4>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <0 63 4>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 7b4099f..2c31242 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -795,5 +795,21 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		ps20: ps2 at 01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <62>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2 at 01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <63>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e21ce59..f35c691 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1093,5 +1093,21 @@
 			#interrupt-cells = <3>;
 			interrupts = <1 9 0xf04>;
 		};
+
+		ps20: ps2 at 01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <0 62 4>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2 at 01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <0 63 4>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 2c31242..8fade3e 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -629,6 +629,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer@01c20c00 {
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index f35c691..f9dd274 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -866,6 +866,20 @@
 				    allwinner,drive = <0>;
 				    allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer@01c20c00 {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 2c31242..8fade3e 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -629,6 +629,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer@01c20c00 {
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index f35c691..f9dd274 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -866,6 +866,20 @@
 				    allwinner,drive = <0>;
 				    allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer@01c20c00 {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 2c31242..8fade3e 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -629,6 +629,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20 at 0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21 at 0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer at 01c20c00 {
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index f35c691..f9dd274 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -866,6 +866,20 @@
 				    allwinner,drive = <0>;
 				    allwinner,pull = <0>;
 			};
+
+			ps20_pins_a: ps20 at 0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			ps21_pins_a: ps21 at 0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
 		};
 
 		timer at 01c20c00 {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov, hdegoede, ijc+devicetree, maxime.ripard
  Cc: linux-arm-kernel, linux-kernel, linux-sunxi, linux-input,
	devicetree, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index ed364d5..3365f12 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -113,6 +113,18 @@
 			status = "okay";
 		};
 
+		ps20: ps2@01c2a000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps20_pins_a>;
+			status = "okay";
+		};
+
+		ps21: ps2@01c2a400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps21_pins_a>;
+			status = "okay";
+		};
+
 		i2c0: i2c@01c2ac00 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c0_pins_a>;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Vishnu Patekar

Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index ed364d5..3365f12 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -113,6 +113,18 @@
 			status = "okay";
 		};
 
+		ps20: ps2@01c2a000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps20_pins_a>;
+			status = "okay";
+		};
+
+		ps21: ps2@01c2a400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps21_pins_a>;
+			status = "okay";
+		};
+
 		i2c0: i2c@01c2ac00 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c0_pins_a>;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-16 14:03   ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-16 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
---
 arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index ed364d5..3365f12 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -113,6 +113,18 @@
 			status = "okay";
 		};
 
+		ps20: ps2 at 01c2a000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps20_pins_a>;
+			status = "okay";
+		};
+
+		ps21: ps2 at 01c2a400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ps21_pins_a>;
+			status = "okay";
+		};
+
 		i2c0: i2c at 01c2ac00 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c0_pins_a>;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-17 22:25     ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-17 22:25 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: hdegoede, ijc+devicetree, maxime.ripard, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  drivers/input/serio/Kconfig     |   11 ++
>  drivers/input/serio/Makefile    |    1 +
>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 342 insertions(+)
>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> 
> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> index bc2d474..964afc5 100644
> --- a/drivers/input/serio/Kconfig
> +++ b/drivers/input/serio/Kconfig
> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called hyperv_keyboard.
>  
> +config SERIO_SUN4I_PS2
> +	tristate "Allwinner A10 PS/2 controller support"
> +	default n
> +	depends on ARCH_SUNXI || COMPILE_TEST
> +	help
> +	  This selects support for the PS/2 Host Controller on
> +	  Allwinner A10.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called sun4i-ps2.
> +
>  endif
> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> index 815d874..c600089 100644
> --- a/drivers/input/serio/Makefile
> +++ b/drivers/input/serio/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
>  obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
>  obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
>  obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
> +obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> new file mode 100644
> index 0000000..06b3fef
> --- /dev/null
> +++ b/drivers/input/serio/sun4i-ps2.c
> @@ -0,0 +1,330 @@
> +/*
> + *	Driver for Allwinner A10 PS2 host controller
> + *
> + *	Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> + *		Aaron.maoye <leafy.myeh@newbietech.com>
> + *
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/serio.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME		"sun4i-ps2"
> +
> +/* register offset definitions */
> +#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
> +#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
> +#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
> +#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
> +#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
> +#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
> +#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
> +
> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> +#define PS2_GCTL_INTFLAG	BIT(4)
> +#define PS2_GCTL_INTEN		BIT(3)
> +#define PS2_GCTL_RESET		BIT(2)
> +#define PS2_GCTL_MASTER		BIT(1)
> +#define PS2_GCTL_BUSEN		BIT(0)
> +
> +/* PS2 LINE CONTROL REGISTER */
> +#define PS2_LCTL_NOACK		BIT(18)
> +#define PS2_LCTL_TXDTOEN	BIT(8)
> +#define PS2_LCTL_STOPERREN	BIT(3)
> +#define PS2_LCTL_ACKERREN	BIT(2)
> +#define PS2_LCTL_PARERREN	BIT(1)
> +#define PS2_LCTL_RXDTOEN	BIT(0)
> +
> +/* PS2 LINE STATUS REGISTER */
> +#define PS2_LSTS_TXTDO		BIT(8)
> +#define PS2_LSTS_STOPERR	BIT(3)
> +#define PS2_LSTS_ACKERR		BIT(2)
> +#define PS2_LSTS_PARERR		BIT(1)
> +#define PS2_LSTS_RXTDO		BIT(0)
> +
> +#define PS2_LINE_ERROR_BIT \
> +	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> +	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> +
> +/* PS2 FIFO CONTROL REGISTER */
> +#define PS2_FCTL_TXRST		BIT(17)
> +#define PS2_FCTL_RXRST		BIT(16)
> +#define PS2_FCTL_TXUFIEN	BIT(10)
> +#define PS2_FCTL_TXOFIEN	BIT(9)
> +#define PS2_FCTL_TXRDYIEN	BIT(8)
> +#define PS2_FCTL_RXUFIEN	BIT(2)
> +#define PS2_FCTL_RXOFIEN	BIT(1)
> +#define PS2_FCTL_RXRDYIEN	BIT(0)
> +
> +/* PS2 FIFO STATUS REGISTER */
> +#define PS2_FSTS_TXUF		BIT(10)
> +#define PS2_FSTS_TXOF		BIT(9)
> +#define PS2_FSTS_TXRDY		BIT(8)
> +#define PS2_FSTS_RXUF		BIT(2)
> +#define PS2_FSTS_RXOF		BIT(1)
> +#define PS2_FSTS_RXRDY		BIT(0)
> +
> +#define PS2_FIFO_ERROR_BIT \
> +	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> +
> +#define PS2_SAMPLE_CLK		1000000
> +#define PS2_SCLK		125000
> +
> +struct sun4i_ps2data {
> +	struct serio *serio;
> +	struct device *dev;
> +
> +	/* IO mapping base */
> +	void __iomem	*reg_base;
> +
> +	/* clock management */
> +	struct clk	*clk;
> +
> +	/* irq */
> +	spinlock_t	lock;
> +	int		irq;
> +};
> +
> +/*********************/
> +/* Interrupt handler */
> +/*********************/
> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> +{
> +	struct sun4i_ps2data *drvdata = dev_id;
> +	u32 intr_status;
> +	u32 fifo_status;
> +	unsigned char byte;
> +	unsigned int rxflags = 0;
> +	u32 rval;
> +
> +	spin_lock(&drvdata->lock);
> +
> +	/* Get the PS/2 interrupts and clear them */
> +	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> +	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> +
> +	/*Check Line Status Register*/
> +	if (intr_status & PS2_LINE_ERROR_BIT) {
> +		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> +
> +		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> +			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> +		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> +	}
> +
> +	/*Check FIFO Status Register*/
> +	if (fifo_status & PS2_FIFO_ERROR_BIT) {
> +		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> +			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> +		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> +	}
> +
> +	rval = (fifo_status >> 16) & 0x3;
> +	while (rval--) {
> +		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> +		serio_interrupt(drvdata->serio, byte, rxflags);
> +	}
> +
> +	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> +	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> +
> +	spin_unlock(&drvdata->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +
> +static int sun4i_ps2_open(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +	u32 src_clk = 0;
> +	u32 clk_scdf;
> +	u32 clk_pcdf;
> +	u32 rval;
> +	unsigned long flags;
> +
> +	/*Set Line Control And Enable Interrupt*/
> +	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> +		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> +	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> +
> +	/*Reset FIFO*/
> +	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> +		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> +		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> +
> +	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> +
> +	src_clk = clk_get_rate(drvdata->clk);
> +	/*Set Clock Divider Register*/
> +	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> +	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> +	rval = (clk_scdf<<8) | clk_pcdf;
> +	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> +
> +
> +	/*Set Global Control Register*/
> +	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> +		| PS2_GCTL_BUSEN;
> +
> +	spin_lock_irqsave(&drvdata->lock, flags);
> +	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> +	spin_unlock_irqrestore(&drvdata->lock, flags);
> +
> +	return 0;
> +}
> +
> +static void sun4i_ps2_close(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +
> +	synchronize_irq(drvdata->irq);

synchronize_irq() on it's own is not very useful. You also need to shut
off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
before calling synchronize_irq.

> +}
> +
> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> +{
> +	unsigned long expire = jiffies + msecs_to_jiffies(10000);
> +	struct sun4i_ps2data *drvdata;
> +
> +	drvdata = (struct sun4i_ps2data *)pserio->port_data;
> +
> +	do {
> +		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> +			writel(val, drvdata->reg_base + PS2_REG_DATA);
> +			return 0;
> +		}
> +	} while (time_before(jiffies, expire));
> +
> +	return SERIO_TIMEOUT;
> +}
> +
> +static int sun4i_ps2_probe(struct platform_device *pdev)
> +{
> +	struct resource *res; /* IO mem resources */
> +	struct sun4i_ps2data *drvdata;
> +	struct serio *serio;
> +	struct device *dev = &pdev->dev;
> +	unsigned int irq;
> +	int error;
> +
> +	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> +	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> +	if (!drvdata || !serio) {
> +		error = -ENOMEM;
> +		goto err_free_mem;
> +	}
> +
> +	spin_lock_init(&drvdata->lock);
> +
> +	/* IO */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drvdata->reg_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(drvdata->reg_base)) {
> +		dev_err(dev, "failed to map registers\n");
> +		error = PTR_ERR(drvdata->reg_base);
> +		goto err_free_mem;
> +	}
> +
> +	drvdata->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(drvdata->clk)) {
> +		error = PTR_ERR(drvdata->clk);
> +		dev_err(dev, "couldn't get clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	error = clk_prepare_enable(drvdata->clk);
> +	if (error) {
> +		dev_err(dev, "failed to enable clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	serio->id.type = SERIO_8042;
> +	serio->write = sun4i_ps2_write;
> +	serio->open = sun4i_ps2_open;
> +	serio->close = sun4i_ps2_close;
> +	serio->port_data = drvdata;
> +	serio->dev.parent = dev;
> +	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> +	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> +
> +	/* Get IRQ for the device */
> +	irq = platform_get_irq(pdev, 0);
> +	if (!irq) {
> +		dev_err(dev, "no IRQ found\n");
> +		error = -ENXIO;
> +		goto error_disable_clk;
> +	}
> +
> +	drvdata->irq = irq;
> +	drvdata->serio = serio;
> +	drvdata->dev = dev;
> +	error = devm_request_threaded_irq(dev, drvdata->irq,
> +		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> +
> +	if (error) {
> +		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> +			drvdata->irq, error);
> +		goto error_disable_clk;
> +	}
> +
> +	serio_register_port(serio);
> +	platform_set_drvdata(pdev, drvdata);
> +
> +	return 0;	/* success */
> +
> +error_disable_clk:
> +	clk_disable_unprepare(drvdata->clk);
> +
> +err_free_mem:
> +	kfree(serio);
> +	return error;
> +}
> +
> +static int sun4i_ps2_remove(struct platform_device *pdev)
> +{
> +	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> +
> +	serio_unregister_port(drvdata->serio);
> +
> +	if (!IS_ERR(drvdata->clk))
> +		clk_disable_unprepare(drvdata->clk);
> +	kfree(drvdata->serio);

Serio is refcounted, you do not free it after its has been registered.
Overall I'd rather you did not use devm* interfaces here since you are
forced to mix managed and manually freed resources.

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_ps2_match[] = {
> +	{ .compatible = "allwinner,sun4i-a10-ps2", },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
> +
> +static struct platform_driver sun4i_ps2_driver = {
> +	.probe		= sun4i_ps2_probe,
> +	.remove		= sun4i_ps2_remove,
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.of_match_table = sun4i_ps2_match,
> +	},
> +};
> +module_platform_driver(sun4i_ps2_driver);
> +
> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.7.9.5
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-17 22:25     ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-17 22:25 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/input/serio/Kconfig     |   11 ++
>  drivers/input/serio/Makefile    |    1 +
>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 342 insertions(+)
>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> 
> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> index bc2d474..964afc5 100644
> --- a/drivers/input/serio/Kconfig
> +++ b/drivers/input/serio/Kconfig
> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called hyperv_keyboard.
>  
> +config SERIO_SUN4I_PS2
> +	tristate "Allwinner A10 PS/2 controller support"
> +	default n
> +	depends on ARCH_SUNXI || COMPILE_TEST
> +	help
> +	  This selects support for the PS/2 Host Controller on
> +	  Allwinner A10.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called sun4i-ps2.
> +
>  endif
> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> index 815d874..c600089 100644
> --- a/drivers/input/serio/Makefile
> +++ b/drivers/input/serio/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
>  obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
>  obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
>  obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
> +obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> new file mode 100644
> index 0000000..06b3fef
> --- /dev/null
> +++ b/drivers/input/serio/sun4i-ps2.c
> @@ -0,0 +1,330 @@
> +/*
> + *	Driver for Allwinner A10 PS2 host controller
> + *
> + *	Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + *		Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
> + *
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/serio.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME		"sun4i-ps2"
> +
> +/* register offset definitions */
> +#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
> +#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
> +#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
> +#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
> +#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
> +#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
> +#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
> +
> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> +#define PS2_GCTL_INTFLAG	BIT(4)
> +#define PS2_GCTL_INTEN		BIT(3)
> +#define PS2_GCTL_RESET		BIT(2)
> +#define PS2_GCTL_MASTER		BIT(1)
> +#define PS2_GCTL_BUSEN		BIT(0)
> +
> +/* PS2 LINE CONTROL REGISTER */
> +#define PS2_LCTL_NOACK		BIT(18)
> +#define PS2_LCTL_TXDTOEN	BIT(8)
> +#define PS2_LCTL_STOPERREN	BIT(3)
> +#define PS2_LCTL_ACKERREN	BIT(2)
> +#define PS2_LCTL_PARERREN	BIT(1)
> +#define PS2_LCTL_RXDTOEN	BIT(0)
> +
> +/* PS2 LINE STATUS REGISTER */
> +#define PS2_LSTS_TXTDO		BIT(8)
> +#define PS2_LSTS_STOPERR	BIT(3)
> +#define PS2_LSTS_ACKERR		BIT(2)
> +#define PS2_LSTS_PARERR		BIT(1)
> +#define PS2_LSTS_RXTDO		BIT(0)
> +
> +#define PS2_LINE_ERROR_BIT \
> +	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> +	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> +
> +/* PS2 FIFO CONTROL REGISTER */
> +#define PS2_FCTL_TXRST		BIT(17)
> +#define PS2_FCTL_RXRST		BIT(16)
> +#define PS2_FCTL_TXUFIEN	BIT(10)
> +#define PS2_FCTL_TXOFIEN	BIT(9)
> +#define PS2_FCTL_TXRDYIEN	BIT(8)
> +#define PS2_FCTL_RXUFIEN	BIT(2)
> +#define PS2_FCTL_RXOFIEN	BIT(1)
> +#define PS2_FCTL_RXRDYIEN	BIT(0)
> +
> +/* PS2 FIFO STATUS REGISTER */
> +#define PS2_FSTS_TXUF		BIT(10)
> +#define PS2_FSTS_TXOF		BIT(9)
> +#define PS2_FSTS_TXRDY		BIT(8)
> +#define PS2_FSTS_RXUF		BIT(2)
> +#define PS2_FSTS_RXOF		BIT(1)
> +#define PS2_FSTS_RXRDY		BIT(0)
> +
> +#define PS2_FIFO_ERROR_BIT \
> +	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> +
> +#define PS2_SAMPLE_CLK		1000000
> +#define PS2_SCLK		125000
> +
> +struct sun4i_ps2data {
> +	struct serio *serio;
> +	struct device *dev;
> +
> +	/* IO mapping base */
> +	void __iomem	*reg_base;
> +
> +	/* clock management */
> +	struct clk	*clk;
> +
> +	/* irq */
> +	spinlock_t	lock;
> +	int		irq;
> +};
> +
> +/*********************/
> +/* Interrupt handler */
> +/*********************/
> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> +{
> +	struct sun4i_ps2data *drvdata = dev_id;
> +	u32 intr_status;
> +	u32 fifo_status;
> +	unsigned char byte;
> +	unsigned int rxflags = 0;
> +	u32 rval;
> +
> +	spin_lock(&drvdata->lock);
> +
> +	/* Get the PS/2 interrupts and clear them */
> +	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> +	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> +
> +	/*Check Line Status Register*/
> +	if (intr_status & PS2_LINE_ERROR_BIT) {
> +		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> +
> +		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> +			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> +		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> +	}
> +
> +	/*Check FIFO Status Register*/
> +	if (fifo_status & PS2_FIFO_ERROR_BIT) {
> +		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> +			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> +		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> +	}
> +
> +	rval = (fifo_status >> 16) & 0x3;
> +	while (rval--) {
> +		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> +		serio_interrupt(drvdata->serio, byte, rxflags);
> +	}
> +
> +	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> +	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> +
> +	spin_unlock(&drvdata->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +
> +static int sun4i_ps2_open(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +	u32 src_clk = 0;
> +	u32 clk_scdf;
> +	u32 clk_pcdf;
> +	u32 rval;
> +	unsigned long flags;
> +
> +	/*Set Line Control And Enable Interrupt*/
> +	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> +		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> +	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> +
> +	/*Reset FIFO*/
> +	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> +		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> +		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> +
> +	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> +
> +	src_clk = clk_get_rate(drvdata->clk);
> +	/*Set Clock Divider Register*/
> +	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> +	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> +	rval = (clk_scdf<<8) | clk_pcdf;
> +	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> +
> +
> +	/*Set Global Control Register*/
> +	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> +		| PS2_GCTL_BUSEN;
> +
> +	spin_lock_irqsave(&drvdata->lock, flags);
> +	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> +	spin_unlock_irqrestore(&drvdata->lock, flags);
> +
> +	return 0;
> +}
> +
> +static void sun4i_ps2_close(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +
> +	synchronize_irq(drvdata->irq);

synchronize_irq() on it's own is not very useful. You also need to shut
off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
before calling synchronize_irq.

> +}
> +
> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> +{
> +	unsigned long expire = jiffies + msecs_to_jiffies(10000);
> +	struct sun4i_ps2data *drvdata;
> +
> +	drvdata = (struct sun4i_ps2data *)pserio->port_data;
> +
> +	do {
> +		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> +			writel(val, drvdata->reg_base + PS2_REG_DATA);
> +			return 0;
> +		}
> +	} while (time_before(jiffies, expire));
> +
> +	return SERIO_TIMEOUT;
> +}
> +
> +static int sun4i_ps2_probe(struct platform_device *pdev)
> +{
> +	struct resource *res; /* IO mem resources */
> +	struct sun4i_ps2data *drvdata;
> +	struct serio *serio;
> +	struct device *dev = &pdev->dev;
> +	unsigned int irq;
> +	int error;
> +
> +	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> +	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> +	if (!drvdata || !serio) {
> +		error = -ENOMEM;
> +		goto err_free_mem;
> +	}
> +
> +	spin_lock_init(&drvdata->lock);
> +
> +	/* IO */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drvdata->reg_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(drvdata->reg_base)) {
> +		dev_err(dev, "failed to map registers\n");
> +		error = PTR_ERR(drvdata->reg_base);
> +		goto err_free_mem;
> +	}
> +
> +	drvdata->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(drvdata->clk)) {
> +		error = PTR_ERR(drvdata->clk);
> +		dev_err(dev, "couldn't get clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	error = clk_prepare_enable(drvdata->clk);
> +	if (error) {
> +		dev_err(dev, "failed to enable clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	serio->id.type = SERIO_8042;
> +	serio->write = sun4i_ps2_write;
> +	serio->open = sun4i_ps2_open;
> +	serio->close = sun4i_ps2_close;
> +	serio->port_data = drvdata;
> +	serio->dev.parent = dev;
> +	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> +	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> +
> +	/* Get IRQ for the device */
> +	irq = platform_get_irq(pdev, 0);
> +	if (!irq) {
> +		dev_err(dev, "no IRQ found\n");
> +		error = -ENXIO;
> +		goto error_disable_clk;
> +	}
> +
> +	drvdata->irq = irq;
> +	drvdata->serio = serio;
> +	drvdata->dev = dev;
> +	error = devm_request_threaded_irq(dev, drvdata->irq,
> +		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> +
> +	if (error) {
> +		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> +			drvdata->irq, error);
> +		goto error_disable_clk;
> +	}
> +
> +	serio_register_port(serio);
> +	platform_set_drvdata(pdev, drvdata);
> +
> +	return 0;	/* success */
> +
> +error_disable_clk:
> +	clk_disable_unprepare(drvdata->clk);
> +
> +err_free_mem:
> +	kfree(serio);
> +	return error;
> +}
> +
> +static int sun4i_ps2_remove(struct platform_device *pdev)
> +{
> +	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> +
> +	serio_unregister_port(drvdata->serio);
> +
> +	if (!IS_ERR(drvdata->clk))
> +		clk_disable_unprepare(drvdata->clk);
> +	kfree(drvdata->serio);

Serio is refcounted, you do not free it after its has been registered.
Overall I'd rather you did not use devm* interfaces here since you are
forced to mix managed and manually freed resources.

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_ps2_match[] = {
> +	{ .compatible = "allwinner,sun4i-a10-ps2", },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
> +
> +static struct platform_driver sun4i_ps2_driver = {
> +	.probe		= sun4i_ps2_probe,
> +	.remove		= sun4i_ps2_remove,
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.of_match_table = sun4i_ps2_match,
> +	},
> +};
> +module_platform_driver(sun4i_ps2_driver);
> +
> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>");
> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.7.9.5
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-17 22:25     ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-17 22:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  drivers/input/serio/Kconfig     |   11 ++
>  drivers/input/serio/Makefile    |    1 +
>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 342 insertions(+)
>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> 
> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> index bc2d474..964afc5 100644
> --- a/drivers/input/serio/Kconfig
> +++ b/drivers/input/serio/Kconfig
> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called hyperv_keyboard.
>  
> +config SERIO_SUN4I_PS2
> +	tristate "Allwinner A10 PS/2 controller support"
> +	default n
> +	depends on ARCH_SUNXI || COMPILE_TEST
> +	help
> +	  This selects support for the PS/2 Host Controller on
> +	  Allwinner A10.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called sun4i-ps2.
> +
>  endif
> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> index 815d874..c600089 100644
> --- a/drivers/input/serio/Makefile
> +++ b/drivers/input/serio/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2)	+= arc_ps2.o
>  obj-$(CONFIG_SERIO_APBPS2)	+= apbps2.o
>  obj-$(CONFIG_SERIO_OLPC_APSP)	+= olpc_apsp.o
>  obj-$(CONFIG_HYPERV_KEYBOARD)	+= hyperv-keyboard.o
> +obj-$(CONFIG_SERIO_SUN4I_PS2)	+= sun4i-ps2.o
> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> new file mode 100644
> index 0000000..06b3fef
> --- /dev/null
> +++ b/drivers/input/serio/sun4i-ps2.c
> @@ -0,0 +1,330 @@
> +/*
> + *	Driver for Allwinner A10 PS2 host controller
> + *
> + *	Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> + *		Aaron.maoye <leafy.myeh@newbietech.com>
> + *
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/serio.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME		"sun4i-ps2"
> +
> +/* register offset definitions */
> +#define PS2_REG_GCTL		0x00	/*  PS2 Module Global Control Reg */
> +#define PS2_REG_DATA		0x04	/*  PS2 Module Data Reg		*/
> +#define PS2_REG_LCTL		0x08	/*  PS2 Module Line Control Reg */
> +#define PS2_REG_LSTS		0x0C	/*  PS2 Module Line Status Reg	*/
> +#define PS2_REG_FCTL		0x10	/*  PS2 Module FIFO Control Reg */
> +#define PS2_REG_FSTS		0x14	/*  PS2 Module FIFO Status Reg	*/
> +#define PS2_REG_CLKDR		0x18	/*  PS2 Module Clock Divider Reg*/
> +
> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> +#define PS2_GCTL_INTFLAG	BIT(4)
> +#define PS2_GCTL_INTEN		BIT(3)
> +#define PS2_GCTL_RESET		BIT(2)
> +#define PS2_GCTL_MASTER		BIT(1)
> +#define PS2_GCTL_BUSEN		BIT(0)
> +
> +/* PS2 LINE CONTROL REGISTER */
> +#define PS2_LCTL_NOACK		BIT(18)
> +#define PS2_LCTL_TXDTOEN	BIT(8)
> +#define PS2_LCTL_STOPERREN	BIT(3)
> +#define PS2_LCTL_ACKERREN	BIT(2)
> +#define PS2_LCTL_PARERREN	BIT(1)
> +#define PS2_LCTL_RXDTOEN	BIT(0)
> +
> +/* PS2 LINE STATUS REGISTER */
> +#define PS2_LSTS_TXTDO		BIT(8)
> +#define PS2_LSTS_STOPERR	BIT(3)
> +#define PS2_LSTS_ACKERR		BIT(2)
> +#define PS2_LSTS_PARERR		BIT(1)
> +#define PS2_LSTS_RXTDO		BIT(0)
> +
> +#define PS2_LINE_ERROR_BIT \
> +	(PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> +	PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> +
> +/* PS2 FIFO CONTROL REGISTER */
> +#define PS2_FCTL_TXRST		BIT(17)
> +#define PS2_FCTL_RXRST		BIT(16)
> +#define PS2_FCTL_TXUFIEN	BIT(10)
> +#define PS2_FCTL_TXOFIEN	BIT(9)
> +#define PS2_FCTL_TXRDYIEN	BIT(8)
> +#define PS2_FCTL_RXUFIEN	BIT(2)
> +#define PS2_FCTL_RXOFIEN	BIT(1)
> +#define PS2_FCTL_RXRDYIEN	BIT(0)
> +
> +/* PS2 FIFO STATUS REGISTER */
> +#define PS2_FSTS_TXUF		BIT(10)
> +#define PS2_FSTS_TXOF		BIT(9)
> +#define PS2_FSTS_TXRDY		BIT(8)
> +#define PS2_FSTS_RXUF		BIT(2)
> +#define PS2_FSTS_RXOF		BIT(1)
> +#define PS2_FSTS_RXRDY		BIT(0)
> +
> +#define PS2_FIFO_ERROR_BIT \
> +	(PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> +
> +#define PS2_SAMPLE_CLK		1000000
> +#define PS2_SCLK		125000
> +
> +struct sun4i_ps2data {
> +	struct serio *serio;
> +	struct device *dev;
> +
> +	/* IO mapping base */
> +	void __iomem	*reg_base;
> +
> +	/* clock management */
> +	struct clk	*clk;
> +
> +	/* irq */
> +	spinlock_t	lock;
> +	int		irq;
> +};
> +
> +/*********************/
> +/* Interrupt handler */
> +/*********************/
> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> +{
> +	struct sun4i_ps2data *drvdata = dev_id;
> +	u32 intr_status;
> +	u32 fifo_status;
> +	unsigned char byte;
> +	unsigned int rxflags = 0;
> +	u32 rval;
> +
> +	spin_lock(&drvdata->lock);
> +
> +	/* Get the PS/2 interrupts and clear them */
> +	intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> +	fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> +
> +	/*Check Line Status Register*/
> +	if (intr_status & PS2_LINE_ERROR_BIT) {
> +		rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> +		rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> +
> +		rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> +			PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> +		writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> +	}
> +
> +	/*Check FIFO Status Register*/
> +	if (fifo_status & PS2_FIFO_ERROR_BIT) {
> +		rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> +			PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> +		writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> +	}
> +
> +	rval = (fifo_status >> 16) & 0x3;
> +	while (rval--) {
> +		byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> +		serio_interrupt(drvdata->serio, byte, rxflags);
> +	}
> +
> +	writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> +	writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> +
> +	spin_unlock(&drvdata->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +
> +static int sun4i_ps2_open(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +	u32 src_clk = 0;
> +	u32 clk_scdf;
> +	u32 clk_pcdf;
> +	u32 rval;
> +	unsigned long flags;
> +
> +	/*Set Line Control And Enable Interrupt*/
> +	rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> +		| PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> +	writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> +
> +	/*Reset FIFO*/
> +	rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> +		| PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> +		| PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> +
> +	writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> +
> +	src_clk = clk_get_rate(drvdata->clk);
> +	/*Set Clock Divider Register*/
> +	clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> +	clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> +	rval = (clk_scdf<<8) | clk_pcdf;
> +	writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> +
> +
> +	/*Set Global Control Register*/
> +	rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> +		| PS2_GCTL_BUSEN;
> +
> +	spin_lock_irqsave(&drvdata->lock, flags);
> +	writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> +	spin_unlock_irqrestore(&drvdata->lock, flags);
> +
> +	return 0;
> +}
> +
> +static void sun4i_ps2_close(struct serio *pserio)
> +{
> +	struct sun4i_ps2data *drvdata = pserio->port_data;
> +
> +	synchronize_irq(drvdata->irq);

synchronize_irq() on it's own is not very useful. You also need to shut
off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
before calling synchronize_irq.

> +}
> +
> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> +{
> +	unsigned long expire = jiffies + msecs_to_jiffies(10000);
> +	struct sun4i_ps2data *drvdata;
> +
> +	drvdata = (struct sun4i_ps2data *)pserio->port_data;
> +
> +	do {
> +		if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> +			writel(val, drvdata->reg_base + PS2_REG_DATA);
> +			return 0;
> +		}
> +	} while (time_before(jiffies, expire));
> +
> +	return SERIO_TIMEOUT;
> +}
> +
> +static int sun4i_ps2_probe(struct platform_device *pdev)
> +{
> +	struct resource *res; /* IO mem resources */
> +	struct sun4i_ps2data *drvdata;
> +	struct serio *serio;
> +	struct device *dev = &pdev->dev;
> +	unsigned int irq;
> +	int error;
> +
> +	drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> +	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> +	if (!drvdata || !serio) {
> +		error = -ENOMEM;
> +		goto err_free_mem;
> +	}
> +
> +	spin_lock_init(&drvdata->lock);
> +
> +	/* IO */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drvdata->reg_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(drvdata->reg_base)) {
> +		dev_err(dev, "failed to map registers\n");
> +		error = PTR_ERR(drvdata->reg_base);
> +		goto err_free_mem;
> +	}
> +
> +	drvdata->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(drvdata->clk)) {
> +		error = PTR_ERR(drvdata->clk);
> +		dev_err(dev, "couldn't get clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	error = clk_prepare_enable(drvdata->clk);
> +	if (error) {
> +		dev_err(dev, "failed to enable clock %d\n", error);
> +		goto err_free_mem;
> +	}
> +
> +	serio->id.type = SERIO_8042;
> +	serio->write = sun4i_ps2_write;
> +	serio->open = sun4i_ps2_open;
> +	serio->close = sun4i_ps2_close;
> +	serio->port_data = drvdata;
> +	serio->dev.parent = dev;
> +	strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> +	strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> +
> +	/* Get IRQ for the device */
> +	irq = platform_get_irq(pdev, 0);
> +	if (!irq) {
> +		dev_err(dev, "no IRQ found\n");
> +		error = -ENXIO;
> +		goto error_disable_clk;
> +	}
> +
> +	drvdata->irq = irq;
> +	drvdata->serio = serio;
> +	drvdata->dev = dev;
> +	error = devm_request_threaded_irq(dev, drvdata->irq,
> +		sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> +
> +	if (error) {
> +		dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> +			drvdata->irq, error);
> +		goto error_disable_clk;
> +	}
> +
> +	serio_register_port(serio);
> +	platform_set_drvdata(pdev, drvdata);
> +
> +	return 0;	/* success */
> +
> +error_disable_clk:
> +	clk_disable_unprepare(drvdata->clk);
> +
> +err_free_mem:
> +	kfree(serio);
> +	return error;
> +}
> +
> +static int sun4i_ps2_remove(struct platform_device *pdev)
> +{
> +	struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> +
> +	serio_unregister_port(drvdata->serio);
> +
> +	if (!IS_ERR(drvdata->clk))
> +		clk_disable_unprepare(drvdata->clk);
> +	kfree(drvdata->serio);

Serio is refcounted, you do not free it after its has been registered.
Overall I'd rather you did not use devm* interfaces here since you are
forced to mix managed and manually freed resources.

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_ps2_match[] = {
> +	{ .compatible = "allwinner,sun4i-a10-ps2", },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
> +
> +static struct platform_driver sun4i_ps2_driver = {
> +	.probe		= sun4i_ps2_probe,
> +	.remove		= sun4i_ps2_remove,
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.of_match_table = sun4i_ps2_match,
> +	},
> +};
> +module_platform_driver(sun4i_ps2_driver);
> +
> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.7.9.5
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
  2015-01-17 22:25     ` Dmitry Torokhov
  (?)
@ 2015-01-19  6:07       ` Vishnu Patekar
  -1 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-19  6:07 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Hans de Goede, ijc+devicetree, maxime.ripard, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

Hello Dmitry,

Thank you for review comments. Please see in-lined.

On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> ---
>>  drivers/input/serio/Kconfig     |   11 ++
>>  drivers/input/serio/Makefile    |    1 +
>>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 342 insertions(+)
>>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>>
>> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> index bc2d474..964afc5 100644
>> --- a/drivers/input/serio/Kconfig
>> +++ b/drivers/input/serio/Kconfig
>> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>>         To compile this driver as a module, choose M here: the module will
>>         be called hyperv_keyboard.
>>
>> +config SERIO_SUN4I_PS2
>> +     tristate "Allwinner A10 PS/2 controller support"
>> +     default n
>> +     depends on ARCH_SUNXI || COMPILE_TEST
>> +     help
>> +       This selects support for the PS/2 Host Controller on
>> +       Allwinner A10.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called sun4i-ps2.
>> +
>>  endif
>> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> index 815d874..c600089 100644
>> --- a/drivers/input/serio/Makefile
>> +++ b/drivers/input/serio/Makefile
>> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> new file mode 100644
>> index 0000000..06b3fef
>> --- /dev/null
>> +++ b/drivers/input/serio/sun4i-ps2.c
>> @@ -0,0 +1,330 @@
>> +/*
>> + *   Driver for Allwinner A10 PS2 host controller
>> + *
>> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
>> + *           Aaron.maoye <leafy.myeh@newbietech.com>
>> + *
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/serio.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/errno.h>
>> +#include <linux/slab.h>
>> +#include <linux/list.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +
>> +#define DRIVER_NAME          "sun4i-ps2"
>> +
>> +/* register offset definitions */
>> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> +
>> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> +#define PS2_GCTL_INTFLAG     BIT(4)
>> +#define PS2_GCTL_INTEN               BIT(3)
>> +#define PS2_GCTL_RESET               BIT(2)
>> +#define PS2_GCTL_MASTER              BIT(1)
>> +#define PS2_GCTL_BUSEN               BIT(0)
>> +
>> +/* PS2 LINE CONTROL REGISTER */
>> +#define PS2_LCTL_NOACK               BIT(18)
>> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> +#define PS2_LCTL_STOPERREN   BIT(3)
>> +#define PS2_LCTL_ACKERREN    BIT(2)
>> +#define PS2_LCTL_PARERREN    BIT(1)
>> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> +
>> +/* PS2 LINE STATUS REGISTER */
>> +#define PS2_LSTS_TXTDO               BIT(8)
>> +#define PS2_LSTS_STOPERR     BIT(3)
>> +#define PS2_LSTS_ACKERR              BIT(2)
>> +#define PS2_LSTS_PARERR              BIT(1)
>> +#define PS2_LSTS_RXTDO               BIT(0)
>> +
>> +#define PS2_LINE_ERROR_BIT \
>> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> +
>> +/* PS2 FIFO CONTROL REGISTER */
>> +#define PS2_FCTL_TXRST               BIT(17)
>> +#define PS2_FCTL_RXRST               BIT(16)
>> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> +
>> +/* PS2 FIFO STATUS REGISTER */
>> +#define PS2_FSTS_TXUF                BIT(10)
>> +#define PS2_FSTS_TXOF                BIT(9)
>> +#define PS2_FSTS_TXRDY               BIT(8)
>> +#define PS2_FSTS_RXUF                BIT(2)
>> +#define PS2_FSTS_RXOF                BIT(1)
>> +#define PS2_FSTS_RXRDY               BIT(0)
>> +
>> +#define PS2_FIFO_ERROR_BIT \
>> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> +
>> +#define PS2_SAMPLE_CLK               1000000
>> +#define PS2_SCLK             125000
>> +
>> +struct sun4i_ps2data {
>> +     struct serio *serio;
>> +     struct device *dev;
>> +
>> +     /* IO mapping base */
>> +     void __iomem    *reg_base;
>> +
>> +     /* clock management */
>> +     struct clk      *clk;
>> +
>> +     /* irq */
>> +     spinlock_t      lock;
>> +     int             irq;
>> +};
>> +
>> +/*********************/
>> +/* Interrupt handler */
>> +/*********************/
>> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> +{
>> +     struct sun4i_ps2data *drvdata = dev_id;
>> +     u32 intr_status;
>> +     u32 fifo_status;
>> +     unsigned char byte;
>> +     unsigned int rxflags = 0;
>> +     u32 rval;
>> +
>> +     spin_lock(&drvdata->lock);
>> +
>> +     /* Get the PS/2 interrupts and clear them */
>> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     /*Check Line Status Register*/
>> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> +
>> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> +     }
>> +
>> +     /*Check FIFO Status Register*/
>> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> +     }
>> +
>> +     rval = (fifo_status >> 16) & 0x3;
>> +     while (rval--) {
>> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> +     }
>> +
>> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     spin_unlock(&drvdata->lock);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +
>> +static int sun4i_ps2_open(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +     u32 src_clk = 0;
>> +     u32 clk_scdf;
>> +     u32 clk_pcdf;
>> +     u32 rval;
>> +     unsigned long flags;
>> +
>> +     /*Set Line Control And Enable Interrupt*/
>> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> +
>> +     /*Reset FIFO*/
>> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> +
>> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> +
>> +     src_clk = clk_get_rate(drvdata->clk);
>> +     /*Set Clock Divider Register*/
>> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> +     rval = (clk_scdf<<8) | clk_pcdf;
>> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> +
>> +
>> +     /*Set Global Control Register*/
>> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> +             | PS2_GCTL_BUSEN;
>> +
>> +     spin_lock_irqsave(&drvdata->lock, flags);
>> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> +
>> +     return 0;
>> +}
>> +
>> +static void sun4i_ps2_close(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +
>> +     synchronize_irq(drvdata->irq);
>
> synchronize_irq() on it's own is not very useful. You also need to shut
> off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> before calling synchronize_irq.
Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
>> +}
>> +
>> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> +{
>> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> +     struct sun4i_ps2data *drvdata;
>> +
>> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> +
>> +     do {
>> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> +                     return 0;
>> +             }
>> +     } while (time_before(jiffies, expire));
>> +
>> +     return SERIO_TIMEOUT;
>> +}
>> +
>> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> +{
>> +     struct resource *res; /* IO mem resources */
>> +     struct sun4i_ps2data *drvdata;
>> +     struct serio *serio;
>> +     struct device *dev = &pdev->dev;
>> +     unsigned int irq;
>> +     int error;
>> +
>> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> +     if (!drvdata || !serio) {
>> +             error = -ENOMEM;
>> +             goto err_free_mem;
>> +     }
>> +
>> +     spin_lock_init(&drvdata->lock);
>> +
>> +     /* IO */
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> +     if (IS_ERR(drvdata->reg_base)) {
>> +             dev_err(dev, "failed to map registers\n");
>> +             error = PTR_ERR(drvdata->reg_base);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     drvdata->clk = devm_clk_get(dev, NULL);
>> +     if (IS_ERR(drvdata->clk)) {
>> +             error = PTR_ERR(drvdata->clk);
>> +             dev_err(dev, "couldn't get clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     error = clk_prepare_enable(drvdata->clk);
>> +     if (error) {
>> +             dev_err(dev, "failed to enable clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     serio->id.type = SERIO_8042;
>> +     serio->write = sun4i_ps2_write;
>> +     serio->open = sun4i_ps2_open;
>> +     serio->close = sun4i_ps2_close;
>> +     serio->port_data = drvdata;
>> +     serio->dev.parent = dev;
>> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> +
>> +     /* Get IRQ for the device */
>> +     irq = platform_get_irq(pdev, 0);
>> +     if (!irq) {
>> +             dev_err(dev, "no IRQ found\n");
>> +             error = -ENXIO;
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     drvdata->irq = irq;
>> +     drvdata->serio = serio;
>> +     drvdata->dev = dev;
>> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> +
>> +     if (error) {
>> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> +                     drvdata->irq, error);
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     serio_register_port(serio);
>> +     platform_set_drvdata(pdev, drvdata);
>> +
>> +     return 0;       /* success */
>> +
>> +error_disable_clk:
>> +     clk_disable_unprepare(drvdata->clk);
>> +
>> +err_free_mem:
>> +     kfree(serio);
>> +     return error;
>> +}
>> +
>> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> +{
>> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> +
>> +     serio_unregister_port(drvdata->serio);
>> +
>> +     if (!IS_ERR(drvdata->clk))
>> +             clk_disable_unprepare(drvdata->clk);
>> +     kfree(drvdata->serio);
>
> Serio is refcounted, you do not free it after its has been registered.
> Overall I'd rather you did not use devm* interfaces here since you are
> forced to mix managed and manually freed resources.
Okie, No need to free serio here.
If serio is not manually freed here, It is not freeing anything else manually.

do you still feel I should not use devm* interfaces here?
>
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct of_device_id sun4i_ps2_match[] = {
>> +     { .compatible = "allwinner,sun4i-a10-ps2", },
>> +     { },
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
>> +
>> +static struct platform_driver sun4i_ps2_driver = {
>> +     .probe          = sun4i_ps2_probe,
>> +     .remove         = sun4i_ps2_remove,
>> +     .driver = {
>> +             .name = DRIVER_NAME,
>> +             .of_match_table = sun4i_ps2_match,
>> +     },
>> +};
>> +module_platform_driver(sun4i_ps2_driver);
>> +
>> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
>> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
>> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 1.7.9.5
>>
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-19  6:07       ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-19  6:07 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Hans de Goede, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hello Dmitry,

Thank you for review comments. Please see in-lined.

On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
<dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> ---
>>  drivers/input/serio/Kconfig     |   11 ++
>>  drivers/input/serio/Makefile    |    1 +
>>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 342 insertions(+)
>>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>>
>> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> index bc2d474..964afc5 100644
>> --- a/drivers/input/serio/Kconfig
>> +++ b/drivers/input/serio/Kconfig
>> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>>         To compile this driver as a module, choose M here: the module will
>>         be called hyperv_keyboard.
>>
>> +config SERIO_SUN4I_PS2
>> +     tristate "Allwinner A10 PS/2 controller support"
>> +     default n
>> +     depends on ARCH_SUNXI || COMPILE_TEST
>> +     help
>> +       This selects support for the PS/2 Host Controller on
>> +       Allwinner A10.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called sun4i-ps2.
>> +
>>  endif
>> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> index 815d874..c600089 100644
>> --- a/drivers/input/serio/Makefile
>> +++ b/drivers/input/serio/Makefile
>> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> new file mode 100644
>> index 0000000..06b3fef
>> --- /dev/null
>> +++ b/drivers/input/serio/sun4i-ps2.c
>> @@ -0,0 +1,330 @@
>> +/*
>> + *   Driver for Allwinner A10 PS2 host controller
>> + *
>> + *   Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> + *           Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
>> + *
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/serio.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/errno.h>
>> +#include <linux/slab.h>
>> +#include <linux/list.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +
>> +#define DRIVER_NAME          "sun4i-ps2"
>> +
>> +/* register offset definitions */
>> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> +
>> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> +#define PS2_GCTL_INTFLAG     BIT(4)
>> +#define PS2_GCTL_INTEN               BIT(3)
>> +#define PS2_GCTL_RESET               BIT(2)
>> +#define PS2_GCTL_MASTER              BIT(1)
>> +#define PS2_GCTL_BUSEN               BIT(0)
>> +
>> +/* PS2 LINE CONTROL REGISTER */
>> +#define PS2_LCTL_NOACK               BIT(18)
>> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> +#define PS2_LCTL_STOPERREN   BIT(3)
>> +#define PS2_LCTL_ACKERREN    BIT(2)
>> +#define PS2_LCTL_PARERREN    BIT(1)
>> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> +
>> +/* PS2 LINE STATUS REGISTER */
>> +#define PS2_LSTS_TXTDO               BIT(8)
>> +#define PS2_LSTS_STOPERR     BIT(3)
>> +#define PS2_LSTS_ACKERR              BIT(2)
>> +#define PS2_LSTS_PARERR              BIT(1)
>> +#define PS2_LSTS_RXTDO               BIT(0)
>> +
>> +#define PS2_LINE_ERROR_BIT \
>> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> +
>> +/* PS2 FIFO CONTROL REGISTER */
>> +#define PS2_FCTL_TXRST               BIT(17)
>> +#define PS2_FCTL_RXRST               BIT(16)
>> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> +
>> +/* PS2 FIFO STATUS REGISTER */
>> +#define PS2_FSTS_TXUF                BIT(10)
>> +#define PS2_FSTS_TXOF                BIT(9)
>> +#define PS2_FSTS_TXRDY               BIT(8)
>> +#define PS2_FSTS_RXUF                BIT(2)
>> +#define PS2_FSTS_RXOF                BIT(1)
>> +#define PS2_FSTS_RXRDY               BIT(0)
>> +
>> +#define PS2_FIFO_ERROR_BIT \
>> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> +
>> +#define PS2_SAMPLE_CLK               1000000
>> +#define PS2_SCLK             125000
>> +
>> +struct sun4i_ps2data {
>> +     struct serio *serio;
>> +     struct device *dev;
>> +
>> +     /* IO mapping base */
>> +     void __iomem    *reg_base;
>> +
>> +     /* clock management */
>> +     struct clk      *clk;
>> +
>> +     /* irq */
>> +     spinlock_t      lock;
>> +     int             irq;
>> +};
>> +
>> +/*********************/
>> +/* Interrupt handler */
>> +/*********************/
>> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> +{
>> +     struct sun4i_ps2data *drvdata = dev_id;
>> +     u32 intr_status;
>> +     u32 fifo_status;
>> +     unsigned char byte;
>> +     unsigned int rxflags = 0;
>> +     u32 rval;
>> +
>> +     spin_lock(&drvdata->lock);
>> +
>> +     /* Get the PS/2 interrupts and clear them */
>> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     /*Check Line Status Register*/
>> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> +
>> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> +     }
>> +
>> +     /*Check FIFO Status Register*/
>> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> +     }
>> +
>> +     rval = (fifo_status >> 16) & 0x3;
>> +     while (rval--) {
>> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> +     }
>> +
>> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     spin_unlock(&drvdata->lock);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +
>> +static int sun4i_ps2_open(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +     u32 src_clk = 0;
>> +     u32 clk_scdf;
>> +     u32 clk_pcdf;
>> +     u32 rval;
>> +     unsigned long flags;
>> +
>> +     /*Set Line Control And Enable Interrupt*/
>> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> +
>> +     /*Reset FIFO*/
>> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> +
>> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> +
>> +     src_clk = clk_get_rate(drvdata->clk);
>> +     /*Set Clock Divider Register*/
>> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> +     rval = (clk_scdf<<8) | clk_pcdf;
>> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> +
>> +
>> +     /*Set Global Control Register*/
>> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> +             | PS2_GCTL_BUSEN;
>> +
>> +     spin_lock_irqsave(&drvdata->lock, flags);
>> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> +
>> +     return 0;
>> +}
>> +
>> +static void sun4i_ps2_close(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +
>> +     synchronize_irq(drvdata->irq);
>
> synchronize_irq() on it's own is not very useful. You also need to shut
> off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> before calling synchronize_irq.
Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
>> +}
>> +
>> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> +{
>> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> +     struct sun4i_ps2data *drvdata;
>> +
>> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> +
>> +     do {
>> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> +                     return 0;
>> +             }
>> +     } while (time_before(jiffies, expire));
>> +
>> +     return SERIO_TIMEOUT;
>> +}
>> +
>> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> +{
>> +     struct resource *res; /* IO mem resources */
>> +     struct sun4i_ps2data *drvdata;
>> +     struct serio *serio;
>> +     struct device *dev = &pdev->dev;
>> +     unsigned int irq;
>> +     int error;
>> +
>> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> +     if (!drvdata || !serio) {
>> +             error = -ENOMEM;
>> +             goto err_free_mem;
>> +     }
>> +
>> +     spin_lock_init(&drvdata->lock);
>> +
>> +     /* IO */
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> +     if (IS_ERR(drvdata->reg_base)) {
>> +             dev_err(dev, "failed to map registers\n");
>> +             error = PTR_ERR(drvdata->reg_base);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     drvdata->clk = devm_clk_get(dev, NULL);
>> +     if (IS_ERR(drvdata->clk)) {
>> +             error = PTR_ERR(drvdata->clk);
>> +             dev_err(dev, "couldn't get clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     error = clk_prepare_enable(drvdata->clk);
>> +     if (error) {
>> +             dev_err(dev, "failed to enable clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     serio->id.type = SERIO_8042;
>> +     serio->write = sun4i_ps2_write;
>> +     serio->open = sun4i_ps2_open;
>> +     serio->close = sun4i_ps2_close;
>> +     serio->port_data = drvdata;
>> +     serio->dev.parent = dev;
>> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> +
>> +     /* Get IRQ for the device */
>> +     irq = platform_get_irq(pdev, 0);
>> +     if (!irq) {
>> +             dev_err(dev, "no IRQ found\n");
>> +             error = -ENXIO;
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     drvdata->irq = irq;
>> +     drvdata->serio = serio;
>> +     drvdata->dev = dev;
>> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> +
>> +     if (error) {
>> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> +                     drvdata->irq, error);
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     serio_register_port(serio);
>> +     platform_set_drvdata(pdev, drvdata);
>> +
>> +     return 0;       /* success */
>> +
>> +error_disable_clk:
>> +     clk_disable_unprepare(drvdata->clk);
>> +
>> +err_free_mem:
>> +     kfree(serio);
>> +     return error;
>> +}
>> +
>> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> +{
>> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> +
>> +     serio_unregister_port(drvdata->serio);
>> +
>> +     if (!IS_ERR(drvdata->clk))
>> +             clk_disable_unprepare(drvdata->clk);
>> +     kfree(drvdata->serio);
>
> Serio is refcounted, you do not free it after its has been registered.
> Overall I'd rather you did not use devm* interfaces here since you are
> forced to mix managed and manually freed resources.
Okie, No need to free serio here.
If serio is not manually freed here, It is not freeing anything else manually.

do you still feel I should not use devm* interfaces here?
>
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct of_device_id sun4i_ps2_match[] = {
>> +     { .compatible = "allwinner,sun4i-a10-ps2", },
>> +     { },
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
>> +
>> +static struct platform_driver sun4i_ps2_driver = {
>> +     .probe          = sun4i_ps2_probe,
>> +     .remove         = sun4i_ps2_remove,
>> +     .driver = {
>> +             .name = DRIVER_NAME,
>> +             .of_match_table = sun4i_ps2_match,
>> +     },
>> +};
>> +module_platform_driver(sun4i_ps2_driver);
>> +
>> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
>> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>");
>> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 1.7.9.5
>>
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-19  6:07       ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-19  6:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Dmitry,

Thank you for review comments. Please see in-lined.

On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> ---
>>  drivers/input/serio/Kconfig     |   11 ++
>>  drivers/input/serio/Makefile    |    1 +
>>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 342 insertions(+)
>>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>>
>> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> index bc2d474..964afc5 100644
>> --- a/drivers/input/serio/Kconfig
>> +++ b/drivers/input/serio/Kconfig
>> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>>         To compile this driver as a module, choose M here: the module will
>>         be called hyperv_keyboard.
>>
>> +config SERIO_SUN4I_PS2
>> +     tristate "Allwinner A10 PS/2 controller support"
>> +     default n
>> +     depends on ARCH_SUNXI || COMPILE_TEST
>> +     help
>> +       This selects support for the PS/2 Host Controller on
>> +       Allwinner A10.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called sun4i-ps2.
>> +
>>  endif
>> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> index 815d874..c600089 100644
>> --- a/drivers/input/serio/Makefile
>> +++ b/drivers/input/serio/Makefile
>> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> new file mode 100644
>> index 0000000..06b3fef
>> --- /dev/null
>> +++ b/drivers/input/serio/sun4i-ps2.c
>> @@ -0,0 +1,330 @@
>> +/*
>> + *   Driver for Allwinner A10 PS2 host controller
>> + *
>> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
>> + *           Aaron.maoye <leafy.myeh@newbietech.com>
>> + *
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/serio.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/errno.h>
>> +#include <linux/slab.h>
>> +#include <linux/list.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +
>> +#define DRIVER_NAME          "sun4i-ps2"
>> +
>> +/* register offset definitions */
>> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> +
>> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> +#define PS2_GCTL_INTFLAG     BIT(4)
>> +#define PS2_GCTL_INTEN               BIT(3)
>> +#define PS2_GCTL_RESET               BIT(2)
>> +#define PS2_GCTL_MASTER              BIT(1)
>> +#define PS2_GCTL_BUSEN               BIT(0)
>> +
>> +/* PS2 LINE CONTROL REGISTER */
>> +#define PS2_LCTL_NOACK               BIT(18)
>> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> +#define PS2_LCTL_STOPERREN   BIT(3)
>> +#define PS2_LCTL_ACKERREN    BIT(2)
>> +#define PS2_LCTL_PARERREN    BIT(1)
>> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> +
>> +/* PS2 LINE STATUS REGISTER */
>> +#define PS2_LSTS_TXTDO               BIT(8)
>> +#define PS2_LSTS_STOPERR     BIT(3)
>> +#define PS2_LSTS_ACKERR              BIT(2)
>> +#define PS2_LSTS_PARERR              BIT(1)
>> +#define PS2_LSTS_RXTDO               BIT(0)
>> +
>> +#define PS2_LINE_ERROR_BIT \
>> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> +
>> +/* PS2 FIFO CONTROL REGISTER */
>> +#define PS2_FCTL_TXRST               BIT(17)
>> +#define PS2_FCTL_RXRST               BIT(16)
>> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> +
>> +/* PS2 FIFO STATUS REGISTER */
>> +#define PS2_FSTS_TXUF                BIT(10)
>> +#define PS2_FSTS_TXOF                BIT(9)
>> +#define PS2_FSTS_TXRDY               BIT(8)
>> +#define PS2_FSTS_RXUF                BIT(2)
>> +#define PS2_FSTS_RXOF                BIT(1)
>> +#define PS2_FSTS_RXRDY               BIT(0)
>> +
>> +#define PS2_FIFO_ERROR_BIT \
>> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> +
>> +#define PS2_SAMPLE_CLK               1000000
>> +#define PS2_SCLK             125000
>> +
>> +struct sun4i_ps2data {
>> +     struct serio *serio;
>> +     struct device *dev;
>> +
>> +     /* IO mapping base */
>> +     void __iomem    *reg_base;
>> +
>> +     /* clock management */
>> +     struct clk      *clk;
>> +
>> +     /* irq */
>> +     spinlock_t      lock;
>> +     int             irq;
>> +};
>> +
>> +/*********************/
>> +/* Interrupt handler */
>> +/*********************/
>> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> +{
>> +     struct sun4i_ps2data *drvdata = dev_id;
>> +     u32 intr_status;
>> +     u32 fifo_status;
>> +     unsigned char byte;
>> +     unsigned int rxflags = 0;
>> +     u32 rval;
>> +
>> +     spin_lock(&drvdata->lock);
>> +
>> +     /* Get the PS/2 interrupts and clear them */
>> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     /*Check Line Status Register*/
>> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> +
>> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> +     }
>> +
>> +     /*Check FIFO Status Register*/
>> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> +     }
>> +
>> +     rval = (fifo_status >> 16) & 0x3;
>> +     while (rval--) {
>> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> +     }
>> +
>> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> +
>> +     spin_unlock(&drvdata->lock);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +
>> +static int sun4i_ps2_open(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +     u32 src_clk = 0;
>> +     u32 clk_scdf;
>> +     u32 clk_pcdf;
>> +     u32 rval;
>> +     unsigned long flags;
>> +
>> +     /*Set Line Control And Enable Interrupt*/
>> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> +
>> +     /*Reset FIFO*/
>> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> +
>> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> +
>> +     src_clk = clk_get_rate(drvdata->clk);
>> +     /*Set Clock Divider Register*/
>> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> +     rval = (clk_scdf<<8) | clk_pcdf;
>> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> +
>> +
>> +     /*Set Global Control Register*/
>> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> +             | PS2_GCTL_BUSEN;
>> +
>> +     spin_lock_irqsave(&drvdata->lock, flags);
>> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> +
>> +     return 0;
>> +}
>> +
>> +static void sun4i_ps2_close(struct serio *pserio)
>> +{
>> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> +
>> +     synchronize_irq(drvdata->irq);
>
> synchronize_irq() on it's own is not very useful. You also need to shut
> off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> before calling synchronize_irq.
Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
>> +}
>> +
>> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> +{
>> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> +     struct sun4i_ps2data *drvdata;
>> +
>> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> +
>> +     do {
>> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> +                     return 0;
>> +             }
>> +     } while (time_before(jiffies, expire));
>> +
>> +     return SERIO_TIMEOUT;
>> +}
>> +
>> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> +{
>> +     struct resource *res; /* IO mem resources */
>> +     struct sun4i_ps2data *drvdata;
>> +     struct serio *serio;
>> +     struct device *dev = &pdev->dev;
>> +     unsigned int irq;
>> +     int error;
>> +
>> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> +     if (!drvdata || !serio) {
>> +             error = -ENOMEM;
>> +             goto err_free_mem;
>> +     }
>> +
>> +     spin_lock_init(&drvdata->lock);
>> +
>> +     /* IO */
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> +     if (IS_ERR(drvdata->reg_base)) {
>> +             dev_err(dev, "failed to map registers\n");
>> +             error = PTR_ERR(drvdata->reg_base);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     drvdata->clk = devm_clk_get(dev, NULL);
>> +     if (IS_ERR(drvdata->clk)) {
>> +             error = PTR_ERR(drvdata->clk);
>> +             dev_err(dev, "couldn't get clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     error = clk_prepare_enable(drvdata->clk);
>> +     if (error) {
>> +             dev_err(dev, "failed to enable clock %d\n", error);
>> +             goto err_free_mem;
>> +     }
>> +
>> +     serio->id.type = SERIO_8042;
>> +     serio->write = sun4i_ps2_write;
>> +     serio->open = sun4i_ps2_open;
>> +     serio->close = sun4i_ps2_close;
>> +     serio->port_data = drvdata;
>> +     serio->dev.parent = dev;
>> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> +
>> +     /* Get IRQ for the device */
>> +     irq = platform_get_irq(pdev, 0);
>> +     if (!irq) {
>> +             dev_err(dev, "no IRQ found\n");
>> +             error = -ENXIO;
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     drvdata->irq = irq;
>> +     drvdata->serio = serio;
>> +     drvdata->dev = dev;
>> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> +
>> +     if (error) {
>> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> +                     drvdata->irq, error);
>> +             goto error_disable_clk;
>> +     }
>> +
>> +     serio_register_port(serio);
>> +     platform_set_drvdata(pdev, drvdata);
>> +
>> +     return 0;       /* success */
>> +
>> +error_disable_clk:
>> +     clk_disable_unprepare(drvdata->clk);
>> +
>> +err_free_mem:
>> +     kfree(serio);
>> +     return error;
>> +}
>> +
>> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> +{
>> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> +
>> +     serio_unregister_port(drvdata->serio);
>> +
>> +     if (!IS_ERR(drvdata->clk))
>> +             clk_disable_unprepare(drvdata->clk);
>> +     kfree(drvdata->serio);
>
> Serio is refcounted, you do not free it after its has been registered.
> Overall I'd rather you did not use devm* interfaces here since you are
> forced to mix managed and manually freed resources.
Okie, No need to free serio here.
If serio is not manually freed here, It is not freeing anything else manually.

do you still feel I should not use devm* interfaces here?
>
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct of_device_id sun4i_ps2_match[] = {
>> +     { .compatible = "allwinner,sun4i-a10-ps2", },
>> +     { },
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
>> +
>> +static struct platform_driver sun4i_ps2_driver = {
>> +     .probe          = sun4i_ps2_probe,
>> +     .remove         = sun4i_ps2_remove,
>> +     .driver = {
>> +             .name = DRIVER_NAME,
>> +             .of_match_table = sun4i_ps2_match,
>> +     },
>> +};
>> +module_platform_driver(sun4i_ps2_driver);
>> +
>> +MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
>> +MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
>> +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 1.7.9.5
>>
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-20  0:35         ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-20  0:35 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Hans de Goede, ijc+devicetree, maxime.ripard, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> Thank you for review comments. Please see in-lined.
> 
> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> ---
> >>  drivers/input/serio/Kconfig     |   11 ++
> >>  drivers/input/serio/Makefile    |    1 +
> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 342 insertions(+)
> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >>
> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> index bc2d474..964afc5 100644
> >> --- a/drivers/input/serio/Kconfig
> >> +++ b/drivers/input/serio/Kconfig
> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >>         To compile this driver as a module, choose M here: the module will
> >>         be called hyperv_keyboard.
> >>
> >> +config SERIO_SUN4I_PS2
> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> +     default n
> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> +     help
> >> +       This selects support for the PS/2 Host Controller on
> >> +       Allwinner A10.
> >> +
> >> +       To compile this driver as a module, choose M here: the
> >> +       module will be called sun4i-ps2.
> >> +
> >>  endif
> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> index 815d874..c600089 100644
> >> --- a/drivers/input/serio/Makefile
> >> +++ b/drivers/input/serio/Makefile
> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> new file mode 100644
> >> index 0000000..06b3fef
> >> --- /dev/null
> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> @@ -0,0 +1,330 @@
> >> +/*
> >> + *   Driver for Allwinner A10 PS2 host controller
> >> + *
> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
> >> + *
> >> + *
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/serio.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/list.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/delay.h>
> >> +
> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> +
> >> +/* register offset definitions */
> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> +
> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> +#define PS2_GCTL_RESET               BIT(2)
> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> +
> >> +/* PS2 LINE CONTROL REGISTER */
> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> +
> >> +/* PS2 LINE STATUS REGISTER */
> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> +
> >> +#define PS2_LINE_ERROR_BIT \
> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> +
> >> +/* PS2 FIFO CONTROL REGISTER */
> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> +
> >> +/* PS2 FIFO STATUS REGISTER */
> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> +
> >> +#define PS2_FIFO_ERROR_BIT \
> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> +
> >> +#define PS2_SAMPLE_CLK               1000000
> >> +#define PS2_SCLK             125000
> >> +
> >> +struct sun4i_ps2data {
> >> +     struct serio *serio;
> >> +     struct device *dev;
> >> +
> >> +     /* IO mapping base */
> >> +     void __iomem    *reg_base;
> >> +
> >> +     /* clock management */
> >> +     struct clk      *clk;
> >> +
> >> +     /* irq */
> >> +     spinlock_t      lock;
> >> +     int             irq;
> >> +};
> >> +
> >> +/*********************/
> >> +/* Interrupt handler */
> >> +/*********************/
> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> +     u32 intr_status;
> >> +     u32 fifo_status;
> >> +     unsigned char byte;
> >> +     unsigned int rxflags = 0;
> >> +     u32 rval;
> >> +
> >> +     spin_lock(&drvdata->lock);
> >> +
> >> +     /* Get the PS/2 interrupts and clear them */
> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     /*Check Line Status Register*/
> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> +
> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> +     }
> >> +
> >> +     /*Check FIFO Status Register*/
> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> +     }
> >> +
> >> +     rval = (fifo_status >> 16) & 0x3;
> >> +     while (rval--) {
> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> +     }
> >> +
> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     spin_unlock(&drvdata->lock);
> >> +
> >> +     return IRQ_HANDLED;
> >> +}
> >> +
> >> +
> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +     u32 src_clk = 0;
> >> +     u32 clk_scdf;
> >> +     u32 clk_pcdf;
> >> +     u32 rval;
> >> +     unsigned long flags;
> >> +
> >> +     /*Set Line Control And Enable Interrupt*/
> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> +
> >> +     /*Reset FIFO*/
> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> +
> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> +
> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> +     /*Set Clock Divider Register*/
> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> +
> >> +
> >> +     /*Set Global Control Register*/
> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> +             | PS2_GCTL_BUSEN;
> >> +
> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +
> >> +     synchronize_irq(drvdata->irq);
> >
> > synchronize_irq() on it's own is not very useful. You also need to shut
> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> > before calling synchronize_irq.
> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.

Please also do shut off interrupts on the chip before requesting IRQ.

> >
> >> +}
> >> +
> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> +{
> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> +     struct sun4i_ps2data *drvdata;
> >> +
> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> +
> >> +     do {
> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> +                     return 0;
> >> +             }
> >> +     } while (time_before(jiffies, expire));
> >> +
> >> +     return SERIO_TIMEOUT;
> >> +}
> >> +
> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> +{
> >> +     struct resource *res; /* IO mem resources */
> >> +     struct sun4i_ps2data *drvdata;
> >> +     struct serio *serio;
> >> +     struct device *dev = &pdev->dev;
> >> +     unsigned int irq;
> >> +     int error;
> >> +
> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> +     if (!drvdata || !serio) {
> >> +             error = -ENOMEM;
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     spin_lock_init(&drvdata->lock);
> >> +
> >> +     /* IO */
> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> +             dev_err(dev, "failed to map registers\n");
> >> +             error = PTR_ERR(drvdata->reg_base);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> +     if (IS_ERR(drvdata->clk)) {
> >> +             error = PTR_ERR(drvdata->clk);
> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     error = clk_prepare_enable(drvdata->clk);
> >> +     if (error) {
> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     serio->id.type = SERIO_8042;
> >> +     serio->write = sun4i_ps2_write;
> >> +     serio->open = sun4i_ps2_open;
> >> +     serio->close = sun4i_ps2_close;
> >> +     serio->port_data = drvdata;
> >> +     serio->dev.parent = dev;
> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> +
> >> +     /* Get IRQ for the device */
> >> +     irq = platform_get_irq(pdev, 0);
> >> +     if (!irq) {
> >> +             dev_err(dev, "no IRQ found\n");
> >> +             error = -ENXIO;
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     drvdata->irq = irq;
> >> +     drvdata->serio = serio;
> >> +     drvdata->dev = dev;
> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> +
> >> +     if (error) {
> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> +                     drvdata->irq, error);
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     serio_register_port(serio);
> >> +     platform_set_drvdata(pdev, drvdata);
> >> +
> >> +     return 0;       /* success */
> >> +
> >> +error_disable_clk:
> >> +     clk_disable_unprepare(drvdata->clk);
> >> +
> >> +err_free_mem:
> >> +     kfree(serio);
> >> +     return error;
> >> +}
> >> +
> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> +
> >> +     serio_unregister_port(drvdata->serio);
> >> +
> >> +     if (!IS_ERR(drvdata->clk))
> >> +             clk_disable_unprepare(drvdata->clk);
> >> +     kfree(drvdata->serio);
> >
> > Serio is refcounted, you do not free it after its has been registered.
> > Overall I'd rather you did not use devm* interfaces here since you are
> > forced to mix managed and manually freed resources.
> Okie, No need to free serio here.
> If serio is not manually freed here, It is not freeing anything else manually.

You are still unregistering the port manually and disabling the clock manually.
> 
> do you still feel I should not use devm* interfaces here?

Yes, because of above. My rule of thumb - when using devm* API there should not
be remove() at all.

BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
such patch.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-20  0:35         ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-20  0:35 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Hans de Goede, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> Thank you for review comments. Please see in-lined.
> 
> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> ---
> >>  drivers/input/serio/Kconfig     |   11 ++
> >>  drivers/input/serio/Makefile    |    1 +
> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 342 insertions(+)
> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >>
> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> index bc2d474..964afc5 100644
> >> --- a/drivers/input/serio/Kconfig
> >> +++ b/drivers/input/serio/Kconfig
> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >>         To compile this driver as a module, choose M here: the module will
> >>         be called hyperv_keyboard.
> >>
> >> +config SERIO_SUN4I_PS2
> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> +     default n
> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> +     help
> >> +       This selects support for the PS/2 Host Controller on
> >> +       Allwinner A10.
> >> +
> >> +       To compile this driver as a module, choose M here: the
> >> +       module will be called sun4i-ps2.
> >> +
> >>  endif
> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> index 815d874..c600089 100644
> >> --- a/drivers/input/serio/Makefile
> >> +++ b/drivers/input/serio/Makefile
> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> new file mode 100644
> >> index 0000000..06b3fef
> >> --- /dev/null
> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> @@ -0,0 +1,330 @@
> >> +/*
> >> + *   Driver for Allwinner A10 PS2 host controller
> >> + *
> >> + *   Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> + *           Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
> >> + *
> >> + *
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/serio.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/list.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/delay.h>
> >> +
> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> +
> >> +/* register offset definitions */
> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> +
> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> +#define PS2_GCTL_RESET               BIT(2)
> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> +
> >> +/* PS2 LINE CONTROL REGISTER */
> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> +
> >> +/* PS2 LINE STATUS REGISTER */
> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> +
> >> +#define PS2_LINE_ERROR_BIT \
> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> +
> >> +/* PS2 FIFO CONTROL REGISTER */
> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> +
> >> +/* PS2 FIFO STATUS REGISTER */
> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> +
> >> +#define PS2_FIFO_ERROR_BIT \
> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> +
> >> +#define PS2_SAMPLE_CLK               1000000
> >> +#define PS2_SCLK             125000
> >> +
> >> +struct sun4i_ps2data {
> >> +     struct serio *serio;
> >> +     struct device *dev;
> >> +
> >> +     /* IO mapping base */
> >> +     void __iomem    *reg_base;
> >> +
> >> +     /* clock management */
> >> +     struct clk      *clk;
> >> +
> >> +     /* irq */
> >> +     spinlock_t      lock;
> >> +     int             irq;
> >> +};
> >> +
> >> +/*********************/
> >> +/* Interrupt handler */
> >> +/*********************/
> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> +     u32 intr_status;
> >> +     u32 fifo_status;
> >> +     unsigned char byte;
> >> +     unsigned int rxflags = 0;
> >> +     u32 rval;
> >> +
> >> +     spin_lock(&drvdata->lock);
> >> +
> >> +     /* Get the PS/2 interrupts and clear them */
> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     /*Check Line Status Register*/
> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> +
> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> +     }
> >> +
> >> +     /*Check FIFO Status Register*/
> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> +     }
> >> +
> >> +     rval = (fifo_status >> 16) & 0x3;
> >> +     while (rval--) {
> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> +     }
> >> +
> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     spin_unlock(&drvdata->lock);
> >> +
> >> +     return IRQ_HANDLED;
> >> +}
> >> +
> >> +
> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +     u32 src_clk = 0;
> >> +     u32 clk_scdf;
> >> +     u32 clk_pcdf;
> >> +     u32 rval;
> >> +     unsigned long flags;
> >> +
> >> +     /*Set Line Control And Enable Interrupt*/
> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> +
> >> +     /*Reset FIFO*/
> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> +
> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> +
> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> +     /*Set Clock Divider Register*/
> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> +
> >> +
> >> +     /*Set Global Control Register*/
> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> +             | PS2_GCTL_BUSEN;
> >> +
> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +
> >> +     synchronize_irq(drvdata->irq);
> >
> > synchronize_irq() on it's own is not very useful. You also need to shut
> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> > before calling synchronize_irq.
> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.

Please also do shut off interrupts on the chip before requesting IRQ.

> >
> >> +}
> >> +
> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> +{
> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> +     struct sun4i_ps2data *drvdata;
> >> +
> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> +
> >> +     do {
> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> +                     return 0;
> >> +             }
> >> +     } while (time_before(jiffies, expire));
> >> +
> >> +     return SERIO_TIMEOUT;
> >> +}
> >> +
> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> +{
> >> +     struct resource *res; /* IO mem resources */
> >> +     struct sun4i_ps2data *drvdata;
> >> +     struct serio *serio;
> >> +     struct device *dev = &pdev->dev;
> >> +     unsigned int irq;
> >> +     int error;
> >> +
> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> +     if (!drvdata || !serio) {
> >> +             error = -ENOMEM;
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     spin_lock_init(&drvdata->lock);
> >> +
> >> +     /* IO */
> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> +             dev_err(dev, "failed to map registers\n");
> >> +             error = PTR_ERR(drvdata->reg_base);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> +     if (IS_ERR(drvdata->clk)) {
> >> +             error = PTR_ERR(drvdata->clk);
> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     error = clk_prepare_enable(drvdata->clk);
> >> +     if (error) {
> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     serio->id.type = SERIO_8042;
> >> +     serio->write = sun4i_ps2_write;
> >> +     serio->open = sun4i_ps2_open;
> >> +     serio->close = sun4i_ps2_close;
> >> +     serio->port_data = drvdata;
> >> +     serio->dev.parent = dev;
> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> +
> >> +     /* Get IRQ for the device */
> >> +     irq = platform_get_irq(pdev, 0);
> >> +     if (!irq) {
> >> +             dev_err(dev, "no IRQ found\n");
> >> +             error = -ENXIO;
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     drvdata->irq = irq;
> >> +     drvdata->serio = serio;
> >> +     drvdata->dev = dev;
> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> +
> >> +     if (error) {
> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> +                     drvdata->irq, error);
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     serio_register_port(serio);
> >> +     platform_set_drvdata(pdev, drvdata);
> >> +
> >> +     return 0;       /* success */
> >> +
> >> +error_disable_clk:
> >> +     clk_disable_unprepare(drvdata->clk);
> >> +
> >> +err_free_mem:
> >> +     kfree(serio);
> >> +     return error;
> >> +}
> >> +
> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> +
> >> +     serio_unregister_port(drvdata->serio);
> >> +
> >> +     if (!IS_ERR(drvdata->clk))
> >> +             clk_disable_unprepare(drvdata->clk);
> >> +     kfree(drvdata->serio);
> >
> > Serio is refcounted, you do not free it after its has been registered.
> > Overall I'd rather you did not use devm* interfaces here since you are
> > forced to mix managed and manually freed resources.
> Okie, No need to free serio here.
> If serio is not manually freed here, It is not freeing anything else manually.

You are still unregistering the port manually and disabling the clock manually.
> 
> do you still feel I should not use devm* interfaces here?

Yes, because of above. My rule of thumb - when using devm* API there should not
be remove() at all.

BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
such patch.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-20  0:35         ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-20  0:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> Thank you for review comments. Please see in-lined.
> 
> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> ---
> >>  drivers/input/serio/Kconfig     |   11 ++
> >>  drivers/input/serio/Makefile    |    1 +
> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 342 insertions(+)
> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >>
> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> index bc2d474..964afc5 100644
> >> --- a/drivers/input/serio/Kconfig
> >> +++ b/drivers/input/serio/Kconfig
> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >>         To compile this driver as a module, choose M here: the module will
> >>         be called hyperv_keyboard.
> >>
> >> +config SERIO_SUN4I_PS2
> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> +     default n
> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> +     help
> >> +       This selects support for the PS/2 Host Controller on
> >> +       Allwinner A10.
> >> +
> >> +       To compile this driver as a module, choose M here: the
> >> +       module will be called sun4i-ps2.
> >> +
> >>  endif
> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> index 815d874..c600089 100644
> >> --- a/drivers/input/serio/Makefile
> >> +++ b/drivers/input/serio/Makefile
> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> new file mode 100644
> >> index 0000000..06b3fef
> >> --- /dev/null
> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> @@ -0,0 +1,330 @@
> >> +/*
> >> + *   Driver for Allwinner A10 PS2 host controller
> >> + *
> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
> >> + *
> >> + *
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/serio.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/list.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/of_platform.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/delay.h>
> >> +
> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> +
> >> +/* register offset definitions */
> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> +
> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> +#define PS2_GCTL_RESET               BIT(2)
> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> +
> >> +/* PS2 LINE CONTROL REGISTER */
> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> +
> >> +/* PS2 LINE STATUS REGISTER */
> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> +
> >> +#define PS2_LINE_ERROR_BIT \
> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> +
> >> +/* PS2 FIFO CONTROL REGISTER */
> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> +
> >> +/* PS2 FIFO STATUS REGISTER */
> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> +
> >> +#define PS2_FIFO_ERROR_BIT \
> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> +
> >> +#define PS2_SAMPLE_CLK               1000000
> >> +#define PS2_SCLK             125000
> >> +
> >> +struct sun4i_ps2data {
> >> +     struct serio *serio;
> >> +     struct device *dev;
> >> +
> >> +     /* IO mapping base */
> >> +     void __iomem    *reg_base;
> >> +
> >> +     /* clock management */
> >> +     struct clk      *clk;
> >> +
> >> +     /* irq */
> >> +     spinlock_t      lock;
> >> +     int             irq;
> >> +};
> >> +
> >> +/*********************/
> >> +/* Interrupt handler */
> >> +/*********************/
> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> +     u32 intr_status;
> >> +     u32 fifo_status;
> >> +     unsigned char byte;
> >> +     unsigned int rxflags = 0;
> >> +     u32 rval;
> >> +
> >> +     spin_lock(&drvdata->lock);
> >> +
> >> +     /* Get the PS/2 interrupts and clear them */
> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     /*Check Line Status Register*/
> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> +
> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> +     }
> >> +
> >> +     /*Check FIFO Status Register*/
> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> +     }
> >> +
> >> +     rval = (fifo_status >> 16) & 0x3;
> >> +     while (rval--) {
> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> +     }
> >> +
> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> +
> >> +     spin_unlock(&drvdata->lock);
> >> +
> >> +     return IRQ_HANDLED;
> >> +}
> >> +
> >> +
> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +     u32 src_clk = 0;
> >> +     u32 clk_scdf;
> >> +     u32 clk_pcdf;
> >> +     u32 rval;
> >> +     unsigned long flags;
> >> +
> >> +     /*Set Line Control And Enable Interrupt*/
> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> +
> >> +     /*Reset FIFO*/
> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> +
> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> +
> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> +     /*Set Clock Divider Register*/
> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> +
> >> +
> >> +     /*Set Global Control Register*/
> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> +             | PS2_GCTL_BUSEN;
> >> +
> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> +
> >> +     synchronize_irq(drvdata->irq);
> >
> > synchronize_irq() on it's own is not very useful. You also need to shut
> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> > before calling synchronize_irq.
> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.

Please also do shut off interrupts on the chip before requesting IRQ.

> >
> >> +}
> >> +
> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> +{
> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> +     struct sun4i_ps2data *drvdata;
> >> +
> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> +
> >> +     do {
> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> +                     return 0;
> >> +             }
> >> +     } while (time_before(jiffies, expire));
> >> +
> >> +     return SERIO_TIMEOUT;
> >> +}
> >> +
> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> +{
> >> +     struct resource *res; /* IO mem resources */
> >> +     struct sun4i_ps2data *drvdata;
> >> +     struct serio *serio;
> >> +     struct device *dev = &pdev->dev;
> >> +     unsigned int irq;
> >> +     int error;
> >> +
> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> +     if (!drvdata || !serio) {
> >> +             error = -ENOMEM;
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     spin_lock_init(&drvdata->lock);
> >> +
> >> +     /* IO */
> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> +             dev_err(dev, "failed to map registers\n");
> >> +             error = PTR_ERR(drvdata->reg_base);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> +     if (IS_ERR(drvdata->clk)) {
> >> +             error = PTR_ERR(drvdata->clk);
> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     error = clk_prepare_enable(drvdata->clk);
> >> +     if (error) {
> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> +             goto err_free_mem;
> >> +     }
> >> +
> >> +     serio->id.type = SERIO_8042;
> >> +     serio->write = sun4i_ps2_write;
> >> +     serio->open = sun4i_ps2_open;
> >> +     serio->close = sun4i_ps2_close;
> >> +     serio->port_data = drvdata;
> >> +     serio->dev.parent = dev;
> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> +
> >> +     /* Get IRQ for the device */
> >> +     irq = platform_get_irq(pdev, 0);
> >> +     if (!irq) {
> >> +             dev_err(dev, "no IRQ found\n");
> >> +             error = -ENXIO;
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     drvdata->irq = irq;
> >> +     drvdata->serio = serio;
> >> +     drvdata->dev = dev;
> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> +
> >> +     if (error) {
> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> +                     drvdata->irq, error);
> >> +             goto error_disable_clk;
> >> +     }
> >> +
> >> +     serio_register_port(serio);
> >> +     platform_set_drvdata(pdev, drvdata);
> >> +
> >> +     return 0;       /* success */
> >> +
> >> +error_disable_clk:
> >> +     clk_disable_unprepare(drvdata->clk);
> >> +
> >> +err_free_mem:
> >> +     kfree(serio);
> >> +     return error;
> >> +}
> >> +
> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> +{
> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> +
> >> +     serio_unregister_port(drvdata->serio);
> >> +
> >> +     if (!IS_ERR(drvdata->clk))
> >> +             clk_disable_unprepare(drvdata->clk);
> >> +     kfree(drvdata->serio);
> >
> > Serio is refcounted, you do not free it after its has been registered.
> > Overall I'd rather you did not use devm* interfaces here since you are
> > forced to mix managed and manually freed resources.
> Okie, No need to free serio here.
> If serio is not manually freed here, It is not freeing anything else manually.

You are still unregistering the port manually and disabling the clock manually.
> 
> do you still feel I should not use devm* interfaces here?

Yes, because of above. My rule of thumb - when using devm* API there should not
be remove() at all.

BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
such patch.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 17:02     ` Iain Paton
  0 siblings, 0 replies; 57+ messages in thread
From: Iain Paton @ 2015-01-20 17:02 UTC (permalink / raw)
  To: linux-sunxi
  Cc: Vishnu Patekar, dmitry.torokhov, hdegoede, ijc+devicetree,
	maxime.ripard, linux-arm-kernel, linux-kernel, linux-input,
	devicetree

On 16/01/15 14:03, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> index ed364d5..3365f12 100644
> --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> @@ -113,6 +113,18 @@
>  			status = "okay";
>  		};
>  
> +		ps20: ps2@01c2a000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps20_pins_a>;
> +			status = "okay";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps21_pins_a>;
> +			status = "okay";
> +		};
> +
>  		i2c0: i2c@01c2ac00 {
>  			pinctrl-names = "default";
>  			pinctrl-0 = <&i2c0_pins_a>;
> 

As the Lime2 doesn't actually have any PS2 connectors on the board, 
I'd prefer that these are not enabled unconditionally. Doing so 
only makes it more difficult for people who want to use these pins 
for other functions.

Device tree overlays seem to be close to being merged, perhaps we 
could leave enabling this to an overlay?

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 17:02     ` Iain Paton
  0 siblings, 0 replies; 57+ messages in thread
From: Iain Paton @ 2015-01-20 17:02 UTC (permalink / raw)
  To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
  Cc: Vishnu Patekar, dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 16/01/15 14:03, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> index ed364d5..3365f12 100644
> --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> @@ -113,6 +113,18 @@
>  			status = "okay";
>  		};
>  
> +		ps20: ps2@01c2a000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps20_pins_a>;
> +			status = "okay";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps21_pins_a>;
> +			status = "okay";
> +		};
> +
>  		i2c0: i2c@01c2ac00 {
>  			pinctrl-names = "default";
>  			pinctrl-0 = <&i2c0_pins_a>;
> 

As the Lime2 doesn't actually have any PS2 connectors on the board, 
I'd prefer that these are not enabled unconditionally. Doing so 
only makes it more difficult for people who want to use these pins 
for other functions.

Device tree overlays seem to be close to being merged, perhaps we 
could leave enabling this to an overlay?

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 17:02     ` Iain Paton
  0 siblings, 0 replies; 57+ messages in thread
From: Iain Paton @ 2015-01-20 17:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/01/15 14:03, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> index ed364d5..3365f12 100644
> --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> @@ -113,6 +113,18 @@
>  			status = "okay";
>  		};
>  
> +		ps20: ps2 at 01c2a000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps20_pins_a>;
> +			status = "okay";
> +		};
> +
> +		ps21: ps2 at 01c2a400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&ps21_pins_a>;
> +			status = "okay";
> +		};
> +
>  		i2c0: i2c at 01c2ac00 {
>  			pinctrl-names = "default";
>  			pinctrl-0 = <&i2c0_pins_a>;
> 

As the Lime2 doesn't actually have any PS2 connectors on the board, 
I'd prefer that these are not enabled unconditionally. Doing so 
only makes it more difficult for people who want to use these pins 
for other functions.

Device tree overlays seem to be close to being merged, perhaps we 
could leave enabling this to an overlay?

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-20 20:02     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:02 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: dmitry.torokhov, hdegoede, ijc+devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

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

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Why is there Hans Signed-off here?

> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 7b4099f..2c31242 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -795,5 +795,21 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  		};
> +
> +		ps20: ps2@01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <62>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <63>;
> +			clocks = <&apb1_gates 7>;
> +			status = "disabled";
> +		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index e21ce59..f35c691 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -1093,5 +1093,21 @@
>  			#interrupt-cells = <3>;
>  			interrupts = <1 9 0xf04>;
>  		};
> +
> +		ps20: ps2@01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <0 62 4>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <0 63 4>;

We recently switched to using includes and defines for these hardcoded
values.

Could you switch to it as well?

Thanks,
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-20 20:02     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:02 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

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

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Why is there Hans Signed-off here?

> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 7b4099f..2c31242 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -795,5 +795,21 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  		};
> +
> +		ps20: ps2@01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <62>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <63>;
> +			clocks = <&apb1_gates 7>;
> +			status = "disabled";
> +		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index e21ce59..f35c691 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -1093,5 +1093,21 @@
>  			#interrupt-cells = <3>;
>  			interrupts = <1 9 0xf04>;
>  		};
> +
> +		ps20: ps2@01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <0 62 4>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2@01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <0 63 4>;

We recently switched to using includes and defines for these hardcoded
values.

Could you switch to it as well?

Thanks,
Maxime

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-20 20:02     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vishnu,

On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Why is there Hans Signed-off here?

> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 7b4099f..2c31242 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -795,5 +795,21 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  		};
> +
> +		ps20: ps2 at 01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <62>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2 at 01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <63>;
> +			clocks = <&apb1_gates 7>;
> +			status = "disabled";
> +		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index e21ce59..f35c691 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -1093,5 +1093,21 @@
>  			#interrupt-cells = <3>;
>  			interrupts = <1 9 0xf04>;
>  		};
> +
> +		ps20: ps2 at 01c2a000 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a000 0x400>;
> +			interrupts = <0 62 4>;
> +			clocks = <&apb1_gates 6>;
> +			status = "disabled";
> +		};
> +
> +		ps21: ps2 at 01c2a400 {
> +			compatible = "allwinner,sun4i-a10-ps2";
> +			reg = <0x01c2a400 0x400>;
> +			interrupts = <0 63 4>;

We recently switched to using includes and defines for these hardcoded
values.

Could you switch to it as well?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150120/edd97837/attachment.sig>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-20 20:03     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:03 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: dmitry.torokhov, hdegoede, ijc+devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

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

On Fri, Jan 16, 2015 at 07:33:40PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
>  2 files changed, 28 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 2c31242..8fade3e 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -629,6 +629,20 @@
>  				allwinner,drive = <0>;
>  				allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20@0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21@0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};
>  
>  		timer@01c20c00 {
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index f35c691..f9dd274 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -866,6 +866,20 @@
>  				    allwinner,drive = <0>;
>  				    allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20@0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21@0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};

Same thing here, we're using defines now for the values in ,drive and
,pull, please use them.

Thanks,
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-20 20:03     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:03 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

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

On Fri, Jan 16, 2015 at 07:33:40PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
>  2 files changed, 28 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 2c31242..8fade3e 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -629,6 +629,20 @@
>  				allwinner,drive = <0>;
>  				allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20@0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21@0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};
>  
>  		timer@01c20c00 {
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index f35c691..f9dd274 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -866,6 +866,20 @@
>  				    allwinner,drive = <0>;
>  				    allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20@0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21@0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};

Same thing here, we're using defines now for the values in ,drive and
,pull, please use them.

Thanks,
Maxime

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
@ 2015-01-20 20:03     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 16, 2015 at 07:33:40PM +0530, Vishnu Patekar wrote:
> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> ---
>  arch/arm/boot/dts/sun4i-a10.dtsi |   14 ++++++++++++++
>  arch/arm/boot/dts/sun7i-a20.dtsi |   14 ++++++++++++++
>  2 files changed, 28 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 2c31242..8fade3e 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -629,6 +629,20 @@
>  				allwinner,drive = <0>;
>  				allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20 at 0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21 at 0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};
>  
>  		timer at 01c20c00 {
> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
> index f35c691..f9dd274 100644
> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
> @@ -866,6 +866,20 @@
>  				    allwinner,drive = <0>;
>  				    allwinner,pull = <0>;
>  			};
> +
> +			ps20_pins_a: ps20 at 0 {
> +				allwinner,pins = "PI20", "PI21";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +
> +			ps21_pins_a: ps21 at 0 {
> +				allwinner,pins = "PH12", "PH13";
> +				allwinner,function = "ps2";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
>  		};

Same thing here, we're using defines now for the values in ,drive and
,pull, please use them.

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150120/78a0807c/attachment.sig>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 20:07       ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:07 UTC (permalink / raw)
  To: Iain Paton
  Cc: linux-sunxi, Vishnu Patekar, dmitry.torokhov, hdegoede,
	ijc+devicetree, linux-arm-kernel, linux-kernel, linux-input,
	devicetree

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

On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> On 16/01/15 14:03, Vishnu Patekar wrote:
> > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > ---
> >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > index ed364d5..3365f12 100644
> > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > @@ -113,6 +113,18 @@
> >  			status = "okay";
> >  		};
> >  
> > +		ps20: ps2@01c2a000 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps20_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> > +		ps21: ps2@01c2a400 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps21_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> >  		i2c0: i2c@01c2ac00 {
> >  			pinctrl-names = "default";
> >  			pinctrl-0 = <&i2c0_pins_a>;
> > 
> 
> As the Lime2 doesn't actually have any PS2 connectors on the board, 
> I'd prefer that these are not enabled unconditionally. Doing so 
> only makes it more difficult for people who want to use these pins 
> for other functions.
> 
> Device tree overlays seem to be close to being merged, perhaps we 
> could leave enabling this to an overlay?

I already had the exact same reasoning, and this was even removed at
some point. For some reason, it was added back, and I don't really
know why.

Maxime


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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 20:07       ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:07 UTC (permalink / raw)
  To: Iain Paton
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Vishnu Patekar,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

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

On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> On 16/01/15 14:03, Vishnu Patekar wrote:
> > Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > ---
> >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > index ed364d5..3365f12 100644
> > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > @@ -113,6 +113,18 @@
> >  			status = "okay";
> >  		};
> >  
> > +		ps20: ps2@01c2a000 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps20_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> > +		ps21: ps2@01c2a400 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps21_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> >  		i2c0: i2c@01c2ac00 {
> >  			pinctrl-names = "default";
> >  			pinctrl-0 = <&i2c0_pins_a>;
> > 
> 
> As the Lime2 doesn't actually have any PS2 connectors on the board, 
> I'd prefer that these are not enabled unconditionally. Doing so 
> only makes it more difficult for people who want to use these pins 
> for other functions.
> 
> Device tree overlays seem to be close to being merged, perhaps we 
> could leave enabling this to an overlay?

I already had the exact same reasoning, and this was even removed at
some point. For some reason, it was added back, and I don't really
know why.

Maxime


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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-20 20:07       ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-20 20:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> On 16/01/15 14:03, Vishnu Patekar wrote:
> > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > ---
> >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > index ed364d5..3365f12 100644
> > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > @@ -113,6 +113,18 @@
> >  			status = "okay";
> >  		};
> >  
> > +		ps20: ps2 at 01c2a000 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps20_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> > +		ps21: ps2 at 01c2a400 {
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&ps21_pins_a>;
> > +			status = "okay";
> > +		};
> > +
> >  		i2c0: i2c at 01c2ac00 {
> >  			pinctrl-names = "default";
> >  			pinctrl-0 = <&i2c0_pins_a>;
> > 
> 
> As the Lime2 doesn't actually have any PS2 connectors on the board, 
> I'd prefer that these are not enabled unconditionally. Doing so 
> only makes it more difficult for people who want to use these pins 
> for other functions.
> 
> Device tree overlays seem to be close to being merged, perhaps we 
> could leave enabling this to an overlay?

I already had the exact same reasoning, and this was even removed at
some point. For some reason, it was added back, and I don't really
know why.

Maxime


-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150120/26b1bbed/attachment.sig>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
  2015-01-20 20:07       ` Maxime Ripard
  (?)
@ 2015-01-21 11:04         ` Vishnu Patekar
  -1 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Iain Paton, linux-sunxi, Dmitry Torokhov, Hans de Goede,
	ijc+devicetree, linux-arm-kernel, linux-kernel, linux-input,
	devicetree

Hello,

On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
>
> On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > > ---
> > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > >  1 file changed, 12 insertions(+)
> > >
> > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > index ed364d5..3365f12 100644
> > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > @@ -113,6 +113,18 @@
> > >                     status = "okay";
> > >             };
> > >
> > > +           ps20: ps2@01c2a000 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > > +           ps21: ps2@01c2a400 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > >             i2c0: i2c@01c2ac00 {
> > >                     pinctrl-names = "default";
> > >                     pinctrl-0 = <&i2c0_pins_a>;
> > >
> >
> > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > I'd prefer that these are not enabled unconditionally. Doing so
> > only makes it more difficult for people who want to use these pins
> > for other functions.
> >
> > Device tree overlays seem to be close to being merged, perhaps we
> > could leave enabling this to an overlay?
>
> I already had the exact same reasoning, and this was even removed at
> some point. For some reason, it was added back, and I don't really
> know why.
This was removed in consideration that these pins conflict with HDMI,
however, these is not conflict.

It was kept there as an example. But, as there is no ps2 connector on
board, I've no problem to remove these nodes from Lime2 dts file.

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-21 11:04         ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Iain Paton, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Dmitry Torokhov,
	Hans de Goede, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hello,

On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>
> On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > > ---
> > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > >  1 file changed, 12 insertions(+)
> > >
> > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > index ed364d5..3365f12 100644
> > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > @@ -113,6 +113,18 @@
> > >                     status = "okay";
> > >             };
> > >
> > > +           ps20: ps2@01c2a000 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > > +           ps21: ps2@01c2a400 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > >             i2c0: i2c@01c2ac00 {
> > >                     pinctrl-names = "default";
> > >                     pinctrl-0 = <&i2c0_pins_a>;
> > >
> >
> > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > I'd prefer that these are not enabled unconditionally. Doing so
> > only makes it more difficult for people who want to use these pins
> > for other functions.
> >
> > Device tree overlays seem to be close to being merged, perhaps we
> > could leave enabling this to an overlay?
>
> I already had the exact same reasoning, and this was even removed at
> some point. For some reason, it was added back, and I don't really
> know why.
This was removed in consideration that these pins conflict with HDMI,
however, these is not conflict.

It was kept there as an example. But, as there is no ps2 connector on
board, I've no problem to remove these nodes from Lime2 dts file.

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-21 11:04         ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
>
> On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > > ---
> > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > >  1 file changed, 12 insertions(+)
> > >
> > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > index ed364d5..3365f12 100644
> > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > @@ -113,6 +113,18 @@
> > >                     status = "okay";
> > >             };
> > >
> > > +           ps20: ps2 at 01c2a000 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > > +           ps21: ps2 at 01c2a400 {
> > > +                   pinctrl-names = "default";
> > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > +                   status = "okay";
> > > +           };
> > > +
> > >             i2c0: i2c at 01c2ac00 {
> > >                     pinctrl-names = "default";
> > >                     pinctrl-0 = <&i2c0_pins_a>;
> > >
> >
> > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > I'd prefer that these are not enabled unconditionally. Doing so
> > only makes it more difficult for people who want to use these pins
> > for other functions.
> >
> > Device tree overlays seem to be close to being merged, perhaps we
> > could leave enabling this to an overlay?
>
> I already had the exact same reasoning, and this was even removed at
> some point. For some reason, it was added back, and I don't really
> know why.
This was removed in consideration that these pins conflict with HDMI,
however, these is not conflict.

It was kept there as an example. But, as there is no ps2 connector on
board, I've no problem to remove these nodes from Lime2 dts file.

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
  2015-01-20 20:02     ` Maxime Ripard
  (?)
@ 2015-01-21 11:10       ` Vishnu Patekar
  -1 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:10 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Dmitry Torokhov, Hans de Goede, ijc+devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>
> Why is there Hans Signed-off here?
Hans has modified the A10 dtsi and also tested on A10 board.
Shouldn't I add him as Signed-off?
>
>> ---
>>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>>  2 files changed, 32 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
>> index 7b4099f..2c31242 100644
>> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
>> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
>> @@ -795,5 +795,21 @@
>>                       #address-cells = <1>;
>>                       #size-cells = <0>;
>>               };
>> +
>> +             ps20: ps2@01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <62>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2@01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <63>;
>> +                     clocks = <&apb1_gates 7>;
>> +                     status = "disabled";
>> +             };
>>       };
>>  };
>> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
>> index e21ce59..f35c691 100644
>> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
>> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
>> @@ -1093,5 +1093,21 @@
>>                       #interrupt-cells = <3>;
>>                       interrupts = <1 9 0xf04>;
>>               };
>> +
>> +             ps20: ps2@01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <0 62 4>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2@01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <0 63 4>;
>
> We recently switched to using includes and defines for these hardcoded
> values.
>
> Could you switch to it as well?
Okie, I did not notice that. Thanks for pointing out.
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-21 11:10       ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:10 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Dmitry Torokhov, Hans de Goede,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> Why is there Hans Signed-off here?
Hans has modified the A10 dtsi and also tested on A10 board.
Shouldn't I add him as Signed-off?
>
>> ---
>>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>>  2 files changed, 32 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
>> index 7b4099f..2c31242 100644
>> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
>> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
>> @@ -795,5 +795,21 @@
>>                       #address-cells = <1>;
>>                       #size-cells = <0>;
>>               };
>> +
>> +             ps20: ps2@01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <62>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2@01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <63>;
>> +                     clocks = <&apb1_gates 7>;
>> +                     status = "disabled";
>> +             };
>>       };
>>  };
>> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
>> index e21ce59..f35c691 100644
>> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
>> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
>> @@ -1093,5 +1093,21 @@
>>                       #interrupt-cells = <3>;
>>                       interrupts = <1 9 0xf04>;
>>               };
>> +
>> +             ps20: ps2@01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <0 62 4>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2@01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <0 63 4>;
>
> We recently switched to using includes and defines for these hardcoded
> values.
>
> Could you switch to it as well?
Okie, I did not notice that. Thanks for pointing out.
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-21 11:10       ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Vishnu,
>
> On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
>> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>
> Why is there Hans Signed-off here?
Hans has modified the A10 dtsi and also tested on A10 board.
Shouldn't I add him as Signed-off?
>
>> ---
>>  arch/arm/boot/dts/sun4i-a10.dtsi |   16 ++++++++++++++++
>>  arch/arm/boot/dts/sun7i-a20.dtsi |   16 ++++++++++++++++
>>  2 files changed, 32 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
>> index 7b4099f..2c31242 100644
>> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
>> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
>> @@ -795,5 +795,21 @@
>>                       #address-cells = <1>;
>>                       #size-cells = <0>;
>>               };
>> +
>> +             ps20: ps2 at 01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <62>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2 at 01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <63>;
>> +                     clocks = <&apb1_gates 7>;
>> +                     status = "disabled";
>> +             };
>>       };
>>  };
>> diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
>> index e21ce59..f35c691 100644
>> --- a/arch/arm/boot/dts/sun7i-a20.dtsi
>> +++ b/arch/arm/boot/dts/sun7i-a20.dtsi
>> @@ -1093,5 +1093,21 @@
>>                       #interrupt-cells = <3>;
>>                       interrupts = <1 9 0xf04>;
>>               };
>> +
>> +             ps20: ps2 at 01c2a000 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a000 0x400>;
>> +                     interrupts = <0 62 4>;
>> +                     clocks = <&apb1_gates 6>;
>> +                     status = "disabled";
>> +             };
>> +
>> +             ps21: ps2 at 01c2a400 {
>> +                     compatible = "allwinner,sun4i-a10-ps2";
>> +                     reg = <0x01c2a400 0x400>;
>> +                     interrupts = <0 63 4>;
>
> We recently switched to using includes and defines for these hardcoded
> values.
>
> Could you switch to it as well?
Okie, I did not notice that. Thanks for pointing out.
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
  2015-01-20  0:35         ` Dmitry Torokhov
  (?)
@ 2015-01-21 11:22           ` Vishnu Patekar
  -1 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:22 UTC (permalink / raw)
  To: linux-sunxi
  Cc: Hans de Goede, ijc+devicetree, maxime.ripard, linux-arm-kernel,
	linux-kernel, linux-input, devicetree

Hello Dmitry,

On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
>> Hello Dmitry,
>>
>> Thank you for review comments. Please see in-lined.
>>
>> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
>> <dmitry.torokhov@gmail.com> wrote:
>> > Hi Vishnu,
>> >
>> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> >> ---
>> >>  drivers/input/serio/Kconfig     |   11 ++
>> >>  drivers/input/serio/Makefile    |    1 +
>> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>> >>  3 files changed, 342 insertions(+)
>> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>> >>
>> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> >> index bc2d474..964afc5 100644
>> >> --- a/drivers/input/serio/Kconfig
>> >> +++ b/drivers/input/serio/Kconfig
>> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>> >>         To compile this driver as a module, choose M here: the module will
>> >>         be called hyperv_keyboard.
>> >>
>> >> +config SERIO_SUN4I_PS2
>> >> +     tristate "Allwinner A10 PS/2 controller support"
>> >> +     default n
>> >> +     depends on ARCH_SUNXI || COMPILE_TEST
>> >> +     help
>> >> +       This selects support for the PS/2 Host Controller on
>> >> +       Allwinner A10.
>> >> +
>> >> +       To compile this driver as a module, choose M here: the
>> >> +       module will be called sun4i-ps2.
>> >> +
>> >>  endif
>> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> >> index 815d874..c600089 100644
>> >> --- a/drivers/input/serio/Makefile
>> >> +++ b/drivers/input/serio/Makefile
>> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> >> new file mode 100644
>> >> index 0000000..06b3fef
>> >> --- /dev/null
>> >> +++ b/drivers/input/serio/sun4i-ps2.c
>> >> @@ -0,0 +1,330 @@
>> >> +/*
>> >> + *   Driver for Allwinner A10 PS2 host controller
>> >> + *
>> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
>> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
>> >> + *
>> >> + *
>> >> + */
>> >> +
>> >> +#include <linux/module.h>
>> >> +#include <linux/serio.h>
>> >> +#include <linux/interrupt.h>
>> >> +#include <linux/errno.h>
>> >> +#include <linux/slab.h>
>> >> +#include <linux/list.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/of_address.h>
>> >> +#include <linux/of_device.h>
>> >> +#include <linux/of_irq.h>
>> >> +#include <linux/of_platform.h>
>> >> +#include <linux/clk.h>
>> >> +#include <linux/delay.h>
>> >> +
>> >> +#define DRIVER_NAME          "sun4i-ps2"
>> >> +
>> >> +/* register offset definitions */
>> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> >> +
>> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> >> +#define PS2_GCTL_INTFLAG     BIT(4)
>> >> +#define PS2_GCTL_INTEN               BIT(3)
>> >> +#define PS2_GCTL_RESET               BIT(2)
>> >> +#define PS2_GCTL_MASTER              BIT(1)
>> >> +#define PS2_GCTL_BUSEN               BIT(0)
>> >> +
>> >> +/* PS2 LINE CONTROL REGISTER */
>> >> +#define PS2_LCTL_NOACK               BIT(18)
>> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> >> +#define PS2_LCTL_STOPERREN   BIT(3)
>> >> +#define PS2_LCTL_ACKERREN    BIT(2)
>> >> +#define PS2_LCTL_PARERREN    BIT(1)
>> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> >> +
>> >> +/* PS2 LINE STATUS REGISTER */
>> >> +#define PS2_LSTS_TXTDO               BIT(8)
>> >> +#define PS2_LSTS_STOPERR     BIT(3)
>> >> +#define PS2_LSTS_ACKERR              BIT(2)
>> >> +#define PS2_LSTS_PARERR              BIT(1)
>> >> +#define PS2_LSTS_RXTDO               BIT(0)
>> >> +
>> >> +#define PS2_LINE_ERROR_BIT \
>> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> >> +
>> >> +/* PS2 FIFO CONTROL REGISTER */
>> >> +#define PS2_FCTL_TXRST               BIT(17)
>> >> +#define PS2_FCTL_RXRST               BIT(16)
>> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> >> +
>> >> +/* PS2 FIFO STATUS REGISTER */
>> >> +#define PS2_FSTS_TXUF                BIT(10)
>> >> +#define PS2_FSTS_TXOF                BIT(9)
>> >> +#define PS2_FSTS_TXRDY               BIT(8)
>> >> +#define PS2_FSTS_RXUF                BIT(2)
>> >> +#define PS2_FSTS_RXOF                BIT(1)
>> >> +#define PS2_FSTS_RXRDY               BIT(0)
>> >> +
>> >> +#define PS2_FIFO_ERROR_BIT \
>> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> >> +
>> >> +#define PS2_SAMPLE_CLK               1000000
>> >> +#define PS2_SCLK             125000
>> >> +
>> >> +struct sun4i_ps2data {
>> >> +     struct serio *serio;
>> >> +     struct device *dev;
>> >> +
>> >> +     /* IO mapping base */
>> >> +     void __iomem    *reg_base;
>> >> +
>> >> +     /* clock management */
>> >> +     struct clk      *clk;
>> >> +
>> >> +     /* irq */
>> >> +     spinlock_t      lock;
>> >> +     int             irq;
>> >> +};
>> >> +
>> >> +/*********************/
>> >> +/* Interrupt handler */
>> >> +/*********************/
>> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = dev_id;
>> >> +     u32 intr_status;
>> >> +     u32 fifo_status;
>> >> +     unsigned char byte;
>> >> +     unsigned int rxflags = 0;
>> >> +     u32 rval;
>> >> +
>> >> +     spin_lock(&drvdata->lock);
>> >> +
>> >> +     /* Get the PS/2 interrupts and clear them */
>> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     /*Check Line Status Register*/
>> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> >> +
>> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     }
>> >> +
>> >> +     /*Check FIFO Status Register*/
>> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> >> +     }
>> >> +
>> >> +     rval = (fifo_status >> 16) & 0x3;
>> >> +     while (rval--) {
>> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> >> +     }
>> >> +
>> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     spin_unlock(&drvdata->lock);
>> >> +
>> >> +     return IRQ_HANDLED;
>> >> +}
>> >> +
>> >> +
>> >> +static int sun4i_ps2_open(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +     u32 src_clk = 0;
>> >> +     u32 clk_scdf;
>> >> +     u32 clk_pcdf;
>> >> +     u32 rval;
>> >> +     unsigned long flags;
>> >> +
>> >> +     /*Set Line Control And Enable Interrupt*/
>> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> >> +
>> >> +     /*Reset FIFO*/
>> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> >> +
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> >> +
>> >> +     src_clk = clk_get_rate(drvdata->clk);
>> >> +     /*Set Clock Divider Register*/
>> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> >> +     rval = (clk_scdf<<8) | clk_pcdf;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> >> +
>> >> +
>> >> +     /*Set Global Control Register*/
>> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> >> +             | PS2_GCTL_BUSEN;
>> >> +
>> >> +     spin_lock_irqsave(&drvdata->lock, flags);
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static void sun4i_ps2_close(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +
>> >> +     synchronize_irq(drvdata->irq);
>> >
>> > synchronize_irq() on it's own is not very useful. You also need to shut
>> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
>> > before calling synchronize_irq.
>> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
> Please also do shut off interrupts on the chip before requesting IRQ.
Okie
>
>> >
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> >> +{
>> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +
>> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> >> +
>> >> +     do {
>> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> >> +                     return 0;
>> >> +             }
>> >> +     } while (time_before(jiffies, expire));
>> >> +
>> >> +     return SERIO_TIMEOUT;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> >> +{
>> >> +     struct resource *res; /* IO mem resources */
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +     struct serio *serio;
>> >> +     struct device *dev = &pdev->dev;
>> >> +     unsigned int irq;
>> >> +     int error;
>> >> +
>> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> >> +     if (!drvdata || !serio) {
>> >> +             error = -ENOMEM;
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     spin_lock_init(&drvdata->lock);
>> >> +
>> >> +     /* IO */
>> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> >> +     if (IS_ERR(drvdata->reg_base)) {
>> >> +             dev_err(dev, "failed to map registers\n");
>> >> +             error = PTR_ERR(drvdata->reg_base);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     drvdata->clk = devm_clk_get(dev, NULL);
>> >> +     if (IS_ERR(drvdata->clk)) {
>> >> +             error = PTR_ERR(drvdata->clk);
>> >> +             dev_err(dev, "couldn't get clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     error = clk_prepare_enable(drvdata->clk);
>> >> +     if (error) {
>> >> +             dev_err(dev, "failed to enable clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     serio->id.type = SERIO_8042;
>> >> +     serio->write = sun4i_ps2_write;
>> >> +     serio->open = sun4i_ps2_open;
>> >> +     serio->close = sun4i_ps2_close;
>> >> +     serio->port_data = drvdata;
>> >> +     serio->dev.parent = dev;
>> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> >> +
>> >> +     /* Get IRQ for the device */
>> >> +     irq = platform_get_irq(pdev, 0);
>> >> +     if (!irq) {
>> >> +             dev_err(dev, "no IRQ found\n");
>> >> +             error = -ENXIO;
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     drvdata->irq = irq;
>> >> +     drvdata->serio = serio;
>> >> +     drvdata->dev = dev;
>> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> >> +
>> >> +     if (error) {
>> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> >> +                     drvdata->irq, error);
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     serio_register_port(serio);
>> >> +     platform_set_drvdata(pdev, drvdata);
>> >> +
>> >> +     return 0;       /* success */
>> >> +
>> >> +error_disable_clk:
>> >> +     clk_disable_unprepare(drvdata->clk);
>> >> +
>> >> +err_free_mem:
>> >> +     kfree(serio);
>> >> +     return error;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> >> +
>> >> +     serio_unregister_port(drvdata->serio);
>> >> +
>> >> +     if (!IS_ERR(drvdata->clk))
>> >> +             clk_disable_unprepare(drvdata->clk);
>> >> +     kfree(drvdata->serio);
>> >
>> > Serio is refcounted, you do not free it after its has been registered.
>> > Overall I'd rather you did not use devm* interfaces here since you are
>> > forced to mix managed and manually freed resources.
>> Okie, No need to free serio here.
>> If serio is not manually freed here, It is not freeing anything else manually.
>
> You are still unregistering the port manually and disabling the clock manually.
>>
>> do you still feel I should not use devm* interfaces here?
>
> Yes, because of above. My rule of thumb - when using devm* API there should not
> be remove() at all.
Okie, I'll remove devm* interfaces.

>
> BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> such patch.
This seems a ultimate solution to use devm* interfaces. For now, I'll
just avoid using devm* interfaces.
Still, we have to manually disable the clock, didn't we?

Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
have any other way to use managed clk interfaces?

any further information on this interesting patchset
?https://lkml.org/lkml/2012/11/20/173

>
> Thanks.
>
> --
> Dmitry
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-21 11:22           ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:22 UTC (permalink / raw)
  To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
  Cc: Hans de Goede, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hello Dmitry,

On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
<dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
>> Hello Dmitry,
>>
>> Thank you for review comments. Please see in-lined.
>>
>> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
>> <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> > Hi Vishnu,
>> >
>> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> >> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> >> ---
>> >>  drivers/input/serio/Kconfig     |   11 ++
>> >>  drivers/input/serio/Makefile    |    1 +
>> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>> >>  3 files changed, 342 insertions(+)
>> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>> >>
>> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> >> index bc2d474..964afc5 100644
>> >> --- a/drivers/input/serio/Kconfig
>> >> +++ b/drivers/input/serio/Kconfig
>> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>> >>         To compile this driver as a module, choose M here: the module will
>> >>         be called hyperv_keyboard.
>> >>
>> >> +config SERIO_SUN4I_PS2
>> >> +     tristate "Allwinner A10 PS/2 controller support"
>> >> +     default n
>> >> +     depends on ARCH_SUNXI || COMPILE_TEST
>> >> +     help
>> >> +       This selects support for the PS/2 Host Controller on
>> >> +       Allwinner A10.
>> >> +
>> >> +       To compile this driver as a module, choose M here: the
>> >> +       module will be called sun4i-ps2.
>> >> +
>> >>  endif
>> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> >> index 815d874..c600089 100644
>> >> --- a/drivers/input/serio/Makefile
>> >> +++ b/drivers/input/serio/Makefile
>> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> >> new file mode 100644
>> >> index 0000000..06b3fef
>> >> --- /dev/null
>> >> +++ b/drivers/input/serio/sun4i-ps2.c
>> >> @@ -0,0 +1,330 @@
>> >> +/*
>> >> + *   Driver for Allwinner A10 PS2 host controller
>> >> + *
>> >> + *   Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> >> + *           Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
>> >> + *
>> >> + *
>> >> + */
>> >> +
>> >> +#include <linux/module.h>
>> >> +#include <linux/serio.h>
>> >> +#include <linux/interrupt.h>
>> >> +#include <linux/errno.h>
>> >> +#include <linux/slab.h>
>> >> +#include <linux/list.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/of_address.h>
>> >> +#include <linux/of_device.h>
>> >> +#include <linux/of_irq.h>
>> >> +#include <linux/of_platform.h>
>> >> +#include <linux/clk.h>
>> >> +#include <linux/delay.h>
>> >> +
>> >> +#define DRIVER_NAME          "sun4i-ps2"
>> >> +
>> >> +/* register offset definitions */
>> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> >> +
>> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> >> +#define PS2_GCTL_INTFLAG     BIT(4)
>> >> +#define PS2_GCTL_INTEN               BIT(3)
>> >> +#define PS2_GCTL_RESET               BIT(2)
>> >> +#define PS2_GCTL_MASTER              BIT(1)
>> >> +#define PS2_GCTL_BUSEN               BIT(0)
>> >> +
>> >> +/* PS2 LINE CONTROL REGISTER */
>> >> +#define PS2_LCTL_NOACK               BIT(18)
>> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> >> +#define PS2_LCTL_STOPERREN   BIT(3)
>> >> +#define PS2_LCTL_ACKERREN    BIT(2)
>> >> +#define PS2_LCTL_PARERREN    BIT(1)
>> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> >> +
>> >> +/* PS2 LINE STATUS REGISTER */
>> >> +#define PS2_LSTS_TXTDO               BIT(8)
>> >> +#define PS2_LSTS_STOPERR     BIT(3)
>> >> +#define PS2_LSTS_ACKERR              BIT(2)
>> >> +#define PS2_LSTS_PARERR              BIT(1)
>> >> +#define PS2_LSTS_RXTDO               BIT(0)
>> >> +
>> >> +#define PS2_LINE_ERROR_BIT \
>> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> >> +
>> >> +/* PS2 FIFO CONTROL REGISTER */
>> >> +#define PS2_FCTL_TXRST               BIT(17)
>> >> +#define PS2_FCTL_RXRST               BIT(16)
>> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> >> +
>> >> +/* PS2 FIFO STATUS REGISTER */
>> >> +#define PS2_FSTS_TXUF                BIT(10)
>> >> +#define PS2_FSTS_TXOF                BIT(9)
>> >> +#define PS2_FSTS_TXRDY               BIT(8)
>> >> +#define PS2_FSTS_RXUF                BIT(2)
>> >> +#define PS2_FSTS_RXOF                BIT(1)
>> >> +#define PS2_FSTS_RXRDY               BIT(0)
>> >> +
>> >> +#define PS2_FIFO_ERROR_BIT \
>> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> >> +
>> >> +#define PS2_SAMPLE_CLK               1000000
>> >> +#define PS2_SCLK             125000
>> >> +
>> >> +struct sun4i_ps2data {
>> >> +     struct serio *serio;
>> >> +     struct device *dev;
>> >> +
>> >> +     /* IO mapping base */
>> >> +     void __iomem    *reg_base;
>> >> +
>> >> +     /* clock management */
>> >> +     struct clk      *clk;
>> >> +
>> >> +     /* irq */
>> >> +     spinlock_t      lock;
>> >> +     int             irq;
>> >> +};
>> >> +
>> >> +/*********************/
>> >> +/* Interrupt handler */
>> >> +/*********************/
>> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = dev_id;
>> >> +     u32 intr_status;
>> >> +     u32 fifo_status;
>> >> +     unsigned char byte;
>> >> +     unsigned int rxflags = 0;
>> >> +     u32 rval;
>> >> +
>> >> +     spin_lock(&drvdata->lock);
>> >> +
>> >> +     /* Get the PS/2 interrupts and clear them */
>> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     /*Check Line Status Register*/
>> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> >> +
>> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     }
>> >> +
>> >> +     /*Check FIFO Status Register*/
>> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> >> +     }
>> >> +
>> >> +     rval = (fifo_status >> 16) & 0x3;
>> >> +     while (rval--) {
>> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> >> +     }
>> >> +
>> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     spin_unlock(&drvdata->lock);
>> >> +
>> >> +     return IRQ_HANDLED;
>> >> +}
>> >> +
>> >> +
>> >> +static int sun4i_ps2_open(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +     u32 src_clk = 0;
>> >> +     u32 clk_scdf;
>> >> +     u32 clk_pcdf;
>> >> +     u32 rval;
>> >> +     unsigned long flags;
>> >> +
>> >> +     /*Set Line Control And Enable Interrupt*/
>> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> >> +
>> >> +     /*Reset FIFO*/
>> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> >> +
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> >> +
>> >> +     src_clk = clk_get_rate(drvdata->clk);
>> >> +     /*Set Clock Divider Register*/
>> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> >> +     rval = (clk_scdf<<8) | clk_pcdf;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> >> +
>> >> +
>> >> +     /*Set Global Control Register*/
>> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> >> +             | PS2_GCTL_BUSEN;
>> >> +
>> >> +     spin_lock_irqsave(&drvdata->lock, flags);
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static void sun4i_ps2_close(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +
>> >> +     synchronize_irq(drvdata->irq);
>> >
>> > synchronize_irq() on it's own is not very useful. You also need to shut
>> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
>> > before calling synchronize_irq.
>> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
> Please also do shut off interrupts on the chip before requesting IRQ.
Okie
>
>> >
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> >> +{
>> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +
>> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> >> +
>> >> +     do {
>> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> >> +                     return 0;
>> >> +             }
>> >> +     } while (time_before(jiffies, expire));
>> >> +
>> >> +     return SERIO_TIMEOUT;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> >> +{
>> >> +     struct resource *res; /* IO mem resources */
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +     struct serio *serio;
>> >> +     struct device *dev = &pdev->dev;
>> >> +     unsigned int irq;
>> >> +     int error;
>> >> +
>> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> >> +     if (!drvdata || !serio) {
>> >> +             error = -ENOMEM;
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     spin_lock_init(&drvdata->lock);
>> >> +
>> >> +     /* IO */
>> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> >> +     if (IS_ERR(drvdata->reg_base)) {
>> >> +             dev_err(dev, "failed to map registers\n");
>> >> +             error = PTR_ERR(drvdata->reg_base);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     drvdata->clk = devm_clk_get(dev, NULL);
>> >> +     if (IS_ERR(drvdata->clk)) {
>> >> +             error = PTR_ERR(drvdata->clk);
>> >> +             dev_err(dev, "couldn't get clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     error = clk_prepare_enable(drvdata->clk);
>> >> +     if (error) {
>> >> +             dev_err(dev, "failed to enable clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     serio->id.type = SERIO_8042;
>> >> +     serio->write = sun4i_ps2_write;
>> >> +     serio->open = sun4i_ps2_open;
>> >> +     serio->close = sun4i_ps2_close;
>> >> +     serio->port_data = drvdata;
>> >> +     serio->dev.parent = dev;
>> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> >> +
>> >> +     /* Get IRQ for the device */
>> >> +     irq = platform_get_irq(pdev, 0);
>> >> +     if (!irq) {
>> >> +             dev_err(dev, "no IRQ found\n");
>> >> +             error = -ENXIO;
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     drvdata->irq = irq;
>> >> +     drvdata->serio = serio;
>> >> +     drvdata->dev = dev;
>> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> >> +
>> >> +     if (error) {
>> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> >> +                     drvdata->irq, error);
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     serio_register_port(serio);
>> >> +     platform_set_drvdata(pdev, drvdata);
>> >> +
>> >> +     return 0;       /* success */
>> >> +
>> >> +error_disable_clk:
>> >> +     clk_disable_unprepare(drvdata->clk);
>> >> +
>> >> +err_free_mem:
>> >> +     kfree(serio);
>> >> +     return error;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> >> +
>> >> +     serio_unregister_port(drvdata->serio);
>> >> +
>> >> +     if (!IS_ERR(drvdata->clk))
>> >> +             clk_disable_unprepare(drvdata->clk);
>> >> +     kfree(drvdata->serio);
>> >
>> > Serio is refcounted, you do not free it after its has been registered.
>> > Overall I'd rather you did not use devm* interfaces here since you are
>> > forced to mix managed and manually freed resources.
>> Okie, No need to free serio here.
>> If serio is not manually freed here, It is not freeing anything else manually.
>
> You are still unregistering the port manually and disabling the clock manually.
>>
>> do you still feel I should not use devm* interfaces here?
>
> Yes, because of above. My rule of thumb - when using devm* API there should not
> be remove() at all.
Okie, I'll remove devm* interfaces.

>
> BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> such patch.
This seems a ultimate solution to use devm* interfaces. For now, I'll
just avoid using devm* interfaces.
Still, we have to manually disable the clock, didn't we?

Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
have any other way to use managed clk interfaces?

any further information on this interesting patchset
?https://lkml.org/lkml/2012/11/20/173

>
> Thanks.
>
> --
> Dmitry
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
> For more options, visit https://groups.google.com/d/optout.
--
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	[flat|nested] 57+ messages in thread

* [linux-sunxi] Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-21 11:22           ` Vishnu Patekar
  0 siblings, 0 replies; 57+ messages in thread
From: Vishnu Patekar @ 2015-01-21 11:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Dmitry,

On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
>> Hello Dmitry,
>>
>> Thank you for review comments. Please see in-lined.
>>
>> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
>> <dmitry.torokhov@gmail.com> wrote:
>> > Hi Vishnu,
>> >
>> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
>> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
>> >> ---
>> >>  drivers/input/serio/Kconfig     |   11 ++
>> >>  drivers/input/serio/Makefile    |    1 +
>> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
>> >>  3 files changed, 342 insertions(+)
>> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
>> >>
>> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
>> >> index bc2d474..964afc5 100644
>> >> --- a/drivers/input/serio/Kconfig
>> >> +++ b/drivers/input/serio/Kconfig
>> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
>> >>         To compile this driver as a module, choose M here: the module will
>> >>         be called hyperv_keyboard.
>> >>
>> >> +config SERIO_SUN4I_PS2
>> >> +     tristate "Allwinner A10 PS/2 controller support"
>> >> +     default n
>> >> +     depends on ARCH_SUNXI || COMPILE_TEST
>> >> +     help
>> >> +       This selects support for the PS/2 Host Controller on
>> >> +       Allwinner A10.
>> >> +
>> >> +       To compile this driver as a module, choose M here: the
>> >> +       module will be called sun4i-ps2.
>> >> +
>> >>  endif
>> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
>> >> index 815d874..c600089 100644
>> >> --- a/drivers/input/serio/Makefile
>> >> +++ b/drivers/input/serio/Makefile
>> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
>> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
>> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
>> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
>> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
>> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
>> >> new file mode 100644
>> >> index 0000000..06b3fef
>> >> --- /dev/null
>> >> +++ b/drivers/input/serio/sun4i-ps2.c
>> >> @@ -0,0 +1,330 @@
>> >> +/*
>> >> + *   Driver for Allwinner A10 PS2 host controller
>> >> + *
>> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
>> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
>> >> + *
>> >> + *
>> >> + */
>> >> +
>> >> +#include <linux/module.h>
>> >> +#include <linux/serio.h>
>> >> +#include <linux/interrupt.h>
>> >> +#include <linux/errno.h>
>> >> +#include <linux/slab.h>
>> >> +#include <linux/list.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/of_address.h>
>> >> +#include <linux/of_device.h>
>> >> +#include <linux/of_irq.h>
>> >> +#include <linux/of_platform.h>
>> >> +#include <linux/clk.h>
>> >> +#include <linux/delay.h>
>> >> +
>> >> +#define DRIVER_NAME          "sun4i-ps2"
>> >> +
>> >> +/* register offset definitions */
>> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
>> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
>> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
>> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
>> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
>> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
>> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
>> >> +
>> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
>> >> +#define PS2_GCTL_INTFLAG     BIT(4)
>> >> +#define PS2_GCTL_INTEN               BIT(3)
>> >> +#define PS2_GCTL_RESET               BIT(2)
>> >> +#define PS2_GCTL_MASTER              BIT(1)
>> >> +#define PS2_GCTL_BUSEN               BIT(0)
>> >> +
>> >> +/* PS2 LINE CONTROL REGISTER */
>> >> +#define PS2_LCTL_NOACK               BIT(18)
>> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
>> >> +#define PS2_LCTL_STOPERREN   BIT(3)
>> >> +#define PS2_LCTL_ACKERREN    BIT(2)
>> >> +#define PS2_LCTL_PARERREN    BIT(1)
>> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
>> >> +
>> >> +/* PS2 LINE STATUS REGISTER */
>> >> +#define PS2_LSTS_TXTDO               BIT(8)
>> >> +#define PS2_LSTS_STOPERR     BIT(3)
>> >> +#define PS2_LSTS_ACKERR              BIT(2)
>> >> +#define PS2_LSTS_PARERR              BIT(1)
>> >> +#define PS2_LSTS_RXTDO               BIT(0)
>> >> +
>> >> +#define PS2_LINE_ERROR_BIT \
>> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
>> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
>> >> +
>> >> +/* PS2 FIFO CONTROL REGISTER */
>> >> +#define PS2_FCTL_TXRST               BIT(17)
>> >> +#define PS2_FCTL_RXRST               BIT(16)
>> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
>> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
>> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
>> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
>> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
>> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
>> >> +
>> >> +/* PS2 FIFO STATUS REGISTER */
>> >> +#define PS2_FSTS_TXUF                BIT(10)
>> >> +#define PS2_FSTS_TXOF                BIT(9)
>> >> +#define PS2_FSTS_TXRDY               BIT(8)
>> >> +#define PS2_FSTS_RXUF                BIT(2)
>> >> +#define PS2_FSTS_RXOF                BIT(1)
>> >> +#define PS2_FSTS_RXRDY               BIT(0)
>> >> +
>> >> +#define PS2_FIFO_ERROR_BIT \
>> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
>> >> +
>> >> +#define PS2_SAMPLE_CLK               1000000
>> >> +#define PS2_SCLK             125000
>> >> +
>> >> +struct sun4i_ps2data {
>> >> +     struct serio *serio;
>> >> +     struct device *dev;
>> >> +
>> >> +     /* IO mapping base */
>> >> +     void __iomem    *reg_base;
>> >> +
>> >> +     /* clock management */
>> >> +     struct clk      *clk;
>> >> +
>> >> +     /* irq */
>> >> +     spinlock_t      lock;
>> >> +     int             irq;
>> >> +};
>> >> +
>> >> +/*********************/
>> >> +/* Interrupt handler */
>> >> +/*********************/
>> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = dev_id;
>> >> +     u32 intr_status;
>> >> +     u32 fifo_status;
>> >> +     unsigned char byte;
>> >> +     unsigned int rxflags = 0;
>> >> +     u32 rval;
>> >> +
>> >> +     spin_lock(&drvdata->lock);
>> >> +
>> >> +     /* Get the PS/2 interrupts and clear them */
>> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
>> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     /*Check Line Status Register*/
>> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
>> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
>> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
>> >> +
>> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
>> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     }
>> >> +
>> >> +     /*Check FIFO Status Register*/
>> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
>> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
>> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
>> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
>> >> +     }
>> >> +
>> >> +     rval = (fifo_status >> 16) & 0x3;
>> >> +     while (rval--) {
>> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
>> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
>> >> +     }
>> >> +
>> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
>> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
>> >> +
>> >> +     spin_unlock(&drvdata->lock);
>> >> +
>> >> +     return IRQ_HANDLED;
>> >> +}
>> >> +
>> >> +
>> >> +static int sun4i_ps2_open(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +     u32 src_clk = 0;
>> >> +     u32 clk_scdf;
>> >> +     u32 clk_pcdf;
>> >> +     u32 rval;
>> >> +     unsigned long flags;
>> >> +
>> >> +     /*Set Line Control And Enable Interrupt*/
>> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
>> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
>> >> +
>> >> +     /*Reset FIFO*/
>> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
>> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
>> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
>> >> +
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
>> >> +
>> >> +     src_clk = clk_get_rate(drvdata->clk);
>> >> +     /*Set Clock Divider Register*/
>> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
>> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
>> >> +     rval = (clk_scdf<<8) | clk_pcdf;
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
>> >> +
>> >> +
>> >> +     /*Set Global Control Register*/
>> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
>> >> +             | PS2_GCTL_BUSEN;
>> >> +
>> >> +     spin_lock_irqsave(&drvdata->lock, flags);
>> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
>> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static void sun4i_ps2_close(struct serio *pserio)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
>> >> +
>> >> +     synchronize_irq(drvdata->irq);
>> >
>> > synchronize_irq() on it's own is not very useful. You also need to shut
>> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
>> > before calling synchronize_irq.
>> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
>
> Please also do shut off interrupts on the chip before requesting IRQ.
Okie
>
>> >
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
>> >> +{
>> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +
>> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
>> >> +
>> >> +     do {
>> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
>> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
>> >> +                     return 0;
>> >> +             }
>> >> +     } while (time_before(jiffies, expire));
>> >> +
>> >> +     return SERIO_TIMEOUT;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
>> >> +{
>> >> +     struct resource *res; /* IO mem resources */
>> >> +     struct sun4i_ps2data *drvdata;
>> >> +     struct serio *serio;
>> >> +     struct device *dev = &pdev->dev;
>> >> +     unsigned int irq;
>> >> +     int error;
>> >> +
>> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
>> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
>> >> +     if (!drvdata || !serio) {
>> >> +             error = -ENOMEM;
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     spin_lock_init(&drvdata->lock);
>> >> +
>> >> +     /* IO */
>> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
>> >> +     if (IS_ERR(drvdata->reg_base)) {
>> >> +             dev_err(dev, "failed to map registers\n");
>> >> +             error = PTR_ERR(drvdata->reg_base);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     drvdata->clk = devm_clk_get(dev, NULL);
>> >> +     if (IS_ERR(drvdata->clk)) {
>> >> +             error = PTR_ERR(drvdata->clk);
>> >> +             dev_err(dev, "couldn't get clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     error = clk_prepare_enable(drvdata->clk);
>> >> +     if (error) {
>> >> +             dev_err(dev, "failed to enable clock %d\n", error);
>> >> +             goto err_free_mem;
>> >> +     }
>> >> +
>> >> +     serio->id.type = SERIO_8042;
>> >> +     serio->write = sun4i_ps2_write;
>> >> +     serio->open = sun4i_ps2_open;
>> >> +     serio->close = sun4i_ps2_close;
>> >> +     serio->port_data = drvdata;
>> >> +     serio->dev.parent = dev;
>> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
>> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
>> >> +
>> >> +     /* Get IRQ for the device */
>> >> +     irq = platform_get_irq(pdev, 0);
>> >> +     if (!irq) {
>> >> +             dev_err(dev, "no IRQ found\n");
>> >> +             error = -ENXIO;
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     drvdata->irq = irq;
>> >> +     drvdata->serio = serio;
>> >> +     drvdata->dev = dev;
>> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
>> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
>> >> +
>> >> +     if (error) {
>> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
>> >> +                     drvdata->irq, error);
>> >> +             goto error_disable_clk;
>> >> +     }
>> >> +
>> >> +     serio_register_port(serio);
>> >> +     platform_set_drvdata(pdev, drvdata);
>> >> +
>> >> +     return 0;       /* success */
>> >> +
>> >> +error_disable_clk:
>> >> +     clk_disable_unprepare(drvdata->clk);
>> >> +
>> >> +err_free_mem:
>> >> +     kfree(serio);
>> >> +     return error;
>> >> +}
>> >> +
>> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
>> >> +{
>> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
>> >> +
>> >> +     serio_unregister_port(drvdata->serio);
>> >> +
>> >> +     if (!IS_ERR(drvdata->clk))
>> >> +             clk_disable_unprepare(drvdata->clk);
>> >> +     kfree(drvdata->serio);
>> >
>> > Serio is refcounted, you do not free it after its has been registered.
>> > Overall I'd rather you did not use devm* interfaces here since you are
>> > forced to mix managed and manually freed resources.
>> Okie, No need to free serio here.
>> If serio is not manually freed here, It is not freeing anything else manually.
>
> You are still unregistering the port manually and disabling the clock manually.
>>
>> do you still feel I should not use devm* interfaces here?
>
> Yes, because of above. My rule of thumb - when using devm* API there should not
> be remove() at all.
Okie, I'll remove devm* interfaces.

>
> BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> such patch.
This seems a ultimate solution to use devm* interfaces. For now, I'll
just avoid using devm* interfaces.
Still, we have to manually disable the clock, didn't we?

Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
have any other way to use managed clk interfaces?

any further information on this interesting patchset
?https://lkml.org/lkml/2012/11/20/173

>
> Thanks.
>
> --
> Dmitry
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-21 12:23           ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-21 12:23 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Iain Paton, linux-sunxi, Dmitry Torokhov, Hans de Goede,
	ijc+devicetree, linux-arm-kernel, linux-kernel, linux-input,
	devicetree

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

On Wed, Jan 21, 2015 at 04:34:45PM +0530, Vishnu Patekar wrote:
> Hello,
> 
> On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> >
> > On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > > > ---
> > > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > > >  1 file changed, 12 insertions(+)
> > > >
> > > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > index ed364d5..3365f12 100644
> > > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > @@ -113,6 +113,18 @@
> > > >                     status = "okay";
> > > >             };
> > > >
> > > > +           ps20: ps2@01c2a000 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > > +           ps21: ps2@01c2a400 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > >             i2c0: i2c@01c2ac00 {
> > > >                     pinctrl-names = "default";
> > > >                     pinctrl-0 = <&i2c0_pins_a>;
> > > >
> > >
> > > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > > I'd prefer that these are not enabled unconditionally. Doing so
> > > only makes it more difficult for people who want to use these pins
> > > for other functions.
> > >
> > > Device tree overlays seem to be close to being merged, perhaps we
> > > could leave enabling this to an overlay?
> >
> > I already had the exact same reasoning, and this was even removed at
> > some point. For some reason, it was added back, and I don't really
> > know why.
> This was removed in consideration that these pins conflict with HDMI,
> however, these is not conflict.
> 
> It was kept there as an example. But, as there is no ps2 connector on
> board, I've no problem to remove these nodes from Lime2 dts file.

Yet, probing a driver for a device connected to floating lines sounds
like a pretty bad idea.

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-21 12:23           ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-21 12:23 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Iain Paton, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Dmitry Torokhov,
	Hans de Goede, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

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

On Wed, Jan 21, 2015 at 04:34:45PM +0530, Vishnu Patekar wrote:
> Hello,
> 
> On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> >
> > On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > > Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > > > ---
> > > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > > >  1 file changed, 12 insertions(+)
> > > >
> > > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > index ed364d5..3365f12 100644
> > > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > @@ -113,6 +113,18 @@
> > > >                     status = "okay";
> > > >             };
> > > >
> > > > +           ps20: ps2@01c2a000 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > > +           ps21: ps2@01c2a400 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > >             i2c0: i2c@01c2ac00 {
> > > >                     pinctrl-names = "default";
> > > >                     pinctrl-0 = <&i2c0_pins_a>;
> > > >
> > >
> > > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > > I'd prefer that these are not enabled unconditionally. Doing so
> > > only makes it more difficult for people who want to use these pins
> > > for other functions.
> > >
> > > Device tree overlays seem to be close to being merged, perhaps we
> > > could leave enabling this to an overlay?
> >
> > I already had the exact same reasoning, and this was even removed at
> > some point. For some reason, it was added back, and I don't really
> > know why.
> This was removed in consideration that these pins conflict with HDMI,
> however, these is not conflict.
> 
> It was kept there as an example. But, as there is no ps2 connector on
> board, I've no problem to remove these nodes from Lime2 dts file.

Yet, probing a driver for a device connected to floating lines sounds
like a pretty bad idea.

Maxime

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

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [linux-sunxi] [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board
@ 2015-01-21 12:23           ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-21 12:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 21, 2015 at 04:34:45PM +0530, Vishnu Patekar wrote:
> Hello,
> 
> On Wed, Jan 21, 2015 at 1:37 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> >
> > On Tue, Jan 20, 2015 at 05:02:06PM +0000, Iain Paton wrote:
> > > On 16/01/15 14:03, Vishnu Patekar wrote:
> > > > Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> > > > ---
> > > >  arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts |   12 ++++++++++++
> > > >  1 file changed, 12 insertions(+)
> > > >
> > > > diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > index ed364d5..3365f12 100644
> > > > --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
> > > > @@ -113,6 +113,18 @@
> > > >                     status = "okay";
> > > >             };
> > > >
> > > > +           ps20: ps2 at 01c2a000 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps20_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > > +           ps21: ps2 at 01c2a400 {
> > > > +                   pinctrl-names = "default";
> > > > +                   pinctrl-0 = <&ps21_pins_a>;
> > > > +                   status = "okay";
> > > > +           };
> > > > +
> > > >             i2c0: i2c at 01c2ac00 {
> > > >                     pinctrl-names = "default";
> > > >                     pinctrl-0 = <&i2c0_pins_a>;
> > > >
> > >
> > > As the Lime2 doesn't actually have any PS2 connectors on the board,
> > > I'd prefer that these are not enabled unconditionally. Doing so
> > > only makes it more difficult for people who want to use these pins
> > > for other functions.
> > >
> > > Device tree overlays seem to be close to being merged, perhaps we
> > > could leave enabling this to an overlay?
> >
> > I already had the exact same reasoning, and this was even removed at
> > some point. For some reason, it was added back, and I don't really
> > know why.
> This was removed in consideration that these pins conflict with HDMI,
> however, these is not conflict.
> 
> It was kept there as an example. But, as there is no ps2 connector on
> board, I've no problem to remove these nodes from Lime2 dts file.

Yet, probing a driver for a device connected to floating lines sounds
like a pretty bad idea.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150121/8417c5ae/attachment.sig>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
  2015-01-21 11:10       ` Vishnu Patekar
  (?)
@ 2015-01-22 15:50         ` Maxime Ripard
  -1 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-22 15:50 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Dmitry Torokhov, Hans de Goede, ijc+devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

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

On Wed, Jan 21, 2015 at 04:40:28PM +0530, Vishnu Patekar wrote:
> On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >
> > Why is there Hans Signed-off here?
> Hans has modified the A10 dtsi and also tested on A10 board.
> Shouldn't I add him as Signed-off?

Yeah, you should :)

Thanks,
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-22 15:50         ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-22 15:50 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: Dmitry Torokhov, Hans de Goede, ijc+devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-input, devicetree

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

On Wed, Jan 21, 2015 at 04:40:28PM +0530, Vishnu Patekar wrote:
> On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >
> > Why is there Hans Signed-off here?
> Hans has modified the A10 dtsi and also tested on A10 board.
> Shouldn't I add him as Signed-off?

Yeah, you should :)

Thanks,
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20
@ 2015-01-22 15:50         ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-01-22 15:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 21, 2015 at 04:40:28PM +0530, Vishnu Patekar wrote:
> On Wed, Jan 21, 2015 at 1:32 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi Vishnu,
> >
> > On Fri, Jan 16, 2015 at 07:33:39PM +0530, Vishnu Patekar wrote:
> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >
> > Why is there Hans Signed-off here?
> Hans has modified the A10 dtsi and also tested on A10 board.
> Shouldn't I add him as Signed-off?

Yeah, you should :)

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150122/e00ecd7c/attachment.sig>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [linux-sunxi] Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-22 20:07             ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-22 20:07 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: linux-sunxi, Hans de Goede, ijc+devicetree, maxime.ripard,
	linux-arm-kernel, linux-kernel, linux-input, devicetree

On Wed, Jan 21, 2015 at 04:52:04PM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> > On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> >> Hello Dmitry,
> >>
> >> Thank you for review comments. Please see in-lined.
> >>
> >> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> >> <dmitry.torokhov@gmail.com> wrote:
> >> > Hi Vishnu,
> >> >
> >> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> >> ---
> >> >>  drivers/input/serio/Kconfig     |   11 ++
> >> >>  drivers/input/serio/Makefile    |    1 +
> >> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >> >>  3 files changed, 342 insertions(+)
> >> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >> >>
> >> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> >> index bc2d474..964afc5 100644
> >> >> --- a/drivers/input/serio/Kconfig
> >> >> +++ b/drivers/input/serio/Kconfig
> >> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >> >>         To compile this driver as a module, choose M here: the module will
> >> >>         be called hyperv_keyboard.
> >> >>
> >> >> +config SERIO_SUN4I_PS2
> >> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> >> +     default n
> >> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> >> +     help
> >> >> +       This selects support for the PS/2 Host Controller on
> >> >> +       Allwinner A10.
> >> >> +
> >> >> +       To compile this driver as a module, choose M here: the
> >> >> +       module will be called sun4i-ps2.
> >> >> +
> >> >>  endif
> >> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> >> index 815d874..c600089 100644
> >> >> --- a/drivers/input/serio/Makefile
> >> >> +++ b/drivers/input/serio/Makefile
> >> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> >> new file mode 100644
> >> >> index 0000000..06b3fef
> >> >> --- /dev/null
> >> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> >> @@ -0,0 +1,330 @@
> >> >> +/*
> >> >> + *   Driver for Allwinner A10 PS2 host controller
> >> >> + *
> >> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> >> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
> >> >> + *
> >> >> + *
> >> >> + */
> >> >> +
> >> >> +#include <linux/module.h>
> >> >> +#include <linux/serio.h>
> >> >> +#include <linux/interrupt.h>
> >> >> +#include <linux/errno.h>
> >> >> +#include <linux/slab.h>
> >> >> +#include <linux/list.h>
> >> >> +#include <linux/io.h>
> >> >> +#include <linux/of_address.h>
> >> >> +#include <linux/of_device.h>
> >> >> +#include <linux/of_irq.h>
> >> >> +#include <linux/of_platform.h>
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/delay.h>
> >> >> +
> >> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> >> +
> >> >> +/* register offset definitions */
> >> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> >> +
> >> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> >> +#define PS2_GCTL_RESET               BIT(2)
> >> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> >> +
> >> >> +/* PS2 LINE CONTROL REGISTER */
> >> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> >> +
> >> >> +/* PS2 LINE STATUS REGISTER */
> >> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> >> +
> >> >> +#define PS2_LINE_ERROR_BIT \
> >> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> >> +
> >> >> +/* PS2 FIFO CONTROL REGISTER */
> >> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> >> +
> >> >> +/* PS2 FIFO STATUS REGISTER */
> >> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> >> +
> >> >> +#define PS2_FIFO_ERROR_BIT \
> >> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> >> +
> >> >> +#define PS2_SAMPLE_CLK               1000000
> >> >> +#define PS2_SCLK             125000
> >> >> +
> >> >> +struct sun4i_ps2data {
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev;
> >> >> +
> >> >> +     /* IO mapping base */
> >> >> +     void __iomem    *reg_base;
> >> >> +
> >> >> +     /* clock management */
> >> >> +     struct clk      *clk;
> >> >> +
> >> >> +     /* irq */
> >> >> +     spinlock_t      lock;
> >> >> +     int             irq;
> >> >> +};
> >> >> +
> >> >> +/*********************/
> >> >> +/* Interrupt handler */
> >> >> +/*********************/
> >> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> >> +     u32 intr_status;
> >> >> +     u32 fifo_status;
> >> >> +     unsigned char byte;
> >> >> +     unsigned int rxflags = 0;
> >> >> +     u32 rval;
> >> >> +
> >> >> +     spin_lock(&drvdata->lock);
> >> >> +
> >> >> +     /* Get the PS/2 interrupts and clear them */
> >> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     /*Check Line Status Register*/
> >> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> >> +
> >> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     }
> >> >> +
> >> >> +     /*Check FIFO Status Register*/
> >> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +     }
> >> >> +
> >> >> +     rval = (fifo_status >> 16) & 0x3;
> >> >> +     while (rval--) {
> >> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> >> +     }
> >> >> +
> >> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     spin_unlock(&drvdata->lock);
> >> >> +
> >> >> +     return IRQ_HANDLED;
> >> >> +}
> >> >> +
> >> >> +
> >> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +     u32 src_clk = 0;
> >> >> +     u32 clk_scdf;
> >> >> +     u32 clk_pcdf;
> >> >> +     u32 rval;
> >> >> +     unsigned long flags;
> >> >> +
> >> >> +     /*Set Line Control And Enable Interrupt*/
> >> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> >> +
> >> >> +     /*Reset FIFO*/
> >> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> >> +
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> >> +
> >> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> >> +     /*Set Clock Divider Register*/
> >> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> >> +
> >> >> +
> >> >> +     /*Set Global Control Register*/
> >> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> >> +             | PS2_GCTL_BUSEN;
> >> >> +
> >> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> >> +
> >> >> +     return 0;
> >> >> +}
> >> >> +
> >> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +
> >> >> +     synchronize_irq(drvdata->irq);
> >> >
> >> > synchronize_irq() on it's own is not very useful. You also need to shut
> >> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> >> > before calling synchronize_irq.
> >> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
> >
> > Please also do shut off interrupts on the chip before requesting IRQ.
> Okie
> >
> >> >
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> >> +{
> >> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +
> >> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> >> +
> >> >> +     do {
> >> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> >> +                     return 0;
> >> >> +             }
> >> >> +     } while (time_before(jiffies, expire));
> >> >> +
> >> >> +     return SERIO_TIMEOUT;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct resource *res; /* IO mem resources */
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev = &pdev->dev;
> >> >> +     unsigned int irq;
> >> >> +     int error;
> >> >> +
> >> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> >> +     if (!drvdata || !serio) {
> >> >> +             error = -ENOMEM;
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     spin_lock_init(&drvdata->lock);
> >> >> +
> >> >> +     /* IO */
> >> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> >> +             dev_err(dev, "failed to map registers\n");
> >> >> +             error = PTR_ERR(drvdata->reg_base);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> >> +     if (IS_ERR(drvdata->clk)) {
> >> >> +             error = PTR_ERR(drvdata->clk);
> >> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     error = clk_prepare_enable(drvdata->clk);
> >> >> +     if (error) {
> >> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     serio->id.type = SERIO_8042;
> >> >> +     serio->write = sun4i_ps2_write;
> >> >> +     serio->open = sun4i_ps2_open;
> >> >> +     serio->close = sun4i_ps2_close;
> >> >> +     serio->port_data = drvdata;
> >> >> +     serio->dev.parent = dev;
> >> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> >> +
> >> >> +     /* Get IRQ for the device */
> >> >> +     irq = platform_get_irq(pdev, 0);
> >> >> +     if (!irq) {
> >> >> +             dev_err(dev, "no IRQ found\n");
> >> >> +             error = -ENXIO;
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->irq = irq;
> >> >> +     drvdata->serio = serio;
> >> >> +     drvdata->dev = dev;
> >> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> >> +
> >> >> +     if (error) {
> >> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> >> +                     drvdata->irq, error);
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     serio_register_port(serio);
> >> >> +     platform_set_drvdata(pdev, drvdata);
> >> >> +
> >> >> +     return 0;       /* success */
> >> >> +
> >> >> +error_disable_clk:
> >> >> +     clk_disable_unprepare(drvdata->clk);
> >> >> +
> >> >> +err_free_mem:
> >> >> +     kfree(serio);
> >> >> +     return error;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> >> +
> >> >> +     serio_unregister_port(drvdata->serio);
> >> >> +
> >> >> +     if (!IS_ERR(drvdata->clk))
> >> >> +             clk_disable_unprepare(drvdata->clk);
> >> >> +     kfree(drvdata->serio);
> >> >
> >> > Serio is refcounted, you do not free it after its has been registered.
> >> > Overall I'd rather you did not use devm* interfaces here since you are
> >> > forced to mix managed and manually freed resources.
> >> Okie, No need to free serio here.
> >> If serio is not manually freed here, It is not freeing anything else manually.
> >
> > You are still unregistering the port manually and disabling the clock manually.
> >>
> >> do you still feel I should not use devm* interfaces here?
> >
> > Yes, because of above. My rule of thumb - when using devm* API there should not
> > be remove() at all.
> Okie, I'll remove devm* interfaces.
> 
> >
> > BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> > such patch.
> This seems a ultimate solution to use devm* interfaces. For now, I'll
> just avoid using devm* interfaces.
> Still, we have to manually disable the clock, didn't we?
> 
> Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
> have any other way to use managed clk interfaces?

No, I really need to pick it back up...

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-22 20:07             ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-22 20:07 UTC (permalink / raw)
  To: Vishnu Patekar
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Jan 21, 2015 at 04:52:04PM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
> <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> >> Hello Dmitry,
> >>
> >> Thank you for review comments. Please see in-lined.
> >>
> >> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> >> <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >> > Hi Vishnu,
> >> >
> >> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> >> Signed-off-by: VishnuPatekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> >> ---
> >> >>  drivers/input/serio/Kconfig     |   11 ++
> >> >>  drivers/input/serio/Makefile    |    1 +
> >> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >> >>  3 files changed, 342 insertions(+)
> >> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >> >>
> >> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> >> index bc2d474..964afc5 100644
> >> >> --- a/drivers/input/serio/Kconfig
> >> >> +++ b/drivers/input/serio/Kconfig
> >> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >> >>         To compile this driver as a module, choose M here: the module will
> >> >>         be called hyperv_keyboard.
> >> >>
> >> >> +config SERIO_SUN4I_PS2
> >> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> >> +     default n
> >> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> >> +     help
> >> >> +       This selects support for the PS/2 Host Controller on
> >> >> +       Allwinner A10.
> >> >> +
> >> >> +       To compile this driver as a module, choose M here: the
> >> >> +       module will be called sun4i-ps2.
> >> >> +
> >> >>  endif
> >> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> >> index 815d874..c600089 100644
> >> >> --- a/drivers/input/serio/Makefile
> >> >> +++ b/drivers/input/serio/Makefile
> >> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> >> new file mode 100644
> >> >> index 0000000..06b3fef
> >> >> --- /dev/null
> >> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> >> @@ -0,0 +1,330 @@
> >> >> +/*
> >> >> + *   Driver for Allwinner A10 PS2 host controller
> >> >> + *
> >> >> + *   Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> >> + *           Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
> >> >> + *
> >> >> + *
> >> >> + */
> >> >> +
> >> >> +#include <linux/module.h>
> >> >> +#include <linux/serio.h>
> >> >> +#include <linux/interrupt.h>
> >> >> +#include <linux/errno.h>
> >> >> +#include <linux/slab.h>
> >> >> +#include <linux/list.h>
> >> >> +#include <linux/io.h>
> >> >> +#include <linux/of_address.h>
> >> >> +#include <linux/of_device.h>
> >> >> +#include <linux/of_irq.h>
> >> >> +#include <linux/of_platform.h>
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/delay.h>
> >> >> +
> >> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> >> +
> >> >> +/* register offset definitions */
> >> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> >> +
> >> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> >> +#define PS2_GCTL_RESET               BIT(2)
> >> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> >> +
> >> >> +/* PS2 LINE CONTROL REGISTER */
> >> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> >> +
> >> >> +/* PS2 LINE STATUS REGISTER */
> >> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> >> +
> >> >> +#define PS2_LINE_ERROR_BIT \
> >> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> >> +
> >> >> +/* PS2 FIFO CONTROL REGISTER */
> >> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> >> +
> >> >> +/* PS2 FIFO STATUS REGISTER */
> >> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> >> +
> >> >> +#define PS2_FIFO_ERROR_BIT \
> >> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> >> +
> >> >> +#define PS2_SAMPLE_CLK               1000000
> >> >> +#define PS2_SCLK             125000
> >> >> +
> >> >> +struct sun4i_ps2data {
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev;
> >> >> +
> >> >> +     /* IO mapping base */
> >> >> +     void __iomem    *reg_base;
> >> >> +
> >> >> +     /* clock management */
> >> >> +     struct clk      *clk;
> >> >> +
> >> >> +     /* irq */
> >> >> +     spinlock_t      lock;
> >> >> +     int             irq;
> >> >> +};
> >> >> +
> >> >> +/*********************/
> >> >> +/* Interrupt handler */
> >> >> +/*********************/
> >> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> >> +     u32 intr_status;
> >> >> +     u32 fifo_status;
> >> >> +     unsigned char byte;
> >> >> +     unsigned int rxflags = 0;
> >> >> +     u32 rval;
> >> >> +
> >> >> +     spin_lock(&drvdata->lock);
> >> >> +
> >> >> +     /* Get the PS/2 interrupts and clear them */
> >> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     /*Check Line Status Register*/
> >> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> >> +
> >> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     }
> >> >> +
> >> >> +     /*Check FIFO Status Register*/
> >> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +     }
> >> >> +
> >> >> +     rval = (fifo_status >> 16) & 0x3;
> >> >> +     while (rval--) {
> >> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> >> +     }
> >> >> +
> >> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     spin_unlock(&drvdata->lock);
> >> >> +
> >> >> +     return IRQ_HANDLED;
> >> >> +}
> >> >> +
> >> >> +
> >> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +     u32 src_clk = 0;
> >> >> +     u32 clk_scdf;
> >> >> +     u32 clk_pcdf;
> >> >> +     u32 rval;
> >> >> +     unsigned long flags;
> >> >> +
> >> >> +     /*Set Line Control And Enable Interrupt*/
> >> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> >> +
> >> >> +     /*Reset FIFO*/
> >> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> >> +
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> >> +
> >> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> >> +     /*Set Clock Divider Register*/
> >> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> >> +
> >> >> +
> >> >> +     /*Set Global Control Register*/
> >> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> >> +             | PS2_GCTL_BUSEN;
> >> >> +
> >> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> >> +
> >> >> +     return 0;
> >> >> +}
> >> >> +
> >> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +
> >> >> +     synchronize_irq(drvdata->irq);
> >> >
> >> > synchronize_irq() on it's own is not very useful. You also need to shut
> >> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> >> > before calling synchronize_irq.
> >> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
> >
> > Please also do shut off interrupts on the chip before requesting IRQ.
> Okie
> >
> >> >
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> >> +{
> >> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +
> >> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> >> +
> >> >> +     do {
> >> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> >> +                     return 0;
> >> >> +             }
> >> >> +     } while (time_before(jiffies, expire));
> >> >> +
> >> >> +     return SERIO_TIMEOUT;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct resource *res; /* IO mem resources */
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev = &pdev->dev;
> >> >> +     unsigned int irq;
> >> >> +     int error;
> >> >> +
> >> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> >> +     if (!drvdata || !serio) {
> >> >> +             error = -ENOMEM;
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     spin_lock_init(&drvdata->lock);
> >> >> +
> >> >> +     /* IO */
> >> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> >> +             dev_err(dev, "failed to map registers\n");
> >> >> +             error = PTR_ERR(drvdata->reg_base);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> >> +     if (IS_ERR(drvdata->clk)) {
> >> >> +             error = PTR_ERR(drvdata->clk);
> >> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     error = clk_prepare_enable(drvdata->clk);
> >> >> +     if (error) {
> >> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     serio->id.type = SERIO_8042;
> >> >> +     serio->write = sun4i_ps2_write;
> >> >> +     serio->open = sun4i_ps2_open;
> >> >> +     serio->close = sun4i_ps2_close;
> >> >> +     serio->port_data = drvdata;
> >> >> +     serio->dev.parent = dev;
> >> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> >> +
> >> >> +     /* Get IRQ for the device */
> >> >> +     irq = platform_get_irq(pdev, 0);
> >> >> +     if (!irq) {
> >> >> +             dev_err(dev, "no IRQ found\n");
> >> >> +             error = -ENXIO;
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->irq = irq;
> >> >> +     drvdata->serio = serio;
> >> >> +     drvdata->dev = dev;
> >> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> >> +
> >> >> +     if (error) {
> >> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> >> +                     drvdata->irq, error);
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     serio_register_port(serio);
> >> >> +     platform_set_drvdata(pdev, drvdata);
> >> >> +
> >> >> +     return 0;       /* success */
> >> >> +
> >> >> +error_disable_clk:
> >> >> +     clk_disable_unprepare(drvdata->clk);
> >> >> +
> >> >> +err_free_mem:
> >> >> +     kfree(serio);
> >> >> +     return error;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> >> +
> >> >> +     serio_unregister_port(drvdata->serio);
> >> >> +
> >> >> +     if (!IS_ERR(drvdata->clk))
> >> >> +             clk_disable_unprepare(drvdata->clk);
> >> >> +     kfree(drvdata->serio);
> >> >
> >> > Serio is refcounted, you do not free it after its has been registered.
> >> > Overall I'd rather you did not use devm* interfaces here since you are
> >> > forced to mix managed and manually freed resources.
> >> Okie, No need to free serio here.
> >> If serio is not manually freed here, It is not freeing anything else manually.
> >
> > You are still unregistering the port manually and disabling the clock manually.
> >>
> >> do you still feel I should not use devm* interfaces here?
> >
> > Yes, because of above. My rule of thumb - when using devm* API there should not
> > be remove() at all.
> Okie, I'll remove devm* interfaces.
> 
> >
> > BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> > such patch.
> This seems a ultimate solution to use devm* interfaces. For now, I'll
> just avoid using devm* interfaces.
> Still, we have to manually disable the clock, didn't we?
> 
> Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
> have any other way to use managed clk interfaces?

No, I really need to pick it back up...

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [linux-sunxi] Re: [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2
@ 2015-01-22 20:07             ` Dmitry Torokhov
  0 siblings, 0 replies; 57+ messages in thread
From: Dmitry Torokhov @ 2015-01-22 20:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 21, 2015 at 04:52:04PM +0530, Vishnu Patekar wrote:
> Hello Dmitry,
> 
> On Tue, Jan 20, 2015 at 6:05 AM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> > On Mon, Jan 19, 2015 at 11:37:38AM +0530, Vishnu Patekar wrote:
> >> Hello Dmitry,
> >>
> >> Thank you for review comments. Please see in-lined.
> >>
> >> On Sun, Jan 18, 2015 at 3:55 AM, Dmitry Torokhov
> >> <dmitry.torokhov@gmail.com> wrote:
> >> > Hi Vishnu,
> >> >
> >> > On Fri, Jan 16, 2015 at 07:33:38PM +0530, Vishnu Patekar wrote:
> >> >> Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
> >> >> ---
> >> >>  drivers/input/serio/Kconfig     |   11 ++
> >> >>  drivers/input/serio/Makefile    |    1 +
> >> >>  drivers/input/serio/sun4i-ps2.c |  330 +++++++++++++++++++++++++++++++++++++++
> >> >>  3 files changed, 342 insertions(+)
> >> >>  create mode 100644 drivers/input/serio/sun4i-ps2.c
> >> >>
> >> >> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> >> >> index bc2d474..964afc5 100644
> >> >> --- a/drivers/input/serio/Kconfig
> >> >> +++ b/drivers/input/serio/Kconfig
> >> >> @@ -281,4 +281,15 @@ config HYPERV_KEYBOARD
> >> >>         To compile this driver as a module, choose M here: the module will
> >> >>         be called hyperv_keyboard.
> >> >>
> >> >> +config SERIO_SUN4I_PS2
> >> >> +     tristate "Allwinner A10 PS/2 controller support"
> >> >> +     default n
> >> >> +     depends on ARCH_SUNXI || COMPILE_TEST
> >> >> +     help
> >> >> +       This selects support for the PS/2 Host Controller on
> >> >> +       Allwinner A10.
> >> >> +
> >> >> +       To compile this driver as a module, choose M here: the
> >> >> +       module will be called sun4i-ps2.
> >> >> +
> >> >>  endif
> >> >> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> >> >> index 815d874..c600089 100644
> >> >> --- a/drivers/input/serio/Makefile
> >> >> +++ b/drivers/input/serio/Makefile
> >> >> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> >> >>  obj-$(CONFIG_SERIO_APBPS2)   += apbps2.o
> >> >>  obj-$(CONFIG_SERIO_OLPC_APSP)        += olpc_apsp.o
> >> >>  obj-$(CONFIG_HYPERV_KEYBOARD)        += hyperv-keyboard.o
> >> >> +obj-$(CONFIG_SERIO_SUN4I_PS2)        += sun4i-ps2.o
> >> >> diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
> >> >> new file mode 100644
> >> >> index 0000000..06b3fef
> >> >> --- /dev/null
> >> >> +++ b/drivers/input/serio/sun4i-ps2.c
> >> >> @@ -0,0 +1,330 @@
> >> >> +/*
> >> >> + *   Driver for Allwinner A10 PS2 host controller
> >> >> + *
> >> >> + *   Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
> >> >> + *           Aaron.maoye <leafy.myeh@newbietech.com>
> >> >> + *
> >> >> + *
> >> >> + */
> >> >> +
> >> >> +#include <linux/module.h>
> >> >> +#include <linux/serio.h>
> >> >> +#include <linux/interrupt.h>
> >> >> +#include <linux/errno.h>
> >> >> +#include <linux/slab.h>
> >> >> +#include <linux/list.h>
> >> >> +#include <linux/io.h>
> >> >> +#include <linux/of_address.h>
> >> >> +#include <linux/of_device.h>
> >> >> +#include <linux/of_irq.h>
> >> >> +#include <linux/of_platform.h>
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/delay.h>
> >> >> +
> >> >> +#define DRIVER_NAME          "sun4i-ps2"
> >> >> +
> >> >> +/* register offset definitions */
> >> >> +#define PS2_REG_GCTL         0x00    /*  PS2 Module Global Control Reg */
> >> >> +#define PS2_REG_DATA         0x04    /*  PS2 Module Data Reg         */
> >> >> +#define PS2_REG_LCTL         0x08    /*  PS2 Module Line Control Reg */
> >> >> +#define PS2_REG_LSTS         0x0C    /*  PS2 Module Line Status Reg  */
> >> >> +#define PS2_REG_FCTL         0x10    /*  PS2 Module FIFO Control Reg */
> >> >> +#define PS2_REG_FSTS         0x14    /*  PS2 Module FIFO Status Reg  */
> >> >> +#define PS2_REG_CLKDR                0x18    /*  PS2 Module Clock Divider Reg*/
> >> >> +
> >> >> +/*  PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
> >> >> +#define PS2_GCTL_INTFLAG     BIT(4)
> >> >> +#define PS2_GCTL_INTEN               BIT(3)
> >> >> +#define PS2_GCTL_RESET               BIT(2)
> >> >> +#define PS2_GCTL_MASTER              BIT(1)
> >> >> +#define PS2_GCTL_BUSEN               BIT(0)
> >> >> +
> >> >> +/* PS2 LINE CONTROL REGISTER */
> >> >> +#define PS2_LCTL_NOACK               BIT(18)
> >> >> +#define PS2_LCTL_TXDTOEN     BIT(8)
> >> >> +#define PS2_LCTL_STOPERREN   BIT(3)
> >> >> +#define PS2_LCTL_ACKERREN    BIT(2)
> >> >> +#define PS2_LCTL_PARERREN    BIT(1)
> >> >> +#define PS2_LCTL_RXDTOEN     BIT(0)
> >> >> +
> >> >> +/* PS2 LINE STATUS REGISTER */
> >> >> +#define PS2_LSTS_TXTDO               BIT(8)
> >> >> +#define PS2_LSTS_STOPERR     BIT(3)
> >> >> +#define PS2_LSTS_ACKERR              BIT(2)
> >> >> +#define PS2_LSTS_PARERR              BIT(1)
> >> >> +#define PS2_LSTS_RXTDO               BIT(0)
> >> >> +
> >> >> +#define PS2_LINE_ERROR_BIT \
> >> >> +     (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
> >> >> +     PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
> >> >> +
> >> >> +/* PS2 FIFO CONTROL REGISTER */
> >> >> +#define PS2_FCTL_TXRST               BIT(17)
> >> >> +#define PS2_FCTL_RXRST               BIT(16)
> >> >> +#define PS2_FCTL_TXUFIEN     BIT(10)
> >> >> +#define PS2_FCTL_TXOFIEN     BIT(9)
> >> >> +#define PS2_FCTL_TXRDYIEN    BIT(8)
> >> >> +#define PS2_FCTL_RXUFIEN     BIT(2)
> >> >> +#define PS2_FCTL_RXOFIEN     BIT(1)
> >> >> +#define PS2_FCTL_RXRDYIEN    BIT(0)
> >> >> +
> >> >> +/* PS2 FIFO STATUS REGISTER */
> >> >> +#define PS2_FSTS_TXUF                BIT(10)
> >> >> +#define PS2_FSTS_TXOF                BIT(9)
> >> >> +#define PS2_FSTS_TXRDY               BIT(8)
> >> >> +#define PS2_FSTS_RXUF                BIT(2)
> >> >> +#define PS2_FSTS_RXOF                BIT(1)
> >> >> +#define PS2_FSTS_RXRDY               BIT(0)
> >> >> +
> >> >> +#define PS2_FIFO_ERROR_BIT \
> >> >> +     (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
> >> >> +
> >> >> +#define PS2_SAMPLE_CLK               1000000
> >> >> +#define PS2_SCLK             125000
> >> >> +
> >> >> +struct sun4i_ps2data {
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev;
> >> >> +
> >> >> +     /* IO mapping base */
> >> >> +     void __iomem    *reg_base;
> >> >> +
> >> >> +     /* clock management */
> >> >> +     struct clk      *clk;
> >> >> +
> >> >> +     /* irq */
> >> >> +     spinlock_t      lock;
> >> >> +     int             irq;
> >> >> +};
> >> >> +
> >> >> +/*********************/
> >> >> +/* Interrupt handler */
> >> >> +/*********************/
> >> >> +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = dev_id;
> >> >> +     u32 intr_status;
> >> >> +     u32 fifo_status;
> >> >> +     unsigned char byte;
> >> >> +     unsigned int rxflags = 0;
> >> >> +     u32 rval;
> >> >> +
> >> >> +     spin_lock(&drvdata->lock);
> >> >> +
> >> >> +     /* Get the PS/2 interrupts and clear them */
> >> >> +     intr_status  = readl(drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     fifo_status  = readl(drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     /*Check Line Status Register*/
> >> >> +     if (intr_status & PS2_LINE_ERROR_BIT) {
> >> >> +             rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
> >> >> +             rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
> >> >> +
> >> >> +             rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
> >> >> +                     PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     }
> >> >> +
> >> >> +     /*Check FIFO Status Register*/
> >> >> +     if (fifo_status & PS2_FIFO_ERROR_BIT) {
> >> >> +             rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
> >> >> +                     PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
> >> >> +             writel(rval, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +     }
> >> >> +
> >> >> +     rval = (fifo_status >> 16) & 0x3;
> >> >> +     while (rval--) {
> >> >> +             byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
> >> >> +             serio_interrupt(drvdata->serio, byte, rxflags);
> >> >> +     }
> >> >> +
> >> >> +     writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
> >> >> +     writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
> >> >> +
> >> >> +     spin_unlock(&drvdata->lock);
> >> >> +
> >> >> +     return IRQ_HANDLED;
> >> >> +}
> >> >> +
> >> >> +
> >> >> +static int sun4i_ps2_open(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +     u32 src_clk = 0;
> >> >> +     u32 clk_scdf;
> >> >> +     u32 clk_pcdf;
> >> >> +     u32 rval;
> >> >> +     unsigned long flags;
> >> >> +
> >> >> +     /*Set Line Control And Enable Interrupt*/
> >> >> +     rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
> >> >> +             | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_LCTL);
> >> >> +
> >> >> +     /*Reset FIFO*/
> >> >> +     rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
> >> >> +             | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
> >> >> +             | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
> >> >> +
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_FCTL);
> >> >> +
> >> >> +     src_clk = clk_get_rate(drvdata->clk);
> >> >> +     /*Set Clock Divider Register*/
> >> >> +     clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
> >> >> +     clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
> >> >> +     rval = (clk_scdf<<8) | clk_pcdf;
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
> >> >> +
> >> >> +
> >> >> +     /*Set Global Control Register*/
> >> >> +     rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
> >> >> +             | PS2_GCTL_BUSEN;
> >> >> +
> >> >> +     spin_lock_irqsave(&drvdata->lock, flags);
> >> >> +     writel(rval, drvdata->reg_base + PS2_REG_GCTL);
> >> >> +     spin_unlock_irqrestore(&drvdata->lock, flags);
> >> >> +
> >> >> +     return 0;
> >> >> +}
> >> >> +
> >> >> +static void sun4i_ps2_close(struct serio *pserio)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = pserio->port_data;
> >> >> +
> >> >> +     synchronize_irq(drvdata->irq);
> >> >
> >> > synchronize_irq() on it's own is not very useful. You also need to shut
> >> > off interrupts on the chip (I suppose by clearing PS2_GCTL_INTEN?)
> >> > before calling synchronize_irq.
> >> Okie, I'll do it. Yes, clearing PS2_GCTL_INTEN will shut off the interrupts.
> >
> > Please also do shut off interrupts on the chip before requesting IRQ.
> Okie
> >
> >> >
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_write(struct serio *pserio, unsigned char val)
> >> >> +{
> >> >> +     unsigned long expire = jiffies + msecs_to_jiffies(10000);
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +
> >> >> +     drvdata = (struct sun4i_ps2data *)pserio->port_data;
> >> >> +
> >> >> +     do {
> >> >> +             if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
> >> >> +                     writel(val, drvdata->reg_base + PS2_REG_DATA);
> >> >> +                     return 0;
> >> >> +             }
> >> >> +     } while (time_before(jiffies, expire));
> >> >> +
> >> >> +     return SERIO_TIMEOUT;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_probe(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct resource *res; /* IO mem resources */
> >> >> +     struct sun4i_ps2data *drvdata;
> >> >> +     struct serio *serio;
> >> >> +     struct device *dev = &pdev->dev;
> >> >> +     unsigned int irq;
> >> >> +     int error;
> >> >> +
> >> >> +     drvdata = devm_kzalloc(dev, sizeof(struct sun4i_ps2data), GFP_KERNEL);
> >> >> +     serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
> >> >> +     if (!drvdata || !serio) {
> >> >> +             error = -ENOMEM;
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     spin_lock_init(&drvdata->lock);
> >> >> +
> >> >> +     /* IO */
> >> >> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> >> +     drvdata->reg_base = devm_ioremap_resource(dev, res);
> >> >> +     if (IS_ERR(drvdata->reg_base)) {
> >> >> +             dev_err(dev, "failed to map registers\n");
> >> >> +             error = PTR_ERR(drvdata->reg_base);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->clk = devm_clk_get(dev, NULL);
> >> >> +     if (IS_ERR(drvdata->clk)) {
> >> >> +             error = PTR_ERR(drvdata->clk);
> >> >> +             dev_err(dev, "couldn't get clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     error = clk_prepare_enable(drvdata->clk);
> >> >> +     if (error) {
> >> >> +             dev_err(dev, "failed to enable clock %d\n", error);
> >> >> +             goto err_free_mem;
> >> >> +     }
> >> >> +
> >> >> +     serio->id.type = SERIO_8042;
> >> >> +     serio->write = sun4i_ps2_write;
> >> >> +     serio->open = sun4i_ps2_open;
> >> >> +     serio->close = sun4i_ps2_close;
> >> >> +     serio->port_data = drvdata;
> >> >> +     serio->dev.parent = dev;
> >> >> +     strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> >> >> +     strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> >> >> +
> >> >> +     /* Get IRQ for the device */
> >> >> +     irq = platform_get_irq(pdev, 0);
> >> >> +     if (!irq) {
> >> >> +             dev_err(dev, "no IRQ found\n");
> >> >> +             error = -ENXIO;
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     drvdata->irq = irq;
> >> >> +     drvdata->serio = serio;
> >> >> +     drvdata->dev = dev;
> >> >> +     error = devm_request_threaded_irq(dev, drvdata->irq,
> >> >> +             sun4i_ps2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
> >> >> +
> >> >> +     if (error) {
> >> >> +             dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> >> >> +                     drvdata->irq, error);
> >> >> +             goto error_disable_clk;
> >> >> +     }
> >> >> +
> >> >> +     serio_register_port(serio);
> >> >> +     platform_set_drvdata(pdev, drvdata);
> >> >> +
> >> >> +     return 0;       /* success */
> >> >> +
> >> >> +error_disable_clk:
> >> >> +     clk_disable_unprepare(drvdata->clk);
> >> >> +
> >> >> +err_free_mem:
> >> >> +     kfree(serio);
> >> >> +     return error;
> >> >> +}
> >> >> +
> >> >> +static int sun4i_ps2_remove(struct platform_device *pdev)
> >> >> +{
> >> >> +     struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> >> >> +
> >> >> +     serio_unregister_port(drvdata->serio);
> >> >> +
> >> >> +     if (!IS_ERR(drvdata->clk))
> >> >> +             clk_disable_unprepare(drvdata->clk);
> >> >> +     kfree(drvdata->serio);
> >> >
> >> > Serio is refcounted, you do not free it after its has been registered.
> >> > Overall I'd rather you did not use devm* interfaces here since you are
> >> > forced to mix managed and manually freed resources.
> >> Okie, No need to free serio here.
> >> If serio is not manually freed here, It is not freeing anything else manually.
> >
> > You are still unregistering the port manually and disabling the clock manually.
> >>
> >> do you still feel I should not use devm* interfaces here?
> >
> > Yes, because of above. My rule of thumb - when using devm* API there should not
> > be remove() at all.
> Okie, I'll remove devm* interfaces.
> 
> >
> > BTW, if one added devm_* API to serio, similar to devm* in input core, I'd take
> > such patch.
> This seems a ultimate solution to use devm* interfaces. For now, I'll
> just avoid using devm* interfaces.
> Still, we have to manually disable the clock, didn't we?
> 
> Well, I saw your old devm_clk_* patch, it was not mainlined. Do we
> have any other way to use managed clk interfaces?

No, I really need to pick it back up...

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2015-01-22 20:07 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-16 14:03 [PATCH v4 0/5] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller Vishnu Patekar
2015-01-16 14:03 ` Vishnu Patekar
2015-01-16 14:03 ` Vishnu Patekar
2015-01-16 14:03 ` [PATCH v4 1/5] sunxi:dts-bindings:input: bindings for A10/A20 ps2 Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03 ` [PATCH v4 2/5] ARM:sunxi:drivers:input Add support for A10/A20 PS2 Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-17 22:25   ` Dmitry Torokhov
2015-01-17 22:25     ` Dmitry Torokhov
2015-01-17 22:25     ` Dmitry Torokhov
2015-01-19  6:07     ` Vishnu Patekar
2015-01-19  6:07       ` Vishnu Patekar
2015-01-19  6:07       ` Vishnu Patekar
2015-01-20  0:35       ` Dmitry Torokhov
2015-01-20  0:35         ` Dmitry Torokhov
2015-01-20  0:35         ` Dmitry Torokhov
2015-01-21 11:22         ` [linux-sunxi] " Vishnu Patekar
2015-01-21 11:22           ` Vishnu Patekar
2015-01-21 11:22           ` Vishnu Patekar
2015-01-22 20:07           ` Dmitry Torokhov
2015-01-22 20:07             ` Dmitry Torokhov
2015-01-22 20:07             ` Dmitry Torokhov
2015-01-16 14:03 ` [PATCH v4 3/5] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10 and A20 Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-20 20:02   ` Maxime Ripard
2015-01-20 20:02     ` Maxime Ripard
2015-01-20 20:02     ` Maxime Ripard
2015-01-21 11:10     ` Vishnu Patekar
2015-01-21 11:10       ` Vishnu Patekar
2015-01-21 11:10       ` Vishnu Patekar
2015-01-22 15:50       ` Maxime Ripard
2015-01-22 15:50         ` Maxime Ripard
2015-01-22 15:50         ` Maxime Ripard
2015-01-16 14:03 ` [PATCH v4 4/5] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-20 20:03   ` Maxime Ripard
2015-01-20 20:03     ` Maxime Ripard
2015-01-20 20:03     ` Maxime Ripard
2015-01-16 14:03 ` [PATCH v4 5/5] ARM: sunxi: dts: Add PS2 nodes for A20 lime2 board Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-16 14:03   ` Vishnu Patekar
2015-01-20 17:02   ` [linux-sunxi] " Iain Paton
2015-01-20 17:02     ` Iain Paton
2015-01-20 17:02     ` Iain Paton
2015-01-20 20:07     ` [linux-sunxi] " Maxime Ripard
2015-01-20 20:07       ` Maxime Ripard
2015-01-20 20:07       ` Maxime Ripard
2015-01-21 11:04       ` [linux-sunxi] " Vishnu Patekar
2015-01-21 11:04         ` Vishnu Patekar
2015-01-21 11:04         ` Vishnu Patekar
2015-01-21 12:23         ` [linux-sunxi] " Maxime Ripard
2015-01-21 12:23           ` Maxime Ripard
2015-01-21 12:23           ` Maxime Ripard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.