xref: /linux/drivers/acpi/pmic/intel_pmic.c (revision 78bb578528c92424bb40f03a06d2ec28098c466e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * intel_pmic.c - Intel PMIC operation region driver
4  *
5  * Copyright (C) 2014 Intel Corporation. All rights reserved.
6  */
7 
8 #include <linux/export.h>
9 #include <linux/acpi.h>
10 #include <linux/mfd/intel_soc_pmic.h>
11 #include <linux/regmap.h>
12 #include <acpi/acpi_lpat.h>
13 #include "intel_pmic.h"
14 
15 #define PMIC_POWER_OPREGION_ID		0x8d
16 #define PMIC_THERMAL_OPREGION_ID	0x8c
17 #define PMIC_REGS_OPREGION_ID		0x8f
18 
19 struct intel_pmic_regs_handler_ctx {
20 	unsigned int val;
21 	u16 addr;
22 };
23 
24 struct intel_pmic_opregion {
25 	struct mutex lock;
26 	struct acpi_lpat_conversion_table *lpat_table;
27 	struct regmap *regmap;
28 	const struct intel_pmic_opregion_data *data;
29 	struct intel_pmic_regs_handler_ctx ctx;
30 };
31 
32 static struct intel_pmic_opregion *intel_pmic_opregion;
33 
34 static int pmic_get_reg_bit(int address, const struct pmic_table *table,
35 			    int count, int *reg, int *bit)
36 {
37 	int i;
38 
39 	for (i = 0; i < count; i++) {
40 		if (table[i].address == address) {
41 			*reg = table[i].reg;
42 			if (bit)
43 				*bit = table[i].bit;
44 			return 0;
45 		}
46 	}
47 	return -ENOENT;
48 }
49 
50 static acpi_status intel_pmic_power_handler(u32 function,
51 		acpi_physical_address address, u32 bits, u64 *value64,
52 		void *handler_context, void *region_context)
53 {
54 	struct intel_pmic_opregion *opregion = region_context;
55 	struct regmap *regmap = opregion->regmap;
56 	const struct intel_pmic_opregion_data *d = opregion->data;
57 	int reg, bit, result;
58 
59 	if (bits != 32 || !value64)
60 		return AE_BAD_PARAMETER;
61 
62 	if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
63 		return AE_BAD_PARAMETER;
64 
65 	result = pmic_get_reg_bit(address, d->power_table,
66 				  d->power_table_count, &reg, &bit);
67 	if (result == -ENOENT)
68 		return AE_BAD_PARAMETER;
69 
70 	guard(mutex)(&opregion->lock);
71 
72 	result = function == ACPI_READ ?
73 		d->get_power(regmap, reg, bit, value64) :
74 		d->update_power(regmap, reg, bit, *value64 == 1);
75 
76 	return result ? AE_ERROR : AE_OK;
77 }
78 
79 static int pmic_read_temp(struct intel_pmic_opregion *opregion,
80 			  int reg, u64 *value)
81 {
82 	int raw_temp, temp;
83 
84 	if (!opregion->data->get_raw_temp)
85 		return -ENXIO;
86 
87 	raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
88 	if (raw_temp < 0)
89 		return raw_temp;
90 
91 	if (!opregion->lpat_table) {
92 		*value = raw_temp;
93 		return 0;
94 	}
95 
96 	temp = opregion->data->lpat_raw_to_temp(opregion->lpat_table, raw_temp);
97 	if (temp < 0)
98 		return temp;
99 
100 	*value = temp;
101 	return 0;
102 }
103 
104 static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
105 			     u32 function, u64 *value)
106 {
107 	return function == ACPI_READ ?
108 		pmic_read_temp(opregion, reg, value) : -EINVAL;
109 }
110 
111 static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
112 			    u32 function, u64 *value)
113 {
114 	int raw_temp;
115 
116 	if (function == ACPI_READ)
117 		return pmic_read_temp(opregion, reg, value);
118 
119 	if (!opregion->data->update_aux)
120 		return -ENXIO;
121 
122 	if (opregion->lpat_table) {
123 		raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
124 		if (raw_temp < 0)
125 			return raw_temp;
126 	} else {
127 		raw_temp = *value;
128 	}
129 
130 	return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
131 }
132 
133 static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
134 			    int bit, u32 function, u64 *value)
135 {
136 	const struct intel_pmic_opregion_data *d = opregion->data;
137 	struct regmap *regmap = opregion->regmap;
138 
139 	if (!d->get_policy || !d->update_policy)
140 		return -ENXIO;
141 
142 	if (function == ACPI_READ)
143 		return d->get_policy(regmap, reg, bit, value);
144 
145 	if (*value != 0 && *value != 1)
146 		return -EINVAL;
147 
148 	return d->update_policy(regmap, reg, bit, *value);
149 }
150 
151 static bool pmic_thermal_is_temp(int address)
152 {
153 	return (address <= 0x3c) && !(address % 12);
154 }
155 
156 static bool pmic_thermal_is_aux(int address)
157 {
158 	return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
159 	       (address >= 8 && address <= 0x44 && !((address - 8) % 12));
160 }
161 
162 static bool pmic_thermal_is_pen(int address)
163 {
164 	return address >= 0x48 && address <= 0x5c;
165 }
166 
167 static acpi_status intel_pmic_thermal_handler(u32 function,
168 		acpi_physical_address address, u32 bits, u64 *value64,
169 		void *handler_context, void *region_context)
170 {
171 	struct intel_pmic_opregion *opregion = region_context;
172 	const struct intel_pmic_opregion_data *d = opregion->data;
173 	int reg, bit, result;
174 
175 	if (bits != 32 || !value64)
176 		return AE_BAD_PARAMETER;
177 
178 	result = pmic_get_reg_bit(address, d->thermal_table,
179 				  d->thermal_table_count, &reg, &bit);
180 	if (result == -ENOENT)
181 		return AE_BAD_PARAMETER;
182 
183 	scoped_guard(mutex, &opregion->lock) {
184 		if (pmic_thermal_is_temp(address))
185 			result = pmic_thermal_temp(opregion, reg, function, value64);
186 		else if (pmic_thermal_is_aux(address))
187 			result = pmic_thermal_aux(opregion, reg, function, value64);
188 		else if (pmic_thermal_is_pen(address))
189 			result = pmic_thermal_pen(opregion, reg, bit, function, value64);
190 		else
191 			result = -EINVAL;
192 	}
193 
194 	if (result < 0) {
195 		if (result == -EINVAL)
196 			return AE_BAD_PARAMETER;
197 		else
198 			return AE_ERROR;
199 	}
200 
201 	return AE_OK;
202 }
203 
204 static acpi_status intel_pmic_regs_handler(u32 function,
205 		acpi_physical_address address, u32 bits, u64 *value64,
206 		void *handler_context, void *region_context)
207 {
208 	struct intel_pmic_opregion *opregion = region_context;
209 	int result = -EINVAL;
210 
211 	if (function == ACPI_WRITE) {
212 		switch (address) {
213 		case 0:
214 			return AE_OK;
215 		case 1:
216 			opregion->ctx.addr |= (*value64 & 0xff) << 8;
217 			return AE_OK;
218 		case 2:
219 			opregion->ctx.addr |= *value64 & 0xff;
220 			return AE_OK;
221 		case 3:
222 			opregion->ctx.val = *value64 & 0xff;
223 			return AE_OK;
224 		case 4:
225 			if (*value64) {
226 				result = regmap_write(opregion->regmap, opregion->ctx.addr,
227 						      opregion->ctx.val);
228 			} else {
229 				result = regmap_read(opregion->regmap, opregion->ctx.addr,
230 						     &opregion->ctx.val);
231 			}
232 			opregion->ctx.addr = 0;
233 		}
234 	}
235 
236 	if (function == ACPI_READ && address == 3) {
237 		*value64 = opregion->ctx.val;
238 		return AE_OK;
239 	}
240 
241 	if (result < 0) {
242 		if (result == -EINVAL)
243 			return AE_BAD_PARAMETER;
244 		else
245 			return AE_ERROR;
246 	}
247 
248 	return AE_OK;
249 }
250 
251 int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
252 					struct regmap *regmap,
253 					const struct intel_pmic_opregion_data *d)
254 {
255 	acpi_status status = AE_OK;
256 	struct intel_pmic_opregion *opregion;
257 	int ret;
258 
259 	if (!dev || !regmap || !d)
260 		return -EINVAL;
261 
262 	if (!handle)
263 		return -ENODEV;
264 
265 	opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
266 	if (!opregion)
267 		return -ENOMEM;
268 
269 	mutex_init(&opregion->lock);
270 	opregion->regmap = regmap;
271 	opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
272 
273 	if (d->power_table_count)
274 		status = acpi_install_address_space_handler(handle,
275 						    PMIC_POWER_OPREGION_ID,
276 						    intel_pmic_power_handler,
277 						    NULL, opregion);
278 	if (ACPI_FAILURE(status)) {
279 		ret = -ENODEV;
280 		goto out_error;
281 	}
282 
283 	if (d->thermal_table_count)
284 		status = acpi_install_address_space_handler(handle,
285 						    PMIC_THERMAL_OPREGION_ID,
286 						    intel_pmic_thermal_handler,
287 						    NULL, opregion);
288 	if (ACPI_FAILURE(status)) {
289 		ret = -ENODEV;
290 		goto out_remove_power_handler;
291 	}
292 
293 	status = acpi_install_address_space_handler(handle,
294 			PMIC_REGS_OPREGION_ID, intel_pmic_regs_handler, NULL,
295 			opregion);
296 	if (ACPI_FAILURE(status)) {
297 		ret = -ENODEV;
298 		goto out_remove_thermal_handler;
299 	}
300 
301 	opregion->data = d;
302 	intel_pmic_opregion = opregion;
303 	return 0;
304 
305 out_remove_thermal_handler:
306 	if (d->thermal_table_count)
307 		acpi_remove_address_space_handler(handle,
308 						  PMIC_THERMAL_OPREGION_ID,
309 						  intel_pmic_thermal_handler);
310 
311 out_remove_power_handler:
312 	if (d->power_table_count)
313 		acpi_remove_address_space_handler(handle,
314 						  PMIC_POWER_OPREGION_ID,
315 						  intel_pmic_power_handler);
316 
317 out_error:
318 	acpi_lpat_free_conversion_table(opregion->lpat_table);
319 	return ret;
320 }
321 EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
322 
323 /**
324  * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence
325  * @i2c_address:  I2C client address for the PMIC
326  * @reg_address:  PMIC register address
327  * @value:        New value for the register bits to change
328  * @mask:         Mask indicating which register bits to change
329  *
330  * DSI LCD panels describe an initialization sequence in the i915 VBT (Video
331  * BIOS Tables) using so called MIPI sequences. One possible element in these
332  * sequences is a PMIC specific element of 15 bytes.
333  *
334  * This function executes these PMIC specific elements sending the embedded
335  * commands to the PMIC.
336  *
337  * Return 0 on success, < 0 on failure.
338  */
339 int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address,
340 					      u32 value, u32 mask)
341 {
342 	const struct intel_pmic_opregion_data *d;
343 	int ret;
344 
345 	if (!intel_pmic_opregion) {
346 		pr_warn("%s: No PMIC registered\n", __func__);
347 		return -ENXIO;
348 	}
349 
350 	d = intel_pmic_opregion->data;
351 
352 	guard(mutex)(&intel_pmic_opregion->lock);
353 
354 	if (d->exec_mipi_pmic_seq_element) {
355 		return d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap,
356 						    i2c_address, reg_address,
357 						    value, mask);
358 	}
359 
360 	if (d->pmic_i2c_address) {
361 		if (i2c_address == d->pmic_i2c_address) {
362 			ret = regmap_update_bits(intel_pmic_opregion->regmap,
363 						 reg_address, mask, value);
364 		} else {
365 			pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n",
366 			       __func__, i2c_address, reg_address, value, mask);
367 			ret = -ENXIO;
368 		}
369 	} else {
370 		pr_warn("%s: Not implemented\n", __func__);
371 		pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n",
372 			__func__, i2c_address, reg_address, value, mask);
373 		ret = -EOPNOTSUPP;
374 	}
375 
376 	return ret;
377 }
378 EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element);
379