diff options
author | Zhang Rui <rui.zhang@intel.com> | 2015-01-30 03:16:25 -0500 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2015-01-30 03:16:25 -0500 |
commit | 8cb68501e1e9c2093e0997eaf8dd45a8bceeefc0 (patch) | |
tree | 0cf883c0ef19facc11413276f5bf6c7c5093d53d /drivers/thermal | |
parent | 6c355fafeb2cde3fa6bf317777ae3018b7f254e6 (diff) | |
parent | 317d9dda0522c18eb230367c88601c2e46cda4f8 (diff) |
Merge branches 'intel-dts-soc-thermal' and 'int340x-enhancement' of .git into next
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/int340x_thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3402_thermal.c | 208 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3403_thermal.c | 208 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.c | 276 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.h | 68 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/processor_thermal_device.c | 90 |
6 files changed, 482 insertions, 369 deletions
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile index d4413698a85f..ba77a34f659f 100644 --- a/drivers/thermal/int340x_thermal/Makefile +++ b/drivers/thermal/int340x_thermal/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o | 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o |
2 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o | ||
2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o | 3 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o |
3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o | 4 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o |
4 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o | 5 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o |
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index c5cbc3af3a05..69df3d960303 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c | |||
@@ -14,152 +14,39 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/acpi.h> | 15 | #include <linux/acpi.h> |
16 | #include <linux/thermal.h> | 16 | #include <linux/thermal.h> |
17 | #include "int340x_thermal_zone.h" | ||
17 | 18 | ||
18 | #define ACPI_ACTIVE_COOLING_MAX_NR 10 | 19 | #define INT3402_PERF_CHANGED_EVENT 0x80 |
19 | 20 | #define INT3402_THERMAL_EVENT 0x90 | |
20 | struct active_trip { | ||
21 | unsigned long temp; | ||
22 | int id; | ||
23 | bool valid; | ||
24 | }; | ||
25 | 21 | ||
26 | struct int3402_thermal_data { | 22 | struct int3402_thermal_data { |
27 | unsigned long *aux_trips; | ||
28 | int aux_trip_nr; | ||
29 | unsigned long psv_temp; | ||
30 | int psv_trip_id; | ||
31 | unsigned long crt_temp; | ||
32 | int crt_trip_id; | ||
33 | unsigned long hot_temp; | ||
34 | int hot_trip_id; | ||
35 | struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR]; | ||
36 | acpi_handle *handle; | 23 | acpi_handle *handle; |
24 | struct int34x_thermal_zone *int340x_zone; | ||
37 | }; | 25 | }; |
38 | 26 | ||
39 | static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, | 27 | static void int3402_notify(acpi_handle handle, u32 event, void *data) |
40 | unsigned long *temp) | ||
41 | { | ||
42 | struct int3402_thermal_data *d = zone->devdata; | ||
43 | unsigned long long tmp; | ||
44 | acpi_status status; | ||
45 | |||
46 | status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp); | ||
47 | if (ACPI_FAILURE(status)) | ||
48 | return -ENODEV; | ||
49 | |||
50 | /* _TMP returns the temperature in tenths of degrees Kelvin */ | ||
51 | *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone, | ||
57 | int trip, unsigned long *temp) | ||
58 | { | 28 | { |
59 | struct int3402_thermal_data *d = zone->devdata; | 29 | struct int3402_thermal_data *priv = data; |
60 | int i; | 30 | |
61 | 31 | if (!priv) | |
62 | if (trip < d->aux_trip_nr) | 32 | return; |
63 | *temp = d->aux_trips[trip]; | 33 | |
64 | else if (trip == d->crt_trip_id) | 34 | switch (event) { |
65 | *temp = d->crt_temp; | 35 | case INT3402_PERF_CHANGED_EVENT: |
66 | else if (trip == d->psv_trip_id) | 36 | break; |
67 | *temp = d->psv_temp; | 37 | case INT3402_THERMAL_EVENT: |
68 | else if (trip == d->hot_trip_id) | 38 | int340x_thermal_zone_device_update(priv->int340x_zone); |
69 | *temp = d->hot_temp; | 39 | break; |
70 | else { | 40 | default: |
71 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | 41 | break; |
72 | if (d->act_trips[i].valid && | ||
73 | d->act_trips[i].id == trip) { | ||
74 | *temp = d->act_trips[i].temp; | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
79 | return -EINVAL; | ||
80 | } | 42 | } |
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone, | ||
85 | int trip, enum thermal_trip_type *type) | ||
86 | { | ||
87 | struct int3402_thermal_data *d = zone->devdata; | ||
88 | int i; | ||
89 | |||
90 | if (trip < d->aux_trip_nr) | ||
91 | *type = THERMAL_TRIP_PASSIVE; | ||
92 | else if (trip == d->crt_trip_id) | ||
93 | *type = THERMAL_TRIP_CRITICAL; | ||
94 | else if (trip == d->hot_trip_id) | ||
95 | *type = THERMAL_TRIP_HOT; | ||
96 | else if (trip == d->psv_trip_id) | ||
97 | *type = THERMAL_TRIP_PASSIVE; | ||
98 | else { | ||
99 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
100 | if (d->act_trips[i].valid && | ||
101 | d->act_trips[i].id == trip) { | ||
102 | *type = THERMAL_TRIP_ACTIVE; | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, | ||
113 | unsigned long temp) | ||
114 | { | ||
115 | struct int3402_thermal_data *d = zone->devdata; | ||
116 | acpi_status status; | ||
117 | char name[10]; | ||
118 | |||
119 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
120 | status = acpi_execute_simple_method(d->handle, name, | ||
121 | MILLICELSIUS_TO_DECI_KELVIN(temp)); | ||
122 | if (ACPI_FAILURE(status)) | ||
123 | return -EIO; | ||
124 | |||
125 | d->aux_trips[trip] = temp; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct thermal_zone_device_ops int3402_thermal_zone_ops = { | ||
130 | .get_temp = int3402_thermal_get_zone_temp, | ||
131 | .get_trip_temp = int3402_thermal_get_trip_temp, | ||
132 | .get_trip_type = int3402_thermal_get_trip_type, | ||
133 | .set_trip_temp = int3402_thermal_set_trip_temp, | ||
134 | }; | ||
135 | |||
136 | static struct thermal_zone_params int3402_thermal_params = { | ||
137 | .governor_name = "user_space", | ||
138 | .no_hwmon = true, | ||
139 | }; | ||
140 | |||
141 | static int int3402_thermal_get_temp(acpi_handle handle, char *name, | ||
142 | unsigned long *temp) | ||
143 | { | ||
144 | unsigned long long r; | ||
145 | acpi_status status; | ||
146 | |||
147 | status = acpi_evaluate_integer(handle, name, NULL, &r); | ||
148 | if (ACPI_FAILURE(status)) | ||
149 | return -EIO; | ||
150 | |||
151 | *temp = DECI_KELVIN_TO_MILLICELSIUS(r); | ||
152 | return 0; | ||
153 | } | 43 | } |
154 | 44 | ||
155 | static int int3402_thermal_probe(struct platform_device *pdev) | 45 | static int int3402_thermal_probe(struct platform_device *pdev) |
156 | { | 46 | { |
157 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); | 47 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); |
158 | struct int3402_thermal_data *d; | 48 | struct int3402_thermal_data *d; |
159 | struct thermal_zone_device *zone; | 49 | int ret; |
160 | acpi_status status; | ||
161 | unsigned long long trip_cnt; | ||
162 | int trip_mask = 0, i; | ||
163 | 50 | ||
164 | if (!acpi_has_method(adev->handle, "_TMP")) | 51 | if (!acpi_has_method(adev->handle, "_TMP")) |
165 | return -ENODEV; | 52 | return -ENODEV; |
@@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev) | |||
168 | if (!d) | 55 | if (!d) |
169 | return -ENOMEM; | 56 | return -ENOMEM; |
170 | 57 | ||
171 | status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); | 58 | d->int340x_zone = int340x_thermal_zone_add(adev, NULL); |
172 | if (ACPI_FAILURE(status)) | 59 | if (IS_ERR(d->int340x_zone)) |
173 | trip_cnt = 0; | 60 | return PTR_ERR(d->int340x_zone); |
174 | else { | 61 | |
175 | d->aux_trips = devm_kzalloc(&pdev->dev, | 62 | ret = acpi_install_notify_handler(adev->handle, |
176 | sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); | 63 | ACPI_DEVICE_NOTIFY, |
177 | if (!d->aux_trips) | 64 | int3402_notify, |
178 | return -ENOMEM; | 65 | d); |
179 | trip_mask = trip_cnt - 1; | 66 | if (ret) { |
180 | d->handle = adev->handle; | 67 | int340x_thermal_zone_remove(d->int340x_zone); |
181 | d->aux_trip_nr = trip_cnt; | 68 | return ret; |
182 | } | ||
183 | |||
184 | d->crt_trip_id = -1; | ||
185 | if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp)) | ||
186 | d->crt_trip_id = trip_cnt++; | ||
187 | d->hot_trip_id = -1; | ||
188 | if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp)) | ||
189 | d->hot_trip_id = trip_cnt++; | ||
190 | d->psv_trip_id = -1; | ||
191 | if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp)) | ||
192 | d->psv_trip_id = trip_cnt++; | ||
193 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
194 | char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; | ||
195 | if (int3402_thermal_get_temp(adev->handle, name, | ||
196 | &d->act_trips[i].temp)) | ||
197 | break; | ||
198 | d->act_trips[i].id = trip_cnt++; | ||
199 | d->act_trips[i].valid = true; | ||
200 | } | 69 | } |
201 | 70 | ||
202 | zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, | 71 | d->handle = adev->handle; |
203 | trip_mask, d, | 72 | platform_set_drvdata(pdev, d); |
204 | &int3402_thermal_zone_ops, | ||
205 | &int3402_thermal_params, | ||
206 | 0, 0); | ||
207 | if (IS_ERR(zone)) | ||
208 | return PTR_ERR(zone); | ||
209 | platform_set_drvdata(pdev, zone); | ||
210 | 73 | ||
211 | return 0; | 74 | return 0; |
212 | } | 75 | } |
213 | 76 | ||
214 | static int int3402_thermal_remove(struct platform_device *pdev) | 77 | static int int3402_thermal_remove(struct platform_device *pdev) |
215 | { | 78 | { |
216 | struct thermal_zone_device *zone = platform_get_drvdata(pdev); | 79 | struct int3402_thermal_data *d = platform_get_drvdata(pdev); |
80 | |||
81 | acpi_remove_notify_handler(d->handle, | ||
82 | ACPI_DEVICE_NOTIFY, int3402_notify); | ||
83 | int340x_thermal_zone_remove(d->int340x_zone); | ||
217 | 84 | ||
218 | thermal_zone_device_unregister(zone); | ||
219 | return 0; | 85 | return 0; |
220 | } | 86 | } |
221 | 87 | ||
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 0faf500d8a77..50a7a08e3a15 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/thermal.h> | 20 | #include <linux/thermal.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include "int340x_thermal_zone.h" | ||
22 | 23 | ||
23 | #define INT3403_TYPE_SENSOR 0x03 | 24 | #define INT3403_TYPE_SENSOR 0x03 |
24 | #define INT3403_TYPE_CHARGER 0x0B | 25 | #define INT3403_TYPE_CHARGER 0x0B |
@@ -26,18 +27,9 @@ | |||
26 | #define INT3403_PERF_CHANGED_EVENT 0x80 | 27 | #define INT3403_PERF_CHANGED_EVENT 0x80 |
27 | #define INT3403_THERMAL_EVENT 0x90 | 28 | #define INT3403_THERMAL_EVENT 0x90 |
28 | 29 | ||
29 | #define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) | 30 | /* Preserved structure for future expandbility */ |
30 | #define KELVIN_OFFSET 2732 | ||
31 | #define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) | ||
32 | |||
33 | struct int3403_sensor { | 31 | struct int3403_sensor { |
34 | struct thermal_zone_device *tzone; | 32 | struct int34x_thermal_zone *int340x_zone; |
35 | unsigned long *thresholds; | ||
36 | unsigned long crit_temp; | ||
37 | int crit_trip_id; | ||
38 | unsigned long psv_temp; | ||
39 | int psv_trip_id; | ||
40 | |||
41 | }; | 33 | }; |
42 | 34 | ||
43 | struct int3403_performance_state { | 35 | struct int3403_performance_state { |
@@ -63,126 +55,6 @@ struct int3403_priv { | |||
63 | void *priv; | 55 | void *priv; |
64 | }; | 56 | }; |
65 | 57 | ||
66 | static int sys_get_curr_temp(struct thermal_zone_device *tzone, | ||
67 | unsigned long *temp) | ||
68 | { | ||
69 | struct int3403_priv *priv = tzone->devdata; | ||
70 | struct acpi_device *device = priv->adev; | ||
71 | unsigned long long tmp; | ||
72 | acpi_status status; | ||
73 | |||
74 | status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); | ||
75 | if (ACPI_FAILURE(status)) | ||
76 | return -EIO; | ||
77 | |||
78 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int sys_get_trip_hyst(struct thermal_zone_device *tzone, | ||
84 | int trip, unsigned long *temp) | ||
85 | { | ||
86 | struct int3403_priv *priv = tzone->devdata; | ||
87 | struct acpi_device *device = priv->adev; | ||
88 | unsigned long long hyst; | ||
89 | acpi_status status; | ||
90 | |||
91 | status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); | ||
92 | if (ACPI_FAILURE(status)) | ||
93 | return -EIO; | ||
94 | |||
95 | /* | ||
96 | * Thermal hysteresis represents a temperature difference. | ||
97 | * Kelvin and Celsius have same degree size. So the | ||
98 | * conversion here between tenths of degree Kelvin unit | ||
99 | * and Milli-Celsius unit is just to multiply 100. | ||
100 | */ | ||
101 | *temp = hyst * 100; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int sys_get_trip_temp(struct thermal_zone_device *tzone, | ||
107 | int trip, unsigned long *temp) | ||
108 | { | ||
109 | struct int3403_priv *priv = tzone->devdata; | ||
110 | struct int3403_sensor *obj = priv->priv; | ||
111 | |||
112 | if (priv->type != INT3403_TYPE_SENSOR || !obj) | ||
113 | return -EINVAL; | ||
114 | |||
115 | if (trip == obj->crit_trip_id) | ||
116 | *temp = obj->crit_temp; | ||
117 | else if (trip == obj->psv_trip_id) | ||
118 | *temp = obj->psv_temp; | ||
119 | else { | ||
120 | /* | ||
121 | * get_trip_temp is a mandatory callback but | ||
122 | * PATx method doesn't return any value, so return | ||
123 | * cached value, which was last set from user space | ||
124 | */ | ||
125 | *temp = obj->thresholds[trip]; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int sys_get_trip_type(struct thermal_zone_device *thermal, | ||
132 | int trip, enum thermal_trip_type *type) | ||
133 | { | ||
134 | struct int3403_priv *priv = thermal->devdata; | ||
135 | struct int3403_sensor *obj = priv->priv; | ||
136 | |||
137 | /* Mandatory callback, may not mean much here */ | ||
138 | if (trip == obj->crit_trip_id) | ||
139 | *type = THERMAL_TRIP_CRITICAL; | ||
140 | else | ||
141 | *type = THERMAL_TRIP_PASSIVE; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, | ||
147 | unsigned long temp) | ||
148 | { | ||
149 | struct int3403_priv *priv = tzone->devdata; | ||
150 | struct acpi_device *device = priv->adev; | ||
151 | struct int3403_sensor *obj = priv->priv; | ||
152 | acpi_status status; | ||
153 | char name[10]; | ||
154 | int ret = 0; | ||
155 | |||
156 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
157 | if (acpi_has_method(device->handle, name)) { | ||
158 | status = acpi_execute_simple_method(device->handle, name, | ||
159 | MILLI_CELSIUS_TO_DECI_KELVIN(temp, | ||
160 | KELVIN_OFFSET)); | ||
161 | if (ACPI_FAILURE(status)) | ||
162 | ret = -EIO; | ||
163 | else | ||
164 | obj->thresholds[trip] = temp; | ||
165 | } else { | ||
166 | ret = -EIO; | ||
167 | dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); | ||
168 | } | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static struct thermal_zone_device_ops tzone_ops = { | ||
174 | .get_temp = sys_get_curr_temp, | ||
175 | .get_trip_temp = sys_get_trip_temp, | ||
176 | .get_trip_type = sys_get_trip_type, | ||
177 | .set_trip_temp = sys_set_trip_temp, | ||
178 | .get_trip_hyst = sys_get_trip_hyst, | ||
179 | }; | ||
180 | |||
181 | static struct thermal_zone_params int3403_thermal_params = { | ||
182 | .governor_name = "user_space", | ||
183 | .no_hwmon = true, | ||
184 | }; | ||
185 | |||
186 | static void int3403_notify(acpi_handle handle, | 58 | static void int3403_notify(acpi_handle handle, |
187 | u32 event, void *data) | 59 | u32 event, void *data) |
188 | { | 60 | { |
@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle, | |||
200 | case INT3403_PERF_CHANGED_EVENT: | 72 | case INT3403_PERF_CHANGED_EVENT: |
201 | break; | 73 | break; |
202 | case INT3403_THERMAL_EVENT: | 74 | case INT3403_THERMAL_EVENT: |
203 | thermal_zone_device_update(obj->tzone); | 75 | int340x_thermal_zone_device_update(obj->int340x_zone); |
204 | break; | 76 | break; |
205 | default: | 77 | default: |
206 | dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); | 78 | dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); |
@@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle, | |||
208 | } | 80 | } |
209 | } | 81 | } |
210 | 82 | ||
211 | static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) | ||
212 | { | ||
213 | unsigned long long crt; | ||
214 | acpi_status status; | ||
215 | |||
216 | status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); | ||
217 | if (ACPI_FAILURE(status)) | ||
218 | return -EIO; | ||
219 | |||
220 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) | ||
226 | { | ||
227 | unsigned long long psv; | ||
228 | acpi_status status; | ||
229 | |||
230 | status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); | ||
231 | if (ACPI_FAILURE(status)) | ||
232 | return -EIO; | ||
233 | |||
234 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int int3403_sensor_add(struct int3403_priv *priv) | 83 | static int int3403_sensor_add(struct int3403_priv *priv) |
240 | { | 84 | { |
241 | int result = 0; | 85 | int result = 0; |
242 | acpi_status status; | ||
243 | struct int3403_sensor *obj; | 86 | struct int3403_sensor *obj; |
244 | unsigned long long trip_cnt; | ||
245 | int trip_mask = 0; | ||
246 | 87 | ||
247 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); | 88 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); |
248 | if (!obj) | 89 | if (!obj) |
@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv) | |||
250 | 91 | ||
251 | priv->priv = obj; | 92 | priv->priv = obj; |
252 | 93 | ||
253 | status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, | 94 | obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL); |
254 | &trip_cnt); | 95 | if (IS_ERR(obj->int340x_zone)) |
255 | if (ACPI_FAILURE(status)) | 96 | return PTR_ERR(obj->int340x_zone); |
256 | trip_cnt = 0; | ||
257 | |||
258 | if (trip_cnt) { | ||
259 | /* We have to cache, thresholds can't be readback */ | ||
260 | obj->thresholds = devm_kzalloc(&priv->pdev->dev, | ||
261 | sizeof(*obj->thresholds) * trip_cnt, | ||
262 | GFP_KERNEL); | ||
263 | if (!obj->thresholds) { | ||
264 | result = -ENOMEM; | ||
265 | goto err_free_obj; | ||
266 | } | ||
267 | trip_mask = BIT(trip_cnt) - 1; | ||
268 | } | ||
269 | |||
270 | obj->psv_trip_id = -1; | ||
271 | if (!sys_get_trip_psv(priv->adev, &obj->psv_temp)) | ||
272 | obj->psv_trip_id = trip_cnt++; | ||
273 | |||
274 | obj->crit_trip_id = -1; | ||
275 | if (!sys_get_trip_crt(priv->adev, &obj->crit_temp)) | ||
276 | obj->crit_trip_id = trip_cnt++; | ||
277 | |||
278 | obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev), | ||
279 | trip_cnt, trip_mask, priv, &tzone_ops, | ||
280 | &int3403_thermal_params, 0, 0); | ||
281 | if (IS_ERR(obj->tzone)) { | ||
282 | result = PTR_ERR(obj->tzone); | ||
283 | obj->tzone = NULL; | ||
284 | goto err_free_obj; | ||
285 | } | ||
286 | 97 | ||
287 | result = acpi_install_notify_handler(priv->adev->handle, | 98 | result = acpi_install_notify_handler(priv->adev->handle, |
288 | ACPI_DEVICE_NOTIFY, int3403_notify, | 99 | ACPI_DEVICE_NOTIFY, int3403_notify, |
@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv) | |||
293 | return 0; | 104 | return 0; |
294 | 105 | ||
295 | err_free_obj: | 106 | err_free_obj: |
296 | thermal_zone_device_unregister(obj->tzone); | 107 | int340x_thermal_zone_remove(obj->int340x_zone); |
297 | return result; | 108 | return result; |
298 | } | 109 | } |
299 | 110 | ||
@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) | |||
303 | 114 | ||
304 | acpi_remove_notify_handler(priv->adev->handle, | 115 | acpi_remove_notify_handler(priv->adev->handle, |
305 | ACPI_DEVICE_NOTIFY, int3403_notify); | 116 | ACPI_DEVICE_NOTIFY, int3403_notify); |
306 | thermal_zone_device_unregister(obj->tzone); | 117 | int340x_thermal_zone_remove(obj->int340x_zone); |
118 | |||
307 | return 0; | 119 | return 0; |
308 | } | 120 | } |
309 | 121 | ||
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c new file mode 100644 index 000000000000..f88b08877025 --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * int340x_thermal_zone.c | ||
3 | * Copyright (c) 2015, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/acpi.h> | ||
19 | #include <linux/thermal.h> | ||
20 | #include "int340x_thermal_zone.h" | ||
21 | |||
22 | static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, | ||
23 | unsigned long *temp) | ||
24 | { | ||
25 | struct int34x_thermal_zone *d = zone->devdata; | ||
26 | unsigned long long tmp; | ||
27 | acpi_status status; | ||
28 | |||
29 | if (d->override_ops && d->override_ops->get_temp) | ||
30 | return d->override_ops->get_temp(zone, temp); | ||
31 | |||
32 | status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp); | ||
33 | if (ACPI_FAILURE(status)) | ||
34 | return -EIO; | ||
35 | |||
36 | if (d->lpat_table) { | ||
37 | int conv_temp; | ||
38 | |||
39 | conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp); | ||
40 | if (conv_temp < 0) | ||
41 | return conv_temp; | ||
42 | |||
43 | *temp = (unsigned long)conv_temp * 10; | ||
44 | } else | ||
45 | /* _TMP returns the temperature in tenths of degrees Kelvin */ | ||
46 | *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, | ||
52 | int trip, unsigned long *temp) | ||
53 | { | ||
54 | struct int34x_thermal_zone *d = zone->devdata; | ||
55 | int i; | ||
56 | |||
57 | if (d->override_ops && d->override_ops->get_trip_temp) | ||
58 | return d->override_ops->get_trip_temp(zone, trip, temp); | ||
59 | |||
60 | if (trip < d->aux_trip_nr) | ||
61 | *temp = d->aux_trips[trip]; | ||
62 | else if (trip == d->crt_trip_id) | ||
63 | *temp = d->crt_temp; | ||
64 | else if (trip == d->psv_trip_id) | ||
65 | *temp = d->psv_temp; | ||
66 | else if (trip == d->hot_trip_id) | ||
67 | *temp = d->hot_temp; | ||
68 | else { | ||
69 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
70 | if (d->act_trips[i].valid && | ||
71 | d->act_trips[i].id == trip) { | ||
72 | *temp = d->act_trips[i].temp; | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, | ||
84 | int trip, | ||
85 | enum thermal_trip_type *type) | ||
86 | { | ||
87 | struct int34x_thermal_zone *d = zone->devdata; | ||
88 | int i; | ||
89 | |||
90 | if (d->override_ops && d->override_ops->get_trip_type) | ||
91 | return d->override_ops->get_trip_type(zone, trip, type); | ||
92 | |||
93 | if (trip < d->aux_trip_nr) | ||
94 | *type = THERMAL_TRIP_PASSIVE; | ||
95 | else if (trip == d->crt_trip_id) | ||
96 | *type = THERMAL_TRIP_CRITICAL; | ||
97 | else if (trip == d->hot_trip_id) | ||
98 | *type = THERMAL_TRIP_HOT; | ||
99 | else if (trip == d->psv_trip_id) | ||
100 | *type = THERMAL_TRIP_PASSIVE; | ||
101 | else { | ||
102 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
103 | if (d->act_trips[i].valid && | ||
104 | d->act_trips[i].id == trip) { | ||
105 | *type = THERMAL_TRIP_ACTIVE; | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, | ||
117 | int trip, unsigned long temp) | ||
118 | { | ||
119 | struct int34x_thermal_zone *d = zone->devdata; | ||
120 | acpi_status status; | ||
121 | char name[10]; | ||
122 | |||
123 | if (d->override_ops && d->override_ops->set_trip_temp) | ||
124 | return d->override_ops->set_trip_temp(zone, trip, temp); | ||
125 | |||
126 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
127 | status = acpi_execute_simple_method(d->adev->handle, name, | ||
128 | MILLICELSIUS_TO_DECI_KELVIN(temp)); | ||
129 | if (ACPI_FAILURE(status)) | ||
130 | return -EIO; | ||
131 | |||
132 | d->aux_trips[trip] = temp; | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | |||
138 | static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, | ||
139 | int trip, unsigned long *temp) | ||
140 | { | ||
141 | struct int34x_thermal_zone *d = zone->devdata; | ||
142 | acpi_status status; | ||
143 | unsigned long long hyst; | ||
144 | |||
145 | if (d->override_ops && d->override_ops->get_trip_hyst) | ||
146 | return d->override_ops->get_trip_hyst(zone, trip, temp); | ||
147 | |||
148 | status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); | ||
149 | if (ACPI_FAILURE(status)) | ||
150 | return -EIO; | ||
151 | |||
152 | *temp = hyst * 100; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct thermal_zone_device_ops int340x_thermal_zone_ops = { | ||
158 | .get_temp = int340x_thermal_get_zone_temp, | ||
159 | .get_trip_temp = int340x_thermal_get_trip_temp, | ||
160 | .get_trip_type = int340x_thermal_get_trip_type, | ||
161 | .set_trip_temp = int340x_thermal_set_trip_temp, | ||
162 | .get_trip_hyst = int340x_thermal_get_trip_hyst, | ||
163 | }; | ||
164 | |||
165 | static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, | ||
166 | unsigned long *temp) | ||
167 | { | ||
168 | unsigned long long r; | ||
169 | acpi_status status; | ||
170 | |||
171 | status = acpi_evaluate_integer(handle, name, NULL, &r); | ||
172 | if (ACPI_FAILURE(status)) | ||
173 | return -EIO; | ||
174 | |||
175 | *temp = DECI_KELVIN_TO_MILLICELSIUS(r); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static struct thermal_zone_params int340x_thermal_params = { | ||
181 | .governor_name = "user_space", | ||
182 | .no_hwmon = true, | ||
183 | }; | ||
184 | |||
185 | struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, | ||
186 | struct thermal_zone_device_ops *override_ops) | ||
187 | { | ||
188 | struct int34x_thermal_zone *int34x_thermal_zone; | ||
189 | acpi_status status; | ||
190 | unsigned long long trip_cnt; | ||
191 | int trip_mask = 0, i; | ||
192 | int ret; | ||
193 | |||
194 | int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), | ||
195 | GFP_KERNEL); | ||
196 | if (!int34x_thermal_zone) | ||
197 | return ERR_PTR(-ENOMEM); | ||
198 | |||
199 | int34x_thermal_zone->adev = adev; | ||
200 | int34x_thermal_zone->override_ops = override_ops; | ||
201 | |||
202 | status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); | ||
203 | if (ACPI_FAILURE(status)) | ||
204 | trip_cnt = 0; | ||
205 | else { | ||
206 | int34x_thermal_zone->aux_trips = kzalloc( | ||
207 | sizeof(*int34x_thermal_zone->aux_trips) * | ||
208 | trip_cnt, GFP_KERNEL); | ||
209 | if (!int34x_thermal_zone->aux_trips) { | ||
210 | ret = -ENOMEM; | ||
211 | goto free_mem; | ||
212 | } | ||
213 | trip_mask = BIT(trip_cnt) - 1; | ||
214 | int34x_thermal_zone->aux_trip_nr = trip_cnt; | ||
215 | } | ||
216 | |||
217 | int34x_thermal_zone->crt_trip_id = -1; | ||
218 | if (!int340x_thermal_get_trip_config(adev->handle, "_CRT", | ||
219 | &int34x_thermal_zone->crt_temp)) | ||
220 | int34x_thermal_zone->crt_trip_id = trip_cnt++; | ||
221 | int34x_thermal_zone->hot_trip_id = -1; | ||
222 | if (!int340x_thermal_get_trip_config(adev->handle, "_HOT", | ||
223 | &int34x_thermal_zone->hot_temp)) | ||
224 | int34x_thermal_zone->hot_trip_id = trip_cnt++; | ||
225 | int34x_thermal_zone->psv_trip_id = -1; | ||
226 | if (!int340x_thermal_get_trip_config(adev->handle, "_PSV", | ||
227 | &int34x_thermal_zone->psv_temp)) | ||
228 | int34x_thermal_zone->psv_trip_id = trip_cnt++; | ||
229 | for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { | ||
230 | char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; | ||
231 | |||
232 | if (int340x_thermal_get_trip_config(adev->handle, name, | ||
233 | &int34x_thermal_zone->act_trips[i].temp)) | ||
234 | break; | ||
235 | |||
236 | int34x_thermal_zone->act_trips[i].id = trip_cnt++; | ||
237 | int34x_thermal_zone->act_trips[i].valid = true; | ||
238 | } | ||
239 | int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( | ||
240 | adev->handle); | ||
241 | |||
242 | int34x_thermal_zone->zone = thermal_zone_device_register( | ||
243 | acpi_device_bid(adev), | ||
244 | trip_cnt, | ||
245 | trip_mask, int34x_thermal_zone, | ||
246 | &int340x_thermal_zone_ops, | ||
247 | &int340x_thermal_params, | ||
248 | 0, 0); | ||
249 | if (IS_ERR(int34x_thermal_zone->zone)) { | ||
250 | ret = PTR_ERR(int34x_thermal_zone->zone); | ||
251 | goto free_lpat; | ||
252 | } | ||
253 | |||
254 | return int34x_thermal_zone; | ||
255 | |||
256 | free_lpat: | ||
257 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | ||
258 | free_mem: | ||
259 | kfree(int34x_thermal_zone); | ||
260 | return ERR_PTR(ret); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_add); | ||
263 | |||
264 | void int340x_thermal_zone_remove(struct int34x_thermal_zone | ||
265 | *int34x_thermal_zone) | ||
266 | { | ||
267 | thermal_zone_device_unregister(int34x_thermal_zone->zone); | ||
268 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | ||
269 | kfree(int34x_thermal_zone); | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); | ||
272 | |||
273 | MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>"); | ||
274 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
275 | MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); | ||
276 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h new file mode 100644 index 000000000000..9f38ab72c4bf --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * int340x_thermal_zone.h | ||
3 | * Copyright (c) 2015, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #ifndef __INT340X_THERMAL_ZONE_H__ | ||
17 | #define __INT340X_THERMAL_ZONE_H__ | ||
18 | |||
19 | #include <acpi/acpi_lpat.h> | ||
20 | |||
21 | #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 | ||
22 | |||
23 | struct active_trip { | ||
24 | unsigned long temp; | ||
25 | int id; | ||
26 | bool valid; | ||
27 | }; | ||
28 | |||
29 | struct int34x_thermal_zone { | ||
30 | struct acpi_device *adev; | ||
31 | struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; | ||
32 | unsigned long *aux_trips; | ||
33 | int aux_trip_nr; | ||
34 | unsigned long psv_temp; | ||
35 | int psv_trip_id; | ||
36 | unsigned long crt_temp; | ||
37 | int crt_trip_id; | ||
38 | unsigned long hot_temp; | ||
39 | int hot_trip_id; | ||
40 | struct thermal_zone_device *zone; | ||
41 | struct thermal_zone_device_ops *override_ops; | ||
42 | void *priv_data; | ||
43 | struct acpi_lpat_conversion_table *lpat_table; | ||
44 | }; | ||
45 | |||
46 | struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, | ||
47 | struct thermal_zone_device_ops *override_ops); | ||
48 | void int340x_thermal_zone_remove(struct int34x_thermal_zone *); | ||
49 | |||
50 | static inline void int340x_thermal_zone_set_priv_data( | ||
51 | struct int34x_thermal_zone *tzone, void *priv_data) | ||
52 | { | ||
53 | tzone->priv_data = priv_data; | ||
54 | } | ||
55 | |||
56 | static inline void *int340x_thermal_zone_get_priv_data( | ||
57 | struct int34x_thermal_zone *tzone) | ||
58 | { | ||
59 | return tzone->priv_data; | ||
60 | } | ||
61 | |||
62 | static inline void int340x_thermal_zone_device_update( | ||
63 | struct int34x_thermal_zone *tzone) | ||
64 | { | ||
65 | thermal_zone_device_update(tzone->zone); | ||
66 | } | ||
67 | |||
68 | #endif | ||
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 0fe5dbbea968..7c3848da2df0 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/acpi.h> | 20 | #include <linux/acpi.h> |
21 | #include <linux/thermal.h> | ||
22 | #include "int340x_thermal_zone.h" | ||
21 | 23 | ||
22 | /* Broadwell-U/HSB thermal reporting device */ | 24 | /* Broadwell-U/HSB thermal reporting device */ |
23 | #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 | 25 | #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 |
@@ -39,6 +41,7 @@ struct proc_thermal_device { | |||
39 | struct device *dev; | 41 | struct device *dev; |
40 | struct acpi_device *adev; | 42 | struct acpi_device *adev; |
41 | struct power_config power_limits[2]; | 43 | struct power_config power_limits[2]; |
44 | struct int34x_thermal_zone *int340x_zone; | ||
42 | }; | 45 | }; |
43 | 46 | ||
44 | enum proc_thermal_emum_mode_type { | 47 | enum proc_thermal_emum_mode_type { |
@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = { | |||
117 | .name = "power_limits" | 120 | .name = "power_limits" |
118 | }; | 121 | }; |
119 | 122 | ||
123 | static int stored_tjmax; /* since it is fixed, we can have local storage */ | ||
124 | |||
125 | static int get_tjmax(void) | ||
126 | { | ||
127 | u32 eax, edx; | ||
128 | u32 val; | ||
129 | int err; | ||
130 | |||
131 | err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); | ||
132 | if (err) | ||
133 | return err; | ||
134 | |||
135 | val = (eax >> 16) & 0xff; | ||
136 | if (val) | ||
137 | return val; | ||
138 | |||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | static int read_temp_msr(unsigned long *temp) | ||
143 | { | ||
144 | int cpu; | ||
145 | u32 eax, edx; | ||
146 | int err; | ||
147 | unsigned long curr_temp_off = 0; | ||
148 | |||
149 | *temp = 0; | ||
150 | |||
151 | for_each_online_cpu(cpu) { | ||
152 | err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, | ||
153 | &edx); | ||
154 | if (err) | ||
155 | goto err_ret; | ||
156 | else { | ||
157 | if (eax & 0x80000000) { | ||
158 | curr_temp_off = (eax >> 16) & 0x7f; | ||
159 | if (!*temp || curr_temp_off < *temp) | ||
160 | *temp = curr_temp_off; | ||
161 | } else { | ||
162 | err = -EINVAL; | ||
163 | goto err_ret; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | err_ret: | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, | ||
174 | unsigned long *temp) | ||
175 | { | ||
176 | int ret; | ||
177 | |||
178 | ret = read_temp_msr(temp); | ||
179 | if (!ret) | ||
180 | *temp = (stored_tjmax - *temp) * 1000; | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static struct thermal_zone_device_ops proc_thermal_local_ops = { | ||
186 | .get_temp = proc_thermal_get_zone_temp, | ||
187 | }; | ||
188 | |||
120 | static int proc_thermal_add(struct device *dev, | 189 | static int proc_thermal_add(struct device *dev, |
121 | struct proc_thermal_device **priv) | 190 | struct proc_thermal_device **priv) |
122 | { | 191 | { |
@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev, | |||
126 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | 195 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
127 | union acpi_object *elements, *ppcc; | 196 | union acpi_object *elements, *ppcc; |
128 | union acpi_object *p; | 197 | union acpi_object *p; |
198 | unsigned long long tmp; | ||
199 | struct thermal_zone_device_ops *ops = NULL; | ||
129 | int i; | 200 | int i; |
130 | int ret; | 201 | int ret; |
131 | 202 | ||
@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev, | |||
178 | 249 | ||
179 | ret = sysfs_create_group(&dev->kobj, | 250 | ret = sysfs_create_group(&dev->kobj, |
180 | &power_limit_attribute_group); | 251 | &power_limit_attribute_group); |
252 | if (ret) | ||
253 | goto free_buffer; | ||
254 | |||
255 | status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); | ||
256 | if (ACPI_FAILURE(status)) { | ||
257 | /* there is no _TMP method, add local method */ | ||
258 | stored_tjmax = get_tjmax(); | ||
259 | if (stored_tjmax > 0) | ||
260 | ops = &proc_thermal_local_ops; | ||
261 | } | ||
262 | |||
263 | proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); | ||
264 | if (IS_ERR(proc_priv->int340x_zone)) { | ||
265 | sysfs_remove_group(&proc_priv->dev->kobj, | ||
266 | &power_limit_attribute_group); | ||
267 | ret = PTR_ERR(proc_priv->int340x_zone); | ||
268 | } else | ||
269 | ret = 0; | ||
181 | 270 | ||
182 | free_buffer: | 271 | free_buffer: |
183 | kfree(buf.pointer); | 272 | kfree(buf.pointer); |
@@ -187,6 +276,7 @@ free_buffer: | |||
187 | 276 | ||
188 | void proc_thermal_remove(struct proc_thermal_device *proc_priv) | 277 | void proc_thermal_remove(struct proc_thermal_device *proc_priv) |
189 | { | 278 | { |
279 | int340x_thermal_zone_remove(proc_priv->int340x_zone); | ||
190 | sysfs_remove_group(&proc_priv->dev->kobj, | 280 | sysfs_remove_group(&proc_priv->dev->kobj, |
191 | &power_limit_attribute_group); | 281 | &power_limit_attribute_group); |
192 | } | 282 | } |