aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/int340x_thermal/processor_thermal_device.c108
1 files changed, 77 insertions, 31 deletions
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index 36fa724a36c8..42c1ac057bad 100644
--- a/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -198,49 +198,33 @@ static struct thermal_zone_device_ops proc_thermal_local_ops = {
198 .get_temp = proc_thermal_get_zone_temp, 198 .get_temp = proc_thermal_get_zone_temp,
199}; 199};
200 200
201static int proc_thermal_add(struct device *dev, 201static int proc_thermal_read_ppcc(struct proc_thermal_device *proc_priv)
202 struct proc_thermal_device **priv)
203{ 202{
204 struct proc_thermal_device *proc_priv; 203 int i;
205 struct acpi_device *adev;
206 acpi_status status; 204 acpi_status status;
207 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; 205 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
208 union acpi_object *elements, *ppcc; 206 union acpi_object *elements, *ppcc;
209 union acpi_object *p; 207 union acpi_object *p;
210 unsigned long long tmp; 208 int ret = 0;
211 struct thermal_zone_device_ops *ops = NULL;
212 int i;
213 int ret;
214
215 adev = ACPI_COMPANION(dev);
216 if (!adev)
217 return -ENODEV;
218 209
219 status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf); 210 status = acpi_evaluate_object(proc_priv->adev->handle, "PPCC",
211 NULL, &buf);
220 if (ACPI_FAILURE(status)) 212 if (ACPI_FAILURE(status))
221 return -ENODEV; 213 return -ENODEV;
222 214
223 p = buf.pointer; 215 p = buf.pointer;
224 if (!p || (p->type != ACPI_TYPE_PACKAGE)) { 216 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
225 dev_err(dev, "Invalid PPCC data\n"); 217 dev_err(proc_priv->dev, "Invalid PPCC data\n");
226 ret = -EFAULT; 218 ret = -EFAULT;
227 goto free_buffer; 219 goto free_buffer;
228 } 220 }
221
229 if (!p->package.count) { 222 if (!p->package.count) {
230 dev_err(dev, "Invalid PPCC package size\n"); 223 dev_err(proc_priv->dev, "Invalid PPCC package size\n");
231 ret = -EFAULT; 224 ret = -EFAULT;
232 goto free_buffer; 225 goto free_buffer;
233 } 226 }
234 227
235 proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
236 if (!proc_priv) {
237 ret = -ENOMEM;
238 goto free_buffer;
239 }
240
241 proc_priv->dev = dev;
242 proc_priv->adev = adev;
243
244 for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { 228 for (i = 0; i < min((int)p->package.count - 1, 2); ++i) {
245 elements = &(p->package.elements[i+1]); 229 elements = &(p->package.elements[i+1]);
246 if (elements->type != ACPI_TYPE_PACKAGE || 230 if (elements->type != ACPI_TYPE_PACKAGE ||
@@ -257,12 +241,62 @@ static int proc_thermal_add(struct device *dev,
257 proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; 241 proc_priv->power_limits[i].step_uw = ppcc[5].integer.value;
258 } 242 }
259 243
244free_buffer:
245 kfree(buf.pointer);
246
247 return ret;
248}
249
250#define PROC_POWER_CAPABILITY_CHANGED 0x83
251static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
252{
253 struct proc_thermal_device *proc_priv = data;
254
255 if (!proc_priv)
256 return;
257
258 switch (event) {
259 case PROC_POWER_CAPABILITY_CHANGED:
260 proc_thermal_read_ppcc(proc_priv);
261 int340x_thermal_zone_device_update(proc_priv->int340x_zone);
262 break;
263 default:
264 dev_err(proc_priv->dev, "Unsupported event [0x%x]\n", event);
265 break;
266 }
267}
268
269
270static int proc_thermal_add(struct device *dev,
271 struct proc_thermal_device **priv)
272{
273 struct proc_thermal_device *proc_priv;
274 struct acpi_device *adev;
275 acpi_status status;
276 unsigned long long tmp;
277 struct thermal_zone_device_ops *ops = NULL;
278 int ret;
279
280 adev = ACPI_COMPANION(dev);
281 if (!adev)
282 return -ENODEV;
283
284 proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
285 if (!proc_priv)
286 return -ENOMEM;
287
288 proc_priv->dev = dev;
289 proc_priv->adev = adev;
260 *priv = proc_priv; 290 *priv = proc_priv;
261 291
262 ret = sysfs_create_group(&dev->kobj, 292 ret = proc_thermal_read_ppcc(proc_priv);
263 &power_limit_attribute_group); 293 if (!ret) {
294 ret = sysfs_create_group(&dev->kobj,
295 &power_limit_attribute_group);
296
297 }
264 if (ret) 298 if (ret)
265 goto free_buffer; 299 return ret;
266 300
267 status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); 301 status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
268 if (ACPI_FAILURE(status)) { 302 if (ACPI_FAILURE(status)) {
@@ -274,20 +308,32 @@ static int proc_thermal_add(struct device *dev,
274 308
275 proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); 309 proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);
276 if (IS_ERR(proc_priv->int340x_zone)) { 310 if (IS_ERR(proc_priv->int340x_zone)) {
277 sysfs_remove_group(&proc_priv->dev->kobj,
278 &power_limit_attribute_group);
279 ret = PTR_ERR(proc_priv->int340x_zone); 311 ret = PTR_ERR(proc_priv->int340x_zone);
312 goto remove_group;
280 } else 313 } else
281 ret = 0; 314 ret = 0;
282 315
283free_buffer: 316 ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
284 kfree(buf.pointer); 317 proc_thermal_notify,
318 (void *)proc_priv);
319 if (ret)
320 goto remove_zone;
321
322 return 0;
323
324remove_zone:
325 int340x_thermal_zone_remove(proc_priv->int340x_zone);
326remove_group:
327 sysfs_remove_group(&proc_priv->dev->kobj,
328 &power_limit_attribute_group);
285 329
286 return ret; 330 return ret;
287} 331}
288 332
289static void proc_thermal_remove(struct proc_thermal_device *proc_priv) 333static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
290{ 334{
335 acpi_remove_notify_handler(proc_priv->adev->handle,
336 ACPI_DEVICE_NOTIFY, proc_thermal_notify);
291 int340x_thermal_zone_remove(proc_priv->int340x_zone); 337 int340x_thermal_zone_remove(proc_priv->int340x_zone);
292 sysfs_remove_group(&proc_priv->dev->kobj, 338 sysfs_remove_group(&proc_priv->dev->kobj,
293 &power_limit_attribute_group); 339 &power_limit_attribute_group);