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 }
409 
410 static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
411 			int *temp)
412 {
413 	*temp = 20 * 1000; /* faked temp sensor with 20C */
414 	return 0;
415 }
416 
417 static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
418 				       enum thermal_device_mode mode)
419 {
420 	struct int3400_thermal_priv *priv = thermal->devdata;
421 	int result = 0;
422 
423 	if (!priv)
424 		return -EINVAL;
425 
426 	if (mode != thermal->mode)
427 		result = int3400_thermal_run_osc(priv->adev->handle,
428 						priv->current_uuid_index,
429 						mode == THERMAL_DEVICE_ENABLED);
430 
431 
432 	evaluate_odvp(priv);
433 
434 	return result;
435 }
436 
437 static struct thermal_zone_device_ops int3400_thermal_ops = {
438 	.get_temp = int3400_thermal_get_temp,
439 	.change_mode = int3400_thermal_change_mode,
440 };
441 
442 static struct thermal_zone_params int3400_thermal_params = {
443 	.governor_name = "user_space",
444 	.no_hwmon = true,
445 };
446 
447 static void int3400_setup_gddv(struct int3400_thermal_priv *priv)
448 {
449 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
450 	union acpi_object *obj;
451 	acpi_status status;
452 
453 	status = acpi_evaluate_object(priv->adev->handle, "GDDV", NULL,
454 				      &buffer);
455 	if (ACPI_FAILURE(status) || !buffer.length)
456 		return;
457 
458 	obj = buffer.pointer;
459 	if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 1
460 	    || obj->package.elements[0].type != ACPI_TYPE_BUFFER) {
461 		kfree(buffer.pointer);
462 		return;
463 	}
464 
465 	priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,
466 				   obj->package.elements[0].buffer.length,
467 				   GFP_KERNEL);
468 	bin_attr_data_vault.private = priv->data_vault;
469 	bin_attr_data_vault.size = obj->package.elements[0].buffer.length;
470 	kfree(buffer.pointer);
471 }
472 
473 static int int3400_thermal_probe(struct platform_device *pdev)
474 {
475 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
476 	struct int3400_thermal_priv *priv;
477 	int result;
478 
479 	if (!adev)
480 		return -ENODEV;
481 
482 	priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL);
483 	if (!priv)
484 		return -ENOMEM;
485 
486 	priv->pdev = pdev;
487 	priv->adev = adev;
488 
489 	result = int3400_thermal_get_uuids(priv);
490 
491 	/* Missing IDSP isn't fatal */
492 	if (result && result != -ENODEV)
493 		goto free_priv;
494 
495 	priv->current_uuid_index = -1;
496 
497 	result = acpi_parse_art(priv->adev->handle, &priv->art_count,
498 				&priv->arts, true);
499 	if (result)
500 		dev_dbg(&pdev->dev, "_ART table parsing error\n");
501 
502 	result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
503 				&priv->trts, true);
504 	if (result)
505 		dev_dbg(&pdev->dev, "_TRT table parsing error\n");
506 
507 	platform_set_drvdata(pdev, priv);
508 
509 	int3400_setup_gddv(priv);
510 
511 	evaluate_odvp(priv);
512 
513 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
514 						priv, &int3400_thermal_ops,
515 						&int3400_thermal_params, 0, 0);
516 	if (IS_ERR(priv->thermal)) {
517 		result = PTR_ERR(priv->thermal);
518 		goto free_art_trt;
519 	}
520 
521 	priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
522 							priv->adev->handle);
523 
524 	result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group);
525 	if (result)
526 		goto free_rel_misc;
527 
528 	if (acpi_has_method(priv->adev->handle, "IMOK")) {
529 		result = sysfs_create_group(&pdev->dev.kobj, &imok_attribute_group);
530 		if (result)
531 			goto free_imok;
532 	}
533 
534 	if (priv->data_vault) {
535 		result = sysfs_create_group(&pdev->dev.kobj,
536 					    &data_attribute_group);
537 		if (result)
538 			goto free_uuid;
539 	}
540 
541 	result = acpi_install_notify_handler(
542 			priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify,
543 			(void *)priv);
544 	if (result)
545 		goto free_sysfs;
546 
547 	return 0;
548 
549 free_sysfs:
550 	cleanup_odvp(priv);
551 	if (priv->data_vault) {
552 		sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
553 		kfree(priv->data_vault);
554 	}
555 free_uuid:
556 	sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
557 free_imok:
558 	sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
559 free_rel_misc:
560 	if (!priv->rel_misc_dev_res)
561 		acpi_thermal_rel_misc_device_remove(priv->adev->handle);
562 	thermal_zone_device_unregister(priv->thermal);
563 free_art_trt:
564 	kfree(priv->trts);
565 	kfree(priv->arts);
566 free_priv:
567 	kfree(priv);
568 	return result;
569 }
570 
571 static int int3400_thermal_remove(struct platform_device *pdev)
572 {
573 	struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
574 
575 	acpi_remove_notify_handler(
576 			priv->adev->handle, ACPI_DEVICE_NOTIFY,
577 			int3400_notify);
578 
579 	cleanup_odvp(priv);
580 
581 	if (!priv->rel_misc_dev_res)
582 		acpi_thermal_rel_misc_device_remove(priv->adev->handle);
583 
584 	if (priv->data_vault)
585 		sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
586 	sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
587 	sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
588 	thermal_zone_device_unregister(priv->thermal);
589 	kfree(priv->data_vault);
590 	kfree(priv->trts);
591 	kfree(priv->arts);
592 	kfree(priv);
593 	return 0;
594 }
595 
596 static const struct acpi_device_id int3400_thermal_match[] = {
597 	{"INT3400", 0},
598 	{"INTC1040", 0},
599 	{"INTC1041", 0},
600 	{}
601 };
602 
603 MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
604 
605 static struct platform_driver int3400_thermal_driver = {
606 	.probe = int3400_thermal_probe,
607 	.remove = int3400_thermal_remove,
608 	.driver = {
609 		   .name = "int3400 thermal",
610 		   .acpi_match_table = ACPI_PTR(int3400_thermal_match),
611 		   },
612 };
613 
614 module_platform_driver(int3400_thermal_driver);
615 
616 MODULE_DESCRIPTION("INT3400 Thermal driver");
617 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
618 MODULE_LICENSE("GPL");
619