1*95c513ecSRafael J. Wysocki // SPDX-License-Identifier: GPL-2.0 2*95c513ecSRafael J. Wysocki /* 3*95c513ecSRafael J. Wysocki * ACPI Time and Alarm (TAD) Device Driver 4*95c513ecSRafael J. Wysocki * 5*95c513ecSRafael J. Wysocki * Copyright (C) 2018 Intel Corporation 6*95c513ecSRafael J. Wysocki * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 7*95c513ecSRafael J. Wysocki * 8*95c513ecSRafael J. Wysocki * This driver is based on Section 9.18 of the ACPI 6.2 specification revision. 9*95c513ecSRafael J. Wysocki * 10*95c513ecSRafael J. Wysocki * It only supports the system wakeup capabilities of the TAD. 11*95c513ecSRafael J. Wysocki * 12*95c513ecSRafael J. Wysocki * Provided are sysfs attributes, available under the TAD platform device, 13*95c513ecSRafael J. Wysocki * allowing user space to manage the AC and DC wakeup timers of the TAD: 14*95c513ecSRafael J. Wysocki * set and read their values, set and check their expire timer wake policies, 15*95c513ecSRafael J. Wysocki * check and clear their status and check the capabilities of the TAD reported 16*95c513ecSRafael J. Wysocki * by AML. The DC timer attributes are only present if the TAD supports a 17*95c513ecSRafael J. Wysocki * separate DC alarm timer. 18*95c513ecSRafael J. Wysocki * 19*95c513ecSRafael J. Wysocki * The wakeup events handling and power management of the TAD is expected to 20*95c513ecSRafael J. Wysocki * be taken care of by the ACPI PM domain attached to its platform device. 21*95c513ecSRafael J. Wysocki */ 22*95c513ecSRafael J. Wysocki 23*95c513ecSRafael J. Wysocki #include <linux/acpi.h> 24*95c513ecSRafael J. Wysocki #include <linux/kernel.h> 25*95c513ecSRafael J. Wysocki #include <linux/module.h> 26*95c513ecSRafael J. Wysocki #include <linux/platform_device.h> 27*95c513ecSRafael J. Wysocki #include <linux/pm_runtime.h> 28*95c513ecSRafael J. Wysocki #include <linux/suspend.h> 29*95c513ecSRafael J. Wysocki 30*95c513ecSRafael J. Wysocki MODULE_LICENSE("GPL v2"); 31*95c513ecSRafael J. Wysocki MODULE_AUTHOR("Rafael J. Wysocki"); 32*95c513ecSRafael J. Wysocki 33*95c513ecSRafael J. Wysocki /* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */ 34*95c513ecSRafael J. Wysocki #define ACPI_TAD_AC_WAKE BIT(0) 35*95c513ecSRafael J. Wysocki #define ACPI_TAD_DC_WAKE BIT(1) 36*95c513ecSRafael J. Wysocki #define ACPI_TAD_RT BIT(2) 37*95c513ecSRafael J. Wysocki #define ACPI_TAD_RT_IN_MS BIT(3) 38*95c513ecSRafael J. Wysocki #define ACPI_TAD_S4_S5__GWS BIT(4) 39*95c513ecSRafael J. Wysocki #define ACPI_TAD_AC_S4_WAKE BIT(5) 40*95c513ecSRafael J. Wysocki #define ACPI_TAD_AC_S5_WAKE BIT(6) 41*95c513ecSRafael J. Wysocki #define ACPI_TAD_DC_S4_WAKE BIT(7) 42*95c513ecSRafael J. Wysocki #define ACPI_TAD_DC_S5_WAKE BIT(8) 43*95c513ecSRafael J. Wysocki 44*95c513ecSRafael J. Wysocki /* ACPI TAD alarm timer selection */ 45*95c513ecSRafael J. Wysocki #define ACPI_TAD_AC_TIMER (u32)0 46*95c513ecSRafael J. Wysocki #define ACPI_TAD_DC_TIMER (u32)1 47*95c513ecSRafael J. Wysocki 48*95c513ecSRafael J. Wysocki /* Special value for disabled timer or expired timer wake policy. */ 49*95c513ecSRafael J. Wysocki #define ACPI_TAD_WAKE_DISABLED (~(u32)0) 50*95c513ecSRafael J. Wysocki 51*95c513ecSRafael J. Wysocki struct acpi_tad_driver_data { 52*95c513ecSRafael J. Wysocki u32 capabilities; 53*95c513ecSRafael J. Wysocki }; 54*95c513ecSRafael J. Wysocki 55*95c513ecSRafael J. Wysocki static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, 56*95c513ecSRafael J. Wysocki u32 value) 57*95c513ecSRafael J. Wysocki { 58*95c513ecSRafael J. Wysocki acpi_handle handle = ACPI_HANDLE(dev); 59*95c513ecSRafael J. Wysocki union acpi_object args[] = { 60*95c513ecSRafael J. Wysocki { .type = ACPI_TYPE_INTEGER, }, 61*95c513ecSRafael J. Wysocki { .type = ACPI_TYPE_INTEGER, }, 62*95c513ecSRafael J. Wysocki }; 63*95c513ecSRafael J. Wysocki struct acpi_object_list arg_list = { 64*95c513ecSRafael J. Wysocki .pointer = args, 65*95c513ecSRafael J. Wysocki .count = ARRAY_SIZE(args), 66*95c513ecSRafael J. Wysocki }; 67*95c513ecSRafael J. Wysocki unsigned long long retval; 68*95c513ecSRafael J. Wysocki acpi_status status; 69*95c513ecSRafael J. Wysocki 70*95c513ecSRafael J. Wysocki args[0].integer.value = timer_id; 71*95c513ecSRafael J. Wysocki args[1].integer.value = value; 72*95c513ecSRafael J. Wysocki 73*95c513ecSRafael J. Wysocki pm_runtime_get_sync(dev); 74*95c513ecSRafael J. Wysocki 75*95c513ecSRafael J. Wysocki status = acpi_evaluate_integer(handle, method, &arg_list, &retval); 76*95c513ecSRafael J. Wysocki 77*95c513ecSRafael J. Wysocki pm_runtime_put_sync(dev); 78*95c513ecSRafael J. Wysocki 79*95c513ecSRafael J. Wysocki if (ACPI_FAILURE(status) || retval) 80*95c513ecSRafael J. Wysocki return -EIO; 81*95c513ecSRafael J. Wysocki 82*95c513ecSRafael J. Wysocki return 0; 83*95c513ecSRafael J. Wysocki } 84*95c513ecSRafael J. Wysocki 85*95c513ecSRafael J. Wysocki static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method, 86*95c513ecSRafael J. Wysocki u32 timer_id, const char *specval) 87*95c513ecSRafael J. Wysocki { 88*95c513ecSRafael J. Wysocki u32 value; 89*95c513ecSRafael J. Wysocki 90*95c513ecSRafael J. Wysocki if (sysfs_streq(buf, specval)) { 91*95c513ecSRafael J. Wysocki value = ACPI_TAD_WAKE_DISABLED; 92*95c513ecSRafael J. Wysocki } else { 93*95c513ecSRafael J. Wysocki int ret = kstrtou32(buf, 0, &value); 94*95c513ecSRafael J. Wysocki 95*95c513ecSRafael J. Wysocki if (ret) 96*95c513ecSRafael J. Wysocki return ret; 97*95c513ecSRafael J. Wysocki 98*95c513ecSRafael J. Wysocki if (value == ACPI_TAD_WAKE_DISABLED) 99*95c513ecSRafael J. Wysocki return -EINVAL; 100*95c513ecSRafael J. Wysocki } 101*95c513ecSRafael J. Wysocki 102*95c513ecSRafael J. Wysocki return acpi_tad_wake_set(dev, method, timer_id, value); 103*95c513ecSRafael J. Wysocki } 104*95c513ecSRafael J. Wysocki 105*95c513ecSRafael J. Wysocki static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method, 106*95c513ecSRafael J. Wysocki u32 timer_id, const char *specval) 107*95c513ecSRafael J. Wysocki { 108*95c513ecSRafael J. Wysocki acpi_handle handle = ACPI_HANDLE(dev); 109*95c513ecSRafael J. Wysocki union acpi_object args[] = { 110*95c513ecSRafael J. Wysocki { .type = ACPI_TYPE_INTEGER, }, 111*95c513ecSRafael J. Wysocki }; 112*95c513ecSRafael J. Wysocki struct acpi_object_list arg_list = { 113*95c513ecSRafael J. Wysocki .pointer = args, 114*95c513ecSRafael J. Wysocki .count = ARRAY_SIZE(args), 115*95c513ecSRafael J. Wysocki }; 116*95c513ecSRafael J. Wysocki unsigned long long retval; 117*95c513ecSRafael J. Wysocki acpi_status status; 118*95c513ecSRafael J. Wysocki 119*95c513ecSRafael J. Wysocki args[0].integer.value = timer_id; 120*95c513ecSRafael J. Wysocki 121*95c513ecSRafael J. Wysocki pm_runtime_get_sync(dev); 122*95c513ecSRafael J. Wysocki 123*95c513ecSRafael J. Wysocki status = acpi_evaluate_integer(handle, method, &arg_list, &retval); 124*95c513ecSRafael J. Wysocki 125*95c513ecSRafael J. Wysocki pm_runtime_put_sync(dev); 126*95c513ecSRafael J. Wysocki 127*95c513ecSRafael J. Wysocki if (ACPI_FAILURE(status)) 128*95c513ecSRafael J. Wysocki return -EIO; 129*95c513ecSRafael J. Wysocki 130*95c513ecSRafael J. Wysocki if ((u32)retval == ACPI_TAD_WAKE_DISABLED) 131*95c513ecSRafael J. Wysocki return sprintf(buf, "%s\n", specval); 132*95c513ecSRafael J. Wysocki 133*95c513ecSRafael J. Wysocki return sprintf(buf, "%u\n", (u32)retval); 134*95c513ecSRafael J. Wysocki } 135*95c513ecSRafael J. Wysocki 136*95c513ecSRafael J. Wysocki static const char *alarm_specval = "disabled"; 137*95c513ecSRafael J. Wysocki 138*95c513ecSRafael J. Wysocki static int acpi_tad_alarm_write(struct device *dev, const char *buf, 139*95c513ecSRafael J. Wysocki u32 timer_id) 140*95c513ecSRafael J. Wysocki { 141*95c513ecSRafael J. Wysocki return acpi_tad_wake_write(dev, buf, "_STV", timer_id, alarm_specval); 142*95c513ecSRafael J. Wysocki } 143*95c513ecSRafael J. Wysocki 144*95c513ecSRafael J. Wysocki static ssize_t acpi_tad_alarm_read(struct device *dev, char *buf, u32 timer_id) 145*95c513ecSRafael J. Wysocki { 146*95c513ecSRafael J. Wysocki return acpi_tad_wake_read(dev, buf, "_TIV", timer_id, alarm_specval); 147*95c513ecSRafael J. Wysocki } 148*95c513ecSRafael J. Wysocki 149*95c513ecSRafael J. Wysocki static const char *policy_specval = "never"; 150*95c513ecSRafael J. Wysocki 151*95c513ecSRafael J. Wysocki static int acpi_tad_policy_write(struct device *dev, const char *buf, 152*95c513ecSRafael J. Wysocki u32 timer_id) 153*95c513ecSRafael J. Wysocki { 154*95c513ecSRafael J. Wysocki return acpi_tad_wake_write(dev, buf, "_STP", timer_id, policy_specval); 155*95c513ecSRafael J. Wysocki } 156*95c513ecSRafael J. Wysocki 157*95c513ecSRafael J. Wysocki static ssize_t acpi_tad_policy_read(struct device *dev, char *buf, u32 timer_id) 158*95c513ecSRafael J. Wysocki { 159*95c513ecSRafael J. Wysocki return acpi_tad_wake_read(dev, buf, "_TIP", timer_id, policy_specval); 160*95c513ecSRafael J. Wysocki } 161*95c513ecSRafael J. Wysocki 162*95c513ecSRafael J. Wysocki static int acpi_tad_clear_status(struct device *dev, u32 timer_id) 163*95c513ecSRafael J. Wysocki { 164*95c513ecSRafael J. Wysocki acpi_handle handle = ACPI_HANDLE(dev); 165*95c513ecSRafael J. Wysocki union acpi_object args[] = { 166*95c513ecSRafael J. Wysocki { .type = ACPI_TYPE_INTEGER, }, 167*95c513ecSRafael J. Wysocki }; 168*95c513ecSRafael J. Wysocki struct acpi_object_list arg_list = { 169*95c513ecSRafael J. Wysocki .pointer = args, 170*95c513ecSRafael J. Wysocki .count = ARRAY_SIZE(args), 171*95c513ecSRafael J. Wysocki }; 172*95c513ecSRafael J. Wysocki unsigned long long retval; 173*95c513ecSRafael J. Wysocki acpi_status status; 174*95c513ecSRafael J. Wysocki 175*95c513ecSRafael J. Wysocki args[0].integer.value = timer_id; 176*95c513ecSRafael J. Wysocki 177*95c513ecSRafael J. Wysocki pm_runtime_get_sync(dev); 178*95c513ecSRafael J. Wysocki 179*95c513ecSRafael J. Wysocki status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval); 180*95c513ecSRafael J. Wysocki 181*95c513ecSRafael J. Wysocki pm_runtime_put_sync(dev); 182*95c513ecSRafael J. Wysocki 183*95c513ecSRafael J. Wysocki if (ACPI_FAILURE(status) || retval) 184*95c513ecSRafael J. Wysocki return -EIO; 185*95c513ecSRafael J. Wysocki 186*95c513ecSRafael J. Wysocki return 0; 187*95c513ecSRafael J. Wysocki } 188*95c513ecSRafael J. Wysocki 189*95c513ecSRafael J. Wysocki static int acpi_tad_status_write(struct device *dev, const char *buf, u32 timer_id) 190*95c513ecSRafael J. Wysocki { 191*95c513ecSRafael J. Wysocki int ret, value; 192*95c513ecSRafael J. Wysocki 193*95c513ecSRafael J. Wysocki ret = kstrtoint(buf, 0, &value); 194*95c513ecSRafael J. Wysocki if (ret) 195*95c513ecSRafael J. Wysocki return ret; 196*95c513ecSRafael J. Wysocki 197*95c513ecSRafael J. Wysocki if (value) 198*95c513ecSRafael J. Wysocki return -EINVAL; 199*95c513ecSRafael J. Wysocki 200*95c513ecSRafael J. Wysocki return acpi_tad_clear_status(dev, timer_id); 201*95c513ecSRafael J. Wysocki } 202*95c513ecSRafael J. Wysocki 203*95c513ecSRafael J. Wysocki static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id) 204*95c513ecSRafael J. Wysocki { 205*95c513ecSRafael J. Wysocki acpi_handle handle = ACPI_HANDLE(dev); 206*95c513ecSRafael J. Wysocki union acpi_object args[] = { 207*95c513ecSRafael J. Wysocki { .type = ACPI_TYPE_INTEGER, }, 208*95c513ecSRafael J. Wysocki }; 209*95c513ecSRafael J. Wysocki struct acpi_object_list arg_list = { 210*95c513ecSRafael J. Wysocki .pointer = args, 211*95c513ecSRafael J. Wysocki .count = ARRAY_SIZE(args), 212*95c513ecSRafael J. Wysocki }; 213*95c513ecSRafael J. Wysocki unsigned long long retval; 214*95c513ecSRafael J. Wysocki acpi_status status; 215*95c513ecSRafael J. Wysocki 216*95c513ecSRafael J. Wysocki args[0].integer.value = timer_id; 217*95c513ecSRafael J. Wysocki 218*95c513ecSRafael J. Wysocki pm_runtime_get_sync(dev); 219*95c513ecSRafael J. Wysocki 220*95c513ecSRafael J. Wysocki status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval); 221*95c513ecSRafael J. Wysocki 222*95c513ecSRafael J. Wysocki pm_runtime_put_sync(dev); 223*95c513ecSRafael J. Wysocki 224*95c513ecSRafael J. Wysocki if (ACPI_FAILURE(status)) 225*95c513ecSRafael J. Wysocki return -EIO; 226*95c513ecSRafael J. Wysocki 227*95c513ecSRafael J. Wysocki return sprintf(buf, "0x%02X\n", (u32)retval); 228*95c513ecSRafael J. Wysocki } 229*95c513ecSRafael J. Wysocki 230*95c513ecSRafael J. Wysocki static ssize_t caps_show(struct device *dev, struct device_attribute *attr, 231*95c513ecSRafael J. Wysocki char *buf) 232*95c513ecSRafael J. Wysocki { 233*95c513ecSRafael J. Wysocki struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); 234*95c513ecSRafael J. Wysocki 235*95c513ecSRafael J. Wysocki return sprintf(buf, "0x%02X\n", dd->capabilities); 236*95c513ecSRafael J. Wysocki } 237*95c513ecSRafael J. Wysocki 238*95c513ecSRafael J. Wysocki static DEVICE_ATTR_RO(caps); 239*95c513ecSRafael J. Wysocki 240*95c513ecSRafael J. Wysocki static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, 241*95c513ecSRafael J. Wysocki const char *buf, size_t count) 242*95c513ecSRafael J. Wysocki { 243*95c513ecSRafael J. Wysocki int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_AC_TIMER); 244*95c513ecSRafael J. Wysocki 245*95c513ecSRafael J. Wysocki return ret ? ret : count; 246*95c513ecSRafael J. Wysocki } 247*95c513ecSRafael J. Wysocki 248*95c513ecSRafael J. Wysocki static ssize_t ac_alarm_show(struct device *dev, struct device_attribute *attr, 249*95c513ecSRafael J. Wysocki char *buf) 250*95c513ecSRafael J. Wysocki { 251*95c513ecSRafael J. Wysocki return acpi_tad_alarm_read(dev, buf, ACPI_TAD_AC_TIMER); 252*95c513ecSRafael J. Wysocki } 253*95c513ecSRafael J. Wysocki 254*95c513ecSRafael J. Wysocki static DEVICE_ATTR(ac_alarm, S_IRUSR | S_IWUSR, ac_alarm_show, ac_alarm_store); 255*95c513ecSRafael J. Wysocki 256*95c513ecSRafael J. Wysocki static ssize_t ac_policy_store(struct device *dev, struct device_attribute *attr, 257*95c513ecSRafael J. Wysocki const char *buf, size_t count) 258*95c513ecSRafael J. Wysocki { 259*95c513ecSRafael J. Wysocki int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_AC_TIMER); 260*95c513ecSRafael J. Wysocki 261*95c513ecSRafael J. Wysocki return ret ? ret : count; 262*95c513ecSRafael J. Wysocki } 263*95c513ecSRafael J. Wysocki 264*95c513ecSRafael J. Wysocki static ssize_t ac_policy_show(struct device *dev, struct device_attribute *attr, 265*95c513ecSRafael J. Wysocki char *buf) 266*95c513ecSRafael J. Wysocki { 267*95c513ecSRafael J. Wysocki return acpi_tad_policy_read(dev, buf, ACPI_TAD_AC_TIMER); 268*95c513ecSRafael J. Wysocki } 269*95c513ecSRafael J. Wysocki 270*95c513ecSRafael J. Wysocki static DEVICE_ATTR(ac_policy, S_IRUSR | S_IWUSR, ac_policy_show, ac_policy_store); 271*95c513ecSRafael J. Wysocki 272*95c513ecSRafael J. Wysocki static ssize_t ac_status_store(struct device *dev, struct device_attribute *attr, 273*95c513ecSRafael J. Wysocki const char *buf, size_t count) 274*95c513ecSRafael J. Wysocki { 275*95c513ecSRafael J. Wysocki int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_AC_TIMER); 276*95c513ecSRafael J. Wysocki 277*95c513ecSRafael J. Wysocki return ret ? ret : count; 278*95c513ecSRafael J. Wysocki } 279*95c513ecSRafael J. Wysocki 280*95c513ecSRafael J. Wysocki static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, 281*95c513ecSRafael J. Wysocki char *buf) 282*95c513ecSRafael J. Wysocki { 283*95c513ecSRafael J. Wysocki return acpi_tad_status_read(dev, buf, ACPI_TAD_AC_TIMER); 284*95c513ecSRafael J. Wysocki } 285*95c513ecSRafael J. Wysocki 286*95c513ecSRafael J. Wysocki static DEVICE_ATTR(ac_status, S_IRUSR | S_IWUSR, ac_status_show, ac_status_store); 287*95c513ecSRafael J. Wysocki 288*95c513ecSRafael J. Wysocki static struct attribute *acpi_tad_attrs[] = { 289*95c513ecSRafael J. Wysocki &dev_attr_caps.attr, 290*95c513ecSRafael J. Wysocki &dev_attr_ac_alarm.attr, 291*95c513ecSRafael J. Wysocki &dev_attr_ac_policy.attr, 292*95c513ecSRafael J. Wysocki &dev_attr_ac_status.attr, 293*95c513ecSRafael J. Wysocki NULL, 294*95c513ecSRafael J. Wysocki }; 295*95c513ecSRafael J. Wysocki static const struct attribute_group acpi_tad_attr_group = { 296*95c513ecSRafael J. Wysocki .attrs = acpi_tad_attrs, 297*95c513ecSRafael J. Wysocki }; 298*95c513ecSRafael J. Wysocki 299*95c513ecSRafael J. Wysocki static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, 300*95c513ecSRafael J. Wysocki const char *buf, size_t count) 301*95c513ecSRafael J. Wysocki { 302*95c513ecSRafael J. Wysocki int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_DC_TIMER); 303*95c513ecSRafael J. Wysocki 304*95c513ecSRafael J. Wysocki return ret ? ret : count; 305*95c513ecSRafael J. Wysocki } 306*95c513ecSRafael J. Wysocki 307*95c513ecSRafael J. Wysocki static ssize_t dc_alarm_show(struct device *dev, struct device_attribute *attr, 308*95c513ecSRafael J. Wysocki char *buf) 309*95c513ecSRafael J. Wysocki { 310*95c513ecSRafael J. Wysocki return acpi_tad_alarm_read(dev, buf, ACPI_TAD_DC_TIMER); 311*95c513ecSRafael J. Wysocki } 312*95c513ecSRafael J. Wysocki 313*95c513ecSRafael J. Wysocki static DEVICE_ATTR(dc_alarm, S_IRUSR | S_IWUSR, dc_alarm_show, dc_alarm_store); 314*95c513ecSRafael J. Wysocki 315*95c513ecSRafael J. Wysocki static ssize_t dc_policy_store(struct device *dev, struct device_attribute *attr, 316*95c513ecSRafael J. Wysocki const char *buf, size_t count) 317*95c513ecSRafael J. Wysocki { 318*95c513ecSRafael J. Wysocki int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_DC_TIMER); 319*95c513ecSRafael J. Wysocki 320*95c513ecSRafael J. Wysocki return ret ? ret : count; 321*95c513ecSRafael J. Wysocki } 322*95c513ecSRafael J. Wysocki 323*95c513ecSRafael J. Wysocki static ssize_t dc_policy_show(struct device *dev, struct device_attribute *attr, 324*95c513ecSRafael J. Wysocki char *buf) 325*95c513ecSRafael J. Wysocki { 326*95c513ecSRafael J. Wysocki return acpi_tad_policy_read(dev, buf, ACPI_TAD_DC_TIMER); 327*95c513ecSRafael J. Wysocki } 328*95c513ecSRafael J. Wysocki 329*95c513ecSRafael J. Wysocki static DEVICE_ATTR(dc_policy, S_IRUSR | S_IWUSR, dc_policy_show, dc_policy_store); 330*95c513ecSRafael J. Wysocki 331*95c513ecSRafael J. Wysocki static ssize_t dc_status_store(struct device *dev, struct device_attribute *attr, 332*95c513ecSRafael J. Wysocki const char *buf, size_t count) 333*95c513ecSRafael J. Wysocki { 334*95c513ecSRafael J. Wysocki int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_DC_TIMER); 335*95c513ecSRafael J. Wysocki 336*95c513ecSRafael J. Wysocki return ret ? ret : count; 337*95c513ecSRafael J. Wysocki } 338*95c513ecSRafael J. Wysocki 339*95c513ecSRafael J. Wysocki static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr, 340*95c513ecSRafael J. Wysocki char *buf) 341*95c513ecSRafael J. Wysocki { 342*95c513ecSRafael J. Wysocki return acpi_tad_status_read(dev, buf, ACPI_TAD_DC_TIMER); 343*95c513ecSRafael J. Wysocki } 344*95c513ecSRafael J. Wysocki 345*95c513ecSRafael J. Wysocki static DEVICE_ATTR(dc_status, S_IRUSR | S_IWUSR, dc_status_show, dc_status_store); 346*95c513ecSRafael J. Wysocki 347*95c513ecSRafael J. Wysocki static struct attribute *acpi_tad_dc_attrs[] = { 348*95c513ecSRafael J. Wysocki &dev_attr_dc_alarm.attr, 349*95c513ecSRafael J. Wysocki &dev_attr_dc_policy.attr, 350*95c513ecSRafael J. Wysocki &dev_attr_dc_status.attr, 351*95c513ecSRafael J. Wysocki NULL, 352*95c513ecSRafael J. Wysocki }; 353*95c513ecSRafael J. Wysocki static const struct attribute_group acpi_tad_dc_attr_group = { 354*95c513ecSRafael J. Wysocki .attrs = acpi_tad_dc_attrs, 355*95c513ecSRafael J. Wysocki }; 356*95c513ecSRafael J. Wysocki 357*95c513ecSRafael J. Wysocki static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) 358*95c513ecSRafael J. Wysocki { 359*95c513ecSRafael J. Wysocki return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); 360*95c513ecSRafael J. Wysocki } 361*95c513ecSRafael J. Wysocki 362*95c513ecSRafael J. Wysocki static int acpi_tad_remove(struct platform_device *pdev) 363*95c513ecSRafael J. Wysocki { 364*95c513ecSRafael J. Wysocki struct device *dev = &pdev->dev; 365*95c513ecSRafael J. Wysocki struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); 366*95c513ecSRafael J. Wysocki 367*95c513ecSRafael J. Wysocki device_init_wakeup(dev, false); 368*95c513ecSRafael J. Wysocki 369*95c513ecSRafael J. Wysocki pm_runtime_get_sync(dev); 370*95c513ecSRafael J. Wysocki 371*95c513ecSRafael J. Wysocki if (dd->capabilities & ACPI_TAD_DC_WAKE) 372*95c513ecSRafael J. Wysocki sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); 373*95c513ecSRafael J. Wysocki 374*95c513ecSRafael J. Wysocki sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); 375*95c513ecSRafael J. Wysocki 376*95c513ecSRafael J. Wysocki acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); 377*95c513ecSRafael J. Wysocki acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); 378*95c513ecSRafael J. Wysocki if (dd->capabilities & ACPI_TAD_DC_WAKE) { 379*95c513ecSRafael J. Wysocki acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); 380*95c513ecSRafael J. Wysocki acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); 381*95c513ecSRafael J. Wysocki } 382*95c513ecSRafael J. Wysocki 383*95c513ecSRafael J. Wysocki pm_runtime_put_sync(dev); 384*95c513ecSRafael J. Wysocki pm_runtime_disable(dev); 385*95c513ecSRafael J. Wysocki return 0; 386*95c513ecSRafael J. Wysocki } 387*95c513ecSRafael J. Wysocki 388*95c513ecSRafael J. Wysocki static int acpi_tad_probe(struct platform_device *pdev) 389*95c513ecSRafael J. Wysocki { 390*95c513ecSRafael J. Wysocki struct device *dev = &pdev->dev; 391*95c513ecSRafael J. Wysocki acpi_handle handle = ACPI_HANDLE(dev); 392*95c513ecSRafael J. Wysocki struct acpi_tad_driver_data *dd; 393*95c513ecSRafael J. Wysocki acpi_status status; 394*95c513ecSRafael J. Wysocki unsigned long long caps; 395*95c513ecSRafael J. Wysocki int ret; 396*95c513ecSRafael J. Wysocki 397*95c513ecSRafael J. Wysocki /* 398*95c513ecSRafael J. Wysocki * Initialization failure messages are mostly about firmware issues, so 399*95c513ecSRafael J. Wysocki * print them at the "info" level. 400*95c513ecSRafael J. Wysocki */ 401*95c513ecSRafael J. Wysocki status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps); 402*95c513ecSRafael J. Wysocki if (ACPI_FAILURE(status)) { 403*95c513ecSRafael J. Wysocki dev_info(dev, "Unable to get capabilities\n"); 404*95c513ecSRafael J. Wysocki return -ENODEV; 405*95c513ecSRafael J. Wysocki } 406*95c513ecSRafael J. Wysocki 407*95c513ecSRafael J. Wysocki if (!(caps & ACPI_TAD_AC_WAKE)) { 408*95c513ecSRafael J. Wysocki dev_info(dev, "Unsupported capabilities\n"); 409*95c513ecSRafael J. Wysocki return -ENODEV; 410*95c513ecSRafael J. Wysocki } 411*95c513ecSRafael J. Wysocki 412*95c513ecSRafael J. Wysocki if (!acpi_has_method(handle, "_PRW")) { 413*95c513ecSRafael J. Wysocki dev_info(dev, "Missing _PRW\n"); 414*95c513ecSRafael J. Wysocki return -ENODEV; 415*95c513ecSRafael J. Wysocki } 416*95c513ecSRafael J. Wysocki 417*95c513ecSRafael J. Wysocki dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); 418*95c513ecSRafael J. Wysocki if (!dd) 419*95c513ecSRafael J. Wysocki return -ENOMEM; 420*95c513ecSRafael J. Wysocki 421*95c513ecSRafael J. Wysocki dd->capabilities = caps; 422*95c513ecSRafael J. Wysocki dev_set_drvdata(dev, dd); 423*95c513ecSRafael J. Wysocki 424*95c513ecSRafael J. Wysocki /* 425*95c513ecSRafael J. Wysocki * Assume that the ACPI PM domain has been attached to the device and 426*95c513ecSRafael J. Wysocki * simply enable system wakeup and runtime PM and put the device into 427*95c513ecSRafael J. Wysocki * runtime suspend. Everything else should be taken care of by the ACPI 428*95c513ecSRafael J. Wysocki * PM domain callbacks. 429*95c513ecSRafael J. Wysocki */ 430*95c513ecSRafael J. Wysocki device_init_wakeup(dev, true); 431*95c513ecSRafael J. Wysocki dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | 432*95c513ecSRafael J. Wysocki DPM_FLAG_LEAVE_SUSPENDED); 433*95c513ecSRafael J. Wysocki /* 434*95c513ecSRafael J. Wysocki * The platform bus type layer tells the ACPI PM domain powers up the 435*95c513ecSRafael J. Wysocki * device, so set the runtime PM status of it to "active". 436*95c513ecSRafael J. Wysocki */ 437*95c513ecSRafael J. Wysocki pm_runtime_set_active(dev); 438*95c513ecSRafael J. Wysocki pm_runtime_enable(dev); 439*95c513ecSRafael J. Wysocki pm_runtime_suspend(dev); 440*95c513ecSRafael J. Wysocki 441*95c513ecSRafael J. Wysocki ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group); 442*95c513ecSRafael J. Wysocki if (ret) 443*95c513ecSRafael J. Wysocki goto fail; 444*95c513ecSRafael J. Wysocki 445*95c513ecSRafael J. Wysocki if (caps & ACPI_TAD_DC_WAKE) { 446*95c513ecSRafael J. Wysocki ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); 447*95c513ecSRafael J. Wysocki if (ret) 448*95c513ecSRafael J. Wysocki goto fail; 449*95c513ecSRafael J. Wysocki } 450*95c513ecSRafael J. Wysocki 451*95c513ecSRafael J. Wysocki return 0; 452*95c513ecSRafael J. Wysocki 453*95c513ecSRafael J. Wysocki fail: 454*95c513ecSRafael J. Wysocki acpi_tad_remove(pdev); 455*95c513ecSRafael J. Wysocki return ret; 456*95c513ecSRafael J. Wysocki } 457*95c513ecSRafael J. Wysocki 458*95c513ecSRafael J. Wysocki static const struct acpi_device_id acpi_tad_ids[] = { 459*95c513ecSRafael J. Wysocki {"ACPI000E", 0}, 460*95c513ecSRafael J. Wysocki {} 461*95c513ecSRafael J. Wysocki }; 462*95c513ecSRafael J. Wysocki 463*95c513ecSRafael J. Wysocki static struct platform_driver acpi_tad_driver = { 464*95c513ecSRafael J. Wysocki .driver = { 465*95c513ecSRafael J. Wysocki .name = "acpi-tad", 466*95c513ecSRafael J. Wysocki .acpi_match_table = acpi_tad_ids, 467*95c513ecSRafael J. Wysocki }, 468*95c513ecSRafael J. Wysocki .probe = acpi_tad_probe, 469*95c513ecSRafael J. Wysocki .remove = acpi_tad_remove, 470*95c513ecSRafael J. Wysocki }; 471*95c513ecSRafael J. Wysocki MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); 472*95c513ecSRafael J. Wysocki 473*95c513ecSRafael J. Wysocki module_platform_driver(acpi_tad_driver); 474