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