2015-03-02 13:10:34 +03:00
/*
* MFD core driver for the Maxim MAX77843
*
* Copyright ( C ) 2015 Samsung Electronics
* Author : Jaewon Kim < jaewon02 . kim @ samsung . com >
* Author : Beomho Seo < beomho . seo @ samsung . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/interrupt.h>
2016-06-03 03:39:50 +03:00
# include <linux/init.h>
2015-03-02 13:10:34 +03:00
# include <linux/mfd/core.h>
2015-07-15 15:59:51 +03:00
# include <linux/mfd/max77693-common.h>
2015-03-02 13:10:34 +03:00
# include <linux/mfd/max77843-private.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
static const struct mfd_cell max77843_devs [ ] = {
{
. name = " max77843-muic " ,
. of_compatible = " maxim,max77843-muic " ,
} , {
. name = " max77843-regulator " ,
. of_compatible = " maxim,max77843-regulator " ,
} , {
. name = " max77843-charger " ,
. of_compatible = " maxim,max77843-charger "
} , {
. name = " max77843-fuelgauge " ,
. of_compatible = " maxim,max77843-fuelgauge " ,
} , {
. name = " max77843-haptic " ,
. of_compatible = " maxim,max77843-haptic " ,
} ,
} ;
static const struct regmap_config max77843_charger_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = MAX77843_CHG_REG_END ,
} ;
static const struct regmap_config max77843_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = MAX77843_SYS_REG_END ,
} ;
static const struct regmap_irq max77843_irqs [ ] = {
/* TOPSYS interrupts */
{ . reg_offset = 0 , . mask = MAX77843_SYS_IRQ_SYSUVLO_INT , } ,
{ . reg_offset = 0 , . mask = MAX77843_SYS_IRQ_SYSOVLO_INT , } ,
{ . reg_offset = 0 , . mask = MAX77843_SYS_IRQ_TSHDN_INT , } ,
{ . reg_offset = 0 , . mask = MAX77843_SYS_IRQ_TM_INT , } ,
} ;
static const struct regmap_irq_chip max77843_irq_chip = {
. name = " max77843 " ,
. status_base = MAX77843_SYS_REG_SYSINTSRC ,
. mask_base = MAX77843_SYS_REG_SYSINTMASK ,
. mask_invert = false ,
. num_regs = 1 ,
. irqs = max77843_irqs ,
. num_irqs = ARRAY_SIZE ( max77843_irqs ) ,
} ;
/* Charger and Charger regulator use same regmap. */
2015-07-15 15:59:51 +03:00
static int max77843_chg_init ( struct max77693_dev * max77843 )
2015-03-02 13:10:34 +03:00
{
int ret ;
max77843 - > i2c_chg = i2c_new_dummy ( max77843 - > i2c - > adapter , I2C_ADDR_CHG ) ;
if ( ! max77843 - > i2c_chg ) {
dev_err ( & max77843 - > i2c - > dev ,
" Cannot allocate I2C device for Charger \n " ) ;
2015-09-21 15:26:54 +03:00
return - ENODEV ;
2015-03-02 13:10:34 +03:00
}
i2c_set_clientdata ( max77843 - > i2c_chg , max77843 ) ;
max77843 - > regmap_chg = devm_regmap_init_i2c ( max77843 - > i2c_chg ,
& max77843_charger_regmap_config ) ;
if ( IS_ERR ( max77843 - > regmap_chg ) ) {
ret = PTR_ERR ( max77843 - > regmap_chg ) ;
goto err_chg_i2c ;
}
return 0 ;
err_chg_i2c :
i2c_unregister_device ( max77843 - > i2c_chg ) ;
return ret ;
}
static int max77843_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * id )
{
2015-07-15 15:59:51 +03:00
struct max77693_dev * max77843 ;
2015-03-02 13:10:34 +03:00
unsigned int reg_data ;
int ret ;
max77843 = devm_kzalloc ( & i2c - > dev , sizeof ( * max77843 ) , GFP_KERNEL ) ;
if ( ! max77843 )
return - ENOMEM ;
i2c_set_clientdata ( i2c , max77843 ) ;
max77843 - > dev = & i2c - > dev ;
max77843 - > i2c = i2c ;
max77843 - > irq = i2c - > irq ;
2015-07-15 15:59:51 +03:00
max77843 - > type = id - > driver_data ;
2015-03-02 13:10:34 +03:00
max77843 - > regmap = devm_regmap_init_i2c ( i2c ,
& max77843_regmap_config ) ;
if ( IS_ERR ( max77843 - > regmap ) ) {
dev_err ( & i2c - > dev , " Failed to allocate topsys register map \n " ) ;
return PTR_ERR ( max77843 - > regmap ) ;
}
ret = regmap_add_irq_chip ( max77843 - > regmap , max77843 - > irq ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED ,
2015-07-15 15:59:51 +03:00
0 , & max77843_irq_chip , & max77843 - > irq_data_topsys ) ;
2015-03-02 13:10:34 +03:00
if ( ret ) {
dev_err ( & i2c - > dev , " Failed to add TOPSYS IRQ chip \n " ) ;
return ret ;
}
ret = regmap_read ( max77843 - > regmap ,
MAX77843_SYS_REG_PMICID , & reg_data ) ;
if ( ret < 0 ) {
dev_err ( & i2c - > dev , " Failed to read PMIC ID \n " ) ;
goto err_pmic_id ;
}
dev_info ( & i2c - > dev , " device ID: 0x%x \n " , reg_data ) ;
ret = max77843_chg_init ( max77843 ) ;
if ( ret ) {
dev_err ( & i2c - > dev , " Failed to init Charger \n " ) ;
goto err_pmic_id ;
}
ret = regmap_update_bits ( max77843 - > regmap ,
MAX77843_SYS_REG_INTSRCMASK ,
MAX77843_INTSRC_MASK_MASK ,
( unsigned int ) ~ MAX77843_INTSRC_MASK_MASK ) ;
if ( ret < 0 ) {
dev_err ( & i2c - > dev , " Failed to unmask interrupt source \n " ) ;
goto err_pmic_id ;
}
ret = mfd_add_devices ( max77843 - > dev , - 1 , max77843_devs ,
ARRAY_SIZE ( max77843_devs ) , NULL , 0 , NULL ) ;
if ( ret < 0 ) {
dev_err ( & i2c - > dev , " Failed to add mfd device \n " ) ;
goto err_pmic_id ;
}
device_init_wakeup ( max77843 - > dev , true ) ;
return 0 ;
err_pmic_id :
2015-07-15 15:59:51 +03:00
regmap_del_irq_chip ( max77843 - > irq , max77843 - > irq_data_topsys ) ;
2015-03-02 13:10:34 +03:00
return ret ;
}
static const struct of_device_id max77843_dt_match [ ] = {
{ . compatible = " maxim,max77843 " , } ,
{ } ,
} ;
static const struct i2c_device_id max77843_id [ ] = {
2015-07-15 15:59:51 +03:00
{ " max77843 " , TYPE_MAX77843 , } ,
2015-03-02 13:10:34 +03:00
{ } ,
} ;
static int __maybe_unused max77843_suspend ( struct device * dev )
{
2015-12-28 18:00:14 +03:00
struct i2c_client * i2c = to_i2c_client ( dev ) ;
2015-07-15 15:59:51 +03:00
struct max77693_dev * max77843 = i2c_get_clientdata ( i2c ) ;
2015-03-02 13:10:34 +03:00
disable_irq ( max77843 - > irq ) ;
if ( device_may_wakeup ( dev ) )
enable_irq_wake ( max77843 - > irq ) ;
return 0 ;
}
static int __maybe_unused max77843_resume ( struct device * dev )
{
2015-12-28 18:00:14 +03:00
struct i2c_client * i2c = to_i2c_client ( dev ) ;
2015-07-15 15:59:51 +03:00
struct max77693_dev * max77843 = i2c_get_clientdata ( i2c ) ;
2015-03-02 13:10:34 +03:00
if ( device_may_wakeup ( dev ) )
disable_irq_wake ( max77843 - > irq ) ;
enable_irq ( max77843 - > irq ) ;
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( max77843_pm , max77843_suspend , max77843_resume ) ;
static struct i2c_driver max77843_i2c_driver = {
. driver = {
. name = " max77843 " ,
. pm = & max77843_pm ,
. of_match_table = max77843_dt_match ,
2016-06-03 03:39:50 +03:00
. suppress_bind_attrs = true ,
2015-03-02 13:10:34 +03:00
} ,
. probe = max77843_probe ,
. id_table = max77843_id ,
} ;
static int __init max77843_i2c_init ( void )
{
return i2c_add_driver ( & max77843_i2c_driver ) ;
}
subsys_initcall ( max77843_i2c_init ) ;