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