aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/pmic/intel_pmic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/pmic/intel_pmic.c')
-rw-r--r--drivers/acpi/pmic/intel_pmic.c84
1 files changed, 74 insertions, 10 deletions
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index bd772cd56494..ca18e0d23df9 100644
--- a/drivers/acpi/pmic/intel_pmic.c
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -13,7 +13,7 @@
13 * GNU General Public License for more details. 13 * GNU General Public License for more details.
14 */ 14 */
15 15
16#include <linux/module.h> 16#include <linux/export.h>
17#include <linux/acpi.h> 17#include <linux/acpi.h>
18#include <linux/regmap.h> 18#include <linux/regmap.h>
19#include <acpi/acpi_lpat.h> 19#include <acpi/acpi_lpat.h>
@@ -21,12 +21,19 @@
21 21
22#define PMIC_POWER_OPREGION_ID 0x8d 22#define PMIC_POWER_OPREGION_ID 0x8d
23#define PMIC_THERMAL_OPREGION_ID 0x8c 23#define PMIC_THERMAL_OPREGION_ID 0x8c
24#define PMIC_REGS_OPREGION_ID 0x8f
25
26struct intel_pmic_regs_handler_ctx {
27 unsigned int val;
28 u16 addr;
29};
24 30
25struct intel_pmic_opregion { 31struct intel_pmic_opregion {
26 struct mutex lock; 32 struct mutex lock;
27 struct acpi_lpat_conversion_table *lpat_table; 33 struct acpi_lpat_conversion_table *lpat_table;
28 struct regmap *regmap; 34 struct regmap *regmap;
29 struct intel_pmic_opregion_data *data; 35 struct intel_pmic_opregion_data *data;
36 struct intel_pmic_regs_handler_ctx ctx;
30}; 37};
31 38
32static int pmic_get_reg_bit(int address, struct pmic_table *table, 39static int pmic_get_reg_bit(int address, struct pmic_table *table,
@@ -131,7 +138,7 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
131} 138}
132 139
133static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, 140static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
134 u32 function, u64 *value) 141 int bit, u32 function, u64 *value)
135{ 142{
136 struct intel_pmic_opregion_data *d = opregion->data; 143 struct intel_pmic_opregion_data *d = opregion->data;
137 struct regmap *regmap = opregion->regmap; 144 struct regmap *regmap = opregion->regmap;
@@ -140,12 +147,12 @@ static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
140 return -ENXIO; 147 return -ENXIO;
141 148
142 if (function == ACPI_READ) 149 if (function == ACPI_READ)
143 return d->get_policy(regmap, reg, value); 150 return d->get_policy(regmap, reg, bit, value);
144 151
145 if (*value != 0 && *value != 1) 152 if (*value != 0 && *value != 1)
146 return -EINVAL; 153 return -EINVAL;
147 154
148 return d->update_policy(regmap, reg, *value); 155 return d->update_policy(regmap, reg, bit, *value);
149} 156}
150 157
151static bool pmic_thermal_is_temp(int address) 158static bool pmic_thermal_is_temp(int address)
@@ -170,13 +177,13 @@ static acpi_status intel_pmic_thermal_handler(u32 function,
170{ 177{
171 struct intel_pmic_opregion *opregion = region_context; 178 struct intel_pmic_opregion *opregion = region_context;
172 struct intel_pmic_opregion_data *d = opregion->data; 179 struct intel_pmic_opregion_data *d = opregion->data;
173 int reg, result; 180 int reg, bit, result;
174 181
175 if (bits != 32 || !value64) 182 if (bits != 32 || !value64)
176 return AE_BAD_PARAMETER; 183 return AE_BAD_PARAMETER;
177 184
178 result = pmic_get_reg_bit(address, d->thermal_table, 185 result = pmic_get_reg_bit(address, d->thermal_table,
179 d->thermal_table_count, &reg, NULL); 186 d->thermal_table_count, &reg, &bit);
180 if (result == -ENOENT) 187 if (result == -ENOENT)
181 return AE_BAD_PARAMETER; 188 return AE_BAD_PARAMETER;
182 189
@@ -187,7 +194,8 @@ static acpi_status intel_pmic_thermal_handler(u32 function,
187 else if (pmic_thermal_is_aux(address)) 194 else if (pmic_thermal_is_aux(address))
188 result = pmic_thermal_aux(opregion, reg, function, value64); 195 result = pmic_thermal_aux(opregion, reg, function, value64);
189 else if (pmic_thermal_is_pen(address)) 196 else if (pmic_thermal_is_pen(address))
190 result = pmic_thermal_pen(opregion, reg, function, value64); 197 result = pmic_thermal_pen(opregion, reg, bit,
198 function, value64);
191 else 199 else
192 result = -EINVAL; 200 result = -EINVAL;
193 201
@@ -203,6 +211,48 @@ static acpi_status intel_pmic_thermal_handler(u32 function,
203 return AE_OK; 211 return AE_OK;
204} 212}
205 213
214static acpi_status intel_pmic_regs_handler(u32 function,
215 acpi_physical_address address, u32 bits, u64 *value64,
216 void *handler_context, void *region_context)
217{
218 struct intel_pmic_opregion *opregion = region_context;
219 int result = 0;
220
221 switch (address) {
222 case 0:
223 return AE_OK;
224 case 1:
225 opregion->ctx.addr |= (*value64 & 0xff) << 8;
226 return AE_OK;
227 case 2:
228 opregion->ctx.addr |= *value64 & 0xff;
229 return AE_OK;
230 case 3:
231 opregion->ctx.val = *value64 & 0xff;
232 return AE_OK;
233 case 4:
234 if (*value64) {
235 result = regmap_write(opregion->regmap, opregion->ctx.addr,
236 opregion->ctx.val);
237 } else {
238 result = regmap_read(opregion->regmap, opregion->ctx.addr,
239 &opregion->ctx.val);
240 if (result == 0)
241 *value64 = opregion->ctx.val;
242 }
243 memset(&opregion->ctx, 0x00, sizeof(opregion->ctx));
244 }
245
246 if (result < 0) {
247 if (result == -EINVAL)
248 return AE_BAD_PARAMETER;
249 else
250 return AE_ERROR;
251 }
252
253 return AE_OK;
254}
255
206int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, 256int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
207 struct regmap *regmap, 257 struct regmap *regmap,
208 struct intel_pmic_opregion_data *d) 258 struct intel_pmic_opregion_data *d)
@@ -242,16 +292,30 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
242 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, 292 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
243 intel_pmic_power_handler); 293 intel_pmic_power_handler);
244 ret = -ENODEV; 294 ret = -ENODEV;
245 goto out_error; 295 goto out_remove_power_handler;
296 }
297
298 status = acpi_install_address_space_handler(handle,
299 PMIC_REGS_OPREGION_ID, intel_pmic_regs_handler, NULL,
300 opregion);
301 if (ACPI_FAILURE(status)) {
302 ret = -ENODEV;
303 goto out_remove_thermal_handler;
246 } 304 }
247 305
248 opregion->data = d; 306 opregion->data = d;
249 return 0; 307 return 0;
250 308
309out_remove_thermal_handler:
310 acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID,
311 intel_pmic_thermal_handler);
312
313out_remove_power_handler:
314 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
315 intel_pmic_power_handler);
316
251out_error: 317out_error:
252 acpi_lpat_free_conversion_table(opregion->lpat_table); 318 acpi_lpat_free_conversion_table(opregion->lpat_table);
253 return ret; 319 return ret;
254} 320}
255EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); 321EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
256
257MODULE_LICENSE("GPL");