2019-04-23 12:04:46 +03:00
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2018 BayLibre SAS
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
//
// Core MFD driver for MAXIM 77650/77651 charger/power-supply.
// Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
# include <linux/i2c.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/mfd/core.h>
# include <linux/mfd/max77650.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/regmap.h>
# define MAX77650_INT_GPI_F_MSK BIT(0)
# define MAX77650_INT_GPI_R_MSK BIT(1)
# define MAX77650_INT_GPI_MSK \
( MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK )
# define MAX77650_INT_nEN_F_MSK BIT(2)
# define MAX77650_INT_nEN_R_MSK BIT(3)
# define MAX77650_INT_TJAL1_R_MSK BIT(4)
# define MAX77650_INT_TJAL2_R_MSK BIT(5)
# define MAX77650_INT_DOD_R_MSK BIT(6)
# define MAX77650_INT_THM_MSK BIT(0)
# define MAX77650_INT_CHG_MSK BIT(1)
# define MAX77650_INT_CHGIN_MSK BIT(2)
# define MAX77650_INT_TJ_REG_MSK BIT(3)
# define MAX77650_INT_CHGIN_CTRL_MSK BIT(4)
# define MAX77650_INT_SYS_CTRL_MSK BIT(5)
# define MAX77650_INT_SYS_CNFG_MSK BIT(6)
# define MAX77650_INT_GLBL_OFFSET 0
# define MAX77650_INT_CHG_OFFSET 1
# define MAX77650_SBIA_LPM_MASK BIT(5)
# define MAX77650_SBIA_LPM_DISABLED 0x00
enum {
MAX77650_INT_GPI ,
MAX77650_INT_nEN_F ,
MAX77650_INT_nEN_R ,
MAX77650_INT_TJAL1_R ,
MAX77650_INT_TJAL2_R ,
MAX77650_INT_DOD_R ,
MAX77650_INT_THM ,
MAX77650_INT_CHG ,
MAX77650_INT_CHGIN ,
MAX77650_INT_TJ_REG ,
MAX77650_INT_CHGIN_CTRL ,
MAX77650_INT_SYS_CTRL ,
MAX77650_INT_SYS_CNFG ,
} ;
static const struct resource max77650_charger_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( MAX77650_INT_CHG , " CHG " ) ,
DEFINE_RES_IRQ_NAMED ( MAX77650_INT_CHGIN , " CHGIN " ) ,
} ;
static const struct resource max77650_gpio_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( MAX77650_INT_GPI , " GPI " ) ,
} ;
static const struct resource max77650_onkey_resources [ ] = {
DEFINE_RES_IRQ_NAMED ( MAX77650_INT_nEN_F , " nEN_F " ) ,
DEFINE_RES_IRQ_NAMED ( MAX77650_INT_nEN_R , " nEN_R " ) ,
} ;
static const struct mfd_cell max77650_cells [ ] = {
{
. name = " max77650-regulator " ,
. of_compatible = " maxim,max77650-regulator " ,
} , {
. name = " max77650-charger " ,
. of_compatible = " maxim,max77650-charger " ,
. resources = max77650_charger_resources ,
. num_resources = ARRAY_SIZE ( max77650_charger_resources ) ,
} , {
. name = " max77650-gpio " ,
. of_compatible = " maxim,max77650-gpio " ,
. resources = max77650_gpio_resources ,
. num_resources = ARRAY_SIZE ( max77650_gpio_resources ) ,
} , {
. name = " max77650-led " ,
. of_compatible = " maxim,max77650-led " ,
} , {
. name = " max77650-onkey " ,
. of_compatible = " maxim,max77650-onkey " ,
. resources = max77650_onkey_resources ,
. num_resources = ARRAY_SIZE ( max77650_onkey_resources ) ,
} ,
} ;
static const struct regmap_irq max77650_irqs [ ] = {
[ MAX77650_INT_GPI ] = {
. reg_offset = MAX77650_INT_GLBL_OFFSET ,
. mask = MAX77650_INT_GPI_MSK ,
. type = {
. type_falling_val = MAX77650_INT_GPI_F_MSK ,
. type_rising_val = MAX77650_INT_GPI_R_MSK ,
. types_supported = IRQ_TYPE_EDGE_BOTH ,
} ,
} ,
REGMAP_IRQ_REG ( MAX77650_INT_nEN_F ,
MAX77650_INT_GLBL_OFFSET , MAX77650_INT_nEN_F_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_nEN_R ,
MAX77650_INT_GLBL_OFFSET , MAX77650_INT_nEN_R_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_TJAL1_R ,
MAX77650_INT_GLBL_OFFSET , MAX77650_INT_TJAL1_R_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_TJAL2_R ,
MAX77650_INT_GLBL_OFFSET , MAX77650_INT_TJAL2_R_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_DOD_R ,
MAX77650_INT_GLBL_OFFSET , MAX77650_INT_DOD_R_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_THM ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_THM_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_CHG ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_CHG_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_CHGIN ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_CHGIN_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_TJ_REG ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_TJ_REG_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_CHGIN_CTRL ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_CHGIN_CTRL_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_SYS_CTRL ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_SYS_CTRL_MSK ) ,
REGMAP_IRQ_REG ( MAX77650_INT_SYS_CNFG ,
MAX77650_INT_CHG_OFFSET , MAX77650_INT_SYS_CNFG_MSK ) ,
} ;
static const struct regmap_irq_chip max77650_irq_chip = {
. name = " max77650-irq " ,
. irqs = max77650_irqs ,
. num_irqs = ARRAY_SIZE ( max77650_irqs ) ,
. num_regs = 2 ,
. status_base = MAX77650_REG_INT_GLBL ,
. mask_base = MAX77650_REG_INTM_GLBL ,
. type_in_mask = true ,
. init_ack_masked = true ,
. clear_on_unmask = true ,
} ;
static const struct regmap_config max77650_regmap_config = {
. name = " max77650 " ,
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
static int max77650_i2c_probe ( struct i2c_client * i2c )
{
struct regmap_irq_chip_data * irq_data ;
struct device * dev = & i2c - > dev ;
struct irq_domain * domain ;
struct regmap * map ;
unsigned int val ;
int rv , id ;
map = devm_regmap_init_i2c ( i2c , & max77650_regmap_config ) ;
if ( IS_ERR ( map ) ) {
dev_err ( dev , " Unable to initialise I2C Regmap \n " ) ;
return PTR_ERR ( map ) ;
}
rv = regmap_read ( map , MAX77650_REG_CID , & val ) ;
if ( rv ) {
dev_err ( dev , " Unable to read Chip ID \n " ) ;
return rv ;
}
id = MAX77650_CID_BITS ( val ) ;
switch ( id ) {
case MAX77650_CID_77650A :
case MAX77650_CID_77650C :
case MAX77650_CID_77651A :
case MAX77650_CID_77651B :
break ;
default :
dev_err ( dev , " Chip not supported - ID: 0x%02x \n " , id ) ;
return - ENODEV ;
}
/*
* This IC has a low - power mode which reduces the quiescent current
* consumption to ~ 5.6 uA but is only suitable for systems consuming
* less than ~ 2 mA . Since this is not likely the case even on
* linux - based wearables - keep the chip in normal power mode .
*/
rv = regmap_update_bits ( map ,
MAX77650_REG_CNFG_GLBL ,
MAX77650_SBIA_LPM_MASK ,
MAX77650_SBIA_LPM_DISABLED ) ;
if ( rv ) {
dev_err ( dev , " Unable to change the power mode \n " ) ;
return rv ;
}
rv = devm_regmap_add_irq_chip ( dev , map , i2c - > irq ,
IRQF_ONESHOT | IRQF_SHARED , 0 ,
& max77650_irq_chip , & irq_data ) ;
if ( rv ) {
dev_err ( dev , " Unable to add Regmap IRQ chip \n " ) ;
return rv ;
}
domain = regmap_irq_get_domain ( irq_data ) ;
return devm_mfd_add_devices ( dev , PLATFORM_DEVID_NONE ,
max77650_cells , ARRAY_SIZE ( max77650_cells ) ,
NULL , 0 , domain ) ;
}
static const struct of_device_id max77650_of_match [ ] = {
{ . compatible = " maxim,max77650 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , max77650_of_match ) ;
static struct i2c_driver max77650_i2c_driver = {
. driver = {
. name = " max77650 " ,
2020-11-20 19:21:25 +03:00
. of_match_table = max77650_of_match ,
2019-04-23 12:04:46 +03:00
} ,
. probe_new = max77650_i2c_probe ,
} ;
module_i2c_driver ( max77650_i2c_driver ) ;
MODULE_DESCRIPTION ( " MAXIM 77650/77651 multi-function core driver " ) ;
MODULE_AUTHOR ( " Bartosz Golaszewski <bgolaszewski@baylibre.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;