aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlo Caione <carlo@caione.org>2014-05-01 08:29:27 -0400
committerLee Jones <lee.jones@linaro.org>2014-06-03 03:11:25 -0400
commitcfb61a419630a810033f2777aba724ab6b1272b3 (patch)
treea5ca017af08d96d1101fa527e26ccceff0a4a696
parent45330bb434214c83841171eb4c591da74367a589 (diff)
mfd: AXP20x: Add mfd driver for AXP20x PMIC
This patch introduces the preliminary support for PMICs X-Powers AXP202 and AXP209. The AXP209 and AXP202 are the PMUs (Power Management Unit) used by A10, A13 and A20 SoCs and developed by X-Powers, a sister company of Allwinner. The core enables support for two subsystems: - PEK (Power Enable Key) - Regulators Signed-off-by: Carlo Caione <carlo@caione.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--drivers/mfd/Kconfig12
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/axp20x.c258
-rw-r--r--include/linux/mfd/axp20x.h180
4 files changed, 451 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index e166d7176d7a..c681741ce492 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -67,6 +67,18 @@ config MFD_BCM590XX
67 help 67 help
68 Support for the BCM590xx PMUs from Broadcom 68 Support for the BCM590xx PMUs from Broadcom
69 69
70config MFD_AXP20X
71 bool "X-Powers AXP20X"
72 select MFD_CORE
73 select REGMAP_I2C
74 select REGMAP_IRQ
75 depends on I2C=y
76 help
77 If you say Y here you get support for the X-Powers AXP202 and AXP209.
78 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 corresponding menus.
81
70config MFD_CROS_EC 82config MFD_CROS_EC
71 tristate "ChromeOS Embedded Controller" 83 tristate "ChromeOS Embedded Controller"
72 select MFD_CORE 84 select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2851275e2656..1efecf2793ae 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
102obj-$(CONFIG_PMIC_DA9052) += da9052-core.o 102obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
103obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o 103obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
104obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o 104obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
105obj-$(CONFIG_MFD_AXP20X) += axp20x.o
105 106
106obj-$(CONFIG_MFD_LP3943) += lp3943.o 107obj-$(CONFIG_MFD_LP3943) += lp3943.o
107obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o 108obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
new file mode 100644
index 000000000000..dee653989e3a
--- /dev/null
+++ b/drivers/mfd/axp20x.c
@@ -0,0 +1,258 @@
1/*
2 * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
3 *
4 * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
5 * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
6 * as well as 4 configurable GPIOs.
7 *
8 * Author: Carlo Caione <carlo@caione.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/err.h>
16#include <linux/i2c.h>
17#include <linux/interrupt.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/pm_runtime.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23#include <linux/regulator/consumer.h>
24#include <linux/mfd/axp20x.h>
25#include <linux/mfd/core.h>
26#include <linux/of_device.h>
27#include <linux/of_irq.h>
28
29#define AXP20X_OFF 0x80
30
31static const struct regmap_range axp20x_writeable_ranges[] = {
32 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
33 regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
34};
35
36static const struct regmap_range axp20x_volatile_ranges[] = {
37 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
38};
39
40static const struct regmap_access_table axp20x_writeable_table = {
41 .yes_ranges = axp20x_writeable_ranges,
42 .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges),
43};
44
45static const struct regmap_access_table axp20x_volatile_table = {
46 .yes_ranges = axp20x_volatile_ranges,
47 .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
48};
49
50static struct resource axp20x_pek_resources[] = {
51 {
52 .name = "PEK_DBR",
53 .start = AXP20X_IRQ_PEK_RIS_EDGE,
54 .end = AXP20X_IRQ_PEK_RIS_EDGE,
55 .flags = IORESOURCE_IRQ,
56 }, {
57 .name = "PEK_DBF",
58 .start = AXP20X_IRQ_PEK_FAL_EDGE,
59 .end = AXP20X_IRQ_PEK_FAL_EDGE,
60 .flags = IORESOURCE_IRQ,
61 },
62};
63
64static const struct regmap_config axp20x_regmap_config = {
65 .reg_bits = 8,
66 .val_bits = 8,
67 .wr_table = &axp20x_writeable_table,
68 .volatile_table = &axp20x_volatile_table,
69 .max_register = AXP20X_FG_RES,
70 .cache_type = REGCACHE_RBTREE,
71};
72
73#define AXP20X_IRQ(_irq, _off, _mask) \
74 [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
75
76static const struct regmap_irq axp20x_regmap_irqs[] = {
77 AXP20X_IRQ(ACIN_OVER_V, 0, 7),
78 AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
79 AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
80 AXP20X_IRQ(VBUS_OVER_V, 0, 4),
81 AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
82 AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
83 AXP20X_IRQ(VBUS_V_LOW, 0, 1),
84 AXP20X_IRQ(BATT_PLUGIN, 1, 7),
85 AXP20X_IRQ(BATT_REMOVAL, 1, 6),
86 AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
87 AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
88 AXP20X_IRQ(CHARG, 1, 3),
89 AXP20X_IRQ(CHARG_DONE, 1, 2),
90 AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
91 AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
92 AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
93 AXP20X_IRQ(CHARG_I_LOW, 2, 6),
94 AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
95 AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
96 AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
97 AXP20X_IRQ(PEK_SHORT, 2, 1),
98 AXP20X_IRQ(PEK_LONG, 2, 0),
99 AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
100 AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
101 AXP20X_IRQ(VBUS_VALID, 3, 5),
102 AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
103 AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
104 AXP20X_IRQ(VBUS_SESS_END, 3, 2),
105 AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
106 AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
107 AXP20X_IRQ(TIMER, 4, 7),
108 AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
109 AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
110 AXP20X_IRQ(GPIO3_INPUT, 4, 3),
111 AXP20X_IRQ(GPIO2_INPUT, 4, 2),
112 AXP20X_IRQ(GPIO1_INPUT, 4, 1),
113 AXP20X_IRQ(GPIO0_INPUT, 4, 0),
114};
115
116static const struct of_device_id axp20x_of_match[] = {
117 { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
118 { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
119 { },
120};
121MODULE_DEVICE_TABLE(of, axp20x_of_match);
122
123/*
124 * This is useless for OF-enabled devices, but it is needed by I2C subsystem
125 */
126static const struct i2c_device_id axp20x_i2c_id[] = {
127 { },
128};
129MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
130
131static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
132 .name = "axp20x_irq_chip",
133 .status_base = AXP20X_IRQ1_STATE,
134 .ack_base = AXP20X_IRQ1_STATE,
135 .mask_base = AXP20X_IRQ1_EN,
136 .num_regs = 5,
137 .irqs = axp20x_regmap_irqs,
138 .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
139 .mask_invert = true,
140 .init_ack_masked = true,
141};
142
143static const char * const axp20x_supplies[] = {
144 "acin",
145 "vin2",
146 "vin3",
147 "ldo24in",
148 "ldo3in",
149 "ldo5in",
150};
151
152static struct mfd_cell axp20x_cells[] = {
153 {
154 .name = "axp20x-pek",
155 .num_resources = ARRAY_SIZE(axp20x_pek_resources),
156 .resources = axp20x_pek_resources,
157 }, {
158 .name = "axp20x-regulator",
159 .parent_supplies = axp20x_supplies,
160 .num_parent_supplies = ARRAY_SIZE(axp20x_supplies),
161 },
162};
163
164static struct axp20x_dev *axp20x_pm_power_off;
165static void axp20x_power_off(void)
166{
167 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
168 AXP20X_OFF);
169}
170
171static int axp20x_i2c_probe(struct i2c_client *i2c,
172 const struct i2c_device_id *id)
173{
174 struct axp20x_dev *axp20x;
175 const struct of_device_id *of_id;
176 int ret;
177
178 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
179 if (!axp20x)
180 return -ENOMEM;
181
182 of_id = of_match_device(axp20x_of_match, &i2c->dev);
183 if (!of_id) {
184 dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
185 return -ENODEV;
186 }
187 axp20x->variant = (long) of_id->data;
188
189 axp20x->i2c_client = i2c;
190 axp20x->dev = &i2c->dev;
191 dev_set_drvdata(axp20x->dev, axp20x);
192
193 axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
194 if (IS_ERR(axp20x->regmap)) {
195 ret = PTR_ERR(axp20x->regmap);
196 dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
197 return ret;
198 }
199
200 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
201 IRQF_ONESHOT | IRQF_SHARED, -1,
202 &axp20x_regmap_irq_chip,
203 &axp20x->regmap_irqc);
204 if (ret) {
205 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
206 return ret;
207 }
208
209 ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
210 ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
211
212 if (ret) {
213 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
214 regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
215 return ret;
216 }
217
218 if (!pm_power_off) {
219 axp20x_pm_power_off = axp20x;
220 pm_power_off = axp20x_power_off;
221 }
222
223 dev_info(&i2c->dev, "AXP20X driver loaded\n");
224
225 return 0;
226}
227
228static int axp20x_i2c_remove(struct i2c_client *i2c)
229{
230 struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
231
232 if (axp20x == axp20x_pm_power_off) {
233 axp20x_pm_power_off = NULL;
234 pm_power_off = NULL;
235 }
236
237 mfd_remove_devices(axp20x->dev);
238 regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
239
240 return 0;
241}
242
243static struct i2c_driver axp20x_i2c_driver = {
244 .driver = {
245 .name = "axp20x",
246 .owner = THIS_MODULE,
247 .of_match_table = of_match_ptr(axp20x_of_match),
248 },
249 .probe = axp20x_i2c_probe,
250 .remove = axp20x_i2c_remove,
251 .id_table = axp20x_i2c_id,
252};
253
254module_i2c_driver(axp20x_i2c_driver);
255
256MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
257MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
258MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
new file mode 100644
index 000000000000..d0e31a2287ac
--- /dev/null
+++ b/include/linux/mfd/axp20x.h
@@ -0,0 +1,180 @@
1/*
2 * Functions and registers to access AXP20X power management chip.
3 *
4 * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef __LINUX_MFD_AXP20X_H
12#define __LINUX_MFD_AXP20X_H
13
14enum {
15 AXP202_ID = 0,
16 AXP209_ID,
17};
18
19#define AXP20X_DATACACHE(m) (0x04 + (m))
20
21/* Power supply */
22#define AXP20X_PWR_INPUT_STATUS 0x00
23#define AXP20X_PWR_OP_MODE 0x01
24#define AXP20X_USB_OTG_STATUS 0x02
25#define AXP20X_PWR_OUT_CTRL 0x12
26#define AXP20X_DCDC2_V_OUT 0x23
27#define AXP20X_DCDC2_LDO3_V_SCAL 0x25
28#define AXP20X_DCDC3_V_OUT 0x27
29#define AXP20X_LDO24_V_OUT 0x28
30#define AXP20X_LDO3_V_OUT 0x29
31#define AXP20X_VBUS_IPSOUT_MGMT 0x30
32#define AXP20X_V_OFF 0x31
33#define AXP20X_OFF_CTRL 0x32
34#define AXP20X_CHRG_CTRL1 0x33
35#define AXP20X_CHRG_CTRL2 0x34
36#define AXP20X_CHRG_BAK_CTRL 0x35
37#define AXP20X_PEK_KEY 0x36
38#define AXP20X_DCDC_FREQ 0x37
39#define AXP20X_V_LTF_CHRG 0x38
40#define AXP20X_V_HTF_CHRG 0x39
41#define AXP20X_APS_WARN_L1 0x3a
42#define AXP20X_APS_WARN_L2 0x3b
43#define AXP20X_V_LTF_DISCHRG 0x3c
44#define AXP20X_V_HTF_DISCHRG 0x3d
45
46/* Interrupt */
47#define AXP20X_IRQ1_EN 0x40
48#define AXP20X_IRQ2_EN 0x41
49#define AXP20X_IRQ3_EN 0x42
50#define AXP20X_IRQ4_EN 0x43
51#define AXP20X_IRQ5_EN 0x44
52#define AXP20X_IRQ1_STATE 0x48
53#define AXP20X_IRQ2_STATE 0x49
54#define AXP20X_IRQ3_STATE 0x4a
55#define AXP20X_IRQ4_STATE 0x4b
56#define AXP20X_IRQ5_STATE 0x4c
57
58/* ADC */
59#define AXP20X_ACIN_V_ADC_H 0x56
60#define AXP20X_ACIN_V_ADC_L 0x57
61#define AXP20X_ACIN_I_ADC_H 0x58
62#define AXP20X_ACIN_I_ADC_L 0x59
63#define AXP20X_VBUS_V_ADC_H 0x5a
64#define AXP20X_VBUS_V_ADC_L 0x5b
65#define AXP20X_VBUS_I_ADC_H 0x5c
66#define AXP20X_VBUS_I_ADC_L 0x5d
67#define AXP20X_TEMP_ADC_H 0x5e
68#define AXP20X_TEMP_ADC_L 0x5f
69#define AXP20X_TS_IN_H 0x62
70#define AXP20X_TS_IN_L 0x63
71#define AXP20X_GPIO0_V_ADC_H 0x64
72#define AXP20X_GPIO0_V_ADC_L 0x65
73#define AXP20X_GPIO1_V_ADC_H 0x66
74#define AXP20X_GPIO1_V_ADC_L 0x67
75#define AXP20X_PWR_BATT_H 0x70
76#define AXP20X_PWR_BATT_M 0x71
77#define AXP20X_PWR_BATT_L 0x72
78#define AXP20X_BATT_V_H 0x78
79#define AXP20X_BATT_V_L 0x79
80#define AXP20X_BATT_CHRG_I_H 0x7a
81#define AXP20X_BATT_CHRG_I_L 0x7b
82#define AXP20X_BATT_DISCHRG_I_H 0x7c
83#define AXP20X_BATT_DISCHRG_I_L 0x7d
84#define AXP20X_IPSOUT_V_HIGH_H 0x7e
85#define AXP20X_IPSOUT_V_HIGH_L 0x7f
86
87/* Power supply */
88#define AXP20X_DCDC_MODE 0x80
89#define AXP20X_ADC_EN1 0x82
90#define AXP20X_ADC_EN2 0x83
91#define AXP20X_ADC_RATE 0x84
92#define AXP20X_GPIO10_IN_RANGE 0x85
93#define AXP20X_GPIO1_ADC_IRQ_RIS 0x86
94#define AXP20X_GPIO1_ADC_IRQ_FAL 0x87
95#define AXP20X_TIMER_CTRL 0x8a
96#define AXP20X_VBUS_MON 0x8b
97#define AXP20X_OVER_TMP 0x8f
98
99/* GPIO */
100#define AXP20X_GPIO0_CTRL 0x90
101#define AXP20X_LDO5_V_OUT 0x91
102#define AXP20X_GPIO1_CTRL 0x92
103#define AXP20X_GPIO2_CTRL 0x93
104#define AXP20X_GPIO20_SS 0x94
105#define AXP20X_GPIO3_CTRL 0x95
106
107/* Battery */
108#define AXP20X_CHRG_CC_31_24 0xb0
109#define AXP20X_CHRG_CC_23_16 0xb1
110#define AXP20X_CHRG_CC_15_8 0xb2
111#define AXP20X_CHRG_CC_7_0 0xb3
112#define AXP20X_DISCHRG_CC_31_24 0xb4
113#define AXP20X_DISCHRG_CC_23_16 0xb5
114#define AXP20X_DISCHRG_CC_15_8 0xb6
115#define AXP20X_DISCHRG_CC_7_0 0xb7
116#define AXP20X_CC_CTRL 0xb8
117#define AXP20X_FG_RES 0xb9
118
119/* Regulators IDs */
120enum {
121 AXP20X_LDO1 = 0,
122 AXP20X_LDO2,
123 AXP20X_LDO3,
124 AXP20X_LDO4,
125 AXP20X_LDO5,
126 AXP20X_DCDC2,
127 AXP20X_DCDC3,
128 AXP20X_REG_ID_MAX,
129};
130
131/* IRQs */
132enum {
133 AXP20X_IRQ_ACIN_OVER_V = 1,
134 AXP20X_IRQ_ACIN_PLUGIN,
135 AXP20X_IRQ_ACIN_REMOVAL,
136 AXP20X_IRQ_VBUS_OVER_V,
137 AXP20X_IRQ_VBUS_PLUGIN,
138 AXP20X_IRQ_VBUS_REMOVAL,
139 AXP20X_IRQ_VBUS_V_LOW,
140 AXP20X_IRQ_BATT_PLUGIN,
141 AXP20X_IRQ_BATT_REMOVAL,
142 AXP20X_IRQ_BATT_ENT_ACT_MODE,
143 AXP20X_IRQ_BATT_EXIT_ACT_MODE,
144 AXP20X_IRQ_CHARG,
145 AXP20X_IRQ_CHARG_DONE,
146 AXP20X_IRQ_BATT_TEMP_HIGH,
147 AXP20X_IRQ_BATT_TEMP_LOW,
148 AXP20X_IRQ_DIE_TEMP_HIGH,
149 AXP20X_IRQ_CHARG_I_LOW,
150 AXP20X_IRQ_DCDC1_V_LONG,
151 AXP20X_IRQ_DCDC2_V_LONG,
152 AXP20X_IRQ_DCDC3_V_LONG,
153 AXP20X_IRQ_PEK_SHORT = 22,
154 AXP20X_IRQ_PEK_LONG,
155 AXP20X_IRQ_N_OE_PWR_ON,
156 AXP20X_IRQ_N_OE_PWR_OFF,
157 AXP20X_IRQ_VBUS_VALID,
158 AXP20X_IRQ_VBUS_NOT_VALID,
159 AXP20X_IRQ_VBUS_SESS_VALID,
160 AXP20X_IRQ_VBUS_SESS_END,
161 AXP20X_IRQ_LOW_PWR_LVL1,
162 AXP20X_IRQ_LOW_PWR_LVL2,
163 AXP20X_IRQ_TIMER,
164 AXP20X_IRQ_PEK_RIS_EDGE,
165 AXP20X_IRQ_PEK_FAL_EDGE,
166 AXP20X_IRQ_GPIO3_INPUT,
167 AXP20X_IRQ_GPIO2_INPUT,
168 AXP20X_IRQ_GPIO1_INPUT,
169 AXP20X_IRQ_GPIO0_INPUT,
170};
171
172struct axp20x_dev {
173 struct device *dev;
174 struct i2c_client *i2c_client;
175 struct regmap *regmap;
176 struct regmap_irq_chip_data *regmap_irqc;
177 long variant;
178};
179
180#endif /* __LINUX_MFD_AXP20X_H */