1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (C) 2012 Intel, Inc.
7 #include <linux/module.h>
8 #include <linux/interrupt.h>
9 #include <linux/types.h>
10 #include <linux/input.h>
11 #include <linux/kernel.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/irq.h>
16 #include <linux/acpi.h>
25 PAGE_EVBITS
= 0x10000,
26 PAGE_ABSDATA
= 0x20000 | EV_ABS
,
30 struct input_dev
*input
;
36 static irqreturn_t
events_interrupt(int irq
, void *dev_id
)
38 struct event_dev
*edev
= dev_id
;
39 unsigned int type
, code
, value
;
41 type
= __raw_readl(edev
->addr
+ REG_READ
);
42 code
= __raw_readl(edev
->addr
+ REG_READ
);
43 value
= __raw_readl(edev
->addr
+ REG_READ
);
45 input_event(edev
->input
, type
, code
, value
);
46 input_sync(edev
->input
);
50 static void events_import_bits(struct event_dev
*edev
,
51 unsigned long bits
[], unsigned int type
, size_t count
)
53 void __iomem
*addr
= edev
->addr
;
58 __raw_writel(PAGE_EVBITS
| type
, addr
+ REG_SET_PAGE
);
60 size
= __raw_readl(addr
+ REG_LEN
) * 8;
65 for (i
= 0; i
< count
; i
+= 8) {
66 val
= __raw_readb(addr
++);
67 for (j
= 0; j
< 8; j
++)
73 static void events_import_abs_params(struct event_dev
*edev
)
75 struct input_dev
*input_dev
= edev
->input
;
76 void __iomem
*addr
= edev
->addr
;
81 __raw_writel(PAGE_ABSDATA
, addr
+ REG_SET_PAGE
);
83 count
= __raw_readl(addr
+ REG_LEN
) / sizeof(val
);
87 for (i
= 0; i
< count
; i
++) {
88 if (!test_bit(i
, input_dev
->absbit
))
91 for (j
= 0; j
< ARRAY_SIZE(val
); j
++) {
92 int offset
= (i
* ARRAY_SIZE(val
) + j
) * sizeof(u32
);
94 val
[j
] = __raw_readl(edev
->addr
+ REG_DATA
+ offset
);
97 input_set_abs_params(input_dev
, i
,
98 val
[0], val
[1], val
[2], val
[3]);
102 static int events_probe(struct platform_device
*pdev
)
104 struct input_dev
*input_dev
;
105 struct event_dev
*edev
;
106 struct resource
*res
;
107 unsigned int keymapnamelen
;
113 irq
= platform_get_irq(pdev
, 0);
117 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
121 addr
= devm_ioremap(&pdev
->dev
, res
->start
, 4096);
125 __raw_writel(PAGE_NAME
, addr
+ REG_SET_PAGE
);
126 keymapnamelen
= __raw_readl(addr
+ REG_LEN
);
128 edev
= devm_kzalloc(&pdev
->dev
,
129 sizeof(struct event_dev
) + keymapnamelen
+ 1,
134 input_dev
= devm_input_allocate_device(&pdev
->dev
);
138 edev
->input
= input_dev
;
142 for (i
= 0; i
< keymapnamelen
; i
++)
143 edev
->name
[i
] = __raw_readb(edev
->addr
+ REG_DATA
+ i
);
145 pr_debug("%s: keymap=%s\n", __func__
, edev
->name
);
147 input_dev
->name
= edev
->name
;
148 input_dev
->id
.bustype
= BUS_HOST
;
150 events_import_bits(edev
, input_dev
->evbit
, EV_SYN
, EV_MAX
);
151 events_import_bits(edev
, input_dev
->keybit
, EV_KEY
, KEY_MAX
);
152 events_import_bits(edev
, input_dev
->relbit
, EV_REL
, REL_MAX
);
153 events_import_bits(edev
, input_dev
->absbit
, EV_ABS
, ABS_MAX
);
154 events_import_bits(edev
, input_dev
->mscbit
, EV_MSC
, MSC_MAX
);
155 events_import_bits(edev
, input_dev
->ledbit
, EV_LED
, LED_MAX
);
156 events_import_bits(edev
, input_dev
->sndbit
, EV_SND
, SND_MAX
);
157 events_import_bits(edev
, input_dev
->ffbit
, EV_FF
, FF_MAX
);
158 events_import_bits(edev
, input_dev
->swbit
, EV_SW
, SW_MAX
);
160 events_import_abs_params(edev
);
162 error
= devm_request_irq(&pdev
->dev
, edev
->irq
, events_interrupt
, 0,
163 "goldfish-events-keypad", edev
);
167 error
= input_register_device(input_dev
);
174 static const struct of_device_id goldfish_events_of_match
[] = {
175 { .compatible
= "google,goldfish-events-keypad", },
178 MODULE_DEVICE_TABLE(of
, goldfish_events_of_match
);
181 static const struct acpi_device_id goldfish_events_acpi_match
[] = {
185 MODULE_DEVICE_TABLE(acpi
, goldfish_events_acpi_match
);
188 static struct platform_driver events_driver
= {
189 .probe
= events_probe
,
191 .name
= "goldfish_events",
192 .of_match_table
= goldfish_events_of_match
,
193 .acpi_match_table
= ACPI_PTR(goldfish_events_acpi_match
),
197 module_platform_driver(events_driver
);
199 MODULE_AUTHOR("Brian Swetland");
200 MODULE_DESCRIPTION("Goldfish Event Device");
201 MODULE_LICENSE("GPL");