aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Pan <jacob.jun.pan@linux.intel.com>2014-10-07 00:17:14 -0400
committerLee Jones <lee.jones@linaro.org>2014-10-07 04:30:05 -0400
commitaf7e9069543aabd415d7c543f3f89b143ac1a932 (patch)
tree40e00e77c9aef5b83dab704575330e27cc6beed7
parentbfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff)
mfd: axp20x: Extend axp20x to support axp288 pmic
X-Powers AXP288 is a customized PMIC for Intel Baytrail-CR platforms. Similar to AXP202/209, AXP288 comes with USB charger, more LDO and BUCK channels, and AD converters. It also provides extended status and interrupt reporting capabilities than the devices currently supported in axp20x.c. In addition to feature extension, this patch also adds ACPI binding for enumeration. This consolidated driver should support more X-Powers' PMICs in both device tree and ACPI enumerated platforms. Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> Reviewed-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--drivers/mfd/Kconfig3
-rw-r--r--drivers/mfd/axp20x.c361
-rw-r--r--include/linux/mfd/axp20x.h59
3 files changed, 367 insertions, 56 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index de5abf244746..c183edb45b52 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -74,7 +74,8 @@ config MFD_AXP20X
74 select REGMAP_IRQ 74 select REGMAP_IRQ
75 depends on I2C=y 75 depends on I2C=y
76 help 76 help
77 If you say Y here you get support for the X-Powers AXP202 and AXP209. 77 If you say Y here you get support for the X-Powers AXP202, AXP209 and
78 AXP288 power management IC (PMIC).
78 This driver include only the core APIs. You have to select individual 79 This driver include only the core APIs. You have to select individual
79 components like regulators or the PEK (Power Enable Key) under the 80 components like regulators or the PEK (Power Enable Key) under the
80 corresponding menus. 81 corresponding menus.
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index dee653989e3a..b2fb7f492c86 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1,9 +1,9 @@
1/* 1/*
2 * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209 2 * axp20x.c - MFD core driver for the X-Powers' Power Management ICs
3 * 3 *
4 * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC 4 * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
5 * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature 5 * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
6 * as well as 4 configurable GPIOs. 6 * as well as configurable GPIOs.
7 * 7 *
8 * Author: Carlo Caione <carlo@caione.org> 8 * Author: Carlo Caione <carlo@caione.org>
9 * 9 *
@@ -25,9 +25,16 @@
25#include <linux/mfd/core.h> 25#include <linux/mfd/core.h>
26#include <linux/of_device.h> 26#include <linux/of_device.h>
27#include <linux/of_irq.h> 27#include <linux/of_irq.h>
28#include <linux/acpi.h>
28 29
29#define AXP20X_OFF 0x80 30#define AXP20X_OFF 0x80
30 31
32static const char const *axp20x_model_names[] = {
33 "AXP202",
34 "AXP209",
35 "AXP288",
36};
37
31static const struct regmap_range axp20x_writeable_ranges[] = { 38static const struct regmap_range axp20x_writeable_ranges[] = {
32 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), 39 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
33 regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES), 40 regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
@@ -47,6 +54,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
47 .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), 54 .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
48}; 55};
49 56
57static const struct regmap_range axp288_writeable_ranges[] = {
58 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
59 regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
60};
61
62static const struct regmap_range axp288_volatile_ranges[] = {
63 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
64};
65
66static const struct regmap_access_table axp288_writeable_table = {
67 .yes_ranges = axp288_writeable_ranges,
68 .n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges),
69};
70
71static const struct regmap_access_table axp288_volatile_table = {
72 .yes_ranges = axp288_volatile_ranges,
73 .n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
74};
75
50static struct resource axp20x_pek_resources[] = { 76static struct resource axp20x_pek_resources[] = {
51 { 77 {
52 .name = "PEK_DBR", 78 .name = "PEK_DBR",
@@ -61,6 +87,39 @@ static struct resource axp20x_pek_resources[] = {
61 }, 87 },
62}; 88};
63 89
90static struct resource axp288_battery_resources[] = {
91 {
92 .start = AXP288_IRQ_QWBTU,
93 .end = AXP288_IRQ_QWBTU,
94 .flags = IORESOURCE_IRQ,
95 },
96 {
97 .start = AXP288_IRQ_WBTU,
98 .end = AXP288_IRQ_WBTU,
99 .flags = IORESOURCE_IRQ,
100 },
101 {
102 .start = AXP288_IRQ_QWBTO,
103 .end = AXP288_IRQ_QWBTO,
104 .flags = IORESOURCE_IRQ,
105 },
106 {
107 .start = AXP288_IRQ_WBTO,
108 .end = AXP288_IRQ_WBTO,
109 .flags = IORESOURCE_IRQ,
110 },
111 {
112 .start = AXP288_IRQ_WL2,
113 .end = AXP288_IRQ_WL2,
114 .flags = IORESOURCE_IRQ,
115 },
116 {
117 .start = AXP288_IRQ_WL1,
118 .end = AXP288_IRQ_WL1,
119 .flags = IORESOURCE_IRQ,
120 },
121};
122
64static const struct regmap_config axp20x_regmap_config = { 123static const struct regmap_config axp20x_regmap_config = {
65 .reg_bits = 8, 124 .reg_bits = 8,
66 .val_bits = 8, 125 .val_bits = 8,
@@ -70,47 +129,96 @@ static const struct regmap_config axp20x_regmap_config = {
70 .cache_type = REGCACHE_RBTREE, 129 .cache_type = REGCACHE_RBTREE,
71}; 130};
72 131
73#define AXP20X_IRQ(_irq, _off, _mask) \ 132static const struct regmap_config axp288_regmap_config = {
74 [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } 133 .reg_bits = 8,
134 .val_bits = 8,
135 .wr_table = &axp288_writeable_table,
136 .volatile_table = &axp288_volatile_table,
137 .max_register = AXP288_FG_TUNE5,
138 .cache_type = REGCACHE_RBTREE,
139};
140
141#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
142 [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
75 143
76static const struct regmap_irq axp20x_regmap_irqs[] = { 144static const struct regmap_irq axp20x_regmap_irqs[] = {
77 AXP20X_IRQ(ACIN_OVER_V, 0, 7), 145 INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
78 AXP20X_IRQ(ACIN_PLUGIN, 0, 6), 146 INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
79 AXP20X_IRQ(ACIN_REMOVAL, 0, 5), 147 INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5),
80 AXP20X_IRQ(VBUS_OVER_V, 0, 4), 148 INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
81 AXP20X_IRQ(VBUS_PLUGIN, 0, 3), 149 INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
82 AXP20X_IRQ(VBUS_REMOVAL, 0, 2), 150 INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
83 AXP20X_IRQ(VBUS_V_LOW, 0, 1), 151 INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1),
84 AXP20X_IRQ(BATT_PLUGIN, 1, 7), 152 INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
85 AXP20X_IRQ(BATT_REMOVAL, 1, 6), 153 INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
86 AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5), 154 INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5),
87 AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4), 155 INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4),
88 AXP20X_IRQ(CHARG, 1, 3), 156 INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
89 AXP20X_IRQ(CHARG_DONE, 1, 2), 157 INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
90 AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1), 158 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1),
91 AXP20X_IRQ(BATT_TEMP_LOW, 1, 0), 159 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0),
92 AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7), 160 INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7),
93 AXP20X_IRQ(CHARG_I_LOW, 2, 6), 161 INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6),
94 AXP20X_IRQ(DCDC1_V_LONG, 2, 5), 162 INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5),
95 AXP20X_IRQ(DCDC2_V_LONG, 2, 4), 163 INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4),
96 AXP20X_IRQ(DCDC3_V_LONG, 2, 3), 164 INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3),
97 AXP20X_IRQ(PEK_SHORT, 2, 1), 165 INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1),
98 AXP20X_IRQ(PEK_LONG, 2, 0), 166 INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0),
99 AXP20X_IRQ(N_OE_PWR_ON, 3, 7), 167 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7),
100 AXP20X_IRQ(N_OE_PWR_OFF, 3, 6), 168 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6),
101 AXP20X_IRQ(VBUS_VALID, 3, 5), 169 INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5),
102 AXP20X_IRQ(VBUS_NOT_VALID, 3, 4), 170 INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4),
103 AXP20X_IRQ(VBUS_SESS_VALID, 3, 3), 171 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3),
104 AXP20X_IRQ(VBUS_SESS_END, 3, 2), 172 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2),
105 AXP20X_IRQ(LOW_PWR_LVL1, 3, 1), 173 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1),
106 AXP20X_IRQ(LOW_PWR_LVL2, 3, 0), 174 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0),
107 AXP20X_IRQ(TIMER, 4, 7), 175 INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
108 AXP20X_IRQ(PEK_RIS_EDGE, 4, 6), 176 INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6),
109 AXP20X_IRQ(PEK_FAL_EDGE, 4, 5), 177 INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5),
110 AXP20X_IRQ(GPIO3_INPUT, 4, 3), 178 INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3),
111 AXP20X_IRQ(GPIO2_INPUT, 4, 2), 179 INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2),
112 AXP20X_IRQ(GPIO1_INPUT, 4, 1), 180 INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1),
113 AXP20X_IRQ(GPIO0_INPUT, 4, 0), 181 INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
182};
183
184/* some IRQs are compatible with axp20x models */
185static const struct regmap_irq axp288_regmap_irqs[] = {
186 INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
187 INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
188 INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
189
190 INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
191 INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
192 INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
193 INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
194 INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
195 INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
196
197 INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0),
198 INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1),
199 INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2),
200 INIT_REGMAP_IRQ(AXP288, WBTU, 2, 3),
201 INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4),
202 INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5),
203 INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6),
204 INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7),
205
206 INIT_REGMAP_IRQ(AXP288, WL2, 3, 0),
207 INIT_REGMAP_IRQ(AXP288, WL1, 3, 1),
208 INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2),
209 INIT_REGMAP_IRQ(AXP288, OT, 3, 7),
210
211 INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0),
212 INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1),
213 INIT_REGMAP_IRQ(AXP288, POKO, 4, 2),
214 INIT_REGMAP_IRQ(AXP288, POKL, 4, 3),
215 INIT_REGMAP_IRQ(AXP288, POKS, 4, 4),
216 INIT_REGMAP_IRQ(AXP288, POKN, 4, 5),
217 INIT_REGMAP_IRQ(AXP288, POKP, 4, 6),
218 INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
219
220 INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0),
221 INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
114}; 222};
115 223
116static const struct of_device_id axp20x_of_match[] = { 224static const struct of_device_id axp20x_of_match[] = {
@@ -128,16 +236,39 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
128}; 236};
129MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); 237MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
130 238
239static struct acpi_device_id axp20x_acpi_match[] = {
240 {
241 .id = "INT33F4",
242 .driver_data = AXP288_ID,
243 },
244 { },
245};
246MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
247
131static const struct regmap_irq_chip axp20x_regmap_irq_chip = { 248static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
132 .name = "axp20x_irq_chip", 249 .name = "axp20x_irq_chip",
133 .status_base = AXP20X_IRQ1_STATE, 250 .status_base = AXP20X_IRQ1_STATE,
134 .ack_base = AXP20X_IRQ1_STATE, 251 .ack_base = AXP20X_IRQ1_STATE,
135 .mask_base = AXP20X_IRQ1_EN, 252 .mask_base = AXP20X_IRQ1_EN,
136 .num_regs = 5, 253 .mask_invert = true,
254 .init_ack_masked = true,
137 .irqs = axp20x_regmap_irqs, 255 .irqs = axp20x_regmap_irqs,
138 .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), 256 .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
257 .num_regs = 5,
258
259};
260
261static const struct regmap_irq_chip axp288_regmap_irq_chip = {
262 .name = "axp288_irq_chip",
263 .status_base = AXP20X_IRQ1_STATE,
264 .ack_base = AXP20X_IRQ1_STATE,
265 .mask_base = AXP20X_IRQ1_EN,
139 .mask_invert = true, 266 .mask_invert = true,
140 .init_ack_masked = true, 267 .init_ack_masked = true,
268 .irqs = axp288_regmap_irqs,
269 .num_irqs = ARRAY_SIZE(axp288_regmap_irqs),
270 .num_regs = 6,
271
141}; 272};
142 273
143static const char * const axp20x_supplies[] = { 274static const char * const axp20x_supplies[] = {
@@ -161,36 +292,155 @@ static struct mfd_cell axp20x_cells[] = {
161 }, 292 },
162}; 293};
163 294
295static struct resource axp288_adc_resources[] = {
296 {
297 .name = "GPADC",
298 .start = AXP288_IRQ_GPADC,
299 .end = AXP288_IRQ_GPADC,
300 .flags = IORESOURCE_IRQ,
301 },
302};
303
304static struct resource axp288_charger_resources[] = {
305 {
306 .start = AXP288_IRQ_OV,
307 .end = AXP288_IRQ_OV,
308 .flags = IORESOURCE_IRQ,
309 },
310 {
311 .start = AXP288_IRQ_DONE,
312 .end = AXP288_IRQ_DONE,
313 .flags = IORESOURCE_IRQ,
314 },
315 {
316 .start = AXP288_IRQ_CHARGING,
317 .end = AXP288_IRQ_CHARGING,
318 .flags = IORESOURCE_IRQ,
319 },
320 {
321 .start = AXP288_IRQ_SAFE_QUIT,
322 .end = AXP288_IRQ_SAFE_QUIT,
323 .flags = IORESOURCE_IRQ,
324 },
325 {
326 .start = AXP288_IRQ_SAFE_ENTER,
327 .end = AXP288_IRQ_SAFE_ENTER,
328 .flags = IORESOURCE_IRQ,
329 },
330 {
331 .start = AXP288_IRQ_QCBTU,
332 .end = AXP288_IRQ_QCBTU,
333 .flags = IORESOURCE_IRQ,
334 },
335 {
336 .start = AXP288_IRQ_CBTU,
337 .end = AXP288_IRQ_CBTU,
338 .flags = IORESOURCE_IRQ,
339 },
340 {
341 .start = AXP288_IRQ_QCBTO,
342 .end = AXP288_IRQ_QCBTO,
343 .flags = IORESOURCE_IRQ,
344 },
345 {
346 .start = AXP288_IRQ_CBTO,
347 .end = AXP288_IRQ_CBTO,
348 .flags = IORESOURCE_IRQ,
349 },
350};
351
352static struct mfd_cell axp288_cells[] = {
353 {
354 .name = "axp288_adc",
355 .num_resources = ARRAY_SIZE(axp288_adc_resources),
356 .resources = axp288_adc_resources,
357 },
358 {
359 .name = "axp288_charger",
360 .num_resources = ARRAY_SIZE(axp288_charger_resources),
361 .resources = axp288_charger_resources,
362 },
363 {
364 .name = "axp288_battery",
365 .num_resources = ARRAY_SIZE(axp288_battery_resources),
366 .resources = axp288_battery_resources,
367 },
368};
369
164static struct axp20x_dev *axp20x_pm_power_off; 370static struct axp20x_dev *axp20x_pm_power_off;
165static void axp20x_power_off(void) 371static void axp20x_power_off(void)
166{ 372{
373 if (axp20x_pm_power_off->variant == AXP288_ID)
374 return;
375
167 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, 376 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
168 AXP20X_OFF); 377 AXP20X_OFF);
169} 378}
170 379
380static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
381{
382 const struct acpi_device_id *acpi_id;
383 const struct of_device_id *of_id;
384
385 if (dev->of_node) {
386 of_id = of_match_device(axp20x_of_match, dev);
387 if (!of_id) {
388 dev_err(dev, "Unable to match OF ID\n");
389 return -ENODEV;
390 }
391 axp20x->variant = (long) of_id->data;
392 } else {
393 acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
394 if (!acpi_id || !acpi_id->driver_data) {
395 dev_err(dev, "Unable to match ACPI ID and data\n");
396 return -ENODEV;
397 }
398 axp20x->variant = (long) acpi_id->driver_data;
399 }
400
401 switch (axp20x->variant) {
402 case AXP202_ID:
403 case AXP209_ID:
404 axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
405 axp20x->cells = axp20x_cells;
406 axp20x->regmap_cfg = &axp20x_regmap_config;
407 axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
408 break;
409 case AXP288_ID:
410 axp20x->cells = axp288_cells;
411 axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
412 axp20x->regmap_cfg = &axp288_regmap_config;
413 axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
414 break;
415 default:
416 dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
417 return -EINVAL;
418 }
419 dev_info(dev, "AXP20x variant %s found\n",
420 axp20x_model_names[axp20x->variant]);
421
422 return 0;
423}
424
171static int axp20x_i2c_probe(struct i2c_client *i2c, 425static int axp20x_i2c_probe(struct i2c_client *i2c,
172 const struct i2c_device_id *id) 426 const struct i2c_device_id *id)
173{ 427{
174 struct axp20x_dev *axp20x; 428 struct axp20x_dev *axp20x;
175 const struct of_device_id *of_id;
176 int ret; 429 int ret;
177 430
178 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); 431 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
179 if (!axp20x) 432 if (!axp20x)
180 return -ENOMEM; 433 return -ENOMEM;
181 434
182 of_id = of_match_device(axp20x_of_match, &i2c->dev); 435 ret = axp20x_match_device(axp20x, &i2c->dev);
183 if (!of_id) { 436 if (ret)
184 dev_err(&i2c->dev, "Unable to setup AXP20X data\n"); 437 return ret;
185 return -ENODEV;
186 }
187 axp20x->variant = (long) of_id->data;
188 438
189 axp20x->i2c_client = i2c; 439 axp20x->i2c_client = i2c;
190 axp20x->dev = &i2c->dev; 440 axp20x->dev = &i2c->dev;
191 dev_set_drvdata(axp20x->dev, axp20x); 441 dev_set_drvdata(axp20x->dev, axp20x);
192 442
193 axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config); 443 axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
194 if (IS_ERR(axp20x->regmap)) { 444 if (IS_ERR(axp20x->regmap)) {
195 ret = PTR_ERR(axp20x->regmap); 445 ret = PTR_ERR(axp20x->regmap);
196 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 446 dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
@@ -199,15 +449,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
199 449
200 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, 450 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
201 IRQF_ONESHOT | IRQF_SHARED, -1, 451 IRQF_ONESHOT | IRQF_SHARED, -1,
202 &axp20x_regmap_irq_chip, 452 axp20x->regmap_irq_chip,
203 &axp20x->regmap_irqc); 453 &axp20x->regmap_irqc);
204 if (ret) { 454 if (ret) {
205 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); 455 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
206 return ret; 456 return ret;
207 } 457 }
208 458
209 ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells, 459 ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
210 ARRAY_SIZE(axp20x_cells), NULL, 0, NULL); 460 axp20x->nr_cells, NULL, 0, NULL);
211 461
212 if (ret) { 462 if (ret) {
213 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); 463 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
@@ -245,6 +495,7 @@ static struct i2c_driver axp20x_i2c_driver = {
245 .name = "axp20x", 495 .name = "axp20x",
246 .owner = THIS_MODULE, 496 .owner = THIS_MODULE,
247 .of_match_table = of_match_ptr(axp20x_of_match), 497 .of_match_table = of_match_ptr(axp20x_of_match),
498 .acpi_match_table = ACPI_PTR(axp20x_acpi_match),
248 }, 499 },
249 .probe = axp20x_i2c_probe, 500 .probe = axp20x_i2c_probe,
250 .remove = axp20x_i2c_remove, 501 .remove = axp20x_i2c_remove,
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index d0e31a2287ac..81589d176ae8 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -14,6 +14,8 @@
14enum { 14enum {
15 AXP202_ID = 0, 15 AXP202_ID = 0,
16 AXP209_ID, 16 AXP209_ID,
17 AXP288_ID,
18 NR_AXP20X_VARIANTS,
17}; 19};
18 20
19#define AXP20X_DATACACHE(m) (0x04 + (m)) 21#define AXP20X_DATACACHE(m) (0x04 + (m))
@@ -49,11 +51,13 @@ enum {
49#define AXP20X_IRQ3_EN 0x42 51#define AXP20X_IRQ3_EN 0x42
50#define AXP20X_IRQ4_EN 0x43 52#define AXP20X_IRQ4_EN 0x43
51#define AXP20X_IRQ5_EN 0x44 53#define AXP20X_IRQ5_EN 0x44
54#define AXP20X_IRQ6_EN 0x45
52#define AXP20X_IRQ1_STATE 0x48 55#define AXP20X_IRQ1_STATE 0x48
53#define AXP20X_IRQ2_STATE 0x49 56#define AXP20X_IRQ2_STATE 0x49
54#define AXP20X_IRQ3_STATE 0x4a 57#define AXP20X_IRQ3_STATE 0x4a
55#define AXP20X_IRQ4_STATE 0x4b 58#define AXP20X_IRQ4_STATE 0x4b
56#define AXP20X_IRQ5_STATE 0x4c 59#define AXP20X_IRQ5_STATE 0x4c
60#define AXP20X_IRQ6_STATE 0x4d
57 61
58/* ADC */ 62/* ADC */
59#define AXP20X_ACIN_V_ADC_H 0x56 63#define AXP20X_ACIN_V_ADC_H 0x56
@@ -116,6 +120,15 @@ enum {
116#define AXP20X_CC_CTRL 0xb8 120#define AXP20X_CC_CTRL 0xb8
117#define AXP20X_FG_RES 0xb9 121#define AXP20X_FG_RES 0xb9
118 122
123/* AXP288 specific registers */
124#define AXP288_PMIC_ADC_H 0x56
125#define AXP288_PMIC_ADC_L 0x57
126#define AXP288_ADC_TS_PIN_CTRL 0x84
127
128#define AXP288_PMIC_ADC_EN 0x84
129#define AXP288_FG_TUNE5 0xed
130
131
119/* Regulators IDs */ 132/* Regulators IDs */
120enum { 133enum {
121 AXP20X_LDO1 = 0, 134 AXP20X_LDO1 = 0,
@@ -169,12 +182,58 @@ enum {
169 AXP20X_IRQ_GPIO0_INPUT, 182 AXP20X_IRQ_GPIO0_INPUT,
170}; 183};
171 184
185enum axp288_irqs {
186 AXP288_IRQ_VBUS_FALL = 2,
187 AXP288_IRQ_VBUS_RISE,
188 AXP288_IRQ_OV,
189 AXP288_IRQ_FALLING_ALT,
190 AXP288_IRQ_RISING_ALT,
191 AXP288_IRQ_OV_ALT,
192 AXP288_IRQ_DONE = 10,
193 AXP288_IRQ_CHARGING,
194 AXP288_IRQ_SAFE_QUIT,
195 AXP288_IRQ_SAFE_ENTER,
196 AXP288_IRQ_ABSENT,
197 AXP288_IRQ_APPEND,
198 AXP288_IRQ_QWBTU,
199 AXP288_IRQ_WBTU,
200 AXP288_IRQ_QWBTO,
201 AXP288_IRQ_WBTO,
202 AXP288_IRQ_QCBTU,
203 AXP288_IRQ_CBTU,
204 AXP288_IRQ_QCBTO,
205 AXP288_IRQ_CBTO,
206 AXP288_IRQ_WL2,
207 AXP288_IRQ_WL1,
208 AXP288_IRQ_GPADC,
209 AXP288_IRQ_OT = 31,
210 AXP288_IRQ_GPIO0,
211 AXP288_IRQ_GPIO1,
212 AXP288_IRQ_POKO,
213 AXP288_IRQ_POKL,
214 AXP288_IRQ_POKS,
215 AXP288_IRQ_POKN,
216 AXP288_IRQ_POKP,
217 AXP288_IRQ_TIMER,
218 AXP288_IRQ_MV_CHNG,
219 AXP288_IRQ_BC_USB_CHNG,
220};
221
222#define AXP288_TS_ADC_H 0x58
223#define AXP288_TS_ADC_L 0x59
224#define AXP288_GP_ADC_H 0x5a
225#define AXP288_GP_ADC_L 0x5b
226
172struct axp20x_dev { 227struct axp20x_dev {
173 struct device *dev; 228 struct device *dev;
174 struct i2c_client *i2c_client; 229 struct i2c_client *i2c_client;
175 struct regmap *regmap; 230 struct regmap *regmap;
176 struct regmap_irq_chip_data *regmap_irqc; 231 struct regmap_irq_chip_data *regmap_irqc;
177 long variant; 232 long variant;
233 int nr_cells;
234 struct mfd_cell *cells;
235 const struct regmap_config *regmap_cfg;
236 const struct regmap_irq_chip *regmap_irq_chip;
178}; 237};
179 238
180#endif /* __LINUX_MFD_AXP20X_H */ 239#endif /* __LINUX_MFD_AXP20X_H */