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