1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * INT3400 thermal driver
4  *
5  * Copyright (C) 2014, Intel Corporation
6  * Authors: Zhang Rui <rui.zhang@intel.com>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/acpi.h>
12 #include <linux/thermal.h>
13 #include "acpi_thermal_rel.h"
14 
15 #define INT3400_THERMAL_TABLE_CHANGED 0x83
16 #define INT3400_ODVP_CHANGED 0x88
17 #define INT3400_KEEP_ALIVE 0xA0
18 
19 enum int3400_thermal_uuid {
20 	INT3400_THERMAL_PASSIVE_1,
21 	INT3400_THERMAL_ACTIVE,
22 	INT3400_THERMAL_CRITICAL,
23 	INT3400_THERMAL_ADAPTIVE_PERFORMANCE,
24 	INT3400_THERMAL_EMERGENCY_CALL_MODE,
25 	INT3400_THERMAL_PASSIVE_2,
26 	INT3400_THERMAL_POWER_BOSS,
27 	INT3400_THERMAL_VIRTUAL_SENSOR,
28 	INT3400_THERMAL_COOLING_MODE,
29 	INT3400_THERMAL_HARDWARE_DUTY_CYCLING,
30 	INT3400_THERMAL_MAXIMUM_UUID,
31 };
32 
33 static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
34 	"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
35 	"3A95C389-E4B8-4629-A526-C52C88626BAE",
36 	"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
37 	"63BE270F-1C11-48FD-A6F7-3AF253FF3E2D",
38 	"5349962F-71E6-431D-9AE8-0A635B710AEE",
39 	"9E04115A-AE87-4D1C-9500-0F3E340BFE75",
40 	"F5A35014-C209-46A4-993A-EB56DE7530A1",
41 	"6ED722A7-9240-48A5-B479-31EEF723D7CF",
42 	"16CAF1B7-DD38-40ED-B1C1-1B8A1913D531",
43 	"BE84BABF-C4D4-403D-B495-3128FD44dAC1",
44 };
45 
46 struct odvp_attr;
47 
48 struct int3400_thermal_priv {
49 	struct acpi_device *adev;
50 	struct platform_device *pdev;
51 	struct thermal_zone_device *thermal;
52 	int art_count;
53 	struct art *arts;
54 	int trt_count;
55 	struct trt *trts;
56 	u8 uuid_bitmap;
57 	int rel_misc_dev_res;
58 	int current_uuid_index;
59 	char *data_vault;
60 	int odvp_count;
61 	int *odvp;
62 	struct odvp_attr *odvp_attrs;
63 };
64 
65 static int evaluate_odvp(struct int3400_thermal_priv *priv);
66 
67 struct odvp_attr {
68 	int odvp;
69 	struct int3400_thermal_priv *priv;
70 	struct kobj_attribute attr;
71 };
72 
73 static ssize_t data_vault_read(struct file *file, struct kobject *kobj,
74 	     struct bin_attribute *attr, char *buf, loff_t off, size_t count)
75 {
76 	memcpy(buf, attr->private + off, count);
77 	return count;
78 }
79 
80 static BIN_ATTR_RO(data_vault, 0);
81 
82 static struct bin_attribute *data_attributes[] = {
83 	&bin_attr_data_vault,
84 	NULL,
85 };
86 
87 static ssize_t imok_store(struct device *dev, struct device_attribute *attr,
88 			  const char *buf, size_t count)
89 {
90 	struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
91 	acpi_status status;
92 	int input, ret;
93 
94 	ret = kstrtouint(buf, 10, &input);
95 	if (ret)
96 		return ret;
97 	status = acpi_execute_simple_method(priv->adev->handle, "IMOK", input);
98 	if (ACPI_FAILURE(status))
99 		return -EIO;
100 
101 	return count;
102 }
103 
104 static DEVICE_ATTR_WO(imok);
105 
106 static struct attribute *imok_attr[] = {
107 	&dev_attr_imok.attr,
108 	NULL
109 };
110 
111 static const struct attribute_group imok_attribute_group = {
112 	.attrs = imok_attr,
113 };
114 
115 static const struct attribute_group data_attribute_group = {
116 	.bin_attrs = data_attributes,
117 };
118 
119 static ssize_t available_uuids_show(struct device *dev,
120 				    struct device_attribute *attr,
121 				    char *buf)
122 {
123 	struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
124 	int i;
125 	int length = 0;
126 
127 	if (!priv->uuid_bitmap)
128 		return sprintf(buf, "UNKNOWN\n");
129 
130 	for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) {
131 		if (priv->uuid_bitmap & (1 << i))
132 			if (PAGE_SIZE - length > 0)
133 				length += scnprintf(&buf[length],
134 						   PAGE_SIZE - length,
135 						   "%s\n",
136 						   int3400_thermal_uuids[i]);
137 	}
138 
139 	return length;
140 }
141 
142 static ssize_t current_uuid_show(struct device *dev,
143 				 struct device_attribute *devattr, char *buf)
144 {
145 	struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
146 
147 	if (priv->current_uuid_index == -1)
148 		return sprintf(buf, "INVALID\n");
149 
150 	return sprintf(buf, "%s\n",
151 		       int3400_thermal_uuids[priv->current_uuid_index]);
152 }
153 
154 static ssize_t current_uuid_store(struct device *dev,
155 				  struct device_attribute *attr,
156 				  const char *buf, size_t count)
157 {
158 	struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
159 	int i;
160 
161 	for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) {
162 		if (!strncmp(buf, int3400_thermal_uuids[i],
163 			     sizeof(int3400_thermal_uuids[i]) - 1)) {
164 			/*
165 			 * If we have a list of supported UUIDs, make sure
166 			 * this one is supported.
167 			 */
168 			if (priv->uuid_bitmap &&
169 			    !(priv->uuid_bitmap & (1 << i)))
170 				return -EINVAL;
171 
172 			priv->current_uuid_index = i;
173 			return count;
174 		}
175 	}
176 
177 	return -EINVAL;
178 }
179 
180 static DEVICE_ATTR_RW(current_uuid);
181 static DEVICE_ATTR_RO(available_uuids);
182 static struct attribute *uuid_attrs[] = {
183 	&dev_attr_available_uuids.attr,
184 	&dev_attr_current_uuid.attr,
185 	NULL
186 };
187 
188 static const struct attribute_group uuid_attribute_group = {
189 	.attrs = uuid_attrs,
190 	.name = "uuids"
191 };
192 
193 static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv)
194 {
195 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL};
196 	union acpi_object *obja, *objb;
197 	int i, j;
198 	int result = 0;
199 	acpi_status status;
200 
201 	status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf);
202 	if (ACPI_FAILURE(status))
203 		return -ENODEV;
204 
205 	obja = (union acpi_object *)buf.pointer;
206 	if (obja->type != ACPI_TYPE_PACKAGE) {
207 		result = -EINVAL;
208 		goto end;
209 	}
210 
211 	for (i = 0; i < obja->package.count; i++) {
212 		objb = &obja->package.elements[i];
213 		if (objb->type != ACPI_TYPE_BUFFER) {
214 			result = -EINVAL;
215 			goto end;
216 		}
217 
218 		/* UUID must be 16 bytes */
219 		if (objb->buffer.length != 16) {
220 			result = -EINVAL;
221 			goto end;
222 		}
223 
224 		for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) {
225 			guid_t guid;
226 
227 			guid_parse(int3400_thermal_uuids[j], &guid);
228 			if (guid_equal((guid_t *)objb->buffer.pointer, &guid)) {
229 				priv->uuid_bitmap |= (1 << j);
230 				break;
231 			}
232 		}
233 	}
234 
235 end:
236 	kfree(buf.pointer);
237 	return result;
238 }
239 
240 static int int3400_thermal_run_osc(acpi_handle handle,
241 				enum int3400_thermal_uuid uuid, bool enable)
242 {
243 	u32 ret, buf[2];
244 	acpi_status status;
245 	int result = 0;
246 	struct acpi_osc_context context = {
247 		.uuid_str = NULL,
248 		.rev = 1,
249 		.cap.length = 8,
250 	};
251 
252 	if (uuid < 0 || uuid >= INT3400_THERMAL_MAXIMUM_UUID)
253 		return -EINVAL;
254 
255 	context.uuid_str = int3400_thermal_uuids[uuid];
256 
257 	buf[OSC_QUERY_DWORD] = 0;
258 	buf[OSC_SUPPORT_DWORD] = enable;
259 
260 	context.cap.pointer = buf;
261 
262 	status = acpi_run_osc(handle, &context);
263 	if (ACPI_SUCCESS(status)) {
264 		ret = *((u32 *)(context.ret.pointer + 4));
265 		if (ret != enable)
266 			result = -EPERM;
267 	} else
268 		result = -EPERM;
269 
270 	kfree(context.ret.pointer);
271 
272 	return result;
273 }
274 
275 static ssize_t odvp_show(struct kobject *kobj, struct kobj_attribute *attr,
276 			 char *buf)
277 {
278 	struct odvp_attr *odvp_attr;
279 
280 	odvp_attr = container_of(attr, struct odvp_attr, attr);
281 
282 	return sprintf(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]);
283 }
284 
285 static void cleanup_odvp(struct int3400_thermal_priv *priv)
286 {
287 	int i;
288 
289 	if (priv->odvp_attrs) {
290 		for (i = 0; i < priv->odvp_count; i++) {
291 			sysfs_remove_file(&priv->pdev->dev.kobj,
292 					  &priv->odvp_attrs[i].attr.attr);
293 			kfree(priv->odvp_attrs[i].attr.attr.name);
294 		}
295 		kfree(priv->odvp_attrs);
296 	}
297 	kfree(priv->odvp);
298 	priv->odvp_count = 0;
299 }
300 
301 static int evaluate_odvp(struct int3400_thermal_priv *priv)
302 {
303 	struct acpi_buffer odvp = { ACPI_ALLOCATE_BUFFER, NULL };
304 	union acpi_object *obj = NULL;
305 	acpi_status status;
306 	int i, ret;
307 
308 	status = acpi_evaluate_object(priv->adev->handle, "ODVP", NULL, &odvp);
309 	if (ACPI_FAILURE(status)) {
310 		ret = -EINVAL;
311 		goto out_err;
312 	}
313 
314 	obj = odvp.pointer;
315 	if (obj->type != ACPI_TYPE_PACKAGE) {
316 		ret = -EINVAL;
317 		goto out_err;
318 	}
319 
320 	if (priv->odvp == NULL) {
321 		priv->odvp_count = obj->package.count;
322 		priv->odvp = kmalloc_array(priv->odvp_count, sizeof(int),
323 				     GFP_KERNEL);
324 		if (!priv->odvp) {
325 			ret = -ENOMEM;
326 			goto out_err;
327 		}
328 	}
329 
330 	if (priv->odvp_attrs == NULL) {
331 		priv->odvp_attrs = kcalloc(priv->odvp_count,
332 					   sizeof(struct odvp_attr),
333 					   GFP_KERNEL);
334 		if (!priv->odvp_attrs) {
335 			ret = -ENOMEM;
336 			goto out_err;
337 		}
338 		for (i = 0; i < priv->odvp_count; i++) {
339 			struct odvp_attr *odvp = &priv->odvp_attrs[i];
340 
341 			sysfs_attr_init(&odvp->attr.attr);
342 			odvp->priv = priv;
343 			odvp->odvp = i;
344 			odvp->attr.attr.name = kasprintf(GFP_KERNEL,
345 							 "odvp%d", i);
346 
347 			if (!odvp->attr.attr.name) {
348 				ret = -ENOMEM;
349 				goto out_err;
350 			}
351 			odvp->attr.attr.mode = 0444;
352 			odvp->attr.show = odvp_show;
353 			odvp->attr.store = NULL;
354 			ret = sysfs_create_file(&priv->pdev->dev.kobj,
355 						&odvp->attr.attr);
356 			if (ret)
357 				goto out_err;
358 		}
359 	}
360 
361 	for (i = 0; i < obj->package.count; i++) {
362 		if (obj->package.elements[i].type == ACPI_TYPE_INTEGER)
363 			priv->odvp[i] = obj->package.elements[i].integer.value;
364 	}
365 
366 	kfree(obj);
367 	return 0;
368 
369 out_err:
370 	cleanup_odvp(priv);
371 	kfree(obj);
372 	return ret;
373 }
374 
375 static void int3400_notify(acpi_handle handle,
376 			u32 event,
377 			void *data)
378 {
379 	struct int3400_thermal_priv *priv = data;
380 	char *thermal_prop[5];
381 	int therm_event;
382 
383 	if (!priv)
384 		return;
385 
386 	switch (event) {
387 	case INT3400_THERMAL_TABLE_CHANGED:
388 		therm_event = THERMAL_TABLE_CHANGED;
389 		break;
390 	case INT3400_KEEP_ALIVE:
391 		therm_event = THERMAL_EVENT_KEEP_ALIVE;
392 		break;
393 	case INT3400_ODVP_CHANGED:
394 		evaluate_odvp(priv);
395 		therm_event = THERMAL_DEVICE_POWER_CAPABILITY_CHANGED;
396 		break;
397 	default:
398 		/* Ignore unknown notification codes sent to INT3400 device */
399 		return;
400 	}
401 
402 	thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", priv->thermal->type);
403 	thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", priv->thermal->temperature);
404 	thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=");
405 	thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", therm_event);
406 	thermal_prop[4] = NULL;
407 	kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, thermal_prop);
408 	kfree(thermal_prop[0]);
409 	kfree(thermal_prop[1]);
410 	kfree(thermal_prop[2]);
411 	kfree(thermal_prop[3]);
412 }
413 
414 static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
415 			int *temp)
416 {
417 	*temp = 20 * 1000; /* faked temp sensor with 20C */
418 	return 0;
419 }
420 
421 static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
422 				       enum thermal_device_mode mode)
423 {
424 	struct int3400_thermal_priv *priv = thermal->devdata;
425 	int result = 0;
426 
427 	if (!priv)
428 		return -EINVAL;
429 
430 	if (mode != thermal->mode)
431 		result = int3400_thermal_run_osc(priv->adev->handle,
432 						priv->current_uuid_index,
433 						mode == THERMAL_DEVICE_ENABLED);
434 
435 
436 	evaluate_odvp(priv);
437 
438 	return result;
439 }
440 
441 static struct thermal_zone_device_ops int3400_thermal_ops = {
442 	.get_temp = int3400_thermal_get_temp,
443 	.change_mode = int3400_thermal_change_mode,
444 };
445 
446 static struct thermal_zone_params int3400_thermal_params = {
447 	.governor_name = "user_space",
448 	.no_hwmon = true,
449 };
450 
451 static void int3400_setup_gddv(struct int3400_thermal_priv *priv)
452 {
453 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
454 	union acpi_object *obj;
455 	acpi_status status;
456 
457 	status = acpi_evaluate_object(priv->adev->handle, "GDDV", NULL,
458 				      &buffer);
459 	if (ACPI_FAILURE(status) || !buffer.length)
460 		return;
461 
462 	obj = buffer.pointer;
463 	if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 1
464 	    || obj->package.elements[0].type != ACPI_TYPE_BUFFER) {
465 		kfree(buffer.pointer);
466 		return;
467 	}
468 
469 	priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,
470 				   obj->package.elements[0].buffer.length,
471 				   GFP_KERNEL);
472 	bin_attr_data_vault.private = priv->data_vault;
473 	bin_attr_data_vault.size = obj->package.elements[0].buffer.length;
474 	kfree(buffer.pointer);
475 }
476 
477 static int int3400_thermal_probe(struct platform_device *pdev)
478 {
479 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
480 	struct int3400_thermal_priv *priv;
481 	int result;
482 
483 	if (!adev)
484 		return -ENODEV;
485 
486 	priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL);
487 	if (!priv)
488 		return -ENOMEM;
489 
490 	priv->pdev = pdev;
491 	priv->adev = adev;
492 
493 	result = int3400_thermal_get_uuids(priv);
494 
495 	/* Missing IDSP isn't fatal */
496 	if (result && result != -ENODEV)
497 		goto free_priv;
498 
499 	priv->current_uuid_index = -1;
500 
501 	result = acpi_parse_art(priv->adev->handle, &priv->art_count,
502 				&priv->arts, true);
503 	if (result)
504 		dev_dbg(&pdev->dev, "_ART table parsing error\n");
505 
506 	result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
507 				&priv->trts, true);
508 	if (result)
509 		dev_dbg(&pdev->dev, "_TRT table parsing error\n");
510 
511 	platform_set_drvdata(pdev, priv);
512 
513 	int3400_setup_gddv(priv);
514 
515 	evaluate_odvp(priv);
516 
517 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
518 						priv, &int3400_thermal_ops,
519 						&int3400_thermal_params, 0, 0);
520 	if (IS_ERR(priv->thermal)) {
521 		result = PTR_ERR(priv->thermal);
522 		goto free_art_trt;
523 	}
524 
525 	priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
526 							priv->adev->handle);
527 
528 	result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group);
529 	if (result)
530 		goto free_rel_misc;
531 
532 	if (acpi_has_method(priv->adev->handle, "IMOK")) {
533 		result = sysfs_create_group(&pdev->dev.kobj, &imok_attribute_group);
534 		if (result)
535 			goto free_imok;
536 	}
537 
538 	if (priv->data_vault) {
539 		result = sysfs_create_group(&pdev->dev.kobj,
540 					    &data_attribute_group);
541 		if (result)
542 			goto free_uuid;
543 	}
544 
545 	result = acpi_install_notify_handler(
546 			priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify,
547 			(void *)priv);
548 	if (result)
549 		goto free_sysfs;
550 
551 	return 0;
552 
553 free_sysfs:
554 	cleanup_odvp(priv);
555 	if (priv->data_vault) {
556 		sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
557 		kfree(priv->data_vault);
558 	}
559 free_uuid:
560 	sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
561 free_imok:
562 	sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
563 free_rel_misc:
564 	if (!priv->rel_misc_dev_res)
565 		acpi_thermal_rel_misc_device_remove(priv->adev->handle);
566 	thermal_zone_device_unregister(priv->thermal);
567 free_art_trt:
568 	kfree(priv->trts);
569 	kfree(priv->arts);
570 free_priv:
571 	kfree(priv);
572 	return result;
573 }
574 
575 static int int3400_thermal_remove(struct platform_device *pdev)
576 {
577 	struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
578 
579 	acpi_remove_notify_handler(
580 			priv->adev->handle, ACPI_DEVICE_NOTIFY,
581 			int3400_notify);
582 
583 	cleanup_odvp(priv);
584 
585 	if (!priv->rel_misc_dev_res)
586 		acpi_thermal_rel_misc_device_remove(priv->adev->handle);
587 
588 	if (priv->data_vault)
589 		sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
590 	sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
591 	sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
592 	thermal_zone_device_unregister(priv->thermal);
593 	kfree(priv->data_vault);
594 	kfree(priv->trts);
595 	kfree(priv->arts);
596 	kfree(priv);
597 	return 0;
598 }
599 
600 static const struct acpi_device_id int3400_thermal_match[] = {
601 	{"INT3400", 0},
602 	{"INTC1040", 0},
603 	{"INTC1041", 0},
604 	{}
605 };
606 
607 MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
608 
609 static struct platform_driver int3400_thermal_driver = {
610 	.probe = int3400_thermal_probe,
611 	.remove = int3400_thermal_remove,
612 	.driver = {
613 		   .name = "int3400 thermal",
614 		   .acpi_match_table = ACPI_PTR(int3400_thermal_match),
615 		   },
616 };
617 
618 module_platform_driver(int3400_thermal_driver);
619 
620 MODULE_DESCRIPTION("INT3400 Thermal driver");
621 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
622 MODULE_LICENSE("GPL");
623