| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * dptf_power: DPTF platform power driver |
|---|
| 3 | 4 | * Copyright (c) 2016, Intel Corporation. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 19 | 10 | #include <linux/platform_device.h> |
|---|
| 20 | 11 | |
|---|
| 21 | 12 | /* |
|---|
| 22 | | - * Presentation of attributes which are defined for INT3407. They are: |
|---|
| 13 | + * Presentation of attributes which are defined for INT3407 and INT3532. |
|---|
| 14 | + * They are: |
|---|
| 23 | 15 | * PMAX : Maximum platform powe |
|---|
| 24 | 16 | * PSRC : Platform power source |
|---|
| 25 | 17 | * ARTG : Adapter rating |
|---|
| 26 | 18 | * CTYP : Charger type |
|---|
| 27 | 19 | * PBSS : Battery steady power |
|---|
| 20 | + * PROP : Rest of worst case platform Power |
|---|
| 21 | + * PBSS : Power Battery Steady State |
|---|
| 22 | + * PBSS : Power Battery Steady State |
|---|
| 23 | + * RBHF : High Frequency Impedance |
|---|
| 24 | + * VBNL : Instantaneous No-Load Voltage |
|---|
| 25 | + * CMPP : Current Discharge Capability |
|---|
| 28 | 26 | */ |
|---|
| 29 | 27 | #define DPTF_POWER_SHOW(name, object) \ |
|---|
| 30 | 28 | static ssize_t name##_show(struct device *dev,\ |
|---|
| 31 | 29 | struct device_attribute *attr,\ |
|---|
| 32 | 30 | char *buf)\ |
|---|
| 33 | 31 | {\ |
|---|
| 34 | | - struct platform_device *pdev = to_platform_device(dev);\ |
|---|
| 35 | | - struct acpi_device *acpi_dev = platform_get_drvdata(pdev);\ |
|---|
| 32 | + struct acpi_device *acpi_dev = dev_get_drvdata(dev);\ |
|---|
| 36 | 33 | unsigned long long val;\ |
|---|
| 37 | 34 | acpi_status status;\ |
|---|
| 38 | 35 | \ |
|---|
| .. | .. |
|---|
| 49 | 46 | DPTF_POWER_SHOW(adapter_rating_mw, ARTG) |
|---|
| 50 | 47 | DPTF_POWER_SHOW(battery_steady_power_mw, PBSS) |
|---|
| 51 | 48 | DPTF_POWER_SHOW(charger_type, CTYP) |
|---|
| 49 | +DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP) |
|---|
| 50 | +DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS) |
|---|
| 51 | +DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF) |
|---|
| 52 | +DPTF_POWER_SHOW(no_load_voltage_mv, VBNL) |
|---|
| 53 | +DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP); |
|---|
| 52 | 54 | |
|---|
| 53 | 55 | static DEVICE_ATTR_RO(max_platform_power_mw); |
|---|
| 54 | 56 | static DEVICE_ATTR_RO(platform_power_source); |
|---|
| 55 | 57 | static DEVICE_ATTR_RO(adapter_rating_mw); |
|---|
| 56 | 58 | static DEVICE_ATTR_RO(battery_steady_power_mw); |
|---|
| 57 | 59 | static DEVICE_ATTR_RO(charger_type); |
|---|
| 60 | +static DEVICE_ATTR_RO(rest_of_platform_power_mw); |
|---|
| 61 | +static DEVICE_ATTR_RO(max_steady_state_power_mw); |
|---|
| 62 | +static DEVICE_ATTR_RO(high_freq_impedance_mohm); |
|---|
| 63 | +static DEVICE_ATTR_RO(no_load_voltage_mv); |
|---|
| 64 | +static DEVICE_ATTR_RO(current_discharge_capbility_ma); |
|---|
| 65 | + |
|---|
| 66 | +static ssize_t prochot_confirm_store(struct device *dev, |
|---|
| 67 | + struct device_attribute *attr, |
|---|
| 68 | + const char *buf, size_t count) |
|---|
| 69 | +{ |
|---|
| 70 | + struct acpi_device *acpi_dev = dev_get_drvdata(dev); |
|---|
| 71 | + acpi_status status; |
|---|
| 72 | + int seq_no; |
|---|
| 73 | + |
|---|
| 74 | + if (kstrtouint(buf, 0, &seq_no) < 0) |
|---|
| 75 | + return -EINVAL; |
|---|
| 76 | + |
|---|
| 77 | + status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no); |
|---|
| 78 | + if (ACPI_SUCCESS(status)) |
|---|
| 79 | + return count; |
|---|
| 80 | + |
|---|
| 81 | + return -EINVAL; |
|---|
| 82 | +} |
|---|
| 83 | + |
|---|
| 84 | +static DEVICE_ATTR_WO(prochot_confirm); |
|---|
| 58 | 85 | |
|---|
| 59 | 86 | static struct attribute *dptf_power_attrs[] = { |
|---|
| 60 | 87 | &dev_attr_max_platform_power_mw.attr, |
|---|
| .. | .. |
|---|
| 62 | 89 | &dev_attr_adapter_rating_mw.attr, |
|---|
| 63 | 90 | &dev_attr_battery_steady_power_mw.attr, |
|---|
| 64 | 91 | &dev_attr_charger_type.attr, |
|---|
| 92 | + &dev_attr_rest_of_platform_power_mw.attr, |
|---|
| 93 | + &dev_attr_prochot_confirm.attr, |
|---|
| 65 | 94 | NULL |
|---|
| 66 | 95 | }; |
|---|
| 67 | 96 | |
|---|
| .. | .. |
|---|
| 70 | 99 | .name = "dptf_power" |
|---|
| 71 | 100 | }; |
|---|
| 72 | 101 | |
|---|
| 102 | +static struct attribute *dptf_battery_attrs[] = { |
|---|
| 103 | + &dev_attr_max_platform_power_mw.attr, |
|---|
| 104 | + &dev_attr_max_steady_state_power_mw.attr, |
|---|
| 105 | + &dev_attr_high_freq_impedance_mohm.attr, |
|---|
| 106 | + &dev_attr_no_load_voltage_mv.attr, |
|---|
| 107 | + &dev_attr_current_discharge_capbility_ma.attr, |
|---|
| 108 | + NULL |
|---|
| 109 | +}; |
|---|
| 110 | + |
|---|
| 111 | +static const struct attribute_group dptf_battery_attribute_group = { |
|---|
| 112 | + .attrs = dptf_battery_attrs, |
|---|
| 113 | + .name = "dptf_battery" |
|---|
| 114 | +}; |
|---|
| 115 | + |
|---|
| 116 | +#define MAX_POWER_CHANGED 0x80 |
|---|
| 117 | +#define POWER_STATE_CHANGED 0x81 |
|---|
| 118 | +#define STEADY_STATE_POWER_CHANGED 0x83 |
|---|
| 119 | +#define POWER_PROP_CHANGE_EVENT 0x84 |
|---|
| 120 | +#define IMPEDANCED_CHNGED 0x85 |
|---|
| 121 | +#define VOLTAGE_CURRENT_CHANGED 0x86 |
|---|
| 122 | + |
|---|
| 123 | +static long long dptf_participant_type(acpi_handle handle) |
|---|
| 124 | +{ |
|---|
| 125 | + unsigned long long ptype; |
|---|
| 126 | + acpi_status status; |
|---|
| 127 | + |
|---|
| 128 | + status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype); |
|---|
| 129 | + if (ACPI_FAILURE(status)) |
|---|
| 130 | + return -ENODEV; |
|---|
| 131 | + |
|---|
| 132 | + return ptype; |
|---|
| 133 | +} |
|---|
| 134 | + |
|---|
| 135 | +static void dptf_power_notify(acpi_handle handle, u32 event, void *data) |
|---|
| 136 | +{ |
|---|
| 137 | + struct platform_device *pdev = data; |
|---|
| 138 | + char *attr; |
|---|
| 139 | + |
|---|
| 140 | + switch (event) { |
|---|
| 141 | + case POWER_STATE_CHANGED: |
|---|
| 142 | + attr = "platform_power_source"; |
|---|
| 143 | + break; |
|---|
| 144 | + case POWER_PROP_CHANGE_EVENT: |
|---|
| 145 | + attr = "rest_of_platform_power_mw"; |
|---|
| 146 | + break; |
|---|
| 147 | + case MAX_POWER_CHANGED: |
|---|
| 148 | + attr = "max_platform_power_mw"; |
|---|
| 149 | + break; |
|---|
| 150 | + case STEADY_STATE_POWER_CHANGED: |
|---|
| 151 | + attr = "max_steady_state_power_mw"; |
|---|
| 152 | + break; |
|---|
| 153 | + case VOLTAGE_CURRENT_CHANGED: |
|---|
| 154 | + attr = "no_load_voltage_mv"; |
|---|
| 155 | + break; |
|---|
| 156 | + default: |
|---|
| 157 | + dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event); |
|---|
| 158 | + return; |
|---|
| 159 | + } |
|---|
| 160 | + |
|---|
| 161 | + /* |
|---|
| 162 | + * Notify that an attribute is changed, so that user space can read |
|---|
| 163 | + * again. |
|---|
| 164 | + */ |
|---|
| 165 | + if (dptf_participant_type(handle) == 0x0CULL) |
|---|
| 166 | + sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr); |
|---|
| 167 | + else |
|---|
| 168 | + sysfs_notify(&pdev->dev.kobj, "dptf_power", attr); |
|---|
| 169 | +} |
|---|
| 170 | + |
|---|
| 73 | 171 | static int dptf_power_add(struct platform_device *pdev) |
|---|
| 74 | 172 | { |
|---|
| 173 | + const struct attribute_group *attr_group; |
|---|
| 75 | 174 | struct acpi_device *acpi_dev; |
|---|
| 76 | | - acpi_status status; |
|---|
| 77 | 175 | unsigned long long ptype; |
|---|
| 78 | 176 | int result; |
|---|
| 79 | 177 | |
|---|
| .. | .. |
|---|
| 81 | 179 | if (!acpi_dev) |
|---|
| 82 | 180 | return -ENODEV; |
|---|
| 83 | 181 | |
|---|
| 84 | | - status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype); |
|---|
| 85 | | - if (ACPI_FAILURE(status)) |
|---|
| 182 | + ptype = dptf_participant_type(acpi_dev->handle); |
|---|
| 183 | + if (ptype == 0x11) |
|---|
| 184 | + attr_group = &dptf_power_attribute_group; |
|---|
| 185 | + else if (ptype == 0x0C) |
|---|
| 186 | + attr_group = &dptf_battery_attribute_group; |
|---|
| 187 | + else |
|---|
| 86 | 188 | return -ENODEV; |
|---|
| 87 | 189 | |
|---|
| 88 | | - if (ptype != 0x11) |
|---|
| 89 | | - return -ENODEV; |
|---|
| 90 | | - |
|---|
| 91 | | - result = sysfs_create_group(&pdev->dev.kobj, |
|---|
| 92 | | - &dptf_power_attribute_group); |
|---|
| 190 | + result = acpi_install_notify_handler(acpi_dev->handle, |
|---|
| 191 | + ACPI_DEVICE_NOTIFY, |
|---|
| 192 | + dptf_power_notify, |
|---|
| 193 | + (void *)pdev); |
|---|
| 93 | 194 | if (result) |
|---|
| 94 | 195 | return result; |
|---|
| 196 | + |
|---|
| 197 | + result = sysfs_create_group(&pdev->dev.kobj, |
|---|
| 198 | + attr_group); |
|---|
| 199 | + if (result) { |
|---|
| 200 | + acpi_remove_notify_handler(acpi_dev->handle, |
|---|
| 201 | + ACPI_DEVICE_NOTIFY, |
|---|
| 202 | + dptf_power_notify); |
|---|
| 203 | + return result; |
|---|
| 204 | + } |
|---|
| 95 | 205 | |
|---|
| 96 | 206 | platform_set_drvdata(pdev, acpi_dev); |
|---|
| 97 | 207 | |
|---|
| .. | .. |
|---|
| 100 | 210 | |
|---|
| 101 | 211 | static int dptf_power_remove(struct platform_device *pdev) |
|---|
| 102 | 212 | { |
|---|
| 213 | + struct acpi_device *acpi_dev = platform_get_drvdata(pdev); |
|---|
| 103 | 214 | |
|---|
| 104 | | - sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group); |
|---|
| 215 | + acpi_remove_notify_handler(acpi_dev->handle, |
|---|
| 216 | + ACPI_DEVICE_NOTIFY, |
|---|
| 217 | + dptf_power_notify); |
|---|
| 218 | + |
|---|
| 219 | + if (dptf_participant_type(acpi_dev->handle) == 0x0CULL) |
|---|
| 220 | + sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group); |
|---|
| 221 | + else |
|---|
| 222 | + sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group); |
|---|
| 105 | 223 | |
|---|
| 106 | 224 | return 0; |
|---|
| 107 | 225 | } |
|---|
| 108 | 226 | |
|---|
| 109 | 227 | static const struct acpi_device_id int3407_device_ids[] = { |
|---|
| 110 | 228 | {"INT3407", 0}, |
|---|
| 229 | + {"INT3532", 0}, |
|---|
| 230 | + {"INTC1047", 0}, |
|---|
| 231 | + {"INTC1050", 0}, |
|---|
| 232 | + {"INTC1060", 0}, |
|---|
| 233 | + {"INTC1061", 0}, |
|---|
| 111 | 234 | {"", 0}, |
|---|
| 112 | 235 | }; |
|---|
| 113 | 236 | MODULE_DEVICE_TABLE(acpi, int3407_device_ids); |
|---|
| .. | .. |
|---|
| 116 | 239 | .probe = dptf_power_add, |
|---|
| 117 | 240 | .remove = dptf_power_remove, |
|---|
| 118 | 241 | .driver = { |
|---|
| 119 | | - .name = "DPTF Platform Power", |
|---|
| 242 | + .name = "dptf_power", |
|---|
| 120 | 243 | .acpi_match_table = int3407_device_ids, |
|---|
| 121 | 244 | }, |
|---|
| 122 | 245 | }; |
|---|