Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  acpi_ac.c - ACPI AC Adapter Driver (Revision: 27)
0004  *
0005  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
0006  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
0007  */
0008 
0009 #define pr_fmt(fmt) "ACPI: AC: " fmt
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/init.h>
0015 #include <linux/types.h>
0016 #include <linux/dmi.h>
0017 #include <linux/delay.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/power_supply.h>
0020 #include <linux/acpi.h>
0021 #include <acpi/battery.h>
0022 
0023 #define ACPI_AC_CLASS           "ac_adapter"
0024 #define ACPI_AC_DEVICE_NAME     "AC Adapter"
0025 #define ACPI_AC_FILE_STATE      "state"
0026 #define ACPI_AC_NOTIFY_STATUS       0x80
0027 #define ACPI_AC_STATUS_OFFLINE      0x00
0028 #define ACPI_AC_STATUS_ONLINE       0x01
0029 #define ACPI_AC_STATUS_UNKNOWN      0xFF
0030 
0031 MODULE_AUTHOR("Paul Diefenbaugh");
0032 MODULE_DESCRIPTION("ACPI AC Adapter Driver");
0033 MODULE_LICENSE("GPL");
0034 
0035 static int acpi_ac_add(struct acpi_device *device);
0036 static int acpi_ac_remove(struct acpi_device *device);
0037 static void acpi_ac_notify(struct acpi_device *device, u32 event);
0038 
0039 struct acpi_ac_bl {
0040     const char *hid;
0041     int hrv;
0042 };
0043 
0044 static const struct acpi_device_id ac_device_ids[] = {
0045     {"ACPI0003", 0},
0046     {"", 0},
0047 };
0048 MODULE_DEVICE_TABLE(acpi, ac_device_ids);
0049 
0050 #ifdef CONFIG_PM_SLEEP
0051 static int acpi_ac_resume(struct device *dev);
0052 #endif
0053 static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
0054 
0055 static int ac_sleep_before_get_state_ms;
0056 static int ac_only;
0057 
0058 static struct acpi_driver acpi_ac_driver = {
0059     .name = "ac",
0060     .class = ACPI_AC_CLASS,
0061     .ids = ac_device_ids,
0062     .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
0063     .ops = {
0064         .add = acpi_ac_add,
0065         .remove = acpi_ac_remove,
0066         .notify = acpi_ac_notify,
0067         },
0068     .drv.pm = &acpi_ac_pm,
0069 };
0070 
0071 struct acpi_ac {
0072     struct power_supply *charger;
0073     struct power_supply_desc charger_desc;
0074     struct acpi_device *device;
0075     unsigned long long state;
0076     struct notifier_block battery_nb;
0077 };
0078 
0079 #define to_acpi_ac(x) power_supply_get_drvdata(x)
0080 
0081 /* AC Adapter Management */
0082 static int acpi_ac_get_state(struct acpi_ac *ac)
0083 {
0084     acpi_status status = AE_OK;
0085 
0086     if (!ac)
0087         return -EINVAL;
0088 
0089     if (ac_only) {
0090         ac->state = 1;
0091         return 0;
0092     }
0093 
0094     status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL,
0095                        &ac->state);
0096     if (ACPI_FAILURE(status)) {
0097         acpi_handle_info(ac->device->handle,
0098                 "Error reading AC Adapter state: %s\n",
0099                 acpi_format_exception(status));
0100         ac->state = ACPI_AC_STATUS_UNKNOWN;
0101         return -ENODEV;
0102     }
0103 
0104     return 0;
0105 }
0106 
0107 /* sysfs I/F */
0108 static int get_ac_property(struct power_supply *psy,
0109                enum power_supply_property psp,
0110                union power_supply_propval *val)
0111 {
0112     struct acpi_ac *ac = to_acpi_ac(psy);
0113 
0114     if (!ac)
0115         return -ENODEV;
0116 
0117     if (acpi_ac_get_state(ac))
0118         return -ENODEV;
0119 
0120     switch (psp) {
0121     case POWER_SUPPLY_PROP_ONLINE:
0122         val->intval = ac->state;
0123         break;
0124     default:
0125         return -EINVAL;
0126     }
0127 
0128     return 0;
0129 }
0130 
0131 static enum power_supply_property ac_props[] = {
0132     POWER_SUPPLY_PROP_ONLINE,
0133 };
0134 
0135 /* Driver Model */
0136 static void acpi_ac_notify(struct acpi_device *device, u32 event)
0137 {
0138     struct acpi_ac *ac = acpi_driver_data(device);
0139 
0140     if (!ac)
0141         return;
0142 
0143     switch (event) {
0144     default:
0145         acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
0146                   event);
0147         fallthrough;
0148     case ACPI_AC_NOTIFY_STATUS:
0149     case ACPI_NOTIFY_BUS_CHECK:
0150     case ACPI_NOTIFY_DEVICE_CHECK:
0151         /*
0152          * A buggy BIOS may notify AC first and then sleep for
0153          * a specific time before doing actual operations in the
0154          * EC event handler (_Qxx). This will cause the AC state
0155          * reported by the ACPI event to be incorrect, so wait for a
0156          * specific time for the EC event handler to make progress.
0157          */
0158         if (ac_sleep_before_get_state_ms > 0)
0159             msleep(ac_sleep_before_get_state_ms);
0160 
0161         acpi_ac_get_state(ac);
0162         acpi_bus_generate_netlink_event(device->pnp.device_class,
0163                           dev_name(&device->dev), event,
0164                           (u32) ac->state);
0165         acpi_notifier_call_chain(device, event, (u32) ac->state);
0166         kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE);
0167     }
0168 }
0169 
0170 static int acpi_ac_battery_notify(struct notifier_block *nb,
0171                   unsigned long action, void *data)
0172 {
0173     struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb);
0174     struct acpi_bus_event *event = (struct acpi_bus_event *)data;
0175 
0176     /*
0177      * On HP Pavilion dv6-6179er AC status notifications aren't triggered
0178      * when adapter is plugged/unplugged. However, battery status
0179      * notifications are triggered when battery starts charging or
0180      * discharging. Re-reading AC status triggers lost AC notifications,
0181      * if AC status has changed.
0182      */
0183     if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 &&
0184         event->type == ACPI_BATTERY_NOTIFY_STATUS)
0185         acpi_ac_get_state(ac);
0186 
0187     return NOTIFY_OK;
0188 }
0189 
0190 static int __init thinkpad_e530_quirk(const struct dmi_system_id *d)
0191 {
0192     ac_sleep_before_get_state_ms = 1000;
0193     return 0;
0194 }
0195 
0196 static int __init ac_only_quirk(const struct dmi_system_id *d)
0197 {
0198     ac_only = 1;
0199     return 0;
0200 }
0201 
0202 /* Please keep this list alphabetically sorted */
0203 static const struct dmi_system_id ac_dmi_table[]  __initconst = {
0204     {
0205         /* Kodlix GK45 returning incorrect state */
0206         .callback = ac_only_quirk,
0207         .matches = {
0208             DMI_MATCH(DMI_PRODUCT_NAME, "GK45"),
0209         },
0210     },
0211     {
0212         /* Lenovo Thinkpad e530, see comment in acpi_ac_notify() */
0213         .callback = thinkpad_e530_quirk,
0214         .matches = {
0215             DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0216             DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"),
0217         },
0218     },
0219     {},
0220 };
0221 
0222 static int acpi_ac_add(struct acpi_device *device)
0223 {
0224     struct power_supply_config psy_cfg = {};
0225     int result = 0;
0226     struct acpi_ac *ac = NULL;
0227 
0228 
0229     if (!device)
0230         return -EINVAL;
0231 
0232     ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL);
0233     if (!ac)
0234         return -ENOMEM;
0235 
0236     ac->device = device;
0237     strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
0238     strcpy(acpi_device_class(device), ACPI_AC_CLASS);
0239     device->driver_data = ac;
0240 
0241     result = acpi_ac_get_state(ac);
0242     if (result)
0243         goto end;
0244 
0245     psy_cfg.drv_data = ac;
0246 
0247     ac->charger_desc.name = acpi_device_bid(device);
0248     ac->charger_desc.type = POWER_SUPPLY_TYPE_MAINS;
0249     ac->charger_desc.properties = ac_props;
0250     ac->charger_desc.num_properties = ARRAY_SIZE(ac_props);
0251     ac->charger_desc.get_property = get_ac_property;
0252     ac->charger = power_supply_register(&ac->device->dev,
0253                         &ac->charger_desc, &psy_cfg);
0254     if (IS_ERR(ac->charger)) {
0255         result = PTR_ERR(ac->charger);
0256         goto end;
0257     }
0258 
0259     pr_info("%s [%s] (%s)\n", acpi_device_name(device),
0260         acpi_device_bid(device), ac->state ? "on-line" : "off-line");
0261 
0262     ac->battery_nb.notifier_call = acpi_ac_battery_notify;
0263     register_acpi_notifier(&ac->battery_nb);
0264 end:
0265     if (result)
0266         kfree(ac);
0267 
0268     return result;
0269 }
0270 
0271 #ifdef CONFIG_PM_SLEEP
0272 static int acpi_ac_resume(struct device *dev)
0273 {
0274     struct acpi_ac *ac;
0275     unsigned int old_state;
0276 
0277     if (!dev)
0278         return -EINVAL;
0279 
0280     ac = acpi_driver_data(to_acpi_device(dev));
0281     if (!ac)
0282         return -EINVAL;
0283 
0284     old_state = ac->state;
0285     if (acpi_ac_get_state(ac))
0286         return 0;
0287     if (old_state != ac->state)
0288         kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE);
0289 
0290     return 0;
0291 }
0292 #else
0293 #define acpi_ac_resume NULL
0294 #endif
0295 
0296 static int acpi_ac_remove(struct acpi_device *device)
0297 {
0298     struct acpi_ac *ac = NULL;
0299 
0300     if (!device || !acpi_driver_data(device))
0301         return -EINVAL;
0302 
0303     ac = acpi_driver_data(device);
0304 
0305     power_supply_unregister(ac->charger);
0306     unregister_acpi_notifier(&ac->battery_nb);
0307 
0308     kfree(ac);
0309 
0310     return 0;
0311 }
0312 
0313 static int __init acpi_ac_init(void)
0314 {
0315     int result;
0316 
0317     if (acpi_disabled)
0318         return -ENODEV;
0319 
0320     if (acpi_quirk_skip_acpi_ac_and_battery())
0321         return -ENODEV;
0322 
0323     dmi_check_system(ac_dmi_table);
0324 
0325     result = acpi_bus_register_driver(&acpi_ac_driver);
0326     if (result < 0)
0327         return -ENODEV;
0328 
0329     return 0;
0330 }
0331 
0332 static void __exit acpi_ac_exit(void)
0333 {
0334     acpi_bus_unregister_driver(&acpi_ac_driver);
0335 }
0336 module_init(acpi_ac_init);
0337 module_exit(acpi_ac_exit);