xref: /linux/drivers/acpi/pmic/intel_pmic_xpower.c (revision bb1c928df78ee6e3665a0d013e74108cc9abf34b)
1 /*
2  * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
3  *
4  * Copyright (C) 2014 Intel Corporation. All rights reserved.
5  *
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.
9  *
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.
14  */
15 
16 #include <linux/init.h>
17 #include <linux/acpi.h>
18 #include <linux/mfd/axp20x.h>
19 #include <linux/regmap.h>
20 #include <linux/platform_device.h>
21 #include "intel_pmic.h"
22 
23 #define XPOWER_GPADC_LOW	0x5b
24 #define XPOWER_GPI1_CTRL	0x92
25 
26 #define GPI1_LDO_MASK		GENMASK(2, 0)
27 #define GPI1_LDO_ON		(3 << 0)
28 #define GPI1_LDO_OFF		(4 << 0)
29 
30 static struct pmic_table power_table[] = {
31 	{
32 		.address = 0x00,
33 		.reg = 0x13,
34 		.bit = 0x05,
35 	}, /* ALD1 */
36 	{
37 		.address = 0x04,
38 		.reg = 0x13,
39 		.bit = 0x06,
40 	}, /* ALD2 */
41 	{
42 		.address = 0x08,
43 		.reg = 0x13,
44 		.bit = 0x07,
45 	}, /* ALD3 */
46 	{
47 		.address = 0x0c,
48 		.reg = 0x12,
49 		.bit = 0x03,
50 	}, /* DLD1 */
51 	{
52 		.address = 0x10,
53 		.reg = 0x12,
54 		.bit = 0x04,
55 	}, /* DLD2 */
56 	{
57 		.address = 0x14,
58 		.reg = 0x12,
59 		.bit = 0x05,
60 	}, /* DLD3 */
61 	{
62 		.address = 0x18,
63 		.reg = 0x12,
64 		.bit = 0x06,
65 	}, /* DLD4 */
66 	{
67 		.address = 0x1c,
68 		.reg = 0x12,
69 		.bit = 0x00,
70 	}, /* ELD1 */
71 	{
72 		.address = 0x20,
73 		.reg = 0x12,
74 		.bit = 0x01,
75 	}, /* ELD2 */
76 	{
77 		.address = 0x24,
78 		.reg = 0x12,
79 		.bit = 0x02,
80 	}, /* ELD3 */
81 	{
82 		.address = 0x28,
83 		.reg = 0x13,
84 		.bit = 0x02,
85 	}, /* FLD1 */
86 	{
87 		.address = 0x2c,
88 		.reg = 0x13,
89 		.bit = 0x03,
90 	}, /* FLD2 */
91 	{
92 		.address = 0x30,
93 		.reg = 0x13,
94 		.bit = 0x04,
95 	}, /* FLD3 */
96 	{
97 		.address = 0x34,
98 		.reg = 0x10,
99 		.bit = 0x03,
100 	}, /* BUC1 */
101 	{
102 		.address = 0x38,
103 		.reg = 0x10,
104 		.bit = 0x06,
105 	}, /* BUC2 */
106 	{
107 		.address = 0x3c,
108 		.reg = 0x10,
109 		.bit = 0x05,
110 	}, /* BUC3 */
111 	{
112 		.address = 0x40,
113 		.reg = 0x10,
114 		.bit = 0x04,
115 	}, /* BUC4 */
116 	{
117 		.address = 0x44,
118 		.reg = 0x10,
119 		.bit = 0x01,
120 	}, /* BUC5 */
121 	{
122 		.address = 0x48,
123 		.reg = 0x10,
124 		.bit = 0x00
125 	}, /* BUC6 */
126 	{
127 		.address = 0x4c,
128 		.reg = 0x92,
129 	}, /* GPI1 */
130 };
131 
132 /* TMP0 - TMP5 are the same, all from GPADC */
133 static struct pmic_table thermal_table[] = {
134 	{
135 		.address = 0x00,
136 		.reg = XPOWER_GPADC_LOW
137 	},
138 	{
139 		.address = 0x0c,
140 		.reg = XPOWER_GPADC_LOW
141 	},
142 	{
143 		.address = 0x18,
144 		.reg = XPOWER_GPADC_LOW
145 	},
146 	{
147 		.address = 0x24,
148 		.reg = XPOWER_GPADC_LOW
149 	},
150 	{
151 		.address = 0x30,
152 		.reg = XPOWER_GPADC_LOW
153 	},
154 	{
155 		.address = 0x3c,
156 		.reg = XPOWER_GPADC_LOW
157 	},
158 };
159 
160 static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
161 				       int bit, u64 *value)
162 {
163 	int data;
164 
165 	if (regmap_read(regmap, reg, &data))
166 		return -EIO;
167 
168 	/* GPIO1 LDO regulator needs special handling */
169 	if (reg == XPOWER_GPI1_CTRL)
170 		*value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON);
171 	else
172 		*value = (data & BIT(bit)) ? 1 : 0;
173 
174 	return 0;
175 }
176 
177 static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
178 					  int bit, bool on)
179 {
180 	int data;
181 
182 	/* GPIO1 LDO regulator needs special handling */
183 	if (reg == XPOWER_GPI1_CTRL)
184 		return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
185 					  on ? GPI1_LDO_ON : GPI1_LDO_OFF);
186 
187 	if (regmap_read(regmap, reg, &data))
188 		return -EIO;
189 
190 	if (on)
191 		data |= BIT(bit);
192 	else
193 		data &= ~BIT(bit);
194 
195 	if (regmap_write(regmap, reg, data))
196 		return -EIO;
197 
198 	return 0;
199 }
200 
201 /**
202  * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
203  *
204  * @regmap: regmap of the PMIC device
205  * @reg: register to get the reading
206  *
207  * Return a positive value on success, errno on failure.
208  */
209 static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
210 {
211 	u8 buf[2];
212 
213 	if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2))
214 		return -EIO;
215 
216 	return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
217 }
218 
219 static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
220 	.get_power = intel_xpower_pmic_get_power,
221 	.update_power = intel_xpower_pmic_update_power,
222 	.get_raw_temp = intel_xpower_pmic_get_raw_temp,
223 	.power_table = power_table,
224 	.power_table_count = ARRAY_SIZE(power_table),
225 	.thermal_table = thermal_table,
226 	.thermal_table_count = ARRAY_SIZE(thermal_table),
227 };
228 
229 static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
230 		acpi_physical_address address, u32 bit_width, u64 *value,
231 		void *handler_context, void *region_context)
232 {
233 	return AE_OK;
234 }
235 
236 static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
237 {
238 	struct device *parent = pdev->dev.parent;
239 	struct axp20x_dev *axp20x = dev_get_drvdata(parent);
240 	acpi_status status;
241 	int result;
242 
243 	status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
244 			ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
245 			NULL, NULL);
246 	if (ACPI_FAILURE(status))
247 		return -ENODEV;
248 
249 	result = intel_pmic_install_opregion_handler(&pdev->dev,
250 					ACPI_HANDLE(parent), axp20x->regmap,
251 					&intel_xpower_pmic_opregion_data);
252 	if (result)
253 		acpi_remove_address_space_handler(ACPI_HANDLE(parent),
254 						  ACPI_ADR_SPACE_GPIO,
255 						  intel_xpower_pmic_gpio_handler);
256 
257 	return result;
258 }
259 
260 static struct platform_driver intel_xpower_pmic_opregion_driver = {
261 	.probe = intel_xpower_pmic_opregion_probe,
262 	.driver = {
263 		.name = "axp288_pmic_acpi",
264 	},
265 };
266 
267 static int __init intel_xpower_pmic_opregion_driver_init(void)
268 {
269 	return platform_driver_register(&intel_xpower_pmic_opregion_driver);
270 }
271 device_initcall(intel_xpower_pmic_opregion_driver_init);
272