aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iio/adc/Kconfig8
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/axp288_adc.c261
-rw-r--r--drivers/mfd/Kconfig3
-rw-r--r--drivers/mfd/axp20x.c361
5 files changed, 578 insertions, 56 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 88bdc8f612e2..bc4e787096e8 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -127,6 +127,14 @@ config AT91_ADC
127 help 127 help
128 Say yes here to build support for Atmel AT91 ADC. 128 Say yes here to build support for Atmel AT91 ADC.
129 129
130config AXP288_ADC
131 tristate "X-Powers AXP288 ADC driver"
132 depends on MFD_AXP20X
133 help
134 Say yes here to have support for X-Powers power management IC (PMIC) ADC
135 device. Depending on platform configuration, this general purpose ADC can
136 be used for sampling sensors such as thermal resistors.
137
130config EXYNOS_ADC 138config EXYNOS_ADC
131 tristate "Exynos ADC driver support" 139 tristate "Exynos ADC driver support"
132 depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) 140 depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index cb88a6a23b8f..f30093f5b67a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
14obj-$(CONFIG_AD7887) += ad7887.o 14obj-$(CONFIG_AD7887) += ad7887.o
15obj-$(CONFIG_AD799X) += ad799x.o 15obj-$(CONFIG_AD799X) += ad799x.o
16obj-$(CONFIG_AT91_ADC) += at91_adc.o 16obj-$(CONFIG_AT91_ADC) += at91_adc.o
17obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
17obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o 18obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
18obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o 19obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
19obj-$(CONFIG_MAX1027) += max1027.o 20obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
new file mode 100644
index 000000000000..08bcfb061ca5
--- /dev/null
+++ b/drivers/iio/adc/axp288_adc.c
@@ -0,0 +1,261 @@
1/*
2 * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
3 *
4 * Copyright (C) 2014 Intel Corporation
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/device.h>
22#include <linux/regmap.h>
23#include <linux/mfd/axp20x.h>
24#include <linux/platform_device.h>
25
26#include <linux/iio/iio.h>
27#include <linux/iio/machine.h>
28#include <linux/iio/driver.h>
29
30#define AXP288_ADC_EN_MASK 0xF1
31#define AXP288_ADC_TS_PIN_GPADC 0xF2
32#define AXP288_ADC_TS_PIN_ON 0xF3
33
34enum axp288_adc_id {
35 AXP288_ADC_TS,
36 AXP288_ADC_PMIC,
37 AXP288_ADC_GP,
38 AXP288_ADC_BATT_CHRG_I,
39 AXP288_ADC_BATT_DISCHRG_I,
40 AXP288_ADC_BATT_V,
41 AXP288_ADC_NR_CHAN,
42};
43
44struct axp288_adc_info {
45 int irq;
46 struct regmap *regmap;
47};
48
49static const struct iio_chan_spec const axp288_adc_channels[] = {
50 {
51 .indexed = 1,
52 .type = IIO_TEMP,
53 .channel = 0,
54 .address = AXP288_TS_ADC_H,
55 .datasheet_name = "TS_PIN",
56 }, {
57 .indexed = 1,
58 .type = IIO_TEMP,
59 .channel = 1,
60 .address = AXP288_PMIC_ADC_H,
61 .datasheet_name = "PMIC_TEMP",
62 }, {
63 .indexed = 1,
64 .type = IIO_TEMP,
65 .channel = 2,
66 .address = AXP288_GP_ADC_H,
67 .datasheet_name = "GPADC",
68 }, {
69 .indexed = 1,
70 .type = IIO_CURRENT,
71 .channel = 3,
72 .address = AXP20X_BATT_CHRG_I_H,
73 .datasheet_name = "BATT_CHG_I",
74 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
75 }, {
76 .indexed = 1,
77 .type = IIO_CURRENT,
78 .channel = 4,
79 .address = AXP20X_BATT_DISCHRG_I_H,
80 .datasheet_name = "BATT_DISCHRG_I",
81 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
82 }, {
83 .indexed = 1,
84 .type = IIO_VOLTAGE,
85 .channel = 5,
86 .address = AXP20X_BATT_V_H,
87 .datasheet_name = "BATT_V",
88 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
89 },
90};
91
92#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
93 _consumer_channel) \
94 { \
95 .adc_channel_label = _adc_channel_label, \
96 .consumer_dev_name = _consumer_dev_name, \
97 .consumer_channel = _consumer_channel, \
98 }
99
100/* for consumer drivers */
101static struct iio_map axp288_adc_default_maps[] = {
102 AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
103 AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
104 AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
105 AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
106 AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
107 AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
108 {},
109};
110
111static int axp288_adc_read_channel(int *val, unsigned long address,
112 struct regmap *regmap)
113{
114 u8 buf[2];
115
116 if (regmap_bulk_read(regmap, address, buf, 2))
117 return -EIO;
118 *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
119
120 return IIO_VAL_INT;
121}
122
123static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
124 unsigned long address)
125{
126 /* channels other than GPADC do not need to switch TS pin */
127 if (address != AXP288_GP_ADC_H)
128 return 0;
129
130 return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
131}
132
133static int axp288_adc_read_raw(struct iio_dev *indio_dev,
134 struct iio_chan_spec const *chan,
135 int *val, int *val2, long mask)
136{
137 int ret;
138 struct axp288_adc_info *info = iio_priv(indio_dev);
139
140 mutex_lock(&indio_dev->mlock);
141 switch (mask) {
142 case IIO_CHAN_INFO_RAW:
143 if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
144 chan->address)) {
145 dev_err(&indio_dev->dev, "GPADC mode\n");
146 ret = -EINVAL;
147 break;
148 }
149 ret = axp288_adc_read_channel(val, chan->address, info->regmap);
150 if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
151 chan->address))
152 dev_err(&indio_dev->dev, "TS pin restore\n");
153 break;
154 case IIO_CHAN_INFO_PROCESSED:
155 ret = axp288_adc_read_channel(val, chan->address, info->regmap);
156 break;
157 default:
158 ret = -EINVAL;
159 }
160 mutex_unlock(&indio_dev->mlock);
161
162 return ret;
163}
164
165static int axp288_adc_set_state(struct regmap *regmap)
166{
167 /* ADC should be always enabled for internal FG to function */
168 if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
169 return -EIO;
170
171 return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
172}
173
174static const struct iio_info axp288_adc_iio_info = {
175 .read_raw = &axp288_adc_read_raw,
176 .driver_module = THIS_MODULE,
177};
178
179static int axp288_adc_probe(struct platform_device *pdev)
180{
181 int ret;
182 struct axp288_adc_info *info;
183 struct iio_dev *indio_dev;
184 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
185
186 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
187 if (!indio_dev)
188 return -ENOMEM;
189
190 info = iio_priv(indio_dev);
191 info->irq = platform_get_irq(pdev, 0);
192 if (info->irq < 0) {
193 dev_err(&pdev->dev, "no irq resource?\n");
194 return info->irq;
195 }
196 platform_set_drvdata(pdev, indio_dev);
197 info->regmap = axp20x->regmap;
198 /*
199 * Set ADC to enabled state at all time, including system suspend.
200 * otherwise internal fuel gauge functionality may be affected.
201 */
202 ret = axp288_adc_set_state(axp20x->regmap);
203 if (ret) {
204 dev_err(&pdev->dev, "unable to enable ADC device\n");
205 return ret;
206 }
207
208 indio_dev->dev.parent = &pdev->dev;
209 indio_dev->name = pdev->name;
210 indio_dev->channels = axp288_adc_channels;
211 indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
212 indio_dev->info = &axp288_adc_iio_info;
213 indio_dev->modes = INDIO_DIRECT_MODE;
214 ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
215 if (ret < 0)
216 return ret;
217
218 ret = iio_device_register(indio_dev);
219 if (ret < 0) {
220 dev_err(&pdev->dev, "unable to register iio device\n");
221 goto err_array_unregister;
222 }
223 return 0;
224
225err_array_unregister:
226 iio_map_array_unregister(indio_dev);
227
228 return ret;
229}
230
231static int axp288_adc_remove(struct platform_device *pdev)
232{
233 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
234
235 iio_device_unregister(indio_dev);
236 iio_map_array_unregister(indio_dev);
237
238 return 0;
239}
240
241static struct platform_device_id axp288_adc_id_table[] = {
242 { .name = "axp288_adc" },
243 {},
244};
245
246static struct platform_driver axp288_adc_driver = {
247 .probe = axp288_adc_probe,
248 .remove = axp288_adc_remove,
249 .id_table = axp288_adc_id_table,
250 .driver = {
251 .name = "axp288_adc",
252 },
253};
254
255MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
256
257module_platform_driver(axp288_adc_driver);
258
259MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
260MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
261MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1456ea70bbc7..9af299ba711a 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 6231adbb295d..971b0eb8d821 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(AXP288, VBUS_FALL, 0, 2),
187 INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3),
188 INIT_REGMAP_IRQ(AXP288, OV, 0, 4),
189
190 INIT_REGMAP_IRQ(AXP288, DONE, 1, 2),
191 INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
192 INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
193 INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
194 INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6),
195 INIT_REGMAP_IRQ(AXP288, APPEND, 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, WBTO, 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(AXP288, 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 struct mfd_cell axp20x_cells[] = { 274static struct mfd_cell axp20x_cells[] = {
@@ -150,36 +281,155 @@ static struct mfd_cell axp20x_cells[] = {
150 }, 281 },
151}; 282};
152 283
284static struct resource axp288_adc_resources[] = {
285 {
286 .name = "GPADC",
287 .start = AXP288_IRQ_GPADC,
288 .end = AXP288_IRQ_GPADC,
289 .flags = IORESOURCE_IRQ,
290 },
291};
292
293static struct resource axp288_charger_resources[] = {
294 {
295 .start = AXP288_IRQ_OV,
296 .end = AXP288_IRQ_OV,
297 .flags = IORESOURCE_IRQ,
298 },
299 {
300 .start = AXP288_IRQ_DONE,
301 .end = AXP288_IRQ_DONE,
302 .flags = IORESOURCE_IRQ,
303 },
304 {
305 .start = AXP288_IRQ_CHARGING,
306 .end = AXP288_IRQ_CHARGING,
307 .flags = IORESOURCE_IRQ,
308 },
309 {
310 .start = AXP288_IRQ_SAFE_QUIT,
311 .end = AXP288_IRQ_SAFE_QUIT,
312 .flags = IORESOURCE_IRQ,
313 },
314 {
315 .start = AXP288_IRQ_SAFE_ENTER,
316 .end = AXP288_IRQ_SAFE_ENTER,
317 .flags = IORESOURCE_IRQ,
318 },
319 {
320 .start = AXP288_IRQ_QCBTU,
321 .end = AXP288_IRQ_QCBTU,
322 .flags = IORESOURCE_IRQ,
323 },
324 {
325 .start = AXP288_IRQ_CBTU,
326 .end = AXP288_IRQ_CBTU,
327 .flags = IORESOURCE_IRQ,
328 },
329 {
330 .start = AXP288_IRQ_QCBTO,
331 .end = AXP288_IRQ_QCBTO,
332 .flags = IORESOURCE_IRQ,
333 },
334 {
335 .start = AXP288_IRQ_CBTO,
336 .end = AXP288_IRQ_CBTO,
337 .flags = IORESOURCE_IRQ,
338 },
339};
340
341static struct mfd_cell axp288_cells[] = {
342 {
343 .name = "axp288_adc",
344 .num_resources = ARRAY_SIZE(axp288_adc_resources),
345 .resources = axp288_adc_resources,
346 },
347 {
348 .name = "axp288_charger",
349 .num_resources = ARRAY_SIZE(axp288_charger_resources),
350 .resources = axp288_charger_resources,
351 },
352 {
353 .name = "axp288_battery",
354 .num_resources = ARRAY_SIZE(axp288_battery_resources),
355 .resources = axp288_battery_resources,
356 },
357};
358
153static struct axp20x_dev *axp20x_pm_power_off; 359static struct axp20x_dev *axp20x_pm_power_off;
154static void axp20x_power_off(void) 360static void axp20x_power_off(void)
155{ 361{
362 if (axp20x_pm_power_off->variant == AXP288_ID)
363 return;
364
156 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, 365 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
157 AXP20X_OFF); 366 AXP20X_OFF);
158} 367}
159 368
369static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
370{
371 const struct acpi_device_id *acpi_id;
372 const struct of_device_id *of_id;
373
374 if (dev->of_node) {
375 of_id = of_match_device(axp20x_of_match, dev);
376 if (!of_id) {
377 dev_err(dev, "Unable to match OF ID\n");
378 return -ENODEV;
379 }
380 axp20x->variant = (long) of_id->data;
381 } else {
382 acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
383 if (!acpi_id || !acpi_id->driver_data) {
384 dev_err(dev, "Unable to match ACPI ID and data\n");
385 return -ENODEV;
386 }
387 axp20x->variant = (long) acpi_id->driver_data;
388 }
389
390 switch (axp20x->variant) {
391 case AXP202_ID:
392 case AXP209_ID:
393 axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
394 axp20x->cells = axp20x_cells;
395 axp20x->regmap_cfg = &axp20x_regmap_config;
396 axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
397 break;
398 case AXP288_ID:
399 axp20x->cells = axp288_cells;
400 axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
401 axp20x->regmap_cfg = &axp288_regmap_config;
402 axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
403 break;
404 default:
405 dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
406 return -EINVAL;
407 }
408 dev_info(dev, "AXP20x variant %s found\n",
409 axp20x_model_names[axp20x->variant]);
410
411 return 0;
412}
413
160static int axp20x_i2c_probe(struct i2c_client *i2c, 414static int axp20x_i2c_probe(struct i2c_client *i2c,
161 const struct i2c_device_id *id) 415 const struct i2c_device_id *id)
162{ 416{
163 struct axp20x_dev *axp20x; 417 struct axp20x_dev *axp20x;
164 const struct of_device_id *of_id;
165 int ret; 418 int ret;
166 419
167 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); 420 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
168 if (!axp20x) 421 if (!axp20x)
169 return -ENOMEM; 422 return -ENOMEM;
170 423
171 of_id = of_match_device(axp20x_of_match, &i2c->dev); 424 ret = axp20x_match_device(axp20x, &i2c->dev);
172 if (!of_id) { 425 if (ret)
173 dev_err(&i2c->dev, "Unable to setup AXP20X data\n"); 426 return ret;
174 return -ENODEV;
175 }
176 axp20x->variant = (long) of_id->data;
177 427
178 axp20x->i2c_client = i2c; 428 axp20x->i2c_client = i2c;
179 axp20x->dev = &i2c->dev; 429 axp20x->dev = &i2c->dev;
180 dev_set_drvdata(axp20x->dev, axp20x); 430 dev_set_drvdata(axp20x->dev, axp20x);
181 431
182 axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config); 432 axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
183 if (IS_ERR(axp20x->regmap)) { 433 if (IS_ERR(axp20x->regmap)) {
184 ret = PTR_ERR(axp20x->regmap); 434 ret = PTR_ERR(axp20x->regmap);
185 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 435 dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
@@ -188,15 +438,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
188 438
189 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, 439 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
190 IRQF_ONESHOT | IRQF_SHARED, -1, 440 IRQF_ONESHOT | IRQF_SHARED, -1,
191 &axp20x_regmap_irq_chip, 441 axp20x->regmap_irq_chip,
192 &axp20x->regmap_irqc); 442 &axp20x->regmap_irqc);
193 if (ret) { 443 if (ret) {
194 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); 444 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
195 return ret; 445 return ret;
196 } 446 }
197 447
198 ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells, 448 ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
199 ARRAY_SIZE(axp20x_cells), NULL, 0, NULL); 449 axp20x->nr_cells, NULL, 0, NULL);
200 450
201 if (ret) { 451 if (ret) {
202 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); 452 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
@@ -234,6 +484,7 @@ static struct i2c_driver axp20x_i2c_driver = {
234 .name = "axp20x", 484 .name = "axp20x",
235 .owner = THIS_MODULE, 485 .owner = THIS_MODULE,
236 .of_match_table = of_match_ptr(axp20x_of_match), 486 .of_match_table = of_match_ptr(axp20x_of_match),
487 .acpi_match_table = ACPI_PTR(axp20x_acpi_match),
237 }, 488 },
238 .probe = axp20x_i2c_probe, 489 .probe = axp20x_i2c_probe,
239 .remove = axp20x_i2c_remove, 490 .remove = axp20x_i2c_remove,