Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ACPI Time and Alarm (TAD) Device Driver
0004  *
0005  * Copyright (C) 2018 Intel Corporation
0006  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
0007  *
0008  * This driver is based on Section 9.18 of the ACPI 6.2 specification revision.
0009  *
0010  * It only supports the system wakeup capabilities of the TAD.
0011  *
0012  * Provided are sysfs attributes, available under the TAD platform device,
0013  * allowing user space to manage the AC and DC wakeup timers of the TAD:
0014  * set and read their values, set and check their expire timer wake policies,
0015  * check and clear their status and check the capabilities of the TAD reported
0016  * by AML.  The DC timer attributes are only present if the TAD supports a
0017  * separate DC alarm timer.
0018  *
0019  * The wakeup events handling and power management of the TAD is expected to
0020  * be taken care of by the ACPI PM domain attached to its platform device.
0021  */
0022 
0023 #include <linux/acpi.h>
0024 #include <linux/kernel.h>
0025 #include <linux/module.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/pm_runtime.h>
0028 #include <linux/suspend.h>
0029 
0030 MODULE_LICENSE("GPL v2");
0031 MODULE_AUTHOR("Rafael J. Wysocki");
0032 
0033 /* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */
0034 #define ACPI_TAD_AC_WAKE    BIT(0)
0035 #define ACPI_TAD_DC_WAKE    BIT(1)
0036 #define ACPI_TAD_RT     BIT(2)
0037 #define ACPI_TAD_RT_IN_MS   BIT(3)
0038 #define ACPI_TAD_S4_S5__GWS BIT(4)
0039 #define ACPI_TAD_AC_S4_WAKE BIT(5)
0040 #define ACPI_TAD_AC_S5_WAKE BIT(6)
0041 #define ACPI_TAD_DC_S4_WAKE BIT(7)
0042 #define ACPI_TAD_DC_S5_WAKE BIT(8)
0043 
0044 /* ACPI TAD alarm timer selection */
0045 #define ACPI_TAD_AC_TIMER   (u32)0
0046 #define ACPI_TAD_DC_TIMER   (u32)1
0047 
0048 /* Special value for disabled timer or expired timer wake policy. */
0049 #define ACPI_TAD_WAKE_DISABLED  (~(u32)0)
0050 
0051 struct acpi_tad_driver_data {
0052     u32 capabilities;
0053 };
0054 
0055 struct acpi_tad_rt {
0056     u16 year;  /* 1900 - 9999 */
0057     u8 month;  /* 1 - 12 */
0058     u8 day;    /* 1 - 31 */
0059     u8 hour;   /* 0 - 23 */
0060     u8 minute; /* 0 - 59 */
0061     u8 second; /* 0 - 59 */
0062     u8 valid;  /* 0 (failed) or 1 (success) for reads, 0 for writes */
0063     u16 msec;  /* 1 - 1000 */
0064     s16 tz;    /* -1440 to 1440 or 2047 (unspecified) */
0065     u8 daylight;
0066     u8 padding[3]; /* must be 0 */
0067 } __packed;
0068 
0069 static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
0070 {
0071     acpi_handle handle = ACPI_HANDLE(dev);
0072     union acpi_object args[] = {
0073         { .type = ACPI_TYPE_BUFFER, },
0074     };
0075     struct acpi_object_list arg_list = {
0076         .pointer = args,
0077         .count = ARRAY_SIZE(args),
0078     };
0079     unsigned long long retval;
0080     acpi_status status;
0081 
0082     if (rt->year < 1900 || rt->year > 9999 ||
0083         rt->month < 1 || rt->month > 12 ||
0084         rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
0085         rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
0086         rt->daylight > 3)
0087         return -ERANGE;
0088 
0089     args[0].buffer.pointer = (u8 *)rt;
0090     args[0].buffer.length = sizeof(*rt);
0091 
0092     pm_runtime_get_sync(dev);
0093 
0094     status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);
0095 
0096     pm_runtime_put_sync(dev);
0097 
0098     if (ACPI_FAILURE(status) || retval)
0099         return -EIO;
0100 
0101     return 0;
0102 }
0103 
0104 static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
0105 {
0106     acpi_handle handle = ACPI_HANDLE(dev);
0107     struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
0108     union acpi_object *out_obj;
0109     struct acpi_tad_rt *data;
0110     acpi_status status;
0111     int ret = -EIO;
0112 
0113     pm_runtime_get_sync(dev);
0114 
0115     status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
0116 
0117     pm_runtime_put_sync(dev);
0118 
0119     if (ACPI_FAILURE(status))
0120         goto out_free;
0121 
0122     out_obj = output.pointer;
0123     if (out_obj->type != ACPI_TYPE_BUFFER)
0124         goto out_free;
0125 
0126     if (out_obj->buffer.length != sizeof(*rt))
0127         goto out_free;
0128 
0129     data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
0130     if (!data->valid)
0131         goto out_free;
0132 
0133     memcpy(rt, data, sizeof(*rt));
0134     ret = 0;
0135 
0136 out_free:
0137     ACPI_FREE(output.pointer);
0138     return ret;
0139 }
0140 
0141 static char *acpi_tad_rt_next_field(char *s, int *val)
0142 {
0143     char *p;
0144 
0145     p = strchr(s, ':');
0146     if (!p)
0147         return NULL;
0148 
0149     *p = '\0';
0150     if (kstrtoint(s, 10, val))
0151         return NULL;
0152 
0153     return p + 1;
0154 }
0155 
0156 static ssize_t time_store(struct device *dev, struct device_attribute *attr,
0157               const char *buf, size_t count)
0158 {
0159     struct acpi_tad_rt rt;
0160     char *str, *s;
0161     int val, ret = -ENODATA;
0162 
0163     str = kmemdup_nul(buf, count, GFP_KERNEL);
0164     if (!str)
0165         return -ENOMEM;
0166 
0167     s = acpi_tad_rt_next_field(str, &val);
0168     if (!s)
0169         goto out_free;
0170 
0171     rt.year = val;
0172 
0173     s = acpi_tad_rt_next_field(s, &val);
0174     if (!s)
0175         goto out_free;
0176 
0177     rt.month = val;
0178 
0179     s = acpi_tad_rt_next_field(s, &val);
0180     if (!s)
0181         goto out_free;
0182 
0183     rt.day = val;
0184 
0185     s = acpi_tad_rt_next_field(s, &val);
0186     if (!s)
0187         goto out_free;
0188 
0189     rt.hour = val;
0190 
0191     s = acpi_tad_rt_next_field(s, &val);
0192     if (!s)
0193         goto out_free;
0194 
0195     rt.minute = val;
0196 
0197     s = acpi_tad_rt_next_field(s, &val);
0198     if (!s)
0199         goto out_free;
0200 
0201     rt.second = val;
0202 
0203     s = acpi_tad_rt_next_field(s, &val);
0204     if (!s)
0205         goto out_free;
0206 
0207     rt.tz = val;
0208 
0209     if (kstrtoint(s, 10, &val))
0210         goto out_free;
0211 
0212     rt.daylight = val;
0213 
0214     rt.valid = 0;
0215     rt.msec = 0;
0216     memset(rt.padding, 0, 3);
0217 
0218     ret = acpi_tad_set_real_time(dev, &rt);
0219 
0220 out_free:
0221     kfree(str);
0222     return ret ? ret : count;
0223 }
0224 
0225 static ssize_t time_show(struct device *dev, struct device_attribute *attr,
0226              char *buf)
0227 {
0228     struct acpi_tad_rt rt;
0229     int ret;
0230 
0231     ret = acpi_tad_get_real_time(dev, &rt);
0232     if (ret)
0233         return ret;
0234 
0235     return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
0236                rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
0237                rt.tz, rt.daylight);
0238 }
0239 
0240 static DEVICE_ATTR_RW(time);
0241 
0242 static struct attribute *acpi_tad_time_attrs[] = {
0243     &dev_attr_time.attr,
0244     NULL,
0245 };
0246 static const struct attribute_group acpi_tad_time_attr_group = {
0247     .attrs  = acpi_tad_time_attrs,
0248 };
0249 
0250 static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
0251                  u32 value)
0252 {
0253     acpi_handle handle = ACPI_HANDLE(dev);
0254     union acpi_object args[] = {
0255         { .type = ACPI_TYPE_INTEGER, },
0256         { .type = ACPI_TYPE_INTEGER, },
0257     };
0258     struct acpi_object_list arg_list = {
0259         .pointer = args,
0260         .count = ARRAY_SIZE(args),
0261     };
0262     unsigned long long retval;
0263     acpi_status status;
0264 
0265     args[0].integer.value = timer_id;
0266     args[1].integer.value = value;
0267 
0268     pm_runtime_get_sync(dev);
0269 
0270     status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
0271 
0272     pm_runtime_put_sync(dev);
0273 
0274     if (ACPI_FAILURE(status) || retval)
0275         return -EIO;
0276 
0277     return 0;
0278 }
0279 
0280 static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method,
0281                    u32 timer_id, const char *specval)
0282 {
0283     u32 value;
0284 
0285     if (sysfs_streq(buf, specval)) {
0286         value = ACPI_TAD_WAKE_DISABLED;
0287     } else {
0288         int ret = kstrtou32(buf, 0, &value);
0289 
0290         if (ret)
0291             return ret;
0292 
0293         if (value == ACPI_TAD_WAKE_DISABLED)
0294             return -EINVAL;
0295     }
0296 
0297     return acpi_tad_wake_set(dev, method, timer_id, value);
0298 }
0299 
0300 static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method,
0301                   u32 timer_id, const char *specval)
0302 {
0303     acpi_handle handle = ACPI_HANDLE(dev);
0304     union acpi_object args[] = {
0305         { .type = ACPI_TYPE_INTEGER, },
0306     };
0307     struct acpi_object_list arg_list = {
0308         .pointer = args,
0309         .count = ARRAY_SIZE(args),
0310     };
0311     unsigned long long retval;
0312     acpi_status status;
0313 
0314     args[0].integer.value = timer_id;
0315 
0316     pm_runtime_get_sync(dev);
0317 
0318     status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
0319 
0320     pm_runtime_put_sync(dev);
0321 
0322     if (ACPI_FAILURE(status))
0323         return -EIO;
0324 
0325     if ((u32)retval == ACPI_TAD_WAKE_DISABLED)
0326         return sprintf(buf, "%s\n", specval);
0327 
0328     return sprintf(buf, "%u\n", (u32)retval);
0329 }
0330 
0331 static const char *alarm_specval = "disabled";
0332 
0333 static int acpi_tad_alarm_write(struct device *dev, const char *buf,
0334                 u32 timer_id)
0335 {
0336     return acpi_tad_wake_write(dev, buf, "_STV", timer_id, alarm_specval);
0337 }
0338 
0339 static ssize_t acpi_tad_alarm_read(struct device *dev, char *buf, u32 timer_id)
0340 {
0341     return acpi_tad_wake_read(dev, buf, "_TIV", timer_id, alarm_specval);
0342 }
0343 
0344 static const char *policy_specval = "never";
0345 
0346 static int acpi_tad_policy_write(struct device *dev, const char *buf,
0347                  u32 timer_id)
0348 {
0349     return acpi_tad_wake_write(dev, buf, "_STP", timer_id, policy_specval);
0350 }
0351 
0352 static ssize_t acpi_tad_policy_read(struct device *dev, char *buf, u32 timer_id)
0353 {
0354     return acpi_tad_wake_read(dev, buf, "_TIP", timer_id, policy_specval);
0355 }
0356 
0357 static int acpi_tad_clear_status(struct device *dev, u32 timer_id)
0358 {
0359     acpi_handle handle = ACPI_HANDLE(dev);
0360     union acpi_object args[] = {
0361         { .type = ACPI_TYPE_INTEGER, },
0362     };
0363     struct acpi_object_list arg_list = {
0364         .pointer = args,
0365         .count = ARRAY_SIZE(args),
0366     };
0367     unsigned long long retval;
0368     acpi_status status;
0369 
0370     args[0].integer.value = timer_id;
0371 
0372     pm_runtime_get_sync(dev);
0373 
0374     status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval);
0375 
0376     pm_runtime_put_sync(dev);
0377 
0378     if (ACPI_FAILURE(status) || retval)
0379         return -EIO;
0380 
0381     return 0;
0382 }
0383 
0384 static int acpi_tad_status_write(struct device *dev, const char *buf, u32 timer_id)
0385 {
0386     int ret, value;
0387 
0388     ret = kstrtoint(buf, 0, &value);
0389     if (ret)
0390         return ret;
0391 
0392     if (value)
0393         return -EINVAL;
0394 
0395     return acpi_tad_clear_status(dev, timer_id);
0396 }
0397 
0398 static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id)
0399 {
0400     acpi_handle handle = ACPI_HANDLE(dev);
0401     union acpi_object args[] = {
0402         { .type = ACPI_TYPE_INTEGER, },
0403     };
0404     struct acpi_object_list arg_list = {
0405         .pointer = args,
0406         .count = ARRAY_SIZE(args),
0407     };
0408     unsigned long long retval;
0409     acpi_status status;
0410 
0411     args[0].integer.value = timer_id;
0412 
0413     pm_runtime_get_sync(dev);
0414 
0415     status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval);
0416 
0417     pm_runtime_put_sync(dev);
0418 
0419     if (ACPI_FAILURE(status))
0420         return -EIO;
0421 
0422     return sprintf(buf, "0x%02X\n", (u32)retval);
0423 }
0424 
0425 static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
0426              char *buf)
0427 {
0428     struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
0429 
0430     return sprintf(buf, "0x%02X\n", dd->capabilities);
0431 }
0432 
0433 static DEVICE_ATTR_RO(caps);
0434 
0435 static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr,
0436                   const char *buf, size_t count)
0437 {
0438     int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_AC_TIMER);
0439 
0440     return ret ? ret : count;
0441 }
0442 
0443 static ssize_t ac_alarm_show(struct device *dev, struct device_attribute *attr,
0444                  char *buf)
0445 {
0446     return acpi_tad_alarm_read(dev, buf, ACPI_TAD_AC_TIMER);
0447 }
0448 
0449 static DEVICE_ATTR_RW(ac_alarm);
0450 
0451 static ssize_t ac_policy_store(struct device *dev, struct device_attribute *attr,
0452                    const char *buf, size_t count)
0453 {
0454     int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_AC_TIMER);
0455 
0456     return ret ? ret : count;
0457 }
0458 
0459 static ssize_t ac_policy_show(struct device *dev, struct device_attribute *attr,
0460                   char *buf)
0461 {
0462     return acpi_tad_policy_read(dev, buf, ACPI_TAD_AC_TIMER);
0463 }
0464 
0465 static DEVICE_ATTR_RW(ac_policy);
0466 
0467 static ssize_t ac_status_store(struct device *dev, struct device_attribute *attr,
0468                    const char *buf, size_t count)
0469 {
0470     int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_AC_TIMER);
0471 
0472     return ret ? ret : count;
0473 }
0474 
0475 static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr,
0476                   char *buf)
0477 {
0478     return acpi_tad_status_read(dev, buf, ACPI_TAD_AC_TIMER);
0479 }
0480 
0481 static DEVICE_ATTR_RW(ac_status);
0482 
0483 static struct attribute *acpi_tad_attrs[] = {
0484     &dev_attr_caps.attr,
0485     &dev_attr_ac_alarm.attr,
0486     &dev_attr_ac_policy.attr,
0487     &dev_attr_ac_status.attr,
0488     NULL,
0489 };
0490 static const struct attribute_group acpi_tad_attr_group = {
0491     .attrs  = acpi_tad_attrs,
0492 };
0493 
0494 static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr,
0495                   const char *buf, size_t count)
0496 {
0497     int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_DC_TIMER);
0498 
0499     return ret ? ret : count;
0500 }
0501 
0502 static ssize_t dc_alarm_show(struct device *dev, struct device_attribute *attr,
0503                  char *buf)
0504 {
0505     return acpi_tad_alarm_read(dev, buf, ACPI_TAD_DC_TIMER);
0506 }
0507 
0508 static DEVICE_ATTR_RW(dc_alarm);
0509 
0510 static ssize_t dc_policy_store(struct device *dev, struct device_attribute *attr,
0511                    const char *buf, size_t count)
0512 {
0513     int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_DC_TIMER);
0514 
0515     return ret ? ret : count;
0516 }
0517 
0518 static ssize_t dc_policy_show(struct device *dev, struct device_attribute *attr,
0519                   char *buf)
0520 {
0521     return acpi_tad_policy_read(dev, buf, ACPI_TAD_DC_TIMER);
0522 }
0523 
0524 static DEVICE_ATTR_RW(dc_policy);
0525 
0526 static ssize_t dc_status_store(struct device *dev, struct device_attribute *attr,
0527                    const char *buf, size_t count)
0528 {
0529     int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_DC_TIMER);
0530 
0531     return ret ? ret : count;
0532 }
0533 
0534 static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr,
0535                   char *buf)
0536 {
0537     return acpi_tad_status_read(dev, buf, ACPI_TAD_DC_TIMER);
0538 }
0539 
0540 static DEVICE_ATTR_RW(dc_status);
0541 
0542 static struct attribute *acpi_tad_dc_attrs[] = {
0543     &dev_attr_dc_alarm.attr,
0544     &dev_attr_dc_policy.attr,
0545     &dev_attr_dc_status.attr,
0546     NULL,
0547 };
0548 static const struct attribute_group acpi_tad_dc_attr_group = {
0549     .attrs  = acpi_tad_dc_attrs,
0550 };
0551 
0552 static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
0553 {
0554     return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
0555 }
0556 
0557 static int acpi_tad_remove(struct platform_device *pdev)
0558 {
0559     struct device *dev = &pdev->dev;
0560     struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
0561 
0562     device_init_wakeup(dev, false);
0563 
0564     pm_runtime_get_sync(dev);
0565 
0566     if (dd->capabilities & ACPI_TAD_DC_WAKE)
0567         sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group);
0568 
0569     sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
0570 
0571     acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
0572     acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
0573     if (dd->capabilities & ACPI_TAD_DC_WAKE) {
0574         acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
0575         acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
0576     }
0577 
0578     pm_runtime_put_sync(dev);
0579     pm_runtime_disable(dev);
0580     return 0;
0581 }
0582 
0583 static int acpi_tad_probe(struct platform_device *pdev)
0584 {
0585     struct device *dev = &pdev->dev;
0586     acpi_handle handle = ACPI_HANDLE(dev);
0587     struct acpi_tad_driver_data *dd;
0588     acpi_status status;
0589     unsigned long long caps;
0590     int ret;
0591 
0592     /*
0593      * Initialization failure messages are mostly about firmware issues, so
0594      * print them at the "info" level.
0595      */
0596     status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps);
0597     if (ACPI_FAILURE(status)) {
0598         dev_info(dev, "Unable to get capabilities\n");
0599         return -ENODEV;
0600     }
0601 
0602     if (!(caps & ACPI_TAD_AC_WAKE)) {
0603         dev_info(dev, "Unsupported capabilities\n");
0604         return -ENODEV;
0605     }
0606 
0607     if (!acpi_has_method(handle, "_PRW")) {
0608         dev_info(dev, "Missing _PRW\n");
0609         return -ENODEV;
0610     }
0611 
0612     dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
0613     if (!dd)
0614         return -ENOMEM;
0615 
0616     dd->capabilities = caps;
0617     dev_set_drvdata(dev, dd);
0618 
0619     /*
0620      * Assume that the ACPI PM domain has been attached to the device and
0621      * simply enable system wakeup and runtime PM and put the device into
0622      * runtime suspend.  Everything else should be taken care of by the ACPI
0623      * PM domain callbacks.
0624      */
0625     device_init_wakeup(dev, true);
0626     dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
0627                      DPM_FLAG_MAY_SKIP_RESUME);
0628     /*
0629      * The platform bus type layer tells the ACPI PM domain powers up the
0630      * device, so set the runtime PM status of it to "active".
0631      */
0632     pm_runtime_set_active(dev);
0633     pm_runtime_enable(dev);
0634     pm_runtime_suspend(dev);
0635 
0636     ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
0637     if (ret)
0638         goto fail;
0639 
0640     if (caps & ACPI_TAD_DC_WAKE) {
0641         ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
0642         if (ret)
0643             goto fail;
0644     }
0645 
0646     if (caps & ACPI_TAD_RT) {
0647         ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
0648         if (ret)
0649             goto fail;
0650     }
0651 
0652     return 0;
0653 
0654 fail:
0655     acpi_tad_remove(pdev);
0656     return ret;
0657 }
0658 
0659 static const struct acpi_device_id acpi_tad_ids[] = {
0660     {"ACPI000E", 0},
0661     {}
0662 };
0663 
0664 static struct platform_driver acpi_tad_driver = {
0665     .driver = {
0666         .name = "acpi-tad",
0667         .acpi_match_table = acpi_tad_ids,
0668     },
0669     .probe = acpi_tad_probe,
0670     .remove = acpi_tad_remove,
0671 };
0672 MODULE_DEVICE_TABLE(acpi, acpi_tad_ids);
0673 
0674 module_platform_driver(acpi_tad_driver);