]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/acpi/pmic/intel_pmic_xpower.c
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[karo-tx-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
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);