2 * INT3400 thermal driver
4 * Copyright (C) 2014, Intel Corporation
5 * Authors: Zhang Rui <rui.zhang@intel.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/acpi.h>
16 #include <linux/thermal.h>
17 #include "acpi_thermal_rel.h"
19 enum int3400_thermal_uuid
{
20 INT3400_THERMAL_PASSIVE_1
,
21 INT3400_THERMAL_PASSIVE_2
,
22 INT3400_THERMAL_ACTIVE
,
23 INT3400_THERMAL_CRITICAL
,
24 INT3400_THERMAL_COOLING_MODE
,
25 INT3400_THERMAL_MAXIMUM_UUID
,
28 static u8
*int3400_thermal_uuids
[INT3400_THERMAL_MAXIMUM_UUID
] = {
29 "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
30 "9E04115A-AE87-4D1C-9500-0F3E340BFE75",
31 "3A95C389-E4B8-4629-A526-C52C88626BAE",
32 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
33 "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
36 struct int3400_thermal_priv
{
37 struct acpi_device
*adev
;
38 struct thermal_zone_device
*thermal
;
48 static int int3400_thermal_get_uuids(struct int3400_thermal_priv
*priv
)
50 struct acpi_buffer buf
= { ACPI_ALLOCATE_BUFFER
, NULL
};
51 union acpi_object
*obja
, *objb
;
56 status
= acpi_evaluate_object(priv
->adev
->handle
, "IDSP", NULL
, &buf
);
57 if (ACPI_FAILURE(status
))
60 obja
= (union acpi_object
*)buf
.pointer
;
61 if (obja
->type
!= ACPI_TYPE_PACKAGE
) {
66 for (i
= 0; i
< obja
->package
.count
; i
++) {
67 objb
= &obja
->package
.elements
[i
];
68 if (objb
->type
!= ACPI_TYPE_BUFFER
) {
73 /* UUID must be 16 bytes */
74 if (objb
->buffer
.length
!= 16) {
79 for (j
= 0; j
< INT3400_THERMAL_MAXIMUM_UUID
; j
++) {
82 acpi_str_to_uuid(int3400_thermal_uuids
[j
], uuid
);
83 if (!strncmp(uuid
, objb
->buffer
.pointer
, 16)) {
84 priv
->uuid_bitmap
|= (1 << j
);
95 static int int3400_thermal_run_osc(acpi_handle handle
,
96 enum int3400_thermal_uuid uuid
, bool enable
)
101 struct acpi_osc_context context
= {
102 .uuid_str
= int3400_thermal_uuids
[uuid
],
107 buf
[OSC_QUERY_DWORD
] = 0;
108 buf
[OSC_SUPPORT_DWORD
] = enable
;
110 context
.cap
.pointer
= buf
;
112 status
= acpi_run_osc(handle
, &context
);
113 if (ACPI_SUCCESS(status
)) {
114 ret
= *((u32
*)(context
.ret
.pointer
+ 4));
120 kfree(context
.ret
.pointer
);
124 static int int3400_thermal_get_temp(struct thermal_zone_device
*thermal
,
127 *temp
= 20 * 1000; /* faked temp sensor with 20C */
131 static int int3400_thermal_get_mode(struct thermal_zone_device
*thermal
,
132 enum thermal_device_mode
*mode
)
134 struct int3400_thermal_priv
*priv
= thermal
->devdata
;
144 static int int3400_thermal_set_mode(struct thermal_zone_device
*thermal
,
145 enum thermal_device_mode mode
)
147 struct int3400_thermal_priv
*priv
= thermal
->devdata
;
154 if (mode
== THERMAL_DEVICE_ENABLED
)
156 else if (mode
== THERMAL_DEVICE_DISABLED
)
161 if (enable
!= priv
->mode
) {
163 /* currently, only PASSIVE COOLING is supported */
164 result
= int3400_thermal_run_osc(priv
->adev
->handle
,
165 INT3400_THERMAL_PASSIVE_1
, enable
);
170 static struct thermal_zone_device_ops int3400_thermal_ops
= {
171 .get_temp
= int3400_thermal_get_temp
,
174 static struct thermal_zone_params int3400_thermal_params
= {
175 .governor_name
= "user_space",
179 static int int3400_thermal_probe(struct platform_device
*pdev
)
181 struct acpi_device
*adev
= ACPI_COMPANION(&pdev
->dev
);
182 struct int3400_thermal_priv
*priv
;
188 priv
= kzalloc(sizeof(struct int3400_thermal_priv
), GFP_KERNEL
);
194 result
= int3400_thermal_get_uuids(priv
);
198 result
= acpi_parse_art(priv
->adev
->handle
, &priv
->art_count
,
204 result
= acpi_parse_trt(priv
->adev
->handle
, &priv
->trt_count
,
209 platform_set_drvdata(pdev
, priv
);
211 if (priv
->uuid_bitmap
& 1 << INT3400_THERMAL_PASSIVE_1
) {
212 int3400_thermal_ops
.get_mode
= int3400_thermal_get_mode
;
213 int3400_thermal_ops
.set_mode
= int3400_thermal_set_mode
;
215 priv
->thermal
= thermal_zone_device_register("INT3400 Thermal", 0, 0,
216 priv
, &int3400_thermal_ops
,
217 &int3400_thermal_params
, 0, 0);
218 if (IS_ERR(priv
->thermal
)) {
219 result
= PTR_ERR(priv
->thermal
);
223 priv
->rel_misc_dev_res
= acpi_thermal_rel_misc_device_add(
236 static int int3400_thermal_remove(struct platform_device
*pdev
)
238 struct int3400_thermal_priv
*priv
= platform_get_drvdata(pdev
);
240 if (!priv
->rel_misc_dev_res
)
241 acpi_thermal_rel_misc_device_remove(priv
->adev
->handle
);
243 thermal_zone_device_unregister(priv
->thermal
);
250 static const struct acpi_device_id int3400_thermal_match
[] = {
255 MODULE_DEVICE_TABLE(acpi
, int3400_thermal_match
);
257 static struct platform_driver int3400_thermal_driver
= {
258 .probe
= int3400_thermal_probe
,
259 .remove
= int3400_thermal_remove
,
261 .name
= "int3400 thermal",
262 .owner
= THIS_MODULE
,
263 .acpi_match_table
= ACPI_PTR(int3400_thermal_match
),
267 module_platform_driver(int3400_thermal_driver
);
269 MODULE_DESCRIPTION("INT3400 Thermal driver");
270 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
271 MODULE_LICENSE("GPL");