1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Cypress StreetFighter Touchkey Driver 4 * 5 * Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com> 6 */ 7 8 #include <linux/bitmap.h> 9 #include <linux/bitops.h> 10 #include <linux/device.h> 11 #include <linux/i2c.h> 12 #include <linux/input.h> 13 #include <linux/interrupt.h> 14 #include <linux/module.h> 15 #include <linux/pm.h> 16 #include <linux/regulator/consumer.h> 17 18 #define CYPRESS_SF_DEV_NAME "cypress-sf" 19 20 #define CYPRESS_SF_REG_BUTTON_STATUS 0x4a 21 22 struct cypress_sf_data { 23 struct i2c_client *client; 24 struct input_dev *input_dev; 25 struct regulator_bulk_data regulators[2]; 26 u32 *keycodes; 27 unsigned long keystates; 28 int num_keys; 29 }; 30 31 static irqreturn_t cypress_sf_irq_handler(int irq, void *devid) 32 { 33 struct cypress_sf_data *touchkey = devid; 34 unsigned long keystates, changed; 35 bool new_state; 36 int val, key; 37 38 val = i2c_smbus_read_byte_data(touchkey->client, 39 CYPRESS_SF_REG_BUTTON_STATUS); 40 if (val < 0) { 41 dev_err(&touchkey->client->dev, 42 "Failed to read button status: %d", val); 43 return IRQ_NONE; 44 } 45 keystates = val; 46 47 bitmap_xor(&changed, &keystates, &touchkey->keystates, 48 touchkey->num_keys); 49 50 for_each_set_bit(key, &changed, touchkey->num_keys) { 51 new_state = keystates & BIT(key); 52 dev_dbg(&touchkey->client->dev, 53 "Key %d changed to %d", key, new_state); 54 input_report_key(touchkey->input_dev, 55 touchkey->keycodes[key], new_state); 56 } 57 58 input_sync(touchkey->input_dev); 59 touchkey->keystates = keystates; 60 61 return IRQ_HANDLED; 62 } 63 64 static int cypress_sf_probe(struct i2c_client *client) 65 { 66 struct cypress_sf_data *touchkey; 67 int key, error; 68 69 touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL); 70 if (!touchkey) 71 return -ENOMEM; 72 73 touchkey->client = client; 74 i2c_set_clientdata(client, touchkey); 75 76 touchkey->regulators[0].supply = "vdd"; 77 touchkey->regulators[1].supply = "avdd"; 78 79 error = devm_regulator_bulk_get(&client->dev, 80 ARRAY_SIZE(touchkey->regulators), 81 touchkey->regulators); 82 if (error) { 83 dev_err(&client->dev, "Failed to get regulators: %d\n", error); 84 return error; 85 } 86 87 touchkey->num_keys = device_property_read_u32_array(&client->dev, 88 "linux,keycodes", 89 NULL, 0); 90 if (touchkey->num_keys < 0) { 91 /* Default key count */ 92 touchkey->num_keys = 2; 93 } 94 95 touchkey->keycodes = devm_kcalloc(&client->dev, 96 touchkey->num_keys, 97 sizeof(*touchkey->keycodes), 98 GFP_KERNEL); 99 if (!touchkey->keycodes) 100 return -ENOMEM; 101 102 error = device_property_read_u32_array(&client->dev, "linux,keycodes", 103 touchkey->keycodes, 104 touchkey->num_keys); 105 106 if (error) { 107 dev_warn(&client->dev, 108 "Failed to read keycodes: %d, using defaults\n", 109 error); 110 111 /* Default keycodes */ 112 touchkey->keycodes[0] = KEY_BACK; 113 touchkey->keycodes[1] = KEY_MENU; 114 } 115 116 error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), 117 touchkey->regulators); 118 if (error) { 119 dev_err(&client->dev, 120 "Failed to enable regulators: %d\n", error); 121 return error; 122 } 123 124 touchkey->input_dev = devm_input_allocate_device(&client->dev); 125 if (!touchkey->input_dev) { 126 dev_err(&client->dev, "Failed to allocate input device\n"); 127 return -ENOMEM; 128 } 129 130 touchkey->input_dev->name = CYPRESS_SF_DEV_NAME; 131 touchkey->input_dev->id.bustype = BUS_I2C; 132 133 for (key = 0; key < touchkey->num_keys; ++key) 134 input_set_capability(touchkey->input_dev, 135 EV_KEY, touchkey->keycodes[key]); 136 137 error = input_register_device(touchkey->input_dev); 138 if (error) { 139 dev_err(&client->dev, 140 "Failed to register input device: %d\n", error); 141 return error; 142 } 143 144 error = devm_request_threaded_irq(&client->dev, client->irq, 145 NULL, cypress_sf_irq_handler, 146 IRQF_ONESHOT, 147 CYPRESS_SF_DEV_NAME, touchkey); 148 if (error) { 149 dev_err(&client->dev, 150 "Failed to register threaded irq: %d", error); 151 return error; 152 } 153 154 return 0; 155 }; 156 157 static int __maybe_unused cypress_sf_suspend(struct device *dev) 158 { 159 struct i2c_client *client = to_i2c_client(dev); 160 struct cypress_sf_data *touchkey = i2c_get_clientdata(client); 161 int error; 162 163 disable_irq(client->irq); 164 165 error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators), 166 touchkey->regulators); 167 if (error) { 168 dev_err(dev, "Failed to disable regulators: %d", error); 169 enable_irq(client->irq); 170 return error; 171 } 172 173 return 0; 174 } 175 176 static int __maybe_unused cypress_sf_resume(struct device *dev) 177 { 178 struct i2c_client *client = to_i2c_client(dev); 179 struct cypress_sf_data *touchkey = i2c_get_clientdata(client); 180 int error; 181 182 error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), 183 touchkey->regulators); 184 if (error) { 185 dev_err(dev, "Failed to enable regulators: %d", error); 186 return error; 187 } 188 189 enable_irq(client->irq); 190 191 return 0; 192 } 193 194 static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops, 195 cypress_sf_suspend, cypress_sf_resume); 196 197 static struct i2c_device_id cypress_sf_id_table[] = { 198 { CYPRESS_SF_DEV_NAME, 0 }, 199 { } 200 }; 201 MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table); 202 203 #ifdef CONFIG_OF 204 static const struct of_device_id cypress_sf_of_match[] = { 205 { .compatible = "cypress,sf3155", }, 206 { }, 207 }; 208 MODULE_DEVICE_TABLE(of, cypress_sf_of_match); 209 #endif 210 211 static struct i2c_driver cypress_sf_driver = { 212 .driver = { 213 .name = CYPRESS_SF_DEV_NAME, 214 .pm = &cypress_sf_pm_ops, 215 .of_match_table = of_match_ptr(cypress_sf_of_match), 216 }, 217 .id_table = cypress_sf_id_table, 218 .probe_new = cypress_sf_probe, 219 }; 220 module_i2c_driver(cypress_sf_driver); 221 222 MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>"); 223 MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver"); 224 MODULE_LICENSE("GPL v2"); 225