257 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * dptf_power: DPTF platform power driver4 * Copyright (c) 2016, Intel Corporation.5 */6 7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/acpi.h>10#include <linux/platform_device.h>11 12/*13 * Presentation of attributes which are defined for INT3407 and INT3532.14 * They are:15 * PMAX : Maximum platform power16 * PSRC : Platform power source17 * ARTG : Adapter rating18 * CTYP : Charger type19 * PROP : Rest of worst case platform Power20 * PBSS : Power Battery Steady State21 * RBHF : High Frequency Impedance22 * VBNL : Instantaneous No-Load Voltage23 * CMPP : Current Discharge Capability24 */25#define DPTF_POWER_SHOW(name, object) \26static ssize_t name##_show(struct device *dev,\27 struct device_attribute *attr,\28 char *buf)\29{\30 struct acpi_device *acpi_dev = dev_get_drvdata(dev);\31 unsigned long long val;\32 acpi_status status;\33\34 status = acpi_evaluate_integer(acpi_dev->handle, #object,\35 NULL, &val);\36 if (ACPI_SUCCESS(status))\37 return sprintf(buf, "%d\n", (int)val);\38 else \39 return -EINVAL;\40}41 42DPTF_POWER_SHOW(max_platform_power_mw, PMAX)43DPTF_POWER_SHOW(platform_power_source, PSRC)44DPTF_POWER_SHOW(adapter_rating_mw, ARTG)45DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)46DPTF_POWER_SHOW(charger_type, CTYP)47DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)48DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)49DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)50DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)51DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);52 53static DEVICE_ATTR_RO(max_platform_power_mw);54static DEVICE_ATTR_RO(platform_power_source);55static DEVICE_ATTR_RO(adapter_rating_mw);56static DEVICE_ATTR_RO(battery_steady_power_mw);57static DEVICE_ATTR_RO(charger_type);58static DEVICE_ATTR_RO(rest_of_platform_power_mw);59static DEVICE_ATTR_RO(max_steady_state_power_mw);60static DEVICE_ATTR_RO(high_freq_impedance_mohm);61static DEVICE_ATTR_RO(no_load_voltage_mv);62static DEVICE_ATTR_RO(current_discharge_capbility_ma);63 64static ssize_t prochot_confirm_store(struct device *dev,65 struct device_attribute *attr,66 const char *buf, size_t count)67{68 struct acpi_device *acpi_dev = dev_get_drvdata(dev);69 acpi_status status;70 int seq_no;71 72 if (kstrtouint(buf, 0, &seq_no) < 0)73 return -EINVAL;74 75 status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);76 if (ACPI_SUCCESS(status))77 return count;78 79 return -EINVAL;80}81 82static DEVICE_ATTR_WO(prochot_confirm);83 84static struct attribute *dptf_power_attrs[] = {85 &dev_attr_max_platform_power_mw.attr,86 &dev_attr_platform_power_source.attr,87 &dev_attr_adapter_rating_mw.attr,88 &dev_attr_battery_steady_power_mw.attr,89 &dev_attr_charger_type.attr,90 &dev_attr_rest_of_platform_power_mw.attr,91 &dev_attr_prochot_confirm.attr,92 NULL93};94 95static const struct attribute_group dptf_power_attribute_group = {96 .attrs = dptf_power_attrs,97 .name = "dptf_power"98};99 100static struct attribute *dptf_battery_attrs[] = {101 &dev_attr_max_platform_power_mw.attr,102 &dev_attr_max_steady_state_power_mw.attr,103 &dev_attr_high_freq_impedance_mohm.attr,104 &dev_attr_no_load_voltage_mv.attr,105 &dev_attr_current_discharge_capbility_ma.attr,106 NULL107};108 109static const struct attribute_group dptf_battery_attribute_group = {110 .attrs = dptf_battery_attrs,111 .name = "dptf_battery"112};113 114#define MAX_POWER_CHANGED 0x80115#define POWER_STATE_CHANGED 0x81116#define STEADY_STATE_POWER_CHANGED 0x83117#define POWER_PROP_CHANGE_EVENT 0x84118#define IMPEDANCE_CHANGED 0x85119#define VOLTAGE_CURRENT_CHANGED 0x86120 121static long long dptf_participant_type(acpi_handle handle)122{123 unsigned long long ptype;124 acpi_status status;125 126 status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);127 if (ACPI_FAILURE(status))128 return -ENODEV;129 130 return ptype;131}132 133static void dptf_power_notify(acpi_handle handle, u32 event, void *data)134{135 struct platform_device *pdev = data;136 char *attr;137 138 switch (event) {139 case POWER_STATE_CHANGED:140 attr = "platform_power_source";141 break;142 case POWER_PROP_CHANGE_EVENT:143 attr = "rest_of_platform_power_mw";144 break;145 case MAX_POWER_CHANGED:146 attr = "max_platform_power_mw";147 break;148 case STEADY_STATE_POWER_CHANGED:149 attr = "max_steady_state_power_mw";150 break;151 case IMPEDANCE_CHANGED:152 attr = "high_freq_impedance_mohm";153 break;154 case VOLTAGE_CURRENT_CHANGED:155 attr = "no_load_voltage_mv";156 break;157 default:158 dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);159 return;160 }161 162 /*163 * Notify that an attribute is changed, so that user space can read164 * again.165 */166 if (dptf_participant_type(handle) == 0x0CULL)167 sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);168 else169 sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);170}171 172static int dptf_power_add(struct platform_device *pdev)173{174 const struct attribute_group *attr_group;175 struct acpi_device *acpi_dev;176 unsigned long long ptype;177 int result;178 179 acpi_dev = ACPI_COMPANION(&(pdev->dev));180 if (!acpi_dev)181 return -ENODEV;182 183 ptype = dptf_participant_type(acpi_dev->handle);184 if (ptype == 0x11)185 attr_group = &dptf_power_attribute_group;186 else if (ptype == 0x0C)187 attr_group = &dptf_battery_attribute_group;188 else189 return -ENODEV;190 191 result = acpi_install_notify_handler(acpi_dev->handle,192 ACPI_DEVICE_NOTIFY,193 dptf_power_notify,194 (void *)pdev);195 if (result)196 return result;197 198 result = sysfs_create_group(&pdev->dev.kobj,199 attr_group);200 if (result) {201 acpi_remove_notify_handler(acpi_dev->handle,202 ACPI_DEVICE_NOTIFY,203 dptf_power_notify);204 return result;205 }206 207 platform_set_drvdata(pdev, acpi_dev);208 209 return 0;210}211 212static void dptf_power_remove(struct platform_device *pdev)213{214 struct acpi_device *acpi_dev = platform_get_drvdata(pdev);215 216 acpi_remove_notify_handler(acpi_dev->handle,217 ACPI_DEVICE_NOTIFY,218 dptf_power_notify);219 220 if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)221 sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);222 else223 sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);224}225 226static const struct acpi_device_id int3407_device_ids[] = {227 {"INT3407", 0},228 {"INT3532", 0},229 {"INTC1047", 0},230 {"INTC1050", 0},231 {"INTC1060", 0},232 {"INTC1061", 0},233 {"INTC1065", 0},234 {"INTC1066", 0},235 {"INTC106C", 0},236 {"INTC106D", 0},237 {"INTC10A4", 0},238 {"INTC10A5", 0},239 {"", 0},240};241MODULE_DEVICE_TABLE(acpi, int3407_device_ids);242 243static struct platform_driver dptf_power_driver = {244 .probe = dptf_power_add,245 .remove_new = dptf_power_remove,246 .driver = {247 .name = "dptf_power",248 .acpi_match_table = int3407_device_ids,249 },250};251 252module_platform_driver(dptf_power_driver);253 254MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");255MODULE_LICENSE("GPL v2");256MODULE_DESCRIPTION("ACPI DPTF platform power driver");257