]> Git Repo - linux.git/blob - drivers/platform/arm64/acer-aspire1-ec.c
Linux 6.14-rc3
[linux.git] / drivers / platform / arm64 / acer-aspire1-ec.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2024, Nikita Travkin <[email protected]> */
3
4 #include <linux/unaligned.h>
5 #include <drm/drm_bridge.h>
6 #include <linux/bits.h>
7 #include <linux/delay.h>
8 #include <linux/i2c.h>
9 #include <linux/input.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/power_supply.h>
13 #include <linux/usb/typec_mux.h>
14 #include <linux/workqueue_types.h>
15
16 #define MILLI_TO_MICRO                  1000
17
18 #define ASPIRE_EC_EVENT                 0x05
19
20 #define ASPIRE_EC_EVENT_WATCHDOG        0x20
21 #define ASPIRE_EC_EVENT_KBD_BKL_ON      0x57
22 #define ASPIRE_EC_EVENT_KBD_BKL_OFF     0x58
23 #define ASPIRE_EC_EVENT_LID_CLOSE       0x9b
24 #define ASPIRE_EC_EVENT_LID_OPEN        0x9c
25 #define ASPIRE_EC_EVENT_BKL_UNBLANKED   0x9d
26 #define ASPIRE_EC_EVENT_BKL_BLANKED     0x9e
27 #define ASPIRE_EC_EVENT_FG_INF_CHG      0x85
28 #define ASPIRE_EC_EVENT_FG_STA_CHG      0xc6
29 #define ASPIRE_EC_EVENT_HPD_DIS         0xa3
30 #define ASPIRE_EC_EVENT_HPD_CON         0xa4
31
32 #define ASPIRE_EC_FG_DYNAMIC            0x07
33 #define ASPIRE_EC_FG_STATIC             0x08
34
35 #define ASPIRE_EC_FG_FLAG_PRESENT       BIT(0)
36 #define ASPIRE_EC_FG_FLAG_FULL          BIT(1)
37 #define ASPIRE_EC_FG_FLAG_DISCHARGING   BIT(2)
38 #define ASPIRE_EC_FG_FLAG_CHARGING      BIT(3)
39
40 #define ASPIRE_EC_RAM_READ              0x20
41 #define ASPIRE_EC_RAM_WRITE             0x21
42
43 #define ASPIRE_EC_RAM_WATCHDOG          0x19
44 #define ASPIRE_EC_WATCHDOG_BIT          BIT(6)
45
46 #define ASPIRE_EC_RAM_KBD_MODE          0x43
47
48 #define ASPIRE_EC_RAM_KBD_FN_EN         BIT(0)
49 #define ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP  BIT(5)
50 #define ASPIRE_EC_RAM_KBD_ALWAYS_SET    BIT(6)
51 #define ASPIRE_EC_RAM_KBD_NUM_LAYER_EN  BIT(7)
52
53 #define ASPIRE_EC_RAM_KBD_MODE_2        0x60
54
55 #define ASPIRE_EC_RAM_KBD_MEDIA_NOTIFY  BIT(3)
56
57 #define ASPIRE_EC_RAM_HPD_STATUS        0xf4
58 #define ASPIRE_EC_HPD_CONNECTED         0x03
59
60 #define ASPIRE_EC_RAM_LID_STATUS        0x4c
61 #define ASPIRE_EC_LID_OPEN              BIT(6)
62
63 #define ASPIRE_EC_RAM_ADP               0x40
64 #define ASPIRE_EC_AC_STATUS             BIT(0)
65
66 struct aspire_ec {
67         struct i2c_client *client;
68         struct power_supply *bat_psy;
69         struct power_supply *adp_psy;
70         struct input_dev *idev;
71
72         bool bridge_configured;
73         struct drm_bridge bridge;
74         struct work_struct work;
75 };
76
77 static int aspire_ec_ram_read(struct i2c_client *client, u8 off, u8 *data, u8 data_len)
78 {
79         i2c_smbus_write_byte_data(client, ASPIRE_EC_RAM_READ, off);
80         i2c_smbus_read_i2c_block_data(client, ASPIRE_EC_RAM_READ, data_len, data);
81         return 0;
82 }
83
84 static int aspire_ec_ram_write(struct i2c_client *client, u8 off, u8 data)
85 {
86         u8 tmp[2] = {off, data};
87
88         i2c_smbus_write_i2c_block_data(client, ASPIRE_EC_RAM_WRITE, sizeof(tmp), tmp);
89         return 0;
90 }
91
92 static irqreturn_t aspire_ec_irq_handler(int irq, void *data)
93 {
94         struct aspire_ec *ec = data;
95         int id;
96         u8 tmp;
97
98         /*
99          * The original ACPI firmware actually has a small sleep in the handler.
100          *
101          * It seems like in most cases it's not needed but when the device
102          * just exits suspend, our i2c driver has a brief time where data
103          * transfer is not possible yet. So this delay allows us to suppress
104          * quite a bunch of spurious error messages in dmesg. Thus it's kept.
105          */
106         usleep_range(15000, 30000);
107
108         id = i2c_smbus_read_byte_data(ec->client, ASPIRE_EC_EVENT);
109         if (id < 0) {
110                 dev_err(&ec->client->dev, "Failed to read event id: %pe\n", ERR_PTR(id));
111                 return IRQ_HANDLED;
112         }
113
114         switch (id) {
115         case 0x0: /* No event */
116                 break;
117
118         case ASPIRE_EC_EVENT_WATCHDOG:
119                 /*
120                  * Here acpi responds to the event and clears some bit.
121                  * Notify (\_SB.I2C3.BAT1, 0x81) // Information Change
122                  * Notify (\_SB.I2C3.ADP1, 0x80) // Status Change
123                  */
124                 aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_WATCHDOG, &tmp, sizeof(tmp));
125                 tmp &= ~ASPIRE_EC_WATCHDOG_BIT;
126                 aspire_ec_ram_write(ec->client, ASPIRE_EC_RAM_WATCHDOG, tmp);
127                 break;
128
129         case ASPIRE_EC_EVENT_LID_CLOSE:
130                 /* Notify (\_SB.LID0, 0x80) // Status Change */
131                 input_report_switch(ec->idev, SW_LID, 1);
132                 input_sync(ec->idev);
133                 break;
134
135         case ASPIRE_EC_EVENT_LID_OPEN:
136                 /* Notify (\_SB.LID0, 0x80) // Status Change */
137                 input_report_switch(ec->idev, SW_LID, 0);
138                 input_sync(ec->idev);
139                 break;
140
141         case ASPIRE_EC_EVENT_FG_INF_CHG:
142                 /* Notify (\_SB.I2C3.BAT1, 0x81) // Information Change */
143                 fallthrough;
144         case ASPIRE_EC_EVENT_FG_STA_CHG:
145                 /* Notify (\_SB.I2C3.BAT1, 0x80) // Status Change */
146                 power_supply_changed(ec->bat_psy);
147                 power_supply_changed(ec->adp_psy);
148                 break;
149
150         case ASPIRE_EC_EVENT_HPD_DIS:
151                 if (ec->bridge_configured)
152                         drm_bridge_hpd_notify(&ec->bridge, connector_status_disconnected);
153                 break;
154
155         case ASPIRE_EC_EVENT_HPD_CON:
156                 if (ec->bridge_configured)
157                         drm_bridge_hpd_notify(&ec->bridge, connector_status_connected);
158                 break;
159
160         case ASPIRE_EC_EVENT_BKL_BLANKED:
161         case ASPIRE_EC_EVENT_BKL_UNBLANKED:
162                 /* Display backlight blanked on FN+F6. No action needed. */
163                 break;
164
165         case ASPIRE_EC_EVENT_KBD_BKL_ON:
166         case ASPIRE_EC_EVENT_KBD_BKL_OFF:
167                 /*
168                  * There is a keyboard backlight connector on Aspire 1 that is
169                  * controlled by FN+F8. There is no kb backlight on the device though.
170                  * Seems like this is used on other devices like Acer Spin 7.
171                  * No action needed.
172                  */
173                 break;
174
175         default:
176                 dev_warn(&ec->client->dev, "Unknown event id=0x%x\n", id);
177         }
178
179         return IRQ_HANDLED;
180 }
181
182 /*
183  * Power supply.
184  */
185
186 struct aspire_ec_bat_psy_static_data {
187         u8 unk1;
188         u8 flags;
189         __le16 unk2;
190         __le16 voltage_design;
191         __le16 capacity_full;
192         __le16 unk3;
193         __le16 serial;
194         u8 model_id;
195         u8 vendor_id;
196 } __packed;
197
198 static const char * const aspire_ec_bat_psy_battery_model[] = {
199         "AP18C4K",
200         "AP18C8K",
201         "AP19B8K",
202         "AP16M4J",
203         "AP16M5J",
204 };
205
206 static const char * const aspire_ec_bat_psy_battery_vendor[] = {
207         "SANYO",
208         "SONY",
209         "PANASONIC",
210         "SAMSUNG",
211         "SIMPLO",
212         "MOTOROLA",
213         "CELXPERT",
214         "LGC",
215         "GETAC",
216         "MURATA",
217 };
218
219 struct aspire_ec_bat_psy_dynamic_data {
220         u8 unk1;
221         u8 flags;
222         u8 unk2;
223         __le16 capacity_now;
224         __le16 voltage_now;
225         __le16 current_now;
226         __le16 unk3;
227         __le16 unk4;
228 } __packed;
229
230 static int aspire_ec_bat_psy_get_property(struct power_supply *psy,
231                                       enum power_supply_property psp,
232                                       union power_supply_propval *val)
233 {
234         struct aspire_ec *ec = power_supply_get_drvdata(psy);
235         struct aspire_ec_bat_psy_static_data sdat;
236         struct aspire_ec_bat_psy_dynamic_data ddat;
237         int str_index = 0;
238
239         i2c_smbus_read_i2c_block_data(ec->client, ASPIRE_EC_FG_STATIC, sizeof(sdat), (u8 *)&sdat);
240         i2c_smbus_read_i2c_block_data(ec->client, ASPIRE_EC_FG_DYNAMIC, sizeof(ddat), (u8 *)&ddat);
241
242         switch (psp) {
243         case POWER_SUPPLY_PROP_STATUS:
244                 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
245                 if (ddat.flags & ASPIRE_EC_FG_FLAG_CHARGING)
246                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
247                 else if (ddat.flags & ASPIRE_EC_FG_FLAG_DISCHARGING)
248                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
249                 else if (ddat.flags & ASPIRE_EC_FG_FLAG_FULL)
250                         val->intval = POWER_SUPPLY_STATUS_FULL;
251                 break;
252
253         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
254                 val->intval = get_unaligned_le16(&ddat.voltage_now) * MILLI_TO_MICRO;
255                 break;
256
257         case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
258                 val->intval = le16_to_cpu(sdat.voltage_design) * MILLI_TO_MICRO;
259                 break;
260
261         case POWER_SUPPLY_PROP_CHARGE_NOW:
262                 val->intval = get_unaligned_le16(&ddat.capacity_now) * MILLI_TO_MICRO;
263                 break;
264
265         case POWER_SUPPLY_PROP_CHARGE_FULL:
266                 val->intval = le16_to_cpu(sdat.capacity_full) * MILLI_TO_MICRO;
267                 break;
268
269         case POWER_SUPPLY_PROP_CAPACITY:
270                 val->intval = get_unaligned_le16(&ddat.capacity_now) * 100;
271                 val->intval /= le16_to_cpu(sdat.capacity_full);
272                 break;
273
274         case POWER_SUPPLY_PROP_CURRENT_NOW:
275                 val->intval = (s16)get_unaligned_le16(&ddat.current_now) * MILLI_TO_MICRO;
276                 break;
277
278         case POWER_SUPPLY_PROP_PRESENT:
279                 val->intval = !!(ddat.flags & ASPIRE_EC_FG_FLAG_PRESENT);
280                 break;
281
282         case POWER_SUPPLY_PROP_SCOPE:
283                 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
284                 break;
285
286         case POWER_SUPPLY_PROP_MODEL_NAME:
287                 str_index = sdat.model_id - 1;
288
289                 if (str_index >= 0 && str_index < ARRAY_SIZE(aspire_ec_bat_psy_battery_model))
290                         val->strval = aspire_ec_bat_psy_battery_model[str_index];
291                 else
292                         val->strval = "Unknown";
293                 break;
294
295         case POWER_SUPPLY_PROP_MANUFACTURER:
296                 str_index = sdat.vendor_id - 3; /* ACPI uses 3 as an offset here. */
297
298                 if (str_index >= 0 && str_index < ARRAY_SIZE(aspire_ec_bat_psy_battery_vendor))
299                         val->strval = aspire_ec_bat_psy_battery_vendor[str_index];
300                 else
301                         val->strval = "Unknown";
302                 break;
303
304         default:
305                 return -EINVAL;
306         }
307
308         return 0;
309 }
310
311 static enum power_supply_property aspire_ec_bat_psy_props[] = {
312         POWER_SUPPLY_PROP_STATUS,
313         POWER_SUPPLY_PROP_VOLTAGE_NOW,
314         POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
315         POWER_SUPPLY_PROP_CHARGE_NOW,
316         POWER_SUPPLY_PROP_CHARGE_FULL,
317         POWER_SUPPLY_PROP_CAPACITY,
318         POWER_SUPPLY_PROP_CURRENT_NOW,
319         POWER_SUPPLY_PROP_PRESENT,
320         POWER_SUPPLY_PROP_SCOPE,
321         POWER_SUPPLY_PROP_MODEL_NAME,
322         POWER_SUPPLY_PROP_MANUFACTURER,
323 };
324
325 static const struct power_supply_desc aspire_ec_bat_psy_desc = {
326         .name           = "aspire-ec-bat",
327         .type           = POWER_SUPPLY_TYPE_BATTERY,
328         .get_property   = aspire_ec_bat_psy_get_property,
329         .properties     = aspire_ec_bat_psy_props,
330         .num_properties = ARRAY_SIZE(aspire_ec_bat_psy_props),
331 };
332
333 static int aspire_ec_adp_psy_get_property(struct power_supply *psy,
334                                       enum power_supply_property psp,
335                                       union power_supply_propval *val)
336 {
337         struct aspire_ec *ec = power_supply_get_drvdata(psy);
338         u8 tmp;
339
340         switch (psp) {
341         case POWER_SUPPLY_PROP_ONLINE:
342                 aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_ADP, &tmp, sizeof(tmp));
343                 val->intval = !!(tmp & ASPIRE_EC_AC_STATUS);
344                 break;
345
346         default:
347                 return -EINVAL;
348         }
349
350         return 0;
351 }
352
353 static enum power_supply_property aspire_ec_adp_psy_props[] = {
354         POWER_SUPPLY_PROP_ONLINE,
355 };
356
357 static const struct power_supply_desc aspire_ec_adp_psy_desc = {
358         .name           = "aspire-ec-adp",
359         .type           = POWER_SUPPLY_TYPE_MAINS,
360         .get_property   = aspire_ec_adp_psy_get_property,
361         .properties     = aspire_ec_adp_psy_props,
362         .num_properties = ARRAY_SIZE(aspire_ec_adp_psy_props),
363 };
364
365 /*
366  * USB-C DP Alt mode HPD.
367  */
368
369 static int aspire_ec_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
370 {
371         return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
372 }
373
374 static void aspire_ec_bridge_update_hpd_work(struct work_struct *work)
375 {
376         struct aspire_ec *ec = container_of(work, struct aspire_ec, work);
377         u8 tmp;
378
379         aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_HPD_STATUS, &tmp, sizeof(tmp));
380         if (tmp == ASPIRE_EC_HPD_CONNECTED)
381                 drm_bridge_hpd_notify(&ec->bridge, connector_status_connected);
382         else
383                 drm_bridge_hpd_notify(&ec->bridge, connector_status_disconnected);
384 }
385
386 static void aspire_ec_bridge_hpd_enable(struct drm_bridge *bridge)
387 {
388         struct aspire_ec *ec = container_of(bridge, struct aspire_ec, bridge);
389
390         schedule_work(&ec->work);
391 }
392
393 static const struct drm_bridge_funcs aspire_ec_bridge_funcs = {
394         .hpd_enable = aspire_ec_bridge_hpd_enable,
395         .attach = aspire_ec_bridge_attach,
396 };
397
398 /*
399  * Sysfs attributes.
400  */
401
402 static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf)
403 {
404         struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev));
405         u8 tmp;
406
407         aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_KBD_MODE, &tmp, sizeof(tmp));
408
409         return sysfs_emit(buf, "%u\n", !(tmp & ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP));
410 }
411
412 static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr,
413                              const char *buf, size_t count)
414 {
415         struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev));
416         u8 tmp;
417
418         bool state;
419         int ret;
420
421         ret = kstrtobool(buf, &state);
422         if (ret)
423                 return ret;
424
425         aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_KBD_MODE, &tmp, sizeof(tmp));
426
427         if (state)
428                 tmp &= ~ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP;
429         else
430                 tmp |= ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP;
431
432         aspire_ec_ram_write(ec->client, ASPIRE_EC_RAM_KBD_MODE, tmp);
433
434         return count;
435 }
436
437 static DEVICE_ATTR_RW(fn_lock);
438
439 static struct attribute *aspire_ec_attrs[] = {
440         &dev_attr_fn_lock.attr,
441         NULL
442 };
443 ATTRIBUTE_GROUPS(aspire_ec);
444
445 static int aspire_ec_probe(struct i2c_client *client)
446 {
447         struct power_supply_config psy_cfg = {0};
448         struct device *dev = &client->dev;
449         struct fwnode_handle *fwnode;
450         struct aspire_ec *ec;
451         int ret;
452         u8 tmp;
453
454         ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
455         if (!ec)
456                 return -ENOMEM;
457
458         ec->client = client;
459         i2c_set_clientdata(client, ec);
460
461         /* Battery status reports */
462         psy_cfg.drv_data = ec;
463         ec->bat_psy = devm_power_supply_register(dev, &aspire_ec_bat_psy_desc, &psy_cfg);
464         if (IS_ERR(ec->bat_psy))
465                 return dev_err_probe(dev, PTR_ERR(ec->bat_psy),
466                                      "Failed to register battery power supply\n");
467
468         ec->adp_psy = devm_power_supply_register(dev, &aspire_ec_adp_psy_desc, &psy_cfg);
469         if (IS_ERR(ec->adp_psy))
470                 return dev_err_probe(dev, PTR_ERR(ec->adp_psy),
471                                      "Failed to register AC power supply\n");
472
473         /* Lid switch */
474         ec->idev = devm_input_allocate_device(dev);
475         if (!ec->idev)
476                 return -ENOMEM;
477
478         ec->idev->name = "aspire-ec";
479         ec->idev->phys = "aspire-ec/input0";
480         input_set_capability(ec->idev, EV_SW, SW_LID);
481
482         ret = input_register_device(ec->idev);
483         if (ret)
484                 return dev_err_probe(dev, ret, "Input device register failed\n");
485
486         /* Enable the keyboard fn keys */
487         tmp = ASPIRE_EC_RAM_KBD_FN_EN | ASPIRE_EC_RAM_KBD_ALWAYS_SET;
488         tmp |= ASPIRE_EC_RAM_KBD_MEDIA_ON_TOP;
489         aspire_ec_ram_write(client, ASPIRE_EC_RAM_KBD_MODE, tmp);
490
491         aspire_ec_ram_read(client, ASPIRE_EC_RAM_KBD_MODE_2, &tmp, sizeof(tmp));
492         tmp |= ASPIRE_EC_RAM_KBD_MEDIA_NOTIFY;
493         aspire_ec_ram_write(client, ASPIRE_EC_RAM_KBD_MODE_2, tmp);
494
495         /* External Type-C display attach reports */
496         fwnode = device_get_named_child_node(dev, "connector");
497         if (fwnode) {
498                 INIT_WORK(&ec->work, aspire_ec_bridge_update_hpd_work);
499                 ec->bridge.funcs = &aspire_ec_bridge_funcs;
500                 ec->bridge.of_node = to_of_node(fwnode);
501                 ec->bridge.ops = DRM_BRIDGE_OP_HPD;
502                 ec->bridge.type = DRM_MODE_CONNECTOR_USB;
503
504                 ret = devm_drm_bridge_add(dev, &ec->bridge);
505                 if (ret) {
506                         fwnode_handle_put(fwnode);
507                         return dev_err_probe(dev, ret, "Failed to register drm bridge\n");
508                 }
509
510                 ec->bridge_configured = true;
511         }
512
513         ret = devm_request_threaded_irq(dev, client->irq, NULL,
514                                         aspire_ec_irq_handler, IRQF_ONESHOT,
515                                         dev_name(dev), ec);
516         if (ret)
517                 return dev_err_probe(dev, ret, "Failed to request irq\n");
518
519         return 0;
520 }
521
522 static int aspire_ec_resume(struct device *dev)
523 {
524         struct aspire_ec *ec = i2c_get_clientdata(to_i2c_client(dev));
525         u8 tmp;
526
527         aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_LID_STATUS, &tmp, sizeof(tmp));
528         input_report_switch(ec->idev, SW_LID, !!(tmp & ASPIRE_EC_LID_OPEN));
529         input_sync(ec->idev);
530
531         return 0;
532 }
533
534 static const struct i2c_device_id aspire_ec_id[] = {
535         { "aspire1-ec", },
536         { }
537 };
538 MODULE_DEVICE_TABLE(i2c, aspire_ec_id);
539
540 static const struct of_device_id aspire_ec_of_match[] = {
541         { .compatible = "acer,aspire1-ec", },
542         { }
543 };
544 MODULE_DEVICE_TABLE(of, aspire_ec_of_match);
545
546 static DEFINE_SIMPLE_DEV_PM_OPS(aspire_ec_pm_ops, NULL, aspire_ec_resume);
547
548 static struct i2c_driver aspire_ec_driver = {
549         .driver = {
550                 .name = "aspire-ec",
551                 .of_match_table = aspire_ec_of_match,
552                 .pm = pm_sleep_ptr(&aspire_ec_pm_ops),
553                 .dev_groups = aspire_ec_groups,
554         },
555         .probe = aspire_ec_probe,
556         .id_table = aspire_ec_id,
557 };
558 module_i2c_driver(aspire_ec_driver);
559
560 MODULE_DESCRIPTION("Acer Aspire 1 embedded controller");
561 MODULE_AUTHOR("Nikita Travkin <[email protected]>");
562 MODULE_LICENSE("GPL");
This page took 0.066104 seconds and 4 git commands to generate.