12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 26256ebd5SSrinivas Pandruvada /* 36256ebd5SSrinivas Pandruvada * dptf_power: DPTF platform power driver 46256ebd5SSrinivas Pandruvada * Copyright (c) 2016, Intel Corporation. 56256ebd5SSrinivas Pandruvada */ 66256ebd5SSrinivas Pandruvada 76256ebd5SSrinivas Pandruvada #include <linux/kernel.h> 86256ebd5SSrinivas Pandruvada #include <linux/module.h> 96256ebd5SSrinivas Pandruvada #include <linux/acpi.h> 106256ebd5SSrinivas Pandruvada #include <linux/platform_device.h> 116256ebd5SSrinivas Pandruvada 126256ebd5SSrinivas Pandruvada /* 137b52b200SSrinivas Pandruvada * Presentation of attributes which are defined for INT3407 and INT3532. 147b52b200SSrinivas Pandruvada * They are: 156256ebd5SSrinivas Pandruvada * PMAX : Maximum platform powe 166256ebd5SSrinivas Pandruvada * PSRC : Platform power source 176256ebd5SSrinivas Pandruvada * ARTG : Adapter rating 186256ebd5SSrinivas Pandruvada * CTYP : Charger type 196256ebd5SSrinivas Pandruvada * PBSS : Battery steady power 20668ce99eSSrinivas Pandruvada * PROP : Rest of worst case platform Power 217b52b200SSrinivas Pandruvada * PBSS : Power Battery Steady State 227b52b200SSrinivas Pandruvada * PBSS : Power Battery Steady State 237b52b200SSrinivas Pandruvada * RBHF : High Frequency Impedance 247b52b200SSrinivas Pandruvada * VBNL : Instantaneous No-Load Voltage 257b52b200SSrinivas Pandruvada * CMPP : Current Discharge Capability 266256ebd5SSrinivas Pandruvada */ 276256ebd5SSrinivas Pandruvada #define DPTF_POWER_SHOW(name, object) \ 286256ebd5SSrinivas Pandruvada static ssize_t name##_show(struct device *dev,\ 296256ebd5SSrinivas Pandruvada struct device_attribute *attr,\ 306256ebd5SSrinivas Pandruvada char *buf)\ 316256ebd5SSrinivas Pandruvada {\ 32b0f65b91SKefeng Wang struct acpi_device *acpi_dev = dev_get_drvdata(dev);\ 336256ebd5SSrinivas Pandruvada unsigned long long val;\ 346256ebd5SSrinivas Pandruvada acpi_status status;\ 356256ebd5SSrinivas Pandruvada \ 366256ebd5SSrinivas Pandruvada status = acpi_evaluate_integer(acpi_dev->handle, #object,\ 376256ebd5SSrinivas Pandruvada NULL, &val);\ 386256ebd5SSrinivas Pandruvada if (ACPI_SUCCESS(status))\ 396256ebd5SSrinivas Pandruvada return sprintf(buf, "%d\n", (int)val);\ 406256ebd5SSrinivas Pandruvada else \ 416256ebd5SSrinivas Pandruvada return -EINVAL;\ 426256ebd5SSrinivas Pandruvada } 436256ebd5SSrinivas Pandruvada 446256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(max_platform_power_mw, PMAX) 456256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(platform_power_source, PSRC) 466256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(adapter_rating_mw, ARTG) 476256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(battery_steady_power_mw, PBSS) 486256ebd5SSrinivas Pandruvada DPTF_POWER_SHOW(charger_type, CTYP) 49668ce99eSSrinivas Pandruvada DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP) 507b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS) 517b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF) 527b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(no_load_voltage_mv, VBNL) 537b52b200SSrinivas Pandruvada DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP); 546256ebd5SSrinivas Pandruvada 556256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(max_platform_power_mw); 566256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(platform_power_source); 576256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(adapter_rating_mw); 586256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(battery_steady_power_mw); 596256ebd5SSrinivas Pandruvada static DEVICE_ATTR_RO(charger_type); 60668ce99eSSrinivas Pandruvada static DEVICE_ATTR_RO(rest_of_platform_power_mw); 617b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(max_steady_state_power_mw); 627b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(high_freq_impedance_mohm); 637b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(no_load_voltage_mv); 647b52b200SSrinivas Pandruvada static DEVICE_ATTR_RO(current_discharge_capbility_ma); 65668ce99eSSrinivas Pandruvada 66668ce99eSSrinivas Pandruvada static ssize_t prochot_confirm_store(struct device *dev, 67668ce99eSSrinivas Pandruvada struct device_attribute *attr, 68668ce99eSSrinivas Pandruvada const char *buf, size_t count) 69668ce99eSSrinivas Pandruvada { 70668ce99eSSrinivas Pandruvada struct acpi_device *acpi_dev = dev_get_drvdata(dev); 71668ce99eSSrinivas Pandruvada acpi_status status; 72668ce99eSSrinivas Pandruvada int seq_no; 73668ce99eSSrinivas Pandruvada 74668ce99eSSrinivas Pandruvada if (kstrtouint(buf, 0, &seq_no) < 0) 75668ce99eSSrinivas Pandruvada return -EINVAL; 76668ce99eSSrinivas Pandruvada 77668ce99eSSrinivas Pandruvada status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no); 78668ce99eSSrinivas Pandruvada if (ACPI_SUCCESS(status)) 79668ce99eSSrinivas Pandruvada return count; 80668ce99eSSrinivas Pandruvada 81668ce99eSSrinivas Pandruvada return -EINVAL; 82668ce99eSSrinivas Pandruvada } 83668ce99eSSrinivas Pandruvada 84668ce99eSSrinivas Pandruvada static DEVICE_ATTR_WO(prochot_confirm); 856256ebd5SSrinivas Pandruvada 866256ebd5SSrinivas Pandruvada static struct attribute *dptf_power_attrs[] = { 876256ebd5SSrinivas Pandruvada &dev_attr_max_platform_power_mw.attr, 886256ebd5SSrinivas Pandruvada &dev_attr_platform_power_source.attr, 896256ebd5SSrinivas Pandruvada &dev_attr_adapter_rating_mw.attr, 906256ebd5SSrinivas Pandruvada &dev_attr_battery_steady_power_mw.attr, 916256ebd5SSrinivas Pandruvada &dev_attr_charger_type.attr, 92668ce99eSSrinivas Pandruvada &dev_attr_rest_of_platform_power_mw.attr, 93668ce99eSSrinivas Pandruvada &dev_attr_prochot_confirm.attr, 946256ebd5SSrinivas Pandruvada NULL 956256ebd5SSrinivas Pandruvada }; 966256ebd5SSrinivas Pandruvada 979e4de6a8SArvind Yadav static const struct attribute_group dptf_power_attribute_group = { 986256ebd5SSrinivas Pandruvada .attrs = dptf_power_attrs, 996256ebd5SSrinivas Pandruvada .name = "dptf_power" 1006256ebd5SSrinivas Pandruvada }; 1016256ebd5SSrinivas Pandruvada 1027b52b200SSrinivas Pandruvada static struct attribute *dptf_battery_attrs[] = { 1037b52b200SSrinivas Pandruvada &dev_attr_max_platform_power_mw.attr, 1047b52b200SSrinivas Pandruvada &dev_attr_max_steady_state_power_mw.attr, 1057b52b200SSrinivas Pandruvada &dev_attr_high_freq_impedance_mohm.attr, 1067b52b200SSrinivas Pandruvada &dev_attr_no_load_voltage_mv.attr, 1077b52b200SSrinivas Pandruvada &dev_attr_current_discharge_capbility_ma.attr, 1087b52b200SSrinivas Pandruvada NULL 1097b52b200SSrinivas Pandruvada }; 1107b52b200SSrinivas Pandruvada 1117b52b200SSrinivas Pandruvada static const struct attribute_group dptf_battery_attribute_group = { 1127b52b200SSrinivas Pandruvada .attrs = dptf_battery_attrs, 1137b52b200SSrinivas Pandruvada .name = "dptf_battery" 1147b52b200SSrinivas Pandruvada }; 1157b52b200SSrinivas Pandruvada 1167b52b200SSrinivas Pandruvada #define MAX_POWER_CHANGED 0x80 117668ce99eSSrinivas Pandruvada #define POWER_STATE_CHANGED 0x81 1187b52b200SSrinivas Pandruvada #define STEADY_STATE_POWER_CHANGED 0x83 119668ce99eSSrinivas Pandruvada #define POWER_PROP_CHANGE_EVENT 0x84 1207b52b200SSrinivas Pandruvada #define IMPEDANCED_CHNGED 0x85 1217b52b200SSrinivas Pandruvada #define VOLTAGE_CURRENT_CHANGED 0x86 1227b52b200SSrinivas Pandruvada 1237b52b200SSrinivas Pandruvada static long long dptf_participant_type(acpi_handle handle) 1247b52b200SSrinivas Pandruvada { 1257b52b200SSrinivas Pandruvada unsigned long long ptype; 1267b52b200SSrinivas Pandruvada acpi_status status; 1277b52b200SSrinivas Pandruvada 1287b52b200SSrinivas Pandruvada status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype); 1297b52b200SSrinivas Pandruvada if (ACPI_FAILURE(status)) 1307b52b200SSrinivas Pandruvada return -ENODEV; 1317b52b200SSrinivas Pandruvada 1327b52b200SSrinivas Pandruvada return ptype; 1337b52b200SSrinivas Pandruvada } 134668ce99eSSrinivas Pandruvada 135668ce99eSSrinivas Pandruvada static void dptf_power_notify(acpi_handle handle, u32 event, void *data) 136668ce99eSSrinivas Pandruvada { 137668ce99eSSrinivas Pandruvada struct platform_device *pdev = data; 138668ce99eSSrinivas Pandruvada char *attr; 139668ce99eSSrinivas Pandruvada 140668ce99eSSrinivas Pandruvada switch (event) { 141668ce99eSSrinivas Pandruvada case POWER_STATE_CHANGED: 142668ce99eSSrinivas Pandruvada attr = "platform_power_source"; 143668ce99eSSrinivas Pandruvada break; 144668ce99eSSrinivas Pandruvada case POWER_PROP_CHANGE_EVENT: 145668ce99eSSrinivas Pandruvada attr = "rest_of_platform_power_mw"; 146668ce99eSSrinivas Pandruvada break; 1477b52b200SSrinivas Pandruvada case MAX_POWER_CHANGED: 1487b52b200SSrinivas Pandruvada attr = "max_platform_power_mw"; 1497b52b200SSrinivas Pandruvada break; 1507b52b200SSrinivas Pandruvada case STEADY_STATE_POWER_CHANGED: 1517b52b200SSrinivas Pandruvada attr = "max_steady_state_power_mw"; 1527b52b200SSrinivas Pandruvada break; 1537b52b200SSrinivas Pandruvada case VOLTAGE_CURRENT_CHANGED: 1547b52b200SSrinivas Pandruvada attr = "no_load_voltage_mv"; 1557b52b200SSrinivas Pandruvada break; 156668ce99eSSrinivas Pandruvada default: 157668ce99eSSrinivas Pandruvada dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event); 158668ce99eSSrinivas Pandruvada return; 159668ce99eSSrinivas Pandruvada } 160668ce99eSSrinivas Pandruvada 161668ce99eSSrinivas Pandruvada /* 162668ce99eSSrinivas Pandruvada * Notify that an attribute is changed, so that user space can read 163668ce99eSSrinivas Pandruvada * again. 164668ce99eSSrinivas Pandruvada */ 1657b52b200SSrinivas Pandruvada if (dptf_participant_type(handle) == 0x0CULL) 1667b52b200SSrinivas Pandruvada sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr); 1677b52b200SSrinivas Pandruvada else 168668ce99eSSrinivas Pandruvada sysfs_notify(&pdev->dev.kobj, "dptf_power", attr); 169668ce99eSSrinivas Pandruvada } 170668ce99eSSrinivas Pandruvada 1716256ebd5SSrinivas Pandruvada static int dptf_power_add(struct platform_device *pdev) 1726256ebd5SSrinivas Pandruvada { 1737b52b200SSrinivas Pandruvada const struct attribute_group *attr_group; 1746256ebd5SSrinivas Pandruvada struct acpi_device *acpi_dev; 1756256ebd5SSrinivas Pandruvada unsigned long long ptype; 1766256ebd5SSrinivas Pandruvada int result; 1776256ebd5SSrinivas Pandruvada 1786256ebd5SSrinivas Pandruvada acpi_dev = ACPI_COMPANION(&(pdev->dev)); 1796256ebd5SSrinivas Pandruvada if (!acpi_dev) 1806256ebd5SSrinivas Pandruvada return -ENODEV; 1816256ebd5SSrinivas Pandruvada 1827b52b200SSrinivas Pandruvada ptype = dptf_participant_type(acpi_dev->handle); 1837b52b200SSrinivas Pandruvada if (ptype == 0x11) 1847b52b200SSrinivas Pandruvada attr_group = &dptf_power_attribute_group; 1857b52b200SSrinivas Pandruvada else if (ptype == 0x0C) 1867b52b200SSrinivas Pandruvada attr_group = &dptf_battery_attribute_group; 1877b52b200SSrinivas Pandruvada else 1886256ebd5SSrinivas Pandruvada return -ENODEV; 1896256ebd5SSrinivas Pandruvada 190668ce99eSSrinivas Pandruvada result = acpi_install_notify_handler(acpi_dev->handle, 191668ce99eSSrinivas Pandruvada ACPI_DEVICE_NOTIFY, 192668ce99eSSrinivas Pandruvada dptf_power_notify, 193668ce99eSSrinivas Pandruvada (void *)pdev); 1946256ebd5SSrinivas Pandruvada if (result) 1956256ebd5SSrinivas Pandruvada return result; 1966256ebd5SSrinivas Pandruvada 197668ce99eSSrinivas Pandruvada result = sysfs_create_group(&pdev->dev.kobj, 1987b52b200SSrinivas Pandruvada attr_group); 199668ce99eSSrinivas Pandruvada if (result) { 200668ce99eSSrinivas Pandruvada acpi_remove_notify_handler(acpi_dev->handle, 201668ce99eSSrinivas Pandruvada ACPI_DEVICE_NOTIFY, 202668ce99eSSrinivas Pandruvada dptf_power_notify); 203668ce99eSSrinivas Pandruvada return result; 204668ce99eSSrinivas Pandruvada } 205668ce99eSSrinivas Pandruvada 2066256ebd5SSrinivas Pandruvada platform_set_drvdata(pdev, acpi_dev); 2076256ebd5SSrinivas Pandruvada 2086256ebd5SSrinivas Pandruvada return 0; 2096256ebd5SSrinivas Pandruvada } 2106256ebd5SSrinivas Pandruvada 2116256ebd5SSrinivas Pandruvada static int dptf_power_remove(struct platform_device *pdev) 2126256ebd5SSrinivas Pandruvada { 213668ce99eSSrinivas Pandruvada struct acpi_device *acpi_dev = platform_get_drvdata(pdev); 2146256ebd5SSrinivas Pandruvada 215668ce99eSSrinivas Pandruvada acpi_remove_notify_handler(acpi_dev->handle, 216668ce99eSSrinivas Pandruvada ACPI_DEVICE_NOTIFY, 217668ce99eSSrinivas Pandruvada dptf_power_notify); 2187b52b200SSrinivas Pandruvada 2197b52b200SSrinivas Pandruvada if (dptf_participant_type(acpi_dev->handle) == 0x0CULL) 2207b52b200SSrinivas Pandruvada sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group); 2217b52b200SSrinivas Pandruvada else 2226256ebd5SSrinivas Pandruvada sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group); 2236256ebd5SSrinivas Pandruvada 2246256ebd5SSrinivas Pandruvada return 0; 2256256ebd5SSrinivas Pandruvada } 2266256ebd5SSrinivas Pandruvada 2276256ebd5SSrinivas Pandruvada static const struct acpi_device_id int3407_device_ids[] = { 2286256ebd5SSrinivas Pandruvada {"INT3407", 0}, 2297b52b200SSrinivas Pandruvada {"INT3532", 0}, 230b62c770fSGayatri Kammela {"INTC1047", 0}, 2311e05dacaSSrinivas Pandruvada {"INTC1050", 0}, 232*38748bcbSSrinivas Pandruvada {"INTC1060", 0}, 233*38748bcbSSrinivas Pandruvada {"INTC1061", 0}, 2346256ebd5SSrinivas Pandruvada {"", 0}, 2356256ebd5SSrinivas Pandruvada }; 2366256ebd5SSrinivas Pandruvada MODULE_DEVICE_TABLE(acpi, int3407_device_ids); 2376256ebd5SSrinivas Pandruvada 2386256ebd5SSrinivas Pandruvada static struct platform_driver dptf_power_driver = { 2396256ebd5SSrinivas Pandruvada .probe = dptf_power_add, 2406256ebd5SSrinivas Pandruvada .remove = dptf_power_remove, 2416256ebd5SSrinivas Pandruvada .driver = { 242ff44fe3eSRafael J. Wysocki .name = "dptf_power", 2436256ebd5SSrinivas Pandruvada .acpi_match_table = int3407_device_ids, 2446256ebd5SSrinivas Pandruvada }, 2456256ebd5SSrinivas Pandruvada }; 2466256ebd5SSrinivas Pandruvada 2476256ebd5SSrinivas Pandruvada module_platform_driver(dptf_power_driver); 2486256ebd5SSrinivas Pandruvada 2496256ebd5SSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 2506256ebd5SSrinivas Pandruvada MODULE_LICENSE("GPL v2"); 2516256ebd5SSrinivas Pandruvada MODULE_DESCRIPTION("ACPI DPTF platform power driver"); 252