1cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione/*
2cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
3cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione *
4cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
5cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
6cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * as well as 4 configurable GPIOs.
7cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione *
8cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * Author: Carlo Caione <carlo@caione.org>
9cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione *
10cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * This program is free software; you can redistribute it and/or modify
11cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * it under the terms of the GNU General Public License version 2 as
12cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * published by the Free Software Foundation.
13cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione */
14cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
15cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/err.h>
16cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/i2c.h>
17cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/interrupt.h>
18cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/kernel.h>
19cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/module.h>
20cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/pm_runtime.h>
21cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/regmap.h>
22cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/slab.h>
23cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/regulator/consumer.h>
24cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/mfd/axp20x.h>
25cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/mfd/core.h>
26cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/of_device.h>
27cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#include <linux/of_irq.h>
28cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
29cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#define AXP20X_OFF	0x80
30cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
31cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_range axp20x_writeable_ranges[] = {
32cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
33cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
34cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
35cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
36cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_range axp20x_volatile_ranges[] = {
37cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
38cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
39cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
40cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_access_table axp20x_writeable_table = {
41cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.yes_ranges	= axp20x_writeable_ranges,
42cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.n_yes_ranges	= ARRAY_SIZE(axp20x_writeable_ranges),
43cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
44cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
45cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_access_table axp20x_volatile_table = {
46cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.yes_ranges	= axp20x_volatile_ranges,
47cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
48cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
49cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
50cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic struct resource axp20x_pek_resources[] = {
51cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{
52cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.name	= "PEK_DBR",
53cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.start	= AXP20X_IRQ_PEK_RIS_EDGE,
54cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.end	= AXP20X_IRQ_PEK_RIS_EDGE,
55cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.flags	= IORESOURCE_IRQ,
56cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}, {
57cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.name	= "PEK_DBF",
58cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.start	= AXP20X_IRQ_PEK_FAL_EDGE,
59cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.end	= AXP20X_IRQ_PEK_FAL_EDGE,
60cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.flags	= IORESOURCE_IRQ,
61cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	},
62cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
63cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
64cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_config axp20x_regmap_config = {
65cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.reg_bits	= 8,
66cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.val_bits	= 8,
67cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.wr_table	= &axp20x_writeable_table,
68cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.volatile_table	= &axp20x_volatile_table,
69cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.max_register	= AXP20X_FG_RES,
70cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.cache_type	= REGCACHE_RBTREE,
71cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
72cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
73cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione#define AXP20X_IRQ(_irq, _off, _mask) \
74cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
75cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
76cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_irq axp20x_regmap_irqs[] = {
77cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
78cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
79cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
80cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
81cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
82cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
83cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
84cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
85cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
86cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
87cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
88cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(CHARG,		1, 3),
89cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(CHARG_DONE,		1, 2),
90cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
91cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
92cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
93cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
94cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
95cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
96cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
97cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(PEK_SHORT,		2, 1),
98cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(PEK_LONG,		2, 0),
99cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
100cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
101cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_VALID,		3, 5),
102cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
103cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
104cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
105cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
106cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
107cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(TIMER,		4, 7),
108cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
109cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
110cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
111cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
112cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
113cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
114cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
115cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
116cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct of_device_id axp20x_of_match[] = {
117cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
118cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
119cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{ },
120cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
121cfb61a419630a810033f2777aba724ab6b1272b3Carlo CaioneMODULE_DEVICE_TABLE(of, axp20x_of_match);
122cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
123cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione/*
124cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione * This is useless for OF-enabled devices, but it is needed by I2C subsystem
125cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione */
126cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct i2c_device_id axp20x_i2c_id[] = {
127cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{ },
128cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
129cfb61a419630a810033f2777aba724ab6b1272b3Carlo CaioneMODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
130cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
131cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic const struct regmap_irq_chip axp20x_regmap_irq_chip = {
132cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.name			= "axp20x_irq_chip",
133cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.status_base		= AXP20X_IRQ1_STATE,
134cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.ack_base		= AXP20X_IRQ1_STATE,
135cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.mask_base		= AXP20X_IRQ1_EN,
136cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.num_regs		= 5,
137cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.irqs			= axp20x_regmap_irqs,
138cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
139cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.mask_invert		= true,
140cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.init_ack_masked	= true,
141cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
142cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
143cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic struct mfd_cell axp20x_cells[] = {
144cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	{
145cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.name			= "axp20x-pek",
146cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.num_resources		= ARRAY_SIZE(axp20x_pek_resources),
147cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.resources		= axp20x_pek_resources,
148cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}, {
149cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.name			= "axp20x-regulator",
150cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	},
151cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
152cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
153cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic struct axp20x_dev *axp20x_pm_power_off;
154cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic void axp20x_power_off(void)
155cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione{
156cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
157cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		     AXP20X_OFF);
158cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione}
159cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
160cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic int axp20x_i2c_probe(struct i2c_client *i2c,
161cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione			 const struct i2c_device_id *id)
162cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione{
163cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	struct axp20x_dev *axp20x;
164cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	const struct of_device_id *of_id;
165cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	int ret;
166cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
167cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
168cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (!axp20x)
169cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		return -ENOMEM;
170cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
171cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	of_id = of_match_device(axp20x_of_match, &i2c->dev);
172cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (!of_id) {
173cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
174cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		return -ENODEV;
175cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
176cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	axp20x->variant = (long) of_id->data;
177cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
178cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	axp20x->i2c_client = i2c;
179cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	axp20x->dev = &i2c->dev;
180cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	dev_set_drvdata(axp20x->dev, axp20x);
181cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
182cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
183cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (IS_ERR(axp20x->regmap)) {
184cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		ret = PTR_ERR(axp20x->regmap);
185cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
186cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		return ret;
187cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
188cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
189cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
190cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione				  IRQF_ONESHOT | IRQF_SHARED, -1,
191cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione				  &axp20x_regmap_irq_chip,
192cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione				  &axp20x->regmap_irqc);
193cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (ret) {
194cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
195cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		return ret;
196cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
197cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
198cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
199cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
200cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
201cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (ret) {
202cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
203cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
204cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		return ret;
205cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
206cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
207cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (!pm_power_off) {
208cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		axp20x_pm_power_off = axp20x;
209cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		pm_power_off = axp20x_power_off;
210cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
211cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
212cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	dev_info(&i2c->dev, "AXP20X driver loaded\n");
213cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
214cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	return 0;
215cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione}
216cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
217cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic int axp20x_i2c_remove(struct i2c_client *i2c)
218cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione{
219cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
220cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
221cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	if (axp20x == axp20x_pm_power_off) {
222cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		axp20x_pm_power_off = NULL;
223cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		pm_power_off = NULL;
224cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	}
225cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
226cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	mfd_remove_devices(axp20x->dev);
227cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
228cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
229cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	return 0;
230cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione}
231cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
232cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionestatic struct i2c_driver axp20x_i2c_driver = {
233cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.driver = {
234cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.name	= "axp20x",
235cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.owner	= THIS_MODULE,
236cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione		.of_match_table	= of_match_ptr(axp20x_of_match),
237cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	},
238cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.probe		= axp20x_i2c_probe,
239cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.remove		= axp20x_i2c_remove,
240cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione	.id_table	= axp20x_i2c_id,
241cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione};
242cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
243cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caionemodule_i2c_driver(axp20x_i2c_driver);
244cfb61a419630a810033f2777aba724ab6b1272b3Carlo Caione
245cfb61a419630a810033f2777aba724ab6b1272b3Carlo CaioneMODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
246cfb61a419630a810033f2777aba724ab6b1272b3Carlo CaioneMODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
247cfb61a419630a810033f2777aba724ab6b1272b3Carlo CaioneMODULE_LICENSE("GPL");
248