2014-05-01 16:29:27 +04:00
/*
2016-02-12 05:02:42 +03:00
* MFD core driver for the X - Powers ' Power Management ICs
2014-05-01 16:29:27 +04:00
*
2014-10-07 08:17:14 +04:00
* AXP20x typically comprises an adaptive USB - Compatible PWM charger , BUCK DC - DC
* converters , LDOs , multiple 12 - bit ADCs of voltage , current and temperature
* as well as configurable GPIOs .
2014-05-01 16:29:27 +04:00
*
2016-02-12 05:02:42 +03:00
* This file contains the interface independent core functions .
*
2016-02-12 05:02:41 +03:00
* Copyright ( C ) 2014 Carlo Caione
*
2014-05-01 16:29:27 +04:00
* Author : Carlo Caione < carlo @ caione . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/err.h>
2016-06-05 16:50:48 +03:00
# include <linux/delay.h>
2014-05-01 16:29:27 +04:00
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pm_runtime.h>
# include <linux/regmap.h>
# include <linux/regulator/consumer.h>
# include <linux/mfd/axp20x.h>
# include <linux/mfd/core.h>
# include <linux/of_device.h>
2014-10-07 08:17:14 +04:00
# include <linux/acpi.h>
2014-05-01 16:29:27 +04:00
# define AXP20X_OFF 0x80
2015-03-24 13:21:17 +03:00
static const char * const axp20x_model_names [ ] = {
2015-07-11 15:59:56 +03:00
" AXP152 " ,
2014-10-07 08:17:14 +04:00
" AXP202 " ,
" AXP209 " ,
2015-04-10 07:09:01 +03:00
" AXP221 " ,
2016-02-12 05:02:44 +03:00
" AXP223 " ,
2014-10-07 08:17:14 +04:00
" AXP288 " ,
2016-03-29 12:22:26 +03:00
" AXP809 " ,
2014-10-07 08:17:14 +04:00
} ;
2015-07-11 15:59:56 +03:00
static const struct regmap_range axp152_writeable_ranges [ ] = {
regmap_reg_range ( AXP152_LDO3456_DC1234_CTRL , AXP152_IRQ3_STATE ) ,
regmap_reg_range ( AXP152_DCDC_MODE , AXP152_PWM1_DUTY_CYCLE ) ,
} ;
static const struct regmap_range axp152_volatile_ranges [ ] = {
regmap_reg_range ( AXP152_PWR_OP_MODE , AXP152_PWR_OP_MODE ) ,
regmap_reg_range ( AXP152_IRQ1_EN , AXP152_IRQ3_STATE ) ,
regmap_reg_range ( AXP152_GPIO_INPUT , AXP152_GPIO_INPUT ) ,
} ;
static const struct regmap_access_table axp152_writeable_table = {
. yes_ranges = axp152_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp152_writeable_ranges ) ,
} ;
static const struct regmap_access_table axp152_volatile_table = {
. yes_ranges = axp152_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp152_volatile_ranges ) ,
} ;
2014-05-01 16:29:27 +04:00
static const struct regmap_range axp20x_writeable_ranges [ ] = {
regmap_reg_range ( AXP20X_DATACACHE ( 0 ) , AXP20X_IRQ5_STATE ) ,
regmap_reg_range ( AXP20X_DCDC_MODE , AXP20X_FG_RES ) ,
2015-08-08 18:58:40 +03:00
regmap_reg_range ( AXP20X_RDC_H , AXP20X_OCV ( AXP20X_OCV_MAX ) ) ,
2014-05-01 16:29:27 +04:00
} ;
static const struct regmap_range axp20x_volatile_ranges [ ] = {
2015-08-08 18:58:40 +03:00
regmap_reg_range ( AXP20X_PWR_INPUT_STATUS , AXP20X_USB_OTG_STATUS ) ,
regmap_reg_range ( AXP20X_CHRG_CTRL1 , AXP20X_CHRG_CTRL2 ) ,
2014-05-01 16:29:27 +04:00
regmap_reg_range ( AXP20X_IRQ1_EN , AXP20X_IRQ5_STATE ) ,
2015-08-08 18:58:40 +03:00
regmap_reg_range ( AXP20X_ACIN_V_ADC_H , AXP20X_IPSOUT_V_HIGH_L ) ,
regmap_reg_range ( AXP20X_GPIO20_SS , AXP20X_GPIO3_CTRL ) ,
regmap_reg_range ( AXP20X_FG_RES , AXP20X_RDC_L ) ,
2014-05-01 16:29:27 +04:00
} ;
static const struct regmap_access_table axp20x_writeable_table = {
. yes_ranges = axp20x_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp20x_writeable_ranges ) ,
} ;
static const struct regmap_access_table axp20x_volatile_table = {
. yes_ranges = axp20x_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp20x_volatile_ranges ) ,
} ;
2016-03-29 12:22:26 +03:00
/* AXP22x ranges are shared with the AXP809, as they cover the same range */
2015-04-10 07:09:01 +03:00
static const struct regmap_range axp22x_writeable_ranges [ ] = {
regmap_reg_range ( AXP20X_DATACACHE ( 0 ) , AXP20X_IRQ5_STATE ) ,
regmap_reg_range ( AXP20X_DCDC_MODE , AXP22X_BATLOW_THRES1 ) ,
} ;
static const struct regmap_range axp22x_volatile_ranges [ ] = {
2016-05-14 20:51:28 +03:00
regmap_reg_range ( AXP20X_PWR_INPUT_STATUS , AXP20X_PWR_OP_MODE ) ,
2015-04-10 07:09:01 +03:00
regmap_reg_range ( AXP20X_IRQ1_EN , AXP20X_IRQ5_STATE ) ,
2016-05-14 20:51:28 +03:00
regmap_reg_range ( AXP22X_GPIO_STATE , AXP22X_GPIO_STATE ) ,
regmap_reg_range ( AXP20X_FG_RES , AXP20X_FG_RES ) ,
2015-04-10 07:09:01 +03:00
} ;
static const struct regmap_access_table axp22x_writeable_table = {
. yes_ranges = axp22x_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp22x_writeable_ranges ) ,
} ;
static const struct regmap_access_table axp22x_volatile_table = {
. yes_ranges = axp22x_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp22x_volatile_ranges ) ,
} ;
2014-10-07 08:17:14 +04:00
static const struct regmap_range axp288_writeable_ranges [ ] = {
regmap_reg_range ( AXP20X_DATACACHE ( 0 ) , AXP20X_IRQ6_STATE ) ,
regmap_reg_range ( AXP20X_DCDC_MODE , AXP288_FG_TUNE5 ) ,
} ;
static const struct regmap_range axp288_volatile_ranges [ ] = {
regmap_reg_range ( AXP20X_IRQ1_EN , AXP20X_IPSOUT_V_HIGH_L ) ,
} ;
static const struct regmap_access_table axp288_writeable_table = {
. yes_ranges = axp288_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp288_writeable_ranges ) ,
} ;
static const struct regmap_access_table axp288_volatile_table = {
. yes_ranges = axp288_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( axp288_volatile_ranges ) ,
} ;
2015-07-11 15:59:56 +03:00
static struct resource axp152_pek_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( AXP152_IRQ_PEK_RIS_EDGE , " PEK_DBR " ) ,
DEFINE_RES_IRQ_NAMED ( AXP152_IRQ_PEK_FAL_EDGE , " PEK_DBF " ) ,
} ;
2016-05-06 08:19:49 +03:00
static struct resource axp20x_ac_power_supply_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_ACIN_PLUGIN , " ACIN_PLUGIN " ) ,
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_ACIN_REMOVAL , " ACIN_REMOVAL " ) ,
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_ACIN_OVER_V , " ACIN_OVER_V " ) ,
} ;
2014-05-01 16:29:27 +04:00
static struct resource axp20x_pek_resources [ ] = {
{
. name = " PEK_DBR " ,
. start = AXP20X_IRQ_PEK_RIS_EDGE ,
. end = AXP20X_IRQ_PEK_RIS_EDGE ,
. flags = IORESOURCE_IRQ ,
} , {
. name = " PEK_DBF " ,
. start = AXP20X_IRQ_PEK_FAL_EDGE ,
. end = AXP20X_IRQ_PEK_FAL_EDGE ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2015-08-08 18:58:41 +03:00
static struct resource axp20x_usb_power_supply_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_VBUS_PLUGIN , " VBUS_PLUGIN " ) ,
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_VBUS_REMOVAL , " VBUS_REMOVAL " ) ,
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_VBUS_VALID , " VBUS_VALID " ) ,
DEFINE_RES_IRQ_NAMED ( AXP20X_IRQ_VBUS_NOT_VALID , " VBUS_NOT_VALID " ) ,
} ;
2016-06-02 20:18:55 +03:00
static struct resource axp22x_usb_power_supply_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( AXP22X_IRQ_VBUS_PLUGIN , " VBUS_PLUGIN " ) ,
DEFINE_RES_IRQ_NAMED ( AXP22X_IRQ_VBUS_REMOVAL , " VBUS_REMOVAL " ) ,
} ;
2015-04-10 07:09:01 +03:00
static struct resource axp22x_pek_resources [ ] = {
{
. name = " PEK_DBR " ,
. start = AXP22X_IRQ_PEK_RIS_EDGE ,
. end = AXP22X_IRQ_PEK_RIS_EDGE ,
. flags = IORESOURCE_IRQ ,
} , {
. name = " PEK_DBF " ,
. start = AXP22X_IRQ_PEK_FAL_EDGE ,
. end = AXP22X_IRQ_PEK_FAL_EDGE ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2015-10-14 11:16:26 +03:00
static struct resource axp288_power_button_resources [ ] = {
{
. name = " PEK_DBR " ,
. start = AXP288_IRQ_POKN ,
. end = AXP288_IRQ_POKN ,
. flags = IORESOURCE_IRQ ,
} ,
{
. name = " PEK_DBF " ,
. start = AXP288_IRQ_POKP ,
. end = AXP288_IRQ_POKP ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2015-02-03 02:41:41 +03:00
static struct resource axp288_fuel_gauge_resources [ ] = {
2014-10-07 08:17:14 +04:00
{
. start = AXP288_IRQ_QWBTU ,
. end = AXP288_IRQ_QWBTU ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_WBTU ,
. end = AXP288_IRQ_WBTU ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_QWBTO ,
. end = AXP288_IRQ_QWBTO ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_WBTO ,
. end = AXP288_IRQ_WBTO ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_WL2 ,
. end = AXP288_IRQ_WL2 ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_WL1 ,
. end = AXP288_IRQ_WL1 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2016-03-29 12:22:26 +03:00
static struct resource axp809_pek_resources [ ] = {
{
. name = " PEK_DBR " ,
. start = AXP809_IRQ_PEK_RIS_EDGE ,
. end = AXP809_IRQ_PEK_RIS_EDGE ,
. flags = IORESOURCE_IRQ ,
} , {
. name = " PEK_DBF " ,
. start = AXP809_IRQ_PEK_FAL_EDGE ,
. end = AXP809_IRQ_PEK_FAL_EDGE ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2015-07-11 15:59:56 +03:00
static const struct regmap_config axp152_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. wr_table = & axp152_writeable_table ,
. volatile_table = & axp152_volatile_table ,
. max_register = AXP152_PWM1_DUTY_CYCLE ,
. cache_type = REGCACHE_RBTREE ,
} ;
2014-05-01 16:29:27 +04:00
static const struct regmap_config axp20x_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. wr_table = & axp20x_writeable_table ,
. volatile_table = & axp20x_volatile_table ,
2015-08-08 18:58:40 +03:00
. max_register = AXP20X_OCV ( AXP20X_OCV_MAX ) ,
2014-05-01 16:29:27 +04:00
. cache_type = REGCACHE_RBTREE ,
} ;
2015-04-10 07:09:01 +03:00
static const struct regmap_config axp22x_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. wr_table = & axp22x_writeable_table ,
. volatile_table = & axp22x_volatile_table ,
. max_register = AXP22X_BATLOW_THRES1 ,
. cache_type = REGCACHE_RBTREE ,
} ;
2014-10-07 08:17:14 +04:00
static const struct regmap_config axp288_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. wr_table = & axp288_writeable_table ,
. volatile_table = & axp288_volatile_table ,
. max_register = AXP288_FG_TUNE5 ,
. cache_type = REGCACHE_RBTREE ,
} ;
# define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
[ _variant # # _IRQ_ # # _irq ] = { . reg_offset = ( _off ) , . mask = BIT ( _mask ) }
2014-05-01 16:29:27 +04:00
2015-07-11 15:59:56 +03:00
static const struct regmap_irq axp152_regmap_irqs [ ] = {
INIT_REGMAP_IRQ ( AXP152 , LDO0IN_CONNECT , 0 , 6 ) ,
INIT_REGMAP_IRQ ( AXP152 , LDO0IN_REMOVAL , 0 , 5 ) ,
INIT_REGMAP_IRQ ( AXP152 , ALDO0IN_CONNECT , 0 , 3 ) ,
INIT_REGMAP_IRQ ( AXP152 , ALDO0IN_REMOVAL , 0 , 2 ) ,
INIT_REGMAP_IRQ ( AXP152 , DCDC1_V_LOW , 1 , 5 ) ,
INIT_REGMAP_IRQ ( AXP152 , DCDC2_V_LOW , 1 , 4 ) ,
INIT_REGMAP_IRQ ( AXP152 , DCDC3_V_LOW , 1 , 3 ) ,
INIT_REGMAP_IRQ ( AXP152 , DCDC4_V_LOW , 1 , 2 ) ,
INIT_REGMAP_IRQ ( AXP152 , PEK_SHORT , 1 , 1 ) ,
INIT_REGMAP_IRQ ( AXP152 , PEK_LONG , 1 , 0 ) ,
INIT_REGMAP_IRQ ( AXP152 , TIMER , 2 , 7 ) ,
INIT_REGMAP_IRQ ( AXP152 , PEK_RIS_EDGE , 2 , 6 ) ,
INIT_REGMAP_IRQ ( AXP152 , PEK_FAL_EDGE , 2 , 5 ) ,
INIT_REGMAP_IRQ ( AXP152 , GPIO3_INPUT , 2 , 3 ) ,
INIT_REGMAP_IRQ ( AXP152 , GPIO2_INPUT , 2 , 2 ) ,
INIT_REGMAP_IRQ ( AXP152 , GPIO1_INPUT , 2 , 1 ) ,
INIT_REGMAP_IRQ ( AXP152 , GPIO0_INPUT , 2 , 0 ) ,
} ;
2014-05-01 16:29:27 +04:00
static const struct regmap_irq axp20x_regmap_irqs [ ] = {
2014-10-07 08:17:14 +04:00
INIT_REGMAP_IRQ ( AXP20X , ACIN_OVER_V , 0 , 7 ) ,
INIT_REGMAP_IRQ ( AXP20X , ACIN_PLUGIN , 0 , 6 ) ,
INIT_REGMAP_IRQ ( AXP20X , ACIN_REMOVAL , 0 , 5 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_OVER_V , 0 , 4 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_PLUGIN , 0 , 3 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_REMOVAL , 0 , 2 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_V_LOW , 0 , 1 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_PLUGIN , 1 , 7 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_REMOVAL , 1 , 6 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_ENT_ACT_MODE , 1 , 5 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_EXIT_ACT_MODE , 1 , 4 ) ,
INIT_REGMAP_IRQ ( AXP20X , CHARG , 1 , 3 ) ,
INIT_REGMAP_IRQ ( AXP20X , CHARG_DONE , 1 , 2 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_TEMP_HIGH , 1 , 1 ) ,
INIT_REGMAP_IRQ ( AXP20X , BATT_TEMP_LOW , 1 , 0 ) ,
INIT_REGMAP_IRQ ( AXP20X , DIE_TEMP_HIGH , 2 , 7 ) ,
INIT_REGMAP_IRQ ( AXP20X , CHARG_I_LOW , 2 , 6 ) ,
INIT_REGMAP_IRQ ( AXP20X , DCDC1_V_LONG , 2 , 5 ) ,
INIT_REGMAP_IRQ ( AXP20X , DCDC2_V_LONG , 2 , 4 ) ,
INIT_REGMAP_IRQ ( AXP20X , DCDC3_V_LONG , 2 , 3 ) ,
INIT_REGMAP_IRQ ( AXP20X , PEK_SHORT , 2 , 1 ) ,
INIT_REGMAP_IRQ ( AXP20X , PEK_LONG , 2 , 0 ) ,
INIT_REGMAP_IRQ ( AXP20X , N_OE_PWR_ON , 3 , 7 ) ,
INIT_REGMAP_IRQ ( AXP20X , N_OE_PWR_OFF , 3 , 6 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_VALID , 3 , 5 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_NOT_VALID , 3 , 4 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_SESS_VALID , 3 , 3 ) ,
INIT_REGMAP_IRQ ( AXP20X , VBUS_SESS_END , 3 , 2 ) ,
INIT_REGMAP_IRQ ( AXP20X , LOW_PWR_LVL1 , 3 , 1 ) ,
INIT_REGMAP_IRQ ( AXP20X , LOW_PWR_LVL2 , 3 , 0 ) ,
INIT_REGMAP_IRQ ( AXP20X , TIMER , 4 , 7 ) ,
INIT_REGMAP_IRQ ( AXP20X , PEK_RIS_EDGE , 4 , 6 ) ,
INIT_REGMAP_IRQ ( AXP20X , PEK_FAL_EDGE , 4 , 5 ) ,
INIT_REGMAP_IRQ ( AXP20X , GPIO3_INPUT , 4 , 3 ) ,
INIT_REGMAP_IRQ ( AXP20X , GPIO2_INPUT , 4 , 2 ) ,
INIT_REGMAP_IRQ ( AXP20X , GPIO1_INPUT , 4 , 1 ) ,
INIT_REGMAP_IRQ ( AXP20X , GPIO0_INPUT , 4 , 0 ) ,
} ;
2015-04-10 07:09:01 +03:00
static const struct regmap_irq axp22x_regmap_irqs [ ] = {
INIT_REGMAP_IRQ ( AXP22X , ACIN_OVER_V , 0 , 7 ) ,
INIT_REGMAP_IRQ ( AXP22X , ACIN_PLUGIN , 0 , 6 ) ,
INIT_REGMAP_IRQ ( AXP22X , ACIN_REMOVAL , 0 , 5 ) ,
INIT_REGMAP_IRQ ( AXP22X , VBUS_OVER_V , 0 , 4 ) ,
INIT_REGMAP_IRQ ( AXP22X , VBUS_PLUGIN , 0 , 3 ) ,
INIT_REGMAP_IRQ ( AXP22X , VBUS_REMOVAL , 0 , 2 ) ,
INIT_REGMAP_IRQ ( AXP22X , VBUS_V_LOW , 0 , 1 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_PLUGIN , 1 , 7 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_REMOVAL , 1 , 6 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_ENT_ACT_MODE , 1 , 5 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_EXIT_ACT_MODE , 1 , 4 ) ,
INIT_REGMAP_IRQ ( AXP22X , CHARG , 1 , 3 ) ,
INIT_REGMAP_IRQ ( AXP22X , CHARG_DONE , 1 , 2 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_TEMP_HIGH , 1 , 1 ) ,
INIT_REGMAP_IRQ ( AXP22X , BATT_TEMP_LOW , 1 , 0 ) ,
INIT_REGMAP_IRQ ( AXP22X , DIE_TEMP_HIGH , 2 , 7 ) ,
INIT_REGMAP_IRQ ( AXP22X , PEK_SHORT , 2 , 1 ) ,
INIT_REGMAP_IRQ ( AXP22X , PEK_LONG , 2 , 0 ) ,
INIT_REGMAP_IRQ ( AXP22X , LOW_PWR_LVL1 , 3 , 1 ) ,
INIT_REGMAP_IRQ ( AXP22X , LOW_PWR_LVL2 , 3 , 0 ) ,
INIT_REGMAP_IRQ ( AXP22X , TIMER , 4 , 7 ) ,
INIT_REGMAP_IRQ ( AXP22X , PEK_RIS_EDGE , 4 , 6 ) ,
INIT_REGMAP_IRQ ( AXP22X , PEK_FAL_EDGE , 4 , 5 ) ,
INIT_REGMAP_IRQ ( AXP22X , GPIO1_INPUT , 4 , 1 ) ,
INIT_REGMAP_IRQ ( AXP22X , GPIO0_INPUT , 4 , 0 ) ,
} ;
2014-10-07 08:17:14 +04:00
/* some IRQs are compatible with axp20x models */
static const struct regmap_irq axp288_regmap_irqs [ ] = {
2014-11-11 22:30:09 +03:00
INIT_REGMAP_IRQ ( AXP288 , VBUS_FALL , 0 , 2 ) ,
INIT_REGMAP_IRQ ( AXP288 , VBUS_RISE , 0 , 3 ) ,
INIT_REGMAP_IRQ ( AXP288 , OV , 0 , 4 ) ,
2014-10-07 08:17:14 +04:00
2014-11-11 22:30:09 +03:00
INIT_REGMAP_IRQ ( AXP288 , DONE , 1 , 2 ) ,
INIT_REGMAP_IRQ ( AXP288 , CHARGING , 1 , 3 ) ,
2014-10-07 08:17:14 +04:00
INIT_REGMAP_IRQ ( AXP288 , SAFE_QUIT , 1 , 4 ) ,
INIT_REGMAP_IRQ ( AXP288 , SAFE_ENTER , 1 , 5 ) ,
2014-11-11 22:30:09 +03:00
INIT_REGMAP_IRQ ( AXP288 , ABSENT , 1 , 6 ) ,
INIT_REGMAP_IRQ ( AXP288 , APPEND , 1 , 7 ) ,
2014-10-07 08:17:14 +04:00
INIT_REGMAP_IRQ ( AXP288 , QWBTU , 2 , 0 ) ,
INIT_REGMAP_IRQ ( AXP288 , WBTU , 2 , 1 ) ,
INIT_REGMAP_IRQ ( AXP288 , QWBTO , 2 , 2 ) ,
2014-11-11 22:30:09 +03:00
INIT_REGMAP_IRQ ( AXP288 , WBTO , 2 , 3 ) ,
2014-10-07 08:17:14 +04:00
INIT_REGMAP_IRQ ( AXP288 , QCBTU , 2 , 4 ) ,
INIT_REGMAP_IRQ ( AXP288 , CBTU , 2 , 5 ) ,
INIT_REGMAP_IRQ ( AXP288 , QCBTO , 2 , 6 ) ,
INIT_REGMAP_IRQ ( AXP288 , CBTO , 2 , 7 ) ,
INIT_REGMAP_IRQ ( AXP288 , WL2 , 3 , 0 ) ,
INIT_REGMAP_IRQ ( AXP288 , WL1 , 3 , 1 ) ,
INIT_REGMAP_IRQ ( AXP288 , GPADC , 3 , 2 ) ,
INIT_REGMAP_IRQ ( AXP288 , OT , 3 , 7 ) ,
INIT_REGMAP_IRQ ( AXP288 , GPIO0 , 4 , 0 ) ,
INIT_REGMAP_IRQ ( AXP288 , GPIO1 , 4 , 1 ) ,
INIT_REGMAP_IRQ ( AXP288 , POKO , 4 , 2 ) ,
INIT_REGMAP_IRQ ( AXP288 , POKL , 4 , 3 ) ,
INIT_REGMAP_IRQ ( AXP288 , POKS , 4 , 4 ) ,
INIT_REGMAP_IRQ ( AXP288 , POKN , 4 , 5 ) ,
INIT_REGMAP_IRQ ( AXP288 , POKP , 4 , 6 ) ,
2014-11-11 22:30:09 +03:00
INIT_REGMAP_IRQ ( AXP288 , TIMER , 4 , 7 ) ,
2014-10-07 08:17:14 +04:00
INIT_REGMAP_IRQ ( AXP288 , MV_CHNG , 5 , 0 ) ,
INIT_REGMAP_IRQ ( AXP288 , BC_USB_CHNG , 5 , 1 ) ,
2014-05-01 16:29:27 +04:00
} ;
2016-03-29 12:22:26 +03:00
static const struct regmap_irq axp809_regmap_irqs [ ] = {
INIT_REGMAP_IRQ ( AXP809 , ACIN_OVER_V , 0 , 7 ) ,
INIT_REGMAP_IRQ ( AXP809 , ACIN_PLUGIN , 0 , 6 ) ,
INIT_REGMAP_IRQ ( AXP809 , ACIN_REMOVAL , 0 , 5 ) ,
INIT_REGMAP_IRQ ( AXP809 , VBUS_OVER_V , 0 , 4 ) ,
INIT_REGMAP_IRQ ( AXP809 , VBUS_PLUGIN , 0 , 3 ) ,
INIT_REGMAP_IRQ ( AXP809 , VBUS_REMOVAL , 0 , 2 ) ,
INIT_REGMAP_IRQ ( AXP809 , VBUS_V_LOW , 0 , 1 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_PLUGIN , 1 , 7 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_REMOVAL , 1 , 6 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_ENT_ACT_MODE , 1 , 5 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_EXIT_ACT_MODE , 1 , 4 ) ,
INIT_REGMAP_IRQ ( AXP809 , CHARG , 1 , 3 ) ,
INIT_REGMAP_IRQ ( AXP809 , CHARG_DONE , 1 , 2 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_CHG_TEMP_HIGH , 2 , 7 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_CHG_TEMP_HIGH_END , 2 , 6 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_CHG_TEMP_LOW , 2 , 5 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_CHG_TEMP_LOW_END , 2 , 4 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_ACT_TEMP_HIGH , 2 , 3 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_ACT_TEMP_HIGH_END , 2 , 2 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_ACT_TEMP_LOW , 2 , 1 ) ,
INIT_REGMAP_IRQ ( AXP809 , BATT_ACT_TEMP_LOW_END , 2 , 0 ) ,
INIT_REGMAP_IRQ ( AXP809 , DIE_TEMP_HIGH , 3 , 7 ) ,
INIT_REGMAP_IRQ ( AXP809 , LOW_PWR_LVL1 , 3 , 1 ) ,
INIT_REGMAP_IRQ ( AXP809 , LOW_PWR_LVL2 , 3 , 0 ) ,
INIT_REGMAP_IRQ ( AXP809 , TIMER , 4 , 7 ) ,
INIT_REGMAP_IRQ ( AXP809 , PEK_RIS_EDGE , 4 , 6 ) ,
INIT_REGMAP_IRQ ( AXP809 , PEK_FAL_EDGE , 4 , 5 ) ,
INIT_REGMAP_IRQ ( AXP809 , PEK_SHORT , 4 , 4 ) ,
INIT_REGMAP_IRQ ( AXP809 , PEK_LONG , 4 , 3 ) ,
INIT_REGMAP_IRQ ( AXP809 , PEK_OVER_OFF , 4 , 2 ) ,
INIT_REGMAP_IRQ ( AXP809 , GPIO1_INPUT , 4 , 1 ) ,
INIT_REGMAP_IRQ ( AXP809 , GPIO0_INPUT , 4 , 0 ) ,
} ;
2015-07-11 15:59:56 +03:00
static const struct regmap_irq_chip axp152_regmap_irq_chip = {
. name = " axp152_irq_chip " ,
. status_base = AXP152_IRQ1_STATE ,
. ack_base = AXP152_IRQ1_STATE ,
. mask_base = AXP152_IRQ1_EN ,
. mask_invert = true ,
. init_ack_masked = true ,
. irqs = axp152_regmap_irqs ,
. num_irqs = ARRAY_SIZE ( axp152_regmap_irqs ) ,
. num_regs = 3 ,
} ;
2014-05-01 16:29:27 +04:00
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
. name = " axp20x_irq_chip " ,
. status_base = AXP20X_IRQ1_STATE ,
. ack_base = AXP20X_IRQ1_STATE ,
. mask_base = AXP20X_IRQ1_EN ,
2014-10-07 08:17:14 +04:00
. mask_invert = true ,
. init_ack_masked = true ,
2014-05-01 16:29:27 +04:00
. irqs = axp20x_regmap_irqs ,
. num_irqs = ARRAY_SIZE ( axp20x_regmap_irqs ) ,
2014-10-07 08:17:14 +04:00
. num_regs = 5 ,
} ;
2015-04-10 07:09:01 +03:00
static const struct regmap_irq_chip axp22x_regmap_irq_chip = {
. name = " axp22x_irq_chip " ,
. status_base = AXP20X_IRQ1_STATE ,
. ack_base = AXP20X_IRQ1_STATE ,
. mask_base = AXP20X_IRQ1_EN ,
. mask_invert = true ,
. init_ack_masked = true ,
. irqs = axp22x_regmap_irqs ,
. num_irqs = ARRAY_SIZE ( axp22x_regmap_irqs ) ,
. num_regs = 5 ,
} ;
2014-10-07 08:17:14 +04:00
static const struct regmap_irq_chip axp288_regmap_irq_chip = {
. name = " axp288_irq_chip " ,
. status_base = AXP20X_IRQ1_STATE ,
. ack_base = AXP20X_IRQ1_STATE ,
. mask_base = AXP20X_IRQ1_EN ,
2014-05-01 16:29:27 +04:00
. mask_invert = true ,
. init_ack_masked = true ,
2014-10-07 08:17:14 +04:00
. irqs = axp288_regmap_irqs ,
. num_irqs = ARRAY_SIZE ( axp288_regmap_irqs ) ,
. num_regs = 6 ,
2014-05-01 16:29:27 +04:00
} ;
2016-03-29 12:22:26 +03:00
static const struct regmap_irq_chip axp809_regmap_irq_chip = {
. name = " axp809 " ,
. status_base = AXP20X_IRQ1_STATE ,
. ack_base = AXP20X_IRQ1_STATE ,
. mask_base = AXP20X_IRQ1_EN ,
. mask_invert = true ,
. init_ack_masked = true ,
. irqs = axp809_regmap_irqs ,
. num_irqs = ARRAY_SIZE ( axp809_regmap_irqs ) ,
. num_regs = 5 ,
} ;
2014-05-01 16:29:27 +04:00
static struct mfd_cell axp20x_cells [ ] = {
{
2015-08-08 18:58:41 +03:00
. name = " axp20x-pek " ,
. num_resources = ARRAY_SIZE ( axp20x_pek_resources ) ,
. resources = axp20x_pek_resources ,
2014-05-01 16:29:27 +04:00
} , {
2015-08-08 18:58:41 +03:00
. name = " axp20x-regulator " ,
2016-05-06 08:19:49 +03:00
} , {
. name = " axp20x-ac-power-supply " ,
. of_compatible = " x-powers,axp202-ac-power-supply " ,
. num_resources = ARRAY_SIZE ( axp20x_ac_power_supply_resources ) ,
. resources = axp20x_ac_power_supply_resources ,
2015-08-08 18:58:41 +03:00
} , {
. name = " axp20x-usb-power-supply " ,
. of_compatible = " x-powers,axp202-usb-power-supply " ,
. num_resources = ARRAY_SIZE ( axp20x_usb_power_supply_resources ) ,
. resources = axp20x_usb_power_supply_resources ,
2014-05-01 16:29:27 +04:00
} ,
} ;
2015-04-10 07:09:01 +03:00
static struct mfd_cell axp22x_cells [ ] = {
{
. name = " axp20x-pek " ,
. num_resources = ARRAY_SIZE ( axp22x_pek_resources ) ,
. resources = axp22x_pek_resources ,
2015-04-10 07:09:06 +03:00
} , {
. name = " axp20x-regulator " ,
2016-06-02 20:18:55 +03:00
} , {
. name = " axp20x-usb-power-supply " ,
. of_compatible = " x-powers,axp221-usb-power-supply " ,
. num_resources = ARRAY_SIZE ( axp22x_usb_power_supply_resources ) ,
. resources = axp22x_usb_power_supply_resources ,
2015-04-10 07:09:01 +03:00
} ,
} ;
2015-07-11 15:59:56 +03:00
static struct mfd_cell axp152_cells [ ] = {
{
. name = " axp20x-pek " ,
. num_resources = ARRAY_SIZE ( axp152_pek_resources ) ,
. resources = axp152_pek_resources ,
} ,
} ;
2014-10-07 08:17:14 +04:00
static struct resource axp288_adc_resources [ ] = {
{
. name = " GPADC " ,
. start = AXP288_IRQ_GPADC ,
. end = AXP288_IRQ_GPADC ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2015-04-02 22:19:47 +03:00
static struct resource axp288_extcon_resources [ ] = {
{
. start = AXP288_IRQ_VBUS_FALL ,
. end = AXP288_IRQ_VBUS_FALL ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_VBUS_RISE ,
. end = AXP288_IRQ_VBUS_RISE ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_MV_CHNG ,
. end = AXP288_IRQ_MV_CHNG ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_BC_USB_CHNG ,
. end = AXP288_IRQ_BC_USB_CHNG ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2014-10-07 08:17:14 +04:00
static struct resource axp288_charger_resources [ ] = {
{
. start = AXP288_IRQ_OV ,
. end = AXP288_IRQ_OV ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_DONE ,
. end = AXP288_IRQ_DONE ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_CHARGING ,
. end = AXP288_IRQ_CHARGING ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_SAFE_QUIT ,
. end = AXP288_IRQ_SAFE_QUIT ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_SAFE_ENTER ,
. end = AXP288_IRQ_SAFE_ENTER ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_QCBTU ,
. end = AXP288_IRQ_QCBTU ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_CBTU ,
. end = AXP288_IRQ_CBTU ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_QCBTO ,
. end = AXP288_IRQ_QCBTO ,
. flags = IORESOURCE_IRQ ,
} ,
{
. start = AXP288_IRQ_CBTO ,
. end = AXP288_IRQ_CBTO ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct mfd_cell axp288_cells [ ] = {
{
. name = " axp288_adc " ,
. num_resources = ARRAY_SIZE ( axp288_adc_resources ) ,
. resources = axp288_adc_resources ,
} ,
2015-04-02 22:19:47 +03:00
{
. name = " axp288_extcon " ,
. num_resources = ARRAY_SIZE ( axp288_extcon_resources ) ,
. resources = axp288_extcon_resources ,
} ,
2014-10-07 08:17:14 +04:00
{
. name = " axp288_charger " ,
. num_resources = ARRAY_SIZE ( axp288_charger_resources ) ,
. resources = axp288_charger_resources ,
} ,
{
2015-02-03 02:41:41 +03:00
. name = " axp288_fuel_gauge " ,
. num_resources = ARRAY_SIZE ( axp288_fuel_gauge_resources ) ,
. resources = axp288_fuel_gauge_resources ,
2014-10-07 08:17:14 +04:00
} ,
2015-10-14 11:16:26 +03:00
{
. name = " axp20x-pek " ,
. num_resources = ARRAY_SIZE ( axp288_power_button_resources ) ,
. resources = axp288_power_button_resources ,
} ,
2014-11-24 12:24:47 +03:00
{
. name = " axp288_pmic_acpi " ,
} ,
2014-10-07 08:17:14 +04:00
} ;
2016-03-29 12:22:26 +03:00
static struct mfd_cell axp809_cells [ ] = {
{
. name = " axp20x-pek " ,
. num_resources = ARRAY_SIZE ( axp809_pek_resources ) ,
. resources = axp809_pek_resources ,
} , {
. name = " axp20x-regulator " ,
} ,
} ;
2014-05-01 16:29:27 +04:00
static struct axp20x_dev * axp20x_pm_power_off ;
static void axp20x_power_off ( void )
{
2014-10-07 08:17:14 +04:00
if ( axp20x_pm_power_off - > variant = = AXP288_ID )
return ;
2014-05-01 16:29:27 +04:00
regmap_write ( axp20x_pm_power_off - > regmap , AXP20X_OFF_CTRL ,
AXP20X_OFF ) ;
2016-06-05 16:50:48 +03:00
/* Give capacitors etc. time to drain to avoid kernel panic msg. */
msleep ( 500 ) ;
2014-05-01 16:29:27 +04:00
}
2016-02-12 05:02:42 +03:00
int axp20x_match_device ( struct axp20x_dev * axp20x )
2014-10-07 08:17:14 +04:00
{
2016-02-12 05:02:39 +03:00
struct device * dev = axp20x - > dev ;
2014-10-07 08:17:14 +04:00
const struct acpi_device_id * acpi_id ;
const struct of_device_id * of_id ;
if ( dev - > of_node ) {
2016-02-12 05:02:40 +03:00
of_id = of_match_device ( dev - > driver - > of_match_table , dev ) ;
2014-10-07 08:17:14 +04:00
if ( ! of_id ) {
dev_err ( dev , " Unable to match OF ID \n " ) ;
return - ENODEV ;
}
2016-02-12 05:02:43 +03:00
axp20x - > variant = ( long ) of_id - > data ;
2014-10-07 08:17:14 +04:00
} else {
acpi_id = acpi_match_device ( dev - > driver - > acpi_match_table , dev ) ;
if ( ! acpi_id | | ! acpi_id - > driver_data ) {
dev_err ( dev , " Unable to match ACPI ID and data \n " ) ;
return - ENODEV ;
}
2016-02-12 05:02:43 +03:00
axp20x - > variant = ( long ) acpi_id - > driver_data ;
2014-10-07 08:17:14 +04:00
}
switch ( axp20x - > variant ) {
2015-07-11 15:59:56 +03:00
case AXP152_ID :
axp20x - > nr_cells = ARRAY_SIZE ( axp152_cells ) ;
axp20x - > cells = axp152_cells ;
axp20x - > regmap_cfg = & axp152_regmap_config ;
axp20x - > regmap_irq_chip = & axp152_regmap_irq_chip ;
break ;
2014-10-07 08:17:14 +04:00
case AXP202_ID :
case AXP209_ID :
axp20x - > nr_cells = ARRAY_SIZE ( axp20x_cells ) ;
axp20x - > cells = axp20x_cells ;
axp20x - > regmap_cfg = & axp20x_regmap_config ;
axp20x - > regmap_irq_chip = & axp20x_regmap_irq_chip ;
break ;
2015-04-10 07:09:01 +03:00
case AXP221_ID :
2016-02-12 05:02:44 +03:00
case AXP223_ID :
2015-04-10 07:09:01 +03:00
axp20x - > nr_cells = ARRAY_SIZE ( axp22x_cells ) ;
axp20x - > cells = axp22x_cells ;
axp20x - > regmap_cfg = & axp22x_regmap_config ;
axp20x - > regmap_irq_chip = & axp22x_regmap_irq_chip ;
break ;
2014-10-07 08:17:14 +04:00
case AXP288_ID :
axp20x - > cells = axp288_cells ;
axp20x - > nr_cells = ARRAY_SIZE ( axp288_cells ) ;
axp20x - > regmap_cfg = & axp288_regmap_config ;
axp20x - > regmap_irq_chip = & axp288_regmap_irq_chip ;
break ;
2016-03-29 12:22:26 +03:00
case AXP809_ID :
axp20x - > nr_cells = ARRAY_SIZE ( axp809_cells ) ;
axp20x - > cells = axp809_cells ;
axp20x - > regmap_cfg = & axp22x_regmap_config ;
axp20x - > regmap_irq_chip = & axp809_regmap_irq_chip ;
break ;
2014-10-07 08:17:14 +04:00
default :
dev_err ( dev , " unsupported AXP20X ID %lu \n " , axp20x - > variant ) ;
return - EINVAL ;
}
dev_info ( dev , " AXP20x variant %s found \n " ,
2016-02-12 05:02:43 +03:00
axp20x_model_names [ axp20x - > variant ] ) ;
2014-10-07 08:17:14 +04:00
return 0 ;
}
2016-02-12 05:02:42 +03:00
EXPORT_SYMBOL ( axp20x_match_device ) ;
2014-10-07 08:17:14 +04:00
2016-02-12 05:02:42 +03:00
int axp20x_device_probe ( struct axp20x_dev * axp20x )
2014-05-01 16:29:27 +04:00
{
int ret ;
2016-02-12 05:02:42 +03:00
ret = regmap_add_irq_chip ( axp20x - > regmap , axp20x - > irq ,
2014-05-01 16:29:27 +04:00
IRQF_ONESHOT | IRQF_SHARED , - 1 ,
2014-10-07 08:17:14 +04:00
axp20x - > regmap_irq_chip ,
2014-05-01 16:29:27 +04:00
& axp20x - > regmap_irqc ) ;
if ( ret ) {
2016-02-12 05:02:42 +03:00
dev_err ( axp20x - > dev , " failed to add irq chip: %d \n " , ret ) ;
2014-05-01 16:29:27 +04:00
return ret ;
}
2014-10-07 08:17:14 +04:00
ret = mfd_add_devices ( axp20x - > dev , - 1 , axp20x - > cells ,
2016-02-12 05:02:43 +03:00
axp20x - > nr_cells , NULL , 0 , NULL ) ;
2014-05-01 16:29:27 +04:00
if ( ret ) {
2016-02-12 05:02:42 +03:00
dev_err ( axp20x - > dev , " failed to add MFD devices: %d \n " , ret ) ;
regmap_del_irq_chip ( axp20x - > irq , axp20x - > regmap_irqc ) ;
2014-05-01 16:29:27 +04:00
return ret ;
}
if ( ! pm_power_off ) {
axp20x_pm_power_off = axp20x ;
pm_power_off = axp20x_power_off ;
}
2016-02-12 05:02:42 +03:00
dev_info ( axp20x - > dev , " AXP20X driver loaded \n " ) ;
2014-05-01 16:29:27 +04:00
return 0 ;
}
2016-02-12 05:02:42 +03:00
EXPORT_SYMBOL ( axp20x_device_probe ) ;
2014-05-01 16:29:27 +04:00
2016-02-12 05:02:42 +03:00
int axp20x_device_remove ( struct axp20x_dev * axp20x )
2014-05-01 16:29:27 +04:00
{
if ( axp20x = = axp20x_pm_power_off ) {
axp20x_pm_power_off = NULL ;
pm_power_off = NULL ;
}
mfd_remove_devices ( axp20x - > dev ) ;
2016-02-12 05:02:42 +03:00
regmap_del_irq_chip ( axp20x - > irq , axp20x - > regmap_irqc ) ;
2014-05-01 16:29:27 +04:00
return 0 ;
}
2016-02-12 05:02:42 +03:00
EXPORT_SYMBOL ( axp20x_device_remove ) ;
2014-05-01 16:29:27 +04:00
MODULE_DESCRIPTION ( " PMIC MFD core driver for AXP20X " ) ;
MODULE_AUTHOR ( " Carlo Caione <carlo@caione.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;