1 // SPDX-License-Identifier: GPL-2.0-only
3 * Cypress StreetFighter Touchkey Driver
5 * Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
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>
16 #include <linux/regulator/consumer.h>
18 #define CYPRESS_SF_DEV_NAME "cypress-sf"
20 #define CYPRESS_SF_REG_BUTTON_STATUS 0x4a
22 struct cypress_sf_data
{
23 struct i2c_client
*client
;
24 struct input_dev
*input_dev
;
25 struct regulator_bulk_data regulators
[2];
27 unsigned long keystates
;
31 static irqreturn_t
cypress_sf_irq_handler(int irq
, void *devid
)
33 struct cypress_sf_data
*touchkey
= devid
;
34 unsigned long keystates
, changed
;
38 val
= i2c_smbus_read_byte_data(touchkey
->client
,
39 CYPRESS_SF_REG_BUTTON_STATUS
);
41 dev_err(&touchkey
->client
->dev
,
42 "Failed to read button status: %d", val
);
47 bitmap_xor(&changed
, &keystates
, &touchkey
->keystates
,
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
);
58 input_sync(touchkey
->input_dev
);
59 touchkey
->keystates
= keystates
;
64 static void cypress_sf_disable_regulators(void *arg
)
66 struct cypress_sf_data
*touchkey
= arg
;
68 regulator_bulk_disable(ARRAY_SIZE(touchkey
->regulators
),
69 touchkey
->regulators
);
72 static int cypress_sf_probe(struct i2c_client
*client
)
74 struct cypress_sf_data
*touchkey
;
77 touchkey
= devm_kzalloc(&client
->dev
, sizeof(*touchkey
), GFP_KERNEL
);
81 touchkey
->client
= client
;
82 i2c_set_clientdata(client
, touchkey
);
84 touchkey
->regulators
[0].supply
= "vdd";
85 touchkey
->regulators
[1].supply
= "avdd";
87 error
= devm_regulator_bulk_get(&client
->dev
,
88 ARRAY_SIZE(touchkey
->regulators
),
89 touchkey
->regulators
);
91 dev_err(&client
->dev
, "Failed to get regulators: %d\n", error
);
95 touchkey
->num_keys
= device_property_read_u32_array(&client
->dev
,
98 if (touchkey
->num_keys
< 0) {
99 /* Default key count */
100 touchkey
->num_keys
= 2;
103 touchkey
->keycodes
= devm_kcalloc(&client
->dev
,
105 sizeof(*touchkey
->keycodes
),
107 if (!touchkey
->keycodes
)
110 error
= device_property_read_u32_array(&client
->dev
, "linux,keycodes",
115 dev_warn(&client
->dev
,
116 "Failed to read keycodes: %d, using defaults\n",
119 /* Default keycodes */
120 touchkey
->keycodes
[0] = KEY_BACK
;
121 touchkey
->keycodes
[1] = KEY_MENU
;
124 error
= regulator_bulk_enable(ARRAY_SIZE(touchkey
->regulators
),
125 touchkey
->regulators
);
127 dev_err(&client
->dev
,
128 "Failed to enable regulators: %d\n", error
);
132 error
= devm_add_action_or_reset(&client
->dev
,
133 cypress_sf_disable_regulators
,
138 touchkey
->input_dev
= devm_input_allocate_device(&client
->dev
);
139 if (!touchkey
->input_dev
) {
140 dev_err(&client
->dev
, "Failed to allocate input device\n");
144 touchkey
->input_dev
->name
= CYPRESS_SF_DEV_NAME
;
145 touchkey
->input_dev
->id
.bustype
= BUS_I2C
;
147 for (key
= 0; key
< touchkey
->num_keys
; ++key
)
148 input_set_capability(touchkey
->input_dev
,
149 EV_KEY
, touchkey
->keycodes
[key
]);
151 error
= input_register_device(touchkey
->input_dev
);
153 dev_err(&client
->dev
,
154 "Failed to register input device: %d\n", error
);
158 error
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
159 NULL
, cypress_sf_irq_handler
,
161 CYPRESS_SF_DEV_NAME
, touchkey
);
163 dev_err(&client
->dev
,
164 "Failed to register threaded irq: %d", error
);
171 static int cypress_sf_suspend(struct device
*dev
)
173 struct i2c_client
*client
= to_i2c_client(dev
);
174 struct cypress_sf_data
*touchkey
= i2c_get_clientdata(client
);
177 disable_irq(client
->irq
);
179 error
= regulator_bulk_disable(ARRAY_SIZE(touchkey
->regulators
),
180 touchkey
->regulators
);
182 dev_err(dev
, "Failed to disable regulators: %d", error
);
183 enable_irq(client
->irq
);
190 static int cypress_sf_resume(struct device
*dev
)
192 struct i2c_client
*client
= to_i2c_client(dev
);
193 struct cypress_sf_data
*touchkey
= i2c_get_clientdata(client
);
196 error
= regulator_bulk_enable(ARRAY_SIZE(touchkey
->regulators
),
197 touchkey
->regulators
);
199 dev_err(dev
, "Failed to enable regulators: %d", error
);
203 enable_irq(client
->irq
);
208 static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops
,
209 cypress_sf_suspend
, cypress_sf_resume
);
211 static struct i2c_device_id cypress_sf_id_table
[] = {
212 { CYPRESS_SF_DEV_NAME
},
215 MODULE_DEVICE_TABLE(i2c
, cypress_sf_id_table
);
218 static const struct of_device_id cypress_sf_of_match
[] = {
219 { .compatible
= "cypress,sf3155", },
222 MODULE_DEVICE_TABLE(of
, cypress_sf_of_match
);
225 static struct i2c_driver cypress_sf_driver
= {
227 .name
= CYPRESS_SF_DEV_NAME
,
228 .pm
= pm_sleep_ptr(&cypress_sf_pm_ops
),
229 .of_match_table
= of_match_ptr(cypress_sf_of_match
),
231 .id_table
= cypress_sf_id_table
,
232 .probe
= cypress_sf_probe
,
234 module_i2c_driver(cypress_sf_driver
);
236 MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
237 MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver");
238 MODULE_LICENSE("GPL v2");