1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/acpi.h>
19#include <linux/platform_device.h>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#define DPTF_POWER_SHOW(name, object) \
37static ssize_t name##_show(struct device *dev,\
38 struct device_attribute *attr,\
39 char *buf)\
40{\
41 struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
42 unsigned long long val;\
43 acpi_status status;\
44\
45 status = acpi_evaluate_integer(acpi_dev->handle, #object,\
46 NULL, &val);\
47 if (ACPI_SUCCESS(status))\
48 return sprintf(buf, "%d\n", (int)val);\
49 else \
50 return -EINVAL;\
51}
52
53DPTF_POWER_SHOW(max_platform_power_mw, PMAX)
54DPTF_POWER_SHOW(platform_power_source, PSRC)
55DPTF_POWER_SHOW(adapter_rating_mw, ARTG)
56DPTF_POWER_SHOW(battery_steady_power_mw, PBSS)
57DPTF_POWER_SHOW(charger_type, CTYP)
58DPTF_POWER_SHOW(rest_of_platform_power_mw, PROP)
59DPTF_POWER_SHOW(max_steady_state_power_mw, PBSS)
60DPTF_POWER_SHOW(high_freq_impedance_mohm, RBHF)
61DPTF_POWER_SHOW(no_load_voltage_mv, VBNL)
62DPTF_POWER_SHOW(current_discharge_capbility_ma, CMPP);
63
64static DEVICE_ATTR_RO(max_platform_power_mw);
65static DEVICE_ATTR_RO(platform_power_source);
66static DEVICE_ATTR_RO(adapter_rating_mw);
67static DEVICE_ATTR_RO(battery_steady_power_mw);
68static DEVICE_ATTR_RO(charger_type);
69static DEVICE_ATTR_RO(rest_of_platform_power_mw);
70static DEVICE_ATTR_RO(max_steady_state_power_mw);
71static DEVICE_ATTR_RO(high_freq_impedance_mohm);
72static DEVICE_ATTR_RO(no_load_voltage_mv);
73static DEVICE_ATTR_RO(current_discharge_capbility_ma);
74
75static ssize_t prochot_confirm_store(struct device *dev,
76 struct device_attribute *attr,
77 const char *buf, size_t count)
78{
79 struct acpi_device *acpi_dev = dev_get_drvdata(dev);
80 acpi_status status;
81 int seq_no;
82
83 if (kstrtouint(buf, 0, &seq_no) < 0)
84 return -EINVAL;
85
86 status = acpi_execute_simple_method(acpi_dev->handle, "PBOK", seq_no);
87 if (ACPI_SUCCESS(status))
88 return count;
89
90 return -EINVAL;
91}
92
93static DEVICE_ATTR_WO(prochot_confirm);
94
95static struct attribute *dptf_power_attrs[] = {
96 &dev_attr_max_platform_power_mw.attr,
97 &dev_attr_platform_power_source.attr,
98 &dev_attr_adapter_rating_mw.attr,
99 &dev_attr_battery_steady_power_mw.attr,
100 &dev_attr_charger_type.attr,
101 &dev_attr_rest_of_platform_power_mw.attr,
102 &dev_attr_prochot_confirm.attr,
103 NULL
104};
105
106static const struct attribute_group dptf_power_attribute_group = {
107 .attrs = dptf_power_attrs,
108 .name = "dptf_power"
109};
110
111static struct attribute *dptf_battery_attrs[] = {
112 &dev_attr_max_platform_power_mw.attr,
113 &dev_attr_max_steady_state_power_mw.attr,
114 &dev_attr_high_freq_impedance_mohm.attr,
115 &dev_attr_no_load_voltage_mv.attr,
116 &dev_attr_current_discharge_capbility_ma.attr,
117 NULL
118};
119
120static const struct attribute_group dptf_battery_attribute_group = {
121 .attrs = dptf_battery_attrs,
122 .name = "dptf_battery"
123};
124
125#define MAX_POWER_CHANGED 0x80
126#define POWER_STATE_CHANGED 0x81
127#define STEADY_STATE_POWER_CHANGED 0x83
128#define POWER_PROP_CHANGE_EVENT 0x84
129#define IMPEDANCED_CHNGED 0x85
130#define VOLTAGE_CURRENT_CHANGED 0x86
131
132static long long dptf_participant_type(acpi_handle handle)
133{
134 unsigned long long ptype;
135 acpi_status status;
136
137 status = acpi_evaluate_integer(handle, "PTYP", NULL, &ptype);
138 if (ACPI_FAILURE(status))
139 return -ENODEV;
140
141 return ptype;
142}
143
144static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
145{
146 struct platform_device *pdev = data;
147 char *attr;
148
149 switch (event) {
150 case POWER_STATE_CHANGED:
151 attr = "platform_power_source";
152 break;
153 case POWER_PROP_CHANGE_EVENT:
154 attr = "rest_of_platform_power_mw";
155 break;
156 case MAX_POWER_CHANGED:
157 attr = "max_platform_power_mw";
158 break;
159 case STEADY_STATE_POWER_CHANGED:
160 attr = "max_steady_state_power_mw";
161 break;
162 case VOLTAGE_CURRENT_CHANGED:
163 attr = "no_load_voltage_mv";
164 break;
165 default:
166 dev_err(&pdev->dev, "Unsupported event [0x%x]\n", event);
167 return;
168 }
169
170
171
172
173
174 if (dptf_participant_type(handle) == 0x0CULL)
175 sysfs_notify(&pdev->dev.kobj, "dptf_battery", attr);
176 else
177 sysfs_notify(&pdev->dev.kobj, "dptf_power", attr);
178}
179
180static int dptf_power_add(struct platform_device *pdev)
181{
182 const struct attribute_group *attr_group;
183 struct acpi_device *acpi_dev;
184 unsigned long long ptype;
185 int result;
186
187 acpi_dev = ACPI_COMPANION(&(pdev->dev));
188 if (!acpi_dev)
189 return -ENODEV;
190
191 ptype = dptf_participant_type(acpi_dev->handle);
192 if (ptype == 0x11)
193 attr_group = &dptf_power_attribute_group;
194 else if (ptype == 0x0C)
195 attr_group = &dptf_battery_attribute_group;
196 else
197 return -ENODEV;
198
199 result = acpi_install_notify_handler(acpi_dev->handle,
200 ACPI_DEVICE_NOTIFY,
201 dptf_power_notify,
202 (void *)pdev);
203 if (result)
204 return result;
205
206 result = sysfs_create_group(&pdev->dev.kobj,
207 attr_group);
208 if (result) {
209 acpi_remove_notify_handler(acpi_dev->handle,
210 ACPI_DEVICE_NOTIFY,
211 dptf_power_notify);
212 return result;
213 }
214
215 platform_set_drvdata(pdev, acpi_dev);
216
217 return 0;
218}
219
220static int dptf_power_remove(struct platform_device *pdev)
221{
222 struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
223
224 acpi_remove_notify_handler(acpi_dev->handle,
225 ACPI_DEVICE_NOTIFY,
226 dptf_power_notify);
227
228 if (dptf_participant_type(acpi_dev->handle) == 0x0CULL)
229 sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group);
230 else
231 sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group);
232
233 return 0;
234}
235
236static const struct acpi_device_id int3407_device_ids[] = {
237 {"INT3407", 0},
238 {"INT3532", 0},
239 {"INTC1047", 0},
240 {"INTC1050", 0},
241 {"INTC1060", 0},
242 {"INTC1061", 0},
243 {"", 0},
244};
245MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
246
247static 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
256module_platform_driver(dptf_power_driver);
257
258MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
259MODULE_LICENSE("GPL v2");
260MODULE_DESCRIPTION("ACPI DPTF platform power driver");
261