Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Cypress StreetFighter Touchkey Driver
0004  *
0005  * Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
0006  */
0007 
0008 #include <linux/bitmap.h>
0009 #include <linux/bitops.h>
0010 #include <linux/device.h>
0011 #include <linux/i2c.h>
0012 #include <linux/input.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/module.h>
0015 #include <linux/pm.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #define CYPRESS_SF_DEV_NAME "cypress-sf"
0019 
0020 #define CYPRESS_SF_REG_BUTTON_STATUS    0x4a
0021 
0022 struct cypress_sf_data {
0023     struct i2c_client *client;
0024     struct input_dev *input_dev;
0025     struct regulator_bulk_data regulators[2];
0026     u32 *keycodes;
0027     unsigned long keystates;
0028     int num_keys;
0029 };
0030 
0031 static irqreturn_t cypress_sf_irq_handler(int irq, void *devid)
0032 {
0033     struct cypress_sf_data *touchkey = devid;
0034     unsigned long keystates, changed;
0035     bool new_state;
0036     int val, key;
0037 
0038     val = i2c_smbus_read_byte_data(touchkey->client,
0039                        CYPRESS_SF_REG_BUTTON_STATUS);
0040     if (val < 0) {
0041         dev_err(&touchkey->client->dev,
0042             "Failed to read button status: %d", val);
0043         return IRQ_NONE;
0044     }
0045     keystates = val;
0046 
0047     bitmap_xor(&changed, &keystates, &touchkey->keystates,
0048            touchkey->num_keys);
0049 
0050     for_each_set_bit(key, &changed, touchkey->num_keys) {
0051         new_state = keystates & BIT(key);
0052         dev_dbg(&touchkey->client->dev,
0053             "Key %d changed to %d", key, new_state);
0054         input_report_key(touchkey->input_dev,
0055                  touchkey->keycodes[key], new_state);
0056     }
0057 
0058     input_sync(touchkey->input_dev);
0059     touchkey->keystates = keystates;
0060 
0061     return IRQ_HANDLED;
0062 }
0063 
0064 static void cypress_sf_disable_regulators(void *arg)
0065 {
0066     struct cypress_sf_data *touchkey = arg;
0067 
0068     regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
0069                    touchkey->regulators);
0070 }
0071 
0072 static int cypress_sf_probe(struct i2c_client *client)
0073 {
0074     struct cypress_sf_data *touchkey;
0075     int key, error;
0076 
0077     touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
0078     if (!touchkey)
0079         return -ENOMEM;
0080 
0081     touchkey->client = client;
0082     i2c_set_clientdata(client, touchkey);
0083 
0084     touchkey->regulators[0].supply = "vdd";
0085     touchkey->regulators[1].supply = "avdd";
0086 
0087     error = devm_regulator_bulk_get(&client->dev,
0088                     ARRAY_SIZE(touchkey->regulators),
0089                     touchkey->regulators);
0090     if (error) {
0091         dev_err(&client->dev, "Failed to get regulators: %d\n", error);
0092         return error;
0093     }
0094 
0095     touchkey->num_keys = device_property_read_u32_array(&client->dev,
0096                                 "linux,keycodes",
0097                                 NULL, 0);
0098     if (touchkey->num_keys < 0) {
0099         /* Default key count */
0100         touchkey->num_keys = 2;
0101     }
0102 
0103     touchkey->keycodes = devm_kcalloc(&client->dev,
0104                       touchkey->num_keys,
0105                       sizeof(*touchkey->keycodes),
0106                       GFP_KERNEL);
0107     if (!touchkey->keycodes)
0108         return -ENOMEM;
0109 
0110     error = device_property_read_u32_array(&client->dev, "linux,keycodes",
0111                            touchkey->keycodes,
0112                            touchkey->num_keys);
0113 
0114     if (error) {
0115         dev_warn(&client->dev,
0116              "Failed to read keycodes: %d, using defaults\n",
0117              error);
0118 
0119         /* Default keycodes */
0120         touchkey->keycodes[0] = KEY_BACK;
0121         touchkey->keycodes[1] = KEY_MENU;
0122     }
0123 
0124     error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
0125                       touchkey->regulators);
0126     if (error) {
0127         dev_err(&client->dev,
0128             "Failed to enable regulators: %d\n", error);
0129         return error;
0130     }
0131 
0132     error = devm_add_action_or_reset(&client->dev,
0133                      cypress_sf_disable_regulators,
0134                      touchkey);
0135     if (error)
0136         return error;
0137 
0138     touchkey->input_dev = devm_input_allocate_device(&client->dev);
0139     if (!touchkey->input_dev) {
0140         dev_err(&client->dev, "Failed to allocate input device\n");
0141         return -ENOMEM;
0142     }
0143 
0144     touchkey->input_dev->name = CYPRESS_SF_DEV_NAME;
0145     touchkey->input_dev->id.bustype = BUS_I2C;
0146 
0147     for (key = 0; key < touchkey->num_keys; ++key)
0148         input_set_capability(touchkey->input_dev,
0149                      EV_KEY, touchkey->keycodes[key]);
0150 
0151     error = input_register_device(touchkey->input_dev);
0152     if (error) {
0153         dev_err(&client->dev,
0154             "Failed to register input device: %d\n", error);
0155         return error;
0156     }
0157 
0158     error = devm_request_threaded_irq(&client->dev, client->irq,
0159                       NULL, cypress_sf_irq_handler,
0160                       IRQF_ONESHOT,
0161                       CYPRESS_SF_DEV_NAME, touchkey);
0162     if (error) {
0163         dev_err(&client->dev,
0164             "Failed to register threaded irq: %d", error);
0165         return error;
0166     }
0167 
0168     return 0;
0169 };
0170 
0171 static int __maybe_unused cypress_sf_suspend(struct device *dev)
0172 {
0173     struct i2c_client *client = to_i2c_client(dev);
0174     struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
0175     int error;
0176 
0177     disable_irq(client->irq);
0178 
0179     error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
0180                        touchkey->regulators);
0181     if (error) {
0182         dev_err(dev, "Failed to disable regulators: %d", error);
0183         enable_irq(client->irq);
0184         return error;
0185     }
0186 
0187     return 0;
0188 }
0189 
0190 static int __maybe_unused cypress_sf_resume(struct device *dev)
0191 {
0192     struct i2c_client *client = to_i2c_client(dev);
0193     struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
0194     int error;
0195 
0196     error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
0197                       touchkey->regulators);
0198     if (error) {
0199         dev_err(dev, "Failed to enable regulators: %d", error);
0200         return error;
0201     }
0202 
0203     enable_irq(client->irq);
0204 
0205     return 0;
0206 }
0207 
0208 static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
0209              cypress_sf_suspend, cypress_sf_resume);
0210 
0211 static struct i2c_device_id cypress_sf_id_table[] = {
0212     { CYPRESS_SF_DEV_NAME, 0 },
0213     { }
0214 };
0215 MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
0216 
0217 #ifdef CONFIG_OF
0218 static const struct of_device_id cypress_sf_of_match[] = {
0219     { .compatible = "cypress,sf3155", },
0220     { },
0221 };
0222 MODULE_DEVICE_TABLE(of, cypress_sf_of_match);
0223 #endif
0224 
0225 static struct i2c_driver cypress_sf_driver = {
0226     .driver = {
0227         .name = CYPRESS_SF_DEV_NAME,
0228         .pm = &cypress_sf_pm_ops,
0229         .of_match_table = of_match_ptr(cypress_sf_of_match),
0230     },
0231     .id_table = cypress_sf_id_table,
0232     .probe_new = cypress_sf_probe,
0233 };
0234 module_i2c_driver(cypress_sf_driver);
0235 
0236 MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
0237 MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver");
0238 MODULE_LICENSE("GPL v2");