]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/acpi/pmic/intel_pmic_xpower.c
Merge tag 'asoc-v4.16-4' into asoc-next
[linux.git] / drivers / acpi / pmic / intel_pmic_xpower.c
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);