1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2024, Nikita Travkin <nikita@trvn.ru> */ 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 <nikita@trvn.ru>"); 562 MODULE_LICENSE("GPL"); 563