Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0-or-later
0002 /*
0003  * Dell Wyse 3020 a.k.a. "Ariel" Power Button Driver
0004  *
0005  * Copyright (C) 2020 Lubomir Rintel
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/gfp.h>
0010 #include <linux/input.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/module.h>
0014 #include <linux/spi/spi.h>
0015 
0016 #define RESP_COUNTER(response)  (response.header & 0x3)
0017 #define RESP_SIZE(response) ((response.header >> 2) & 0x3)
0018 #define RESP_TYPE(response) ((response.header >> 4) & 0xf)
0019 
0020 struct ec_input_response {
0021     u8 reserved;
0022     u8 header;
0023     u8 data[3];
0024 } __packed;
0025 
0026 struct ariel_pwrbutton {
0027     struct spi_device *client;
0028     struct input_dev *input;
0029     u8 msg_counter;
0030 };
0031 
0032 static int ec_input_read(struct ariel_pwrbutton *priv,
0033              struct ec_input_response *response)
0034 {
0035     u8 read_request[] = { 0x00, 0x5a, 0xa5, 0x00, 0x00 };
0036     struct spi_device *spi = priv->client;
0037     struct spi_transfer t = {
0038         .tx_buf = read_request,
0039         .rx_buf = response,
0040         .len = sizeof(read_request),
0041     };
0042 
0043     compiletime_assert(sizeof(read_request) == sizeof(*response),
0044                "SPI xfer request/response size mismatch");
0045 
0046     return spi_sync_transfer(spi, &t, 1);
0047 }
0048 
0049 static irqreturn_t ec_input_interrupt(int irq, void *dev_id)
0050 {
0051     struct ariel_pwrbutton *priv = dev_id;
0052     struct spi_device *spi = priv->client;
0053     struct ec_input_response response;
0054     int error;
0055     int i;
0056 
0057     error = ec_input_read(priv, &response);
0058     if (error < 0) {
0059         dev_err(&spi->dev, "EC read failed: %d\n", error);
0060         goto out;
0061     }
0062 
0063     if (priv->msg_counter == RESP_COUNTER(response)) {
0064         dev_warn(&spi->dev, "No new data to read?\n");
0065         goto out;
0066     }
0067 
0068     priv->msg_counter = RESP_COUNTER(response);
0069 
0070     if (RESP_TYPE(response) != 0x3 && RESP_TYPE(response) != 0xc) {
0071         dev_dbg(&spi->dev, "Ignoring message that's not kbd data\n");
0072         goto out;
0073     }
0074 
0075     for (i = 0; i < RESP_SIZE(response); i++) {
0076         switch (response.data[i]) {
0077         case 0x74:
0078             input_report_key(priv->input, KEY_POWER, 1);
0079             input_sync(priv->input);
0080             break;
0081         case 0xf4:
0082             input_report_key(priv->input, KEY_POWER, 0);
0083             input_sync(priv->input);
0084             break;
0085         default:
0086             dev_dbg(&spi->dev, "Unknown scan code: %02x\n",
0087                 response.data[i]);
0088         }
0089     }
0090 
0091 out:
0092     return IRQ_HANDLED;
0093 }
0094 
0095 static int ariel_pwrbutton_probe(struct spi_device *spi)
0096 {
0097     struct ec_input_response response;
0098     struct ariel_pwrbutton *priv;
0099     int error;
0100 
0101     if (!spi->irq) {
0102         dev_err(&spi->dev, "Missing IRQ.\n");
0103         return -EINVAL;
0104     }
0105 
0106     priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
0107     if (!priv)
0108         return -ENOMEM;
0109 
0110     priv->client = spi;
0111     spi_set_drvdata(spi, priv);
0112 
0113     priv->input = devm_input_allocate_device(&spi->dev);
0114     if (!priv->input)
0115         return -ENOMEM;
0116     priv->input->name = "Power Button";
0117     priv->input->dev.parent = &spi->dev;
0118     input_set_capability(priv->input, EV_KEY, KEY_POWER);
0119     error = input_register_device(priv->input);
0120     if (error) {
0121         dev_err(&spi->dev, "error registering input device: %d\n", error);
0122         return error;
0123     }
0124 
0125     error = ec_input_read(priv, &response);
0126     if (error < 0) {
0127         dev_err(&spi->dev, "EC read failed: %d\n", error);
0128         return error;
0129     }
0130     priv->msg_counter = RESP_COUNTER(response);
0131 
0132     error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
0133                       ec_input_interrupt,
0134                       IRQF_ONESHOT,
0135                       "Ariel EC Input", priv);
0136 
0137     if (error) {
0138         dev_err(&spi->dev, "Failed to request IRQ %d: %d\n",
0139             spi->irq, error);
0140         return error;
0141     }
0142 
0143     return 0;
0144 }
0145 
0146 static const struct of_device_id ariel_pwrbutton_of_match[] = {
0147     { .compatible = "dell,wyse-ariel-ec-input" },
0148     { }
0149 };
0150 MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
0151 
0152 static const struct spi_device_id ariel_pwrbutton_spi_ids[] = {
0153     { .name = "wyse-ariel-ec-input" },
0154     { }
0155 };
0156 MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids);
0157 
0158 static struct spi_driver ariel_pwrbutton_driver = {
0159     .driver = {
0160         .name = "dell-wyse-ariel-ec-input",
0161         .of_match_table = ariel_pwrbutton_of_match,
0162     },
0163     .probe = ariel_pwrbutton_probe,
0164     .id_table = ariel_pwrbutton_spi_ids,
0165 };
0166 module_spi_driver(ariel_pwrbutton_driver);
0167 
0168 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
0169 MODULE_DESCRIPTION("Dell Wyse 3020 Power Button Input Driver");
0170 MODULE_LICENSE("Dual BSD/GPL");