2 * intel_pmic.c - Intel PMIC operation region driver
4 * Copyright (C) 2014 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/module.h>
17 #include <linux/acpi.h>
18 #include <linux/regmap.h>
19 #include "intel_pmic.h"
21 #define PMIC_POWER_OPREGION_ID 0x8d
22 #define PMIC_THERMAL_OPREGION_ID 0x8c
29 struct intel_pmic_opregion {
31 struct acpi_lpat *lpat;
33 struct regmap *regmap;
34 struct intel_pmic_opregion_data *data;
37 static int pmic_get_reg_bit(int address, struct pmic_table *table,
38 int count, int *reg, int *bit)
42 for (i = 0; i < count; i++) {
43 if (table[i].address == address) {
54 * raw_to_temp(): Return temperature from raw value through LPAT table
56 * @lpat: the temperature_raw mapping table
57 * @count: the count of the above mapping table
58 * @raw: the raw value, used as a key to get the temerature from the
61 * A positive value will be returned on success, a negative errno will
62 * be returned in error cases.
64 static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
66 int i, delta_temp, delta_raw, temp;
68 for (i = 0; i < count - 1; i++) {
69 if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
70 (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
77 delta_temp = lpat[i+1].temp - lpat[i].temp;
78 delta_raw = lpat[i+1].raw - lpat[i].raw;
79 temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
85 * temp_to_raw(): Return raw value from temperature through LPAT table
87 * @lpat: the temperature_raw mapping table
88 * @count: the count of the above mapping table
89 * @temp: the temperature, used as a key to get the raw value from the
92 * A positive value will be returned on success, a negative errno will
93 * be returned in error cases.
95 static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
97 int i, delta_temp, delta_raw, raw;
99 for (i = 0; i < count - 1; i++) {
100 if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
107 delta_temp = lpat[i+1].temp - lpat[i].temp;
108 delta_raw = lpat[i+1].raw - lpat[i].raw;
109 raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
114 static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
115 acpi_handle handle, struct device *dev)
117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
118 union acpi_object *obj_p, *obj_e;
122 status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
123 if (ACPI_FAILURE(status))
126 obj_p = (union acpi_object *)buffer.pointer;
127 if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
128 (obj_p->package.count % 2) || (obj_p->package.count < 4))
131 lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
136 for (i = 0; i < obj_p->package.count; i++) {
137 obj_e = &obj_p->package.elements[i];
138 if (obj_e->type != ACPI_TYPE_INTEGER) {
139 devm_kfree(dev, lpat);
142 lpat[i] = (s64)obj_e->integer.value;
145 opregion->lpat = (struct acpi_lpat *)lpat;
146 opregion->lpat_count = obj_p->package.count / 2;
149 kfree(buffer.pointer);
152 static acpi_status intel_pmic_power_handler(u32 function,
153 acpi_physical_address address, u32 bits, u64 *value64,
154 void *handler_context, void *region_context)
156 struct intel_pmic_opregion *opregion = region_context;
157 struct regmap *regmap = opregion->regmap;
158 struct intel_pmic_opregion_data *d = opregion->data;
159 int reg, bit, result;
161 if (bits != 32 || !value64)
162 return AE_BAD_PARAMETER;
164 if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
165 return AE_BAD_PARAMETER;
167 result = pmic_get_reg_bit(address, d->power_table,
168 d->power_table_count, ®, &bit);
169 if (result == -ENOENT)
170 return AE_BAD_PARAMETER;
172 mutex_lock(&opregion->lock);
174 result = function == ACPI_READ ?
175 d->get_power(regmap, reg, bit, value64) :
176 d->update_power(regmap, reg, bit, *value64 == 1);
178 mutex_unlock(&opregion->lock);
180 return result ? AE_ERROR : AE_OK;
183 static int pmic_read_temp(struct intel_pmic_opregion *opregion,
188 if (!opregion->data->get_raw_temp)
191 raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
195 if (!opregion->lpat) {
200 temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
208 static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
209 u32 function, u64 *value)
211 return function == ACPI_READ ?
212 pmic_read_temp(opregion, reg, value) : -EINVAL;
215 static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
216 u32 function, u64 *value)
220 if (function == ACPI_READ)
221 return pmic_read_temp(opregion, reg, value);
223 if (!opregion->data->update_aux)
226 if (opregion->lpat) {
227 raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
235 return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
238 static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
239 u32 function, u64 *value)
241 struct intel_pmic_opregion_data *d = opregion->data;
242 struct regmap *regmap = opregion->regmap;
244 if (!d->get_policy || !d->update_policy)
247 if (function == ACPI_READ)
248 return d->get_policy(regmap, reg, value);
250 if (*value != 0 && *value != 1)
253 return d->update_policy(regmap, reg, *value);
256 static bool pmic_thermal_is_temp(int address)
258 return (address <= 0x3c) && !(address % 12);
261 static bool pmic_thermal_is_aux(int address)
263 return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
264 (address >= 8 && address <= 0x44 && !((address - 8) % 12));
267 static bool pmic_thermal_is_pen(int address)
269 return address >= 0x48 && address <= 0x5c;
272 static acpi_status intel_pmic_thermal_handler(u32 function,
273 acpi_physical_address address, u32 bits, u64 *value64,
274 void *handler_context, void *region_context)
276 struct intel_pmic_opregion *opregion = region_context;
277 struct intel_pmic_opregion_data *d = opregion->data;
280 if (bits != 32 || !value64)
281 return AE_BAD_PARAMETER;
283 result = pmic_get_reg_bit(address, d->thermal_table,
284 d->thermal_table_count, ®, NULL);
285 if (result == -ENOENT)
286 return AE_BAD_PARAMETER;
288 mutex_lock(&opregion->lock);
290 if (pmic_thermal_is_temp(address))
291 result = pmic_thermal_temp(opregion, reg, function, value64);
292 else if (pmic_thermal_is_aux(address))
293 result = pmic_thermal_aux(opregion, reg, function, value64);
294 else if (pmic_thermal_is_pen(address))
295 result = pmic_thermal_pen(opregion, reg, function, value64);
299 mutex_unlock(&opregion->lock);
302 if (result == -EINVAL)
303 return AE_BAD_PARAMETER;
311 int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
312 struct regmap *regmap,
313 struct intel_pmic_opregion_data *d)
316 struct intel_pmic_opregion *opregion;
318 if (!dev || !regmap || !d)
324 opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
328 mutex_init(&opregion->lock);
329 opregion->regmap = regmap;
330 pmic_thermal_lpat(opregion, handle, dev);
332 status = acpi_install_address_space_handler(handle,
333 PMIC_POWER_OPREGION_ID,
334 intel_pmic_power_handler,
336 if (ACPI_FAILURE(status))
339 status = acpi_install_address_space_handler(handle,
340 PMIC_THERMAL_OPREGION_ID,
341 intel_pmic_thermal_handler,
343 if (ACPI_FAILURE(status)) {
344 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
345 intel_pmic_power_handler);
352 EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
354 MODULE_LICENSE("GPL");