Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/acpi/dptf/dptf_power.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* dptf_power: DPTF platform power driver
4
* 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 power
16
* PSRC : Platform power source
17
* ARTG : Adapter rating
18
* CTYP : Charger type
19
* PROP : Rest of worst case platform Power
20
* PBSS : Power Battery Steady State
21
* RBHF : High Frequency Impedance
22
* VBNL : Instantaneous No-Load Voltage
23
* CMPP : Current Discharge Capability
24
*/
25
#define DPTF_POWER_SHOW(name, object) \
26
static 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
42
DPTF_POWER_SHOW(max_platform_power_mw, PMAX)
43
DPTF_POWER_SHOW(platform_power_source, PSRC)
44
DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
45
DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
46
DPTF_POWER_SHOW(charger_type, CTYP)
47
DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
48
DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
49
DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
50
DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
51
DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
52
53
static DEVICE_ATTR_RO(max_platform_power_mw);
54
static DEVICE_ATTR_RO(platform_power_source);
55
static DEVICE_ATTR_RO(adapter_rating_mw);
56
static DEVICE_ATTR_RO(battery_steady_power_mw);
57
static DEVICE_ATTR_RO(charger_type);
58
static DEVICE_ATTR_RO(rest_of_platform_power_mw);
59
static DEVICE_ATTR_RO(max_steady_state_power_mw);
60
static DEVICE_ATTR_RO(high_freq_impedance_mohm);
61
static DEVICE_ATTR_RO(no_load_voltage_mv);
62
static DEVICE_ATTR_RO(current_discharge_capbility_ma);
63
64
static 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
82
static DEVICE_ATTR_WO(prochot_confirm);
83
84
static 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
NULL
93
};
94
95
static const struct attribute_group dptf_power_attribute_group = {
96
.attrs = dptf_power_attrs,
97
.name = "dptf_power"
98
};
99
100
static 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
NULL
107
};
108
109
static const struct attribute_group dptf_battery_attribute_group = {
110
.attrs = dptf_battery_attrs,
111
.name = "dptf_battery"
112
};
113
114
#define MAX_POWER_CHANGED 0x80
115
#define POWER_STATE_CHANGED 0x81
116
#define STEADY_STATE_POWER_CHANGED 0x83
117
#define POWER_PROP_CHANGE_EVENT 0x84
118
#define IMPEDANCE_CHANGED 0x85
119
#define VOLTAGE_CURRENT_CHANGED 0x86
120
121
static 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
133
static 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 read
164
* again.
165
*/
166
if (dptf_participant_type(handle) == 0x0CULL)
167
sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
168
else
169
sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
170
}
171
172
static 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
else
189
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
212
static 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
else
223
sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
224
}
225
226
static 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
{"INTC10D8", 0},
240
{"INTC10D9", 0},
241
{"INTC1100", 0},
242
{"INTC1101", 0},
243
{"", 0},
244
};
245
MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
246
247
static struct platform_driver dptf_power_driver = {
248
.probe = dptf_power_add,
249
.remove = dptf_power_remove,
250
.driver = {
251
.name = "dptf_power",
252
.acpi_match_table = int3407_device_ids,
253
},
254
};
255
256
module_platform_driver(dptf_power_driver);
257
258
MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
259
MODULE_LICENSE("GPL v2");
260
MODULE_DESCRIPTION("ACPI DPTF platform power driver");
261
262