2015-07-05 09:01:00

by Roman Volkov

[permalink] [raw]
Subject: [PATCH v4 0/4] FDT support for i8042 driver

The i8042 interface is used not only on the x86 architecture. Some of
non-x86 architectures are using Open Firmware device tree, like SPARC
and PowerPC. There is also non-x86 platforms with the FDT support, such
as ARM SoCs. There is no code in Linux to support i8042-capable input
devices on these newer platforms.

This patch creates one more file (i8042-of.h), with OF parsing code
for the ePAPR-compatible binding with the 'compatible' property. The
binding is based on existing OF code for older platforms, making it
possible to reuse this code for these platforms.

v2:
-Changes in the documentation.
-Errors fixed in the initialization function.
-Redundant parameters removed from Device Tree bindings (init-reset, etc.).

v3:
-Reduced amount of 'ifdefs' in the i8042.c file. Initialization order
is now the same for all architectures.

Warning: the change in v3 is more controversial and needs more testing
since affects all architectures which use the driver. Please give
information regarding required steps to get this patch accepted. Would
be great to find testers to get additional tested-by records.

v4:
-Rename i8042-dt.h to i8042-of.h, rewrite init/probe/remove functions with
OF code to be compatible with SPARC/PowerPC.
-Add MODULE_DEVICE_TABLE (it was a mistake to forget about it)
-Remove 'command-reg', 'status-reg', 'data-reg' from the binding; it is not
required for now.
-Yet another variant of changes in i8042.c. Unfortunately, it is not possible
to avoid these changes.
-Move the documentation file into the right place
(thanks to Hans de Goede for the hint)
-Change the order of patches
Tested on: x86, ARM-vt8500, both as a module\built-in.

Roman Volkov (4):
i8042: Add i8042_of.h header
i8042: Kernel configuration for OF/FDT support
i8042: Add OF/FDT support to the driver
Documentation: Add 'intel,8042' FDT bindings

.../devicetree/bindings/serio/intel,8042.txt | 82 ++++++++++
drivers/input/serio/i8042-of.h | 168 +++++++++++++++++++++
drivers/input/serio/i8042.c | 43 +++++-
drivers/input/serio/i8042.h | 3 +
4 files changed, 291 insertions(+), 5 deletions(-)
create mode 100644 Documentation/devicetree/bindings/serio/intel,8042.txt
create mode 100644 drivers/input/serio/i8042-of.h

--
2.4.2


2015-07-05 09:01:34

by Roman Volkov

[permalink] [raw]
Subject: [PATCH v4 1/4] i8042: Add i8042_of.h header

This file contains OF/FDT parsing code, based on older implementations
for SPARC and PowerPC. Currently it can be used to support the i8042
interface on the vt8500 boards. This code can be reused with some
workarounds to support the older SPARC machines. For example, older
machines do not have the 'compatible' property in the device tree,
required by the newer standards. A workaround would be to manually
insert these properties by the platform code.

Signed-off-by: Roman Volkov <[email protected]>
Signed-off-by: Tony Prisk <[email protected]>
---
drivers/input/serio/i8042-of.h | 168 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 168 insertions(+)
create mode 100644 drivers/input/serio/i8042-of.h

diff --git a/drivers/input/serio/i8042-of.h b/drivers/input/serio/i8042-of.h
new file mode 100644
index 0000000..3b95b86
--- /dev/null
+++ b/drivers/input/serio/i8042-of.h
@@ -0,0 +1,168 @@
+#ifndef _I8042_OF_H
+#define _I8042_OF_H
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+static void __iomem *i8042_data;
+static void __iomem *i8042_ctrl;
+#define I8042_DATA_REG i8042_data
+#define I8042_COMMAND_REG i8042_ctrl
+#define I8042_STATUS_REG i8042_ctrl
+
+/*
+ * Names.
+ */
+#define I8042_KBD_PHYS_DESC "i8042/serio0"
+#define I8042_AUX_PHYS_DESC "i8042/serio1"
+#define I8042_MUX_PHYS_DESC "i8042/serio%d"
+
+#define OBP_PS2KBD_NAME1 "kb_ps2"
+#define OBP_PS2KBD_NAME2 "keyboard"
+#define OBP_PS2MS_NAME1 "kdmouse"
+#define OBP_PS2MS_NAME2 "mouse"
+
+/*
+ * IRQs.
+ */
+static int i8042_kbd_irq;
+static int i8042_aux_irq;
+#define I8042_KBD_IRQ i8042_kbd_irq
+#define I8042_AUX_IRQ i8042_aux_irq
+
+static inline int i8042_read_data(void)
+{
+ return readb(I8042_DATA_REG);
+}
+
+static inline void i8042_write_data(int val)
+{
+ writeb(val, I8042_DATA_REG);
+}
+
+static inline int i8042_read_status(void)
+{
+ return readb(I8042_STATUS_REG);
+}
+
+static inline void i8042_write_command(int val)
+{
+ writeb(val, I8042_COMMAND_REG);
+}
+
+/*
+ * Device Tree/platform code
+ */
+static int __init i8042_platform_probe_subdevice(struct platform_device *pdev,
+ struct device_node *psub)
+{
+ if (!pdev || !psub)
+ return -EINVAL;
+
+ if (of_device_is_compatible(psub, "pnpPNP,303") ||
+ !strcmp(psub->name, OBP_PS2KBD_NAME1) ||
+ !strcmp(psub->name, OBP_PS2KBD_NAME2)) {
+ i8042_kbd_irq = irq_of_parse_and_map(psub, 0);
+ if (i8042_kbd_irq <= 0)
+ i8042_kbd_irq = platform_get_irq_byname(pdev, "kbd");
+ if (i8042_kbd_irq <= 0)
+ i8042_kbd_irq = platform_get_irq(pdev, 0);
+ return 0;
+ }
+
+ if (of_device_is_compatible(psub, "pnpPNP,f03") ||
+ !strcmp(psub->name, OBP_PS2MS_NAME1) ||
+ !strcmp(psub->name, OBP_PS2MS_NAME2)) {
+ i8042_aux_irq = irq_of_parse_and_map(psub, 0);
+ if (i8042_aux_irq <= 0)
+ i8042_aux_irq = platform_get_irq_byname(pdev, "aux");
+ if (i8042_aux_irq <= 0)
+ i8042_aux_irq = platform_get_irq(pdev, 1);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int __init i8042_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ struct resource *res;
+
+ if (i8042_data || i8042_ctrl)
+ return -EBUSY;
+
+ node = pdev->dev.of_node;
+ if (!node)
+ return -EINVAL;
+
+ node = node->child;
+ while (node) {
+ i8042_platform_probe_subdevice(pdev, node);
+ node = node->sibling;
+ }
+
+ if (i8042_kbd_irq <= 0)
+ i8042_nokbd = true;
+ if (i8042_aux_irq <= 0)
+ i8042_noaux = true;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i8042_data = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i8042_data))
+ return PTR_ERR(i8042_data);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ i8042_ctrl = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i8042_ctrl)) {
+ devm_iounmap(&pdev->dev, i8042_data);
+ return PTR_ERR(i8042_ctrl);
+ }
+
+ return 0;
+}
+
+static int i8042_platform_remove(struct platform_device *pdev)
+{
+ if (i8042_data) {
+ if (!IS_ERR(i8042_data))
+ devm_iounmap(&pdev->dev, i8042_data);
+ i8042_data = NULL;
+ }
+
+ if (i8042_ctrl) {
+ if (!IS_ERR(i8042_ctrl))
+ devm_iounmap(&pdev->dev, i8042_ctrl);
+ i8042_ctrl = NULL;
+ }
+
+ return 0;
+}
+
+static int __init i8042_platform_init(void)
+{
+ i8042_data = NULL;
+ i8042_ctrl = NULL;
+ i8042_reset = true;
+
+ return 0;
+}
+
+static inline void i8042_platform_exit(void)
+{
+}
+
+static const struct of_device_id i8042_of_match[] = {
+ { .compatible = "intel,8042", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, i8042_of_match);
+
+#endif
--
2.4.2

2015-07-05 09:01:10

by Roman Volkov

[permalink] [raw]
Subject: [PATCH v4 2/4] i8042: Kernel configuration for OF/FDT support

i8042_of.h should be included when CONFIG_ARCH_MIGHT_HAVE_PC_SERIO and
CONFIG_USE_OF are selected. Kconfig is not modified.

Signed-off-by: Roman Volkov <[email protected]>
---
drivers/input/serio/i8042.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index fc080be..55fc856 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -28,6 +28,9 @@
#include "i8042-x86ia64io.h"
#elif defined(CONFIG_UNICORE32)
#include "i8042-unicore32io.h"
+#elif defined(CONFIG_ARCH_MIGHT_HAVE_PC_SERIO) && defined(CONFIG_USE_OF)
+#define SERIO_I8042_OF
+#include "i8042-of.h"
#else
#include "i8042-io.h"
#endif
--
2.4.2

2015-07-05 09:01:28

by Roman Volkov

[permalink] [raw]
Subject: [PATCH v4 3/4] i8042: Add OF/FDT support to the driver

Original driver should be modified to support OF/FDT bindings. The
platform_create_bundle() function should be removed when compiled for
OF-capable machines, since the device tree is already created by the
platform code. The driver should also contain the OF match table and
call platform-specific probe/remove functions.

Signed-off-by: Roman Volkov <[email protected]>
---
drivers/input/serio/i8042.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)

diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index cb5ece7..ec58af1 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1442,8 +1442,27 @@ static int __init i8042_probe(struct platform_device *dev)
{
int error;

- i8042_platform_device = dev;
+ if (i8042_platform_device) {
+ printk("%s: multiple controllers found, ignoring '%s'\n",
+ __func__, dev->name);
+ return 0;
+ }
+#ifdef SERIO_I8042_OF
+ if (!dev->dev.of_node) {
+ printk("%s: non-OF device found, ignoring '%s'\n",
+ __func__, dev->name);
+ return 0;
+ }

+ error = i8042_platform_probe(dev);
+ if (error)
+ return error;
+#endif
+ error = i8042_controller_check();
+ if (error)
+ return error;
+
+ i8042_platform_device = dev;
if (i8042_reset) {
error = i8042_controller_selftest();
if (error)
@@ -1488,9 +1507,17 @@ static int __init i8042_probe(struct platform_device *dev)

static int i8042_remove(struct platform_device *dev)
{
+ if (dev != i8042_platform_device) {
+ dbg("%s: ignoring device %s\n", __func__, dev->name);
+ return 0;
+ }
+
i8042_unregister_ports();
i8042_free_irqs();
i8042_controller_reset(false);
+#ifdef SERIO_I8042_OF
+ i8042_platform_remove(dev);
+#endif
i8042_platform_device = NULL;

return 0;
@@ -1502,6 +1529,9 @@ static struct platform_driver i8042_driver = {
#ifdef CONFIG_PM
.pm = &i8042_pm_ops,
#endif
+#ifdef SERIO_I8042_OF
+ .of_match_table = i8042_of_match,
+#endif
},
.remove = i8042_remove,
.shutdown = i8042_shutdown,
@@ -1514,15 +1544,16 @@ static int __init i8042_init(void)

dbg_init();

+ i8042_platform_device = NULL;
err = i8042_platform_init();
if (err)
return err;

- err = i8042_controller_check();
- if (err)
- goto err_platform_exit;
-
+#ifdef SERIO_I8042_OF
+ pdev = ERR_PTR(platform_driver_probe(&i8042_driver, i8042_probe));
+#else
pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
+#endif
if (IS_ERR(pdev)) {
err = PTR_ERR(pdev);
goto err_platform_exit;
@@ -1539,7 +1570,9 @@ static int __init i8042_init(void)

static void __exit i8042_exit(void)
{
+#ifndef SERIO_I8042_OF
platform_device_unregister(i8042_platform_device);
+#endif
platform_driver_unregister(&i8042_driver);
i8042_platform_exit();

--
2.4.2

2015-07-05 09:01:19

by Roman Volkov

[permalink] [raw]
Subject: [PATCH v4 4/4] Documentation: Add 'intel,8042' FDT bindings

Add a documentation file for the new OF/FDT binding for the i8042 interface.

Signed-off-by: Roman Volkov <[email protected]>
---
.../devicetree/bindings/serio/intel,8042.txt | 82 ++++++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serio/intel,8042.txt

diff --git a/Documentation/devicetree/bindings/serio/intel,8042.txt b/Documentation/devicetree/bindings/serio/intel,8042.txt
new file mode 100644
index 0000000..c2eb26f
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/intel,8042.txt
@@ -0,0 +1,82 @@
+* Intel 8042 interface
+
+This interface has the long history on various non-x86 platforms. The
+binding is based on the SPARC and PowerPC implementations, compatible to
+Open Firmware. The 'compatible' property has been added to make the binding
+compatible to ePAPR.
+
+Required properties:
+- #address-cells: Must be <1>, since the address for input devices is virtual.
+
+- #size-cells: Must be <0>, since the size is not applicable for the virtual
+ address.
+
+- compatible: Should be "intel,8042".
+
+- reg: Specifies the base address and size of the interface registers in the
+ following order:
+ - DATA: The serial data buffer address.
+ - COMMAND/STATUS: Has the status of the keyboard controller and interface,
+ allows to send commands to the controller.
+
+Optional properties:
+- interrupts: One (keyboard) or two (keyboard and auxiliary) interrupts.
+
+- interrupt-names: names of interrupts, must be "kbd", "aux". If not specified,
+ the first interrupt is "kbd", and the second is "aux".
+
+Child nodes:
+The i8042 interface may control input devices such as keyboard and mouse. Each
+input device is represented by a child node. The input device could be
+identified by the 'compatible' property or the node name (obsolete).
+
+Required properties:
+- reg: Specifies the device virtual address. These numbers should not be
+ duplicated.
+- compatible: should be "pnpPNP,303" for keyboard, and "pnpPNP,f03" for mouse.
+
+Optional properties:
+- interrupts: Specifies the interrupt number for the device. Overwrites the
+ value from the parent node.
+
+Examples:
+
+// Most preferred way
+ps2@d8008800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "intel,8042";
+ reg = <0xd8008800 0x1>, <0xd8008804 0x1>;
+ interrupts = <23>, <4>;
+ interrupt-names = "kbd", "aux";
+
+ keyboard@0 {
+ reg = <0x0>;
+ compatible = "pnpPNP,303";
+ };
+
+ mouse@1 {
+ reg = <0x1>;
+ compatible = "pnpPNP,f03";
+ };
+};
+
+// PowerPC
+i8042@60 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x1 0x60 0x1 0x1 0x64 0x1>;
+ interrupts = <1 3 12 3>;
+ interrupt-parent = <&i8259>;
+ // 'compatible' property has to be added by the platform code
+
+ keyboard@0 {
+ reg = <0x0>;
+ compatible = "pnpPNP,303";
+ };
+
+ mouse@1 {
+ reg = <0x1>;
+ compatible = "pnpPNP,f03";
+ };
+};
--
2.4.2