This patch adds basic devicetree support for the i8042 controller driver. Simple properties to specify the register offsets. Optional properties to specify the linux device descriptions. Signed-off-by: Tony Prisk <linux@xxxxxxxxxxxxxxx> --- .../devicetree/bindings/input/intel-8042.txt | 29 +++++ drivers/input/serio/Kconfig | 10 +- drivers/input/serio/i8042-dt.h | 127 ++++++++++++++++++++ drivers/input/serio/i8042.c | 15 ++- drivers/input/serio/i8042.h | 4 +- 5 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/intel-8042.txt create mode 100644 drivers/input/serio/i8042-dt.h diff --git a/Documentation/devicetree/bindings/input/intel-8042.txt b/Documentation/devicetree/bindings/input/intel-8042.txt new file mode 100644 index 0000000..68f6fa2 --- /dev/null +++ b/Documentation/devicetree/bindings/input/intel-8042.txt @@ -0,0 +1,29 @@ +* Intel 8042 Keyboard controller + +Required properties: +- compatible: should be "intel,8042" +- regs: memory for keyboard controller +- interrupts: two interrupts should be specified (keyboard and aux). +- command-reg: offset in memory for command register +- status-reg: offset in memory for status register +- data-reg: offset in memory for data register + +Optional properties: +- init-reset: Controller should be reset on init and cleanup + +Optional linux specific properties: +- linux,kbd_phys_desc: defaults to i8042/serio0 +- linux,aux_phys_desc: defaults to i8042/serio1 +- linux,mux_phys_desc: defaults to i8042/serio%d + + +Example: + keyboard@d8008800 { + compatible = "intel,8042"; + reg = <0xD8008800 0x100>; + interrupts = <23 4>; + command-reg = <0x04>; + status-reg = <0x04>; + data-reg = <0x00>; + mux-ports = <2>; + }; diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 4a4e182..26e97a3 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -21,8 +21,9 @@ if SERIO config SERIO_I8042 tristate "i8042 PC Keyboard controller" if EXPERT || !X86 default y - depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ - (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN + depends on (!PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ + (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN) || \ + (SERIO_I8042_DT) help i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -33,6 +34,11 @@ config SERIO_I8042 To compile this driver as a module, choose M here: the module will be called i8042. +config SERIO_I8042_DT + tristate "i8042 Keyboard controller DT support" if EXPERT || !X86 + depends on USE_OF + select SERIO_I8042 + config SERIO_SERPORT tristate "Serial port line discipline" default y diff --git a/drivers/input/serio/i8042-dt.h b/drivers/input/serio/i8042-dt.h new file mode 100644 index 0000000..3875c90 --- /dev/null +++ b/drivers/input/serio/i8042-dt.h @@ -0,0 +1,127 @@ +#ifndef _I8042_DT_H +#define _I8042_DT_H + +#include <linux/of.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 *dt_base; +static const char *dt_kbd_phys_desc; +static const char *dt_aux_phys_desc; +static const char *dt_mux_phys_desc; +static int dt_kbd_irq; +static int dt_aux_irq; +static unsigned int dt_command_reg; +static unsigned int dt_status_reg; +static unsigned int dt_data_reg; + +#define I8042_KBD_PHYS_DESC dt_kbd_phys_desc +#define I8042_AUX_PHYS_DESC dt_aux_phys_desc +#define I8042_MUX_PHYS_DESC dt_mux_phys_desc + +#define I8042_KBD_IRQ (dt_kbd_irq) +#define I8042_AUX_IRQ (dt_aux_irq) + +#define I8042_COMMAND_REG (dt_command_reg) +#define I8042_STATUS_REG (dt_status_reg) +#define I8042_DATA_REG (dt_data_reg) + + +static inline int i8042_read_data(void) +{ + return readb(dt_base + dt_data_reg); +} + +static inline int i8042_read_status(void) +{ + return readb(dt_base + dt_status_reg); +} + +static inline void i8042_write_data(int val) +{ + writeb(val, dt_base + dt_data_reg); +} + +static inline void i8042_write_command(int val) +{ + writeb(val, dt_base + dt_command_reg); +} + +static inline int dt_parse_node(struct device_node *np) +{ + int ret; + + dt_base = of_iomap(np, 0); + if (!dt_base) + return -ENOMEM; + + ret = of_property_read_u32(np, "command-reg", &dt_command_reg); + if (ret) { + pr_err("i8042-dt: command-reg missing or invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "status-reg", &dt_status_reg); + if (ret) { + pr_err("i8042-dt: status-reg missing or invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "data-reg", &dt_data_reg); + if (ret) { + pr_err("i8042-dt: data-reg missing or invalid\n"); + return ret; + } + + dt_kbd_irq = irq_of_parse_and_map(np, 0); + dt_aux_irq = irq_of_parse_and_map(np, 1); + + ret = of_property_read_string(np, "linux,kbd_phys_desc", + &dt_kbd_phys_desc); + if (ret) + dt_kbd_phys_desc = "i8042/serio0"; + + ret = of_property_read_string(np, "linux,aux_phys_desc", + &dt_aux_phys_desc); + if (ret) + dt_aux_phys_desc = "i8042/serio1"; + + ret = of_property_read_string(np, "linux,mux_phys_desc", + &dt_mux_phys_desc); + if (ret) + dt_mux_phys_desc = "i8042/serio%d"; + + if (of_get_property(np, "init-reset", NULL)) + i8042_reset = true; + + return 0; +} + +static inline int i8042_platform_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "intel,8042"); + if (!np) { + pr_err("%s: no devicetree node found\n", __func__); + return -ENODEV; + } + + dt_parse_node(np); + + return 0; +} + +static inline void i8042_platform_exit(void) +{ + if (dt_base) + iounmap(dt_base); +} + +#endif diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 78e4de4..c4cb1c4 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1447,6 +1447,11 @@ static int i8042_remove(struct platform_device *dev) return 0; } +static struct of_device_id i8042_dt_ids[] = { + { .compatible = "intel,8042" }, + { /* Sentinel */ }, +}; + static struct platform_driver i8042_driver = { .driver = { .name = "i8042", @@ -1454,6 +1459,7 @@ static struct platform_driver i8042_driver = { #ifdef CONFIG_PM .pm = &i8042_pm_ops, #endif + .of_match_table = i8042_dt_ids, }, .remove = i8042_remove, .shutdown = i8042_shutdown, @@ -1461,7 +1467,9 @@ static struct platform_driver i8042_driver = { static int __init i8042_init(void) { +#ifndef CONFIG_SERIO_I8042_DT struct platform_device *pdev; +#endif int err; dbg_init(); @@ -1474,12 +1482,17 @@ static int __init i8042_init(void) if (err) goto err_platform_exit; +#ifdef CONFIG_SERIO_I8042_DT + err = platform_driver_probe(&i8042_driver, i8042_probe); + if (err) + goto err_platform_exit; +#else pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); if (IS_ERR(pdev)) { err = PTR_ERR(pdev); goto err_platform_exit; } - +#endif panic_blink = i8042_panic_blink; return 0; diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index 3452708..c8d70d9 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -14,7 +14,9 @@ * Arch-dependent inline functions and defines. */ -#if defined(CONFIG_MACH_JAZZ) +#if defined(CONFIG_SERIO_I8042_DT) +#include "i8042-dt.h" +#elif defined(CONFIG_MACH_JAZZ) #include "i8042-jazzio.h" #elif defined(CONFIG_SGI_HAS_I8042) #include "i8042-ip22io.h" -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html