1 // SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0-or-later
3 * Dell Wyse 3020 a.k.a. "Ariel" Power Button Driver
5 * Copyright (C) 2020 Lubomir Rintel
8 #include <linux/device.h>
10 #include <linux/input.h>
11 #include <linux/interrupt.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/spi/spi.h>
16 #define RESP_COUNTER(response) (response.header & 0x3)
17 #define RESP_SIZE(response) ((response.header >> 2) & 0x3)
18 #define RESP_TYPE(response) ((response.header >> 4) & 0xf)
20 struct ec_input_response
{
26 struct ariel_pwrbutton
{
27 struct spi_device
*client
;
28 struct input_dev
*input
;
32 static int ec_input_read(struct ariel_pwrbutton
*priv
,
33 struct ec_input_response
*response
)
35 u8 read_request
[] = { 0x00, 0x5a, 0xa5, 0x00, 0x00 };
36 struct spi_device
*spi
= priv
->client
;
37 struct spi_transfer t
= {
38 .tx_buf
= read_request
,
40 .len
= sizeof(read_request
),
43 compiletime_assert(sizeof(read_request
) == sizeof(*response
),
44 "SPI xfer request/response size mismatch");
46 return spi_sync_transfer(spi
, &t
, 1);
49 static irqreturn_t
ec_input_interrupt(int irq
, void *dev_id
)
51 struct ariel_pwrbutton
*priv
= dev_id
;
52 struct spi_device
*spi
= priv
->client
;
53 struct ec_input_response response
;
57 error
= ec_input_read(priv
, &response
);
59 dev_err(&spi
->dev
, "EC read failed: %d\n", error
);
63 if (priv
->msg_counter
== RESP_COUNTER(response
)) {
64 dev_warn(&spi
->dev
, "No new data to read?\n");
68 priv
->msg_counter
= RESP_COUNTER(response
);
70 if (RESP_TYPE(response
) != 0x3 && RESP_TYPE(response
) != 0xc) {
71 dev_dbg(&spi
->dev
, "Ignoring message that's not kbd data\n");
75 for (i
= 0; i
< RESP_SIZE(response
); i
++) {
76 switch (response
.data
[i
]) {
78 input_report_key(priv
->input
, KEY_POWER
, 1);
79 input_sync(priv
->input
);
82 input_report_key(priv
->input
, KEY_POWER
, 0);
83 input_sync(priv
->input
);
86 dev_dbg(&spi
->dev
, "Unknown scan code: %02x\n",
95 static int ariel_pwrbutton_probe(struct spi_device
*spi
)
97 struct ec_input_response response
;
98 struct ariel_pwrbutton
*priv
;
102 dev_err(&spi
->dev
, "Missing IRQ.\n");
106 priv
= devm_kzalloc(&spi
->dev
, sizeof(*priv
), GFP_KERNEL
);
111 spi_set_drvdata(spi
, priv
);
113 priv
->input
= devm_input_allocate_device(&spi
->dev
);
116 priv
->input
->name
= "Power Button";
117 priv
->input
->dev
.parent
= &spi
->dev
;
118 input_set_capability(priv
->input
, EV_KEY
, KEY_POWER
);
119 error
= input_register_device(priv
->input
);
121 dev_err(&spi
->dev
, "error registering input device: %d\n", error
);
125 error
= ec_input_read(priv
, &response
);
127 dev_err(&spi
->dev
, "EC read failed: %d\n", error
);
130 priv
->msg_counter
= RESP_COUNTER(response
);
132 error
= devm_request_threaded_irq(&spi
->dev
, spi
->irq
, NULL
,
135 "Ariel EC Input", priv
);
138 dev_err(&spi
->dev
, "Failed to request IRQ %d: %d\n",
146 static const struct of_device_id ariel_pwrbutton_of_match
[] = {
147 { .compatible
= "dell,wyse-ariel-ec-input" },
150 MODULE_DEVICE_TABLE(of
, ariel_pwrbutton_of_match
);
152 static const struct spi_device_id ariel_pwrbutton_spi_ids
[] = {
153 { .name
= "wyse-ariel-ec-input" },
156 MODULE_DEVICE_TABLE(spi
, ariel_pwrbutton_spi_ids
);
158 static struct spi_driver ariel_pwrbutton_driver
= {
160 .name
= "dell-wyse-ariel-ec-input",
161 .of_match_table
= ariel_pwrbutton_of_match
,
163 .probe
= ariel_pwrbutton_probe
,
164 .id_table
= ariel_pwrbutton_spi_ids
,
166 module_spi_driver(ariel_pwrbutton_driver
);
168 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
169 MODULE_DESCRIPTION("Dell Wyse 3020 Power Button Input Driver");
170 MODULE_LICENSE("Dual BSD/GPL");