diff options
| -rw-r--r-- | drivers/thermal/int340x_thermal/processor_thermal_device.c | 108 |
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 | ||
| 201 | static int proc_thermal_add(struct device *dev, | 201 | static 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 | ||
| 244 | free_buffer: | ||
| 245 | kfree(buf.pointer); | ||
| 246 | |||
| 247 | return ret; | ||
| 248 | } | ||
| 249 | |||
| 250 | #define PROC_POWER_CAPABILITY_CHANGED 0x83 | ||
| 251 | static 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 | |||
| 270 | static 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 | ||
| 283 | free_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 | |||
| 324 | remove_zone: | ||
| 325 | int340x_thermal_zone_remove(proc_priv->int340x_zone); | ||
| 326 | remove_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 | ||
| 289 | static void proc_thermal_remove(struct proc_thermal_device *proc_priv) | 333 | static 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); |
