1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * acpi_ac.c - ACPI AC Adapter Driver (Revision: 27) 4 * 5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 7 */ 8 9#define pr_fmt(fmt) "ACPI: AC: " fmt 10 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/slab.h> 14#include <linux/init.h> 15#include <linux/types.h> 16#include <linux/dmi.h> 17#include <linux/delay.h> 18#include <linux/platform_device.h> 19#include <linux/power_supply.h> 20#include <linux/string_choices.h> 21#include <linux/acpi.h> 22#include <acpi/battery.h> 23 24#define ACPI_AC_CLASS "ac_adapter" 25#define ACPI_AC_DEVICE_NAME "AC Adapter" 26#define ACPI_AC_FILE_STATE "state" 27#define ACPI_AC_NOTIFY_STATUS 0x80 28#define ACPI_AC_STATUS_OFFLINE 0x00 29#define ACPI_AC_STATUS_ONLINE 0x01 30#define ACPI_AC_STATUS_UNKNOWN 0xFF 31 32MODULE_AUTHOR("Paul Diefenbaugh"); 33MODULE_DESCRIPTION("ACPI AC Adapter Driver"); 34MODULE_LICENSE("GPL"); 35 36static int acpi_ac_probe(struct platform_device *pdev); 37static void acpi_ac_remove(struct platform_device *pdev); 38 39static void acpi_ac_notify(acpi_handle handle, u32 event, void *data); 40 41static const struct acpi_device_id ac_device_ids[] = { 42 {"ACPI0003", 0}, 43 {"", 0}, 44}; 45MODULE_DEVICE_TABLE(acpi, ac_device_ids); 46 47#ifdef CONFIG_PM_SLEEP 48static int acpi_ac_resume(struct device *dev); 49#endif 50static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); 51 52static int ac_sleep_before_get_state_ms; 53static int ac_only; 54 55struct acpi_ac { 56 struct power_supply *charger; 57 struct power_supply_desc charger_desc; 58 struct acpi_device *device; 59 unsigned long long state; 60 struct notifier_block battery_nb; 61}; 62 63#define to_acpi_ac(x) power_supply_get_drvdata(x) 64 65/* AC Adapter Management */ 66static int acpi_ac_get_state(struct acpi_ac *ac) 67{ 68 acpi_status status = AE_OK; 69 70 if (!ac) 71 return -EINVAL; 72 73 if (ac_only) { 74 ac->state = 1; 75 return 0; 76 } 77 78 status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, 79 &ac->state); 80 if (ACPI_FAILURE(status)) { 81 acpi_handle_info(ac->device->handle, 82 "Error reading AC Adapter state: %s\n", 83 acpi_format_exception(status)); 84 ac->state = ACPI_AC_STATUS_UNKNOWN; 85 return -ENODEV; 86 } 87 88 return 0; 89} 90 91/* sysfs I/F */ 92static int get_ac_property(struct power_supply *psy, 93 enum power_supply_property psp, 94 union power_supply_propval *val) 95{ 96 struct acpi_ac *ac = to_acpi_ac(psy); 97 98 if (!ac) 99 return -ENODEV; 100 101 if (acpi_ac_get_state(ac)) 102 return -ENODEV; 103 104 switch (psp) { 105 case POWER_SUPPLY_PROP_ONLINE: 106 val->intval = ac->state; 107 break; 108 default: 109 return -EINVAL; 110 } 111 112 return 0; 113} 114 115static enum power_supply_property ac_props[] = { 116 POWER_SUPPLY_PROP_ONLINE, 117}; 118 119/* Driver Model */ 120static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) 121{ 122 struct acpi_ac *ac = data; 123 struct acpi_device *adev = ac->device; 124 125 switch (event) { 126 default: 127 acpi_handle_debug(adev->handle, "Unsupported event [0x%x]\n", 128 event); 129 fallthrough; 130 case ACPI_AC_NOTIFY_STATUS: 131 case ACPI_NOTIFY_BUS_CHECK: 132 case ACPI_NOTIFY_DEVICE_CHECK: 133 /* 134 * A buggy BIOS may notify AC first and then sleep for 135 * a specific time before doing actual operations in the 136 * EC event handler (_Qxx). This will cause the AC state 137 * reported by the ACPI event to be incorrect, so wait for a 138 * specific time for the EC event handler to make progress. 139 */ 140 if (ac_sleep_before_get_state_ms > 0) 141 msleep(ac_sleep_before_get_state_ms); 142 143 acpi_ac_get_state(ac); 144 acpi_bus_generate_netlink_event(adev->pnp.device_class, 145 dev_name(&adev->dev), event, 146 (u32) ac->state); 147 acpi_notifier_call_chain(adev, event, (u32) ac->state); 148 kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE); 149 } 150} 151 152static int acpi_ac_battery_notify(struct notifier_block *nb, 153 unsigned long action, void *data) 154{ 155 struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb); 156 struct acpi_bus_event *event = (struct acpi_bus_event *)data; 157 158 /* 159 * On HP Pavilion dv6-6179er AC status notifications aren't triggered 160 * when adapter is plugged/unplugged. However, battery status 161 * notifications are triggered when battery starts charging or 162 * discharging. Re-reading AC status triggers lost AC notifications, 163 * if AC status has changed. 164 */ 165 if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 && 166 event->type == ACPI_BATTERY_NOTIFY_STATUS) 167 acpi_ac_get_state(ac); 168 169 return NOTIFY_OK; 170} 171 172static int __init thinkpad_e530_quirk(const struct dmi_system_id *d) 173{ 174 ac_sleep_before_get_state_ms = 1000; 175 return 0; 176} 177 178static int __init ac_only_quirk(const struct dmi_system_id *d) 179{ 180 ac_only = 1; 181 return 0; 182} 183 184/* Please keep this list alphabetically sorted */ 185static const struct dmi_system_id ac_dmi_table[] __initconst = { 186 { 187 /* Kodlix GK45 returning incorrect state */ 188 .callback = ac_only_quirk, 189 .matches = { 190 DMI_MATCH(DMI_PRODUCT_NAME, "GK45"), 191 }, 192 }, 193 { 194 /* Lenovo Thinkpad e530, see comment in acpi_ac_notify() */ 195 .callback = thinkpad_e530_quirk, 196 .matches = { 197 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 198 DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), 199 }, 200 }, 201 {}, 202}; 203 204static int acpi_ac_probe(struct platform_device *pdev) 205{ 206 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 207 struct power_supply_config psy_cfg = {}; 208 struct acpi_ac *ac; 209 int result; 210 211 ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL); 212 if (!ac) 213 return -ENOMEM; 214 215 ac->device = adev; 216 strcpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME); 217 strcpy(acpi_device_class(adev), ACPI_AC_CLASS); 218 219 platform_set_drvdata(pdev, ac); 220 221 result = acpi_ac_get_state(ac); 222 if (result) 223 goto err_release_ac; 224 225 psy_cfg.drv_data = ac; 226 227 ac->charger_desc.name = acpi_device_bid(adev); 228 ac->charger_desc.type = POWER_SUPPLY_TYPE_MAINS; 229 ac->charger_desc.properties = ac_props; 230 ac->charger_desc.num_properties = ARRAY_SIZE(ac_props); 231 ac->charger_desc.get_property = get_ac_property; 232 ac->charger = power_supply_register(&pdev->dev, 233 &ac->charger_desc, &psy_cfg); 234 if (IS_ERR(ac->charger)) { 235 result = PTR_ERR(ac->charger); 236 goto err_release_ac; 237 } 238 239 pr_info("%s [%s] (%s-line)\n", acpi_device_name(adev), 240 acpi_device_bid(adev), str_on_off(ac->state)); 241 242 ac->battery_nb.notifier_call = acpi_ac_battery_notify; 243 register_acpi_notifier(&ac->battery_nb); 244 245 result = acpi_dev_install_notify_handler(adev, ACPI_ALL_NOTIFY, 246 acpi_ac_notify, ac); 247 if (result) 248 goto err_unregister; 249 250 return 0; 251 252err_unregister: 253 power_supply_unregister(ac->charger); 254 unregister_acpi_notifier(&ac->battery_nb); 255err_release_ac: 256 kfree(ac); 257 258 return result; 259} 260 261#ifdef CONFIG_PM_SLEEP 262static int acpi_ac_resume(struct device *dev) 263{ 264 struct acpi_ac *ac = dev_get_drvdata(dev); 265 unsigned int old_state; 266 267 old_state = ac->state; 268 if (acpi_ac_get_state(ac)) 269 return 0; 270 if (old_state != ac->state) 271 kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE); 272 273 return 0; 274} 275#else 276#define acpi_ac_resume NULL 277#endif 278 279static void acpi_ac_remove(struct platform_device *pdev) 280{ 281 struct acpi_ac *ac = platform_get_drvdata(pdev); 282 283 acpi_dev_remove_notify_handler(ac->device, ACPI_ALL_NOTIFY, 284 acpi_ac_notify); 285 power_supply_unregister(ac->charger); 286 unregister_acpi_notifier(&ac->battery_nb); 287 288 kfree(ac); 289} 290 291static struct platform_driver acpi_ac_driver = { 292 .probe = acpi_ac_probe, 293 .remove_new = acpi_ac_remove, 294 .driver = { 295 .name = "ac", 296 .acpi_match_table = ac_device_ids, 297 .pm = &acpi_ac_pm, 298 }, 299}; 300 301static int __init acpi_ac_init(void) 302{ 303 int result; 304 305 if (acpi_disabled) 306 return -ENODEV; 307 308 if (acpi_quirk_skip_acpi_ac_and_battery()) 309 return -ENODEV; 310 311 dmi_check_system(ac_dmi_table); 312 313 result = platform_driver_register(&acpi_ac_driver); 314 if (result < 0) 315 return -ENODEV; 316 317 return 0; 318} 319 320static void __exit acpi_ac_exit(void) 321{ 322 platform_driver_unregister(&acpi_ac_driver); 323} 324module_init(acpi_ac_init); 325module_exit(acpi_ac_exit); 326