* [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller
@ 2015-01-25 13:40 Vishnu Patekar
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
0 siblings, 1 reply; 7+ messages in thread
From: Vishnu Patekar @ 2015-01-25 13:40 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 PS2 controller support for Allwinner A10, A20 SOCs.
I've tested PS2 keyboard on A20 Olimex-Lime2 board.
Hans had tested previous patch on A10 as well.
v4 --> v5
1. used legagy calls instead of devm* interfaces to avoid mixing of managed
and manually freed resources.
2. shutoff interrupts before requesting irq and before synchronize_irq.
3. removed freeing serio in sun4i_ps2_remove, as it is refcounted.
4. added defines in dtsi file instead of hardcoded constants.
5. dropped the default enabled ps2 nodes from Lime2 dts, as there is no
dedicated ps2 connector on lime2 board.
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 (4):
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,A20
ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
.../bindings/serio/allwinner,sun4i-ps2.txt | 23 ++
arch/arm/boot/dts/sun4i-a10.dtsi | 30 ++
arch/arm/boot/dts/sun7i-a20.dtsi | 30 ++
drivers/input/serio/Kconfig | 11 +
drivers/input/serio/Makefile | 1 +
drivers/input/serio/sun4i-ps2.c | 347 ++++++++++++++++++++
6 files changed, 442 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] 7+ messages in thread
* [PATCH v5 1/4] sunxi:dts-bindings:input: bindings for A10/A20 ps2
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2015-01-25 13:40 ` Vishnu Patekar
2015-01-25 13:40 ` [PATCH v5 2/4] ARM:sunxi:drivers:input Add support for A10/A20 PS2 Vishnu Patekar
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Patekar @ 2015-01-25 13:40 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] 7+ messages in thread
* [PATCH v5 2/4] ARM:sunxi:drivers:input Add support for A10/A20 PS2
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-25 13:40 ` [PATCH v5 1/4] sunxi:dts-bindings:input: bindings for A10/A20 ps2 Vishnu Patekar
@ 2015-01-25 13:40 ` Vishnu Patekar
[not found] ` <1422193209-17787-3-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-25 13:40 ` [PATCH v5 3/4] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10,A20 Vishnu Patekar
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Vishnu Patekar @ 2015-01-25 13:40 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 | 347 +++++++++++++++++++++++++++++++++++++++
3 files changed, 359 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..d3cf6bc
--- /dev/null
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -0,0 +1,347 @@
+/*
+ * 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;
+ u32 rval;
+
+ /* shutoff the interrupt */
+ rval = readl(drvdata->reg_base + PS2_REG_GCTL);
+ writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL);
+
+ 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 = kzalloc(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 = ioremap(res->start, resource_size(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 = 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_ioremap;
+ }
+
+ error = clk_prepare_enable(drvdata->clk);
+ if (error) {
+ dev_err(dev, "failed to enable clock %d\n", error);
+ goto err_clk;
+ }
+
+ 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));
+
+ /* shutoff interrupt */
+ writel(0, drvdata->reg_base + PS2_REG_GCTL);
+
+ /* Get IRQ for the device */
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(dev, "no IRQ found\n");
+ error = -ENXIO;
+ goto err_disable_clk;
+ }
+
+ drvdata->irq = irq;
+ drvdata->serio = serio;
+ drvdata->dev = dev;
+ error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0,
+ DRIVER_NAME, drvdata);
+
+ if (error) {
+ dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
+ drvdata->irq, error);
+ goto err_disable_clk;
+ }
+
+ serio_register_port(serio);
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0; /* success */
+
+err_disable_clk:
+ clk_disable_unprepare(drvdata->clk);
+err_clk:
+ clk_put(drvdata->clk);
+err_ioremap:
+ iounmap(drvdata->reg_base);
+err_free_mem:
+ kfree(serio);
+ kfree(drvdata);
+ return error;
+}
+
+static int sun4i_ps2_remove(struct platform_device *pdev)
+{
+ struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
+
+ serio_unregister_port(drvdata->serio);
+ free_irq(drvdata->irq, drvdata);
+
+ if (!IS_ERR(drvdata->clk))
+ clk_disable_unprepare(drvdata->clk);
+
+ clk_put(drvdata->clk);
+ iounmap(drvdata->reg_base);
+ kfree(drvdata);
+
+ 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] 7+ messages in thread
* [PATCH v5 3/4] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10,A20
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-25 13:40 ` [PATCH v5 1/4] sunxi:dts-bindings:input: bindings for A10/A20 ps2 Vishnu Patekar
2015-01-25 13:40 ` [PATCH v5 2/4] ARM:sunxi:drivers:input Add support for A10/A20 PS2 Vishnu Patekar
@ 2015-01-25 13:40 ` Vishnu Patekar
2015-01-25 13:40 ` [PATCH v5 4/4] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options Vishnu Patekar
2015-01-25 16:08 ` [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller Maxime Ripard
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Patekar @ 2015-01-25 13:40 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 ae35397..134100b 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -943,5 +943,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 e10c2b8..d7fc31f 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1208,5 +1208,21 @@
#interrupt-cells = <3>;
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+
+ ps20: ps2@01c2a000 {
+ compatible = "allwinner,sun4i-a10-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
+
+ ps21: ps2@01c2a400 {
+ compatible = "allwinner,sun4i-a10-ps2";
+ reg = <0x01c2a400 0x400>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb1_gates 7>;
+ status = "disabled";
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 4/4] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (2 preceding siblings ...)
2015-01-25 13:40 ` [PATCH v5 3/4] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10,A20 Vishnu Patekar
@ 2015-01-25 13:40 ` Vishnu Patekar
2015-01-25 16:08 ` [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller Maxime Ripard
4 siblings, 0 replies; 7+ messages in thread
From: Vishnu Patekar @ 2015-01-25 13:40 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 134100b..5536b01 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -769,6 +769,20 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ ps20_pins_a: ps20@0 {
+ allwinner,pins = "PI20", "PI21";
+ allwinner,function = "ps2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ps21_pins_a: ps21@0 {
+ allwinner,pins = "PH12", "PH13";
+ allwinner,function = "ps2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
timer@01c20c00 {
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index d7fc31f..f011203 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -973,6 +973,20 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ ps20_pins_a: ps20@0 {
+ allwinner,pins = "PI20", "PI21";
+ allwinner,function = "ps2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ps21_pins_a: ps21@0 {
+ allwinner,pins = "PH12", "PH13";
+ allwinner,function = "ps2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
timer@01c20c00 {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (3 preceding siblings ...)
2015-01-25 13:40 ` [PATCH v5 4/4] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options Vishnu Patekar
@ 2015-01-25 16:08 ` Maxime Ripard
4 siblings, 0 replies; 7+ messages in thread
From: Maxime Ripard @ 2015-01-25 16:08 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: 378 bytes --]
On Sun, Jan 25, 2015 at 07:10:05PM +0530, Vishnu Patekar wrote:
> This adds PS2 controller support for Allwinner A10, A20 SOCs.
>
> I've tested PS2 keyboard on A20 Olimex-Lime2 board.
> Hans had tested previous patch on A10 as well.
Applied 3 and 4.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/4] ARM:sunxi:drivers:input Add support for A10/A20 PS2
[not found] ` <1422193209-17787-3-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2015-01-27 8:03 ` Dmitry Torokhov
0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Torokhov @ 2015-01-27 8:03 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 Sun, Jan 25, 2015 at 07:10:07PM +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 | 347 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 359 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..d3cf6bc
> --- /dev/null
> +++ b/drivers/input/serio/sun4i-ps2.c
> @@ -0,0 +1,347 @@
> +/*
> + * 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>
You do not really need all these of_* includes. Neither you need list.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;
> + u32 rval;
> +
> + /* shutoff the interrupt */
> + rval = readl(drvdata->reg_base + PS2_REG_GCTL);
> + writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL);
> +
> + 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 = kzalloc(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);
If you get NULL here you'll end up dereferencing it later.
> +
> + drvdata->reg_base = ioremap(res->start, resource_size(res));
> + if (IS_ERR(drvdata->reg_base)) {
ioremap returns NULL on failure, not ERR_PTR-encoded result.
> + dev_err(dev, "failed to map registers\n");
> + error = PTR_ERR(drvdata->reg_base);
> + goto err_free_mem;
> + }
> +
> + drvdata->clk = 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_ioremap;
> + }
> +
> + error = clk_prepare_enable(drvdata->clk);
> + if (error) {
> + dev_err(dev, "failed to enable clock %d\n", error);
> + goto err_clk;
> + }
> +
> + 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));
> +
> + /* shutoff interrupt */
> + writel(0, drvdata->reg_base + PS2_REG_GCTL);
> +
> + /* Get IRQ for the device */
> + irq = platform_get_irq(pdev, 0);
> + if (!irq) {
> + dev_err(dev, "no IRQ found\n");
> + error = -ENXIO;
> + goto err_disable_clk;
> + }
> +
> + drvdata->irq = irq;
> + drvdata->serio = serio;
> + drvdata->dev = dev;
> + error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0,
> + DRIVER_NAME, drvdata);
> +
> + if (error) {
> + dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
> + drvdata->irq, error);
> + goto err_disable_clk;
> + }
> +
> + serio_register_port(serio);
> + platform_set_drvdata(pdev, drvdata);
> +
> + return 0; /* success */
> +
> +err_disable_clk:
> + clk_disable_unprepare(drvdata->clk);
> +err_clk:
> + clk_put(drvdata->clk);
> +err_ioremap:
> + iounmap(drvdata->reg_base);
> +err_free_mem:
> + kfree(serio);
> + kfree(drvdata);
> + return error;
> +}
> +
> +static int sun4i_ps2_remove(struct platform_device *pdev)
> +{
> + struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
> +
> + serio_unregister_port(drvdata->serio);
> + free_irq(drvdata->irq, drvdata);
> +
> + if (!IS_ERR(drvdata->clk))
> + clk_disable_unprepare(drvdata->clk);
If you fail to get clk you abort the probe so it is not possible to have
IS_ERR() clk here.
I fixed up the issues and applied the patch, thank you.
--
Dmitry
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-01-27 8:03 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-25 13:40 [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller Vishnu Patekar
[not found] ` <1422193209-17787-1-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-25 13:40 ` [PATCH v5 1/4] sunxi:dts-bindings:input: bindings for A10/A20 ps2 Vishnu Patekar
2015-01-25 13:40 ` [PATCH v5 2/4] ARM:sunxi:drivers:input Add support for A10/A20 PS2 Vishnu Patekar
[not found] ` <1422193209-17787-3-git-send-email-vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-27 8:03 ` Dmitry Torokhov
2015-01-25 13:40 ` [PATCH v5 3/4] ARM: sunxi: dts: Add PS2 nodes to dtsi for A10,A20 Vishnu Patekar
2015-01-25 13:40 ` [PATCH v5 4/4] ARM: sunxi: dts: Add A10/A20 PS2 pin muxing options Vishnu Patekar
2015-01-25 16:08 ` [PATCH v5 0/4] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).