2012-03-16 09:40:19 +04:00
/*
* Core driver for TI TPS65090 PMIC family
*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/mfd/core.h>
# include <linux/mfd/tps65090.h>
# include <linux/err.h>
# define NUM_INT_REG 2
# define TOTAL_NUM_REG 0x18
/* interrupt status registers */
# define TPS65090_INT_STS 0x0
# define TPS65090_INT_STS2 0x1
/* interrupt mask registers */
# define TPS65090_INT_MSK 0x2
# define TPS65090_INT_MSK2 0x3
2012-11-20 07:14:49 +04:00
# define TPS65090_INT1_MASK_VAC_STATUS_CHANGE 1
# define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE 2
# define TPS65090_INT1_MASK_BAT_STATUS_CHANGE 3
# define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE 4
# define TPS65090_INT1_MASK_CHARGING_COMPLETE 5
# define TPS65090_INT1_MASK_OVERLOAD_DCDC1 6
# define TPS65090_INT1_MASK_OVERLOAD_DCDC2 7
# define TPS65090_INT2_MASK_OVERLOAD_DCDC3 0
# define TPS65090_INT2_MASK_OVERLOAD_FET1 1
# define TPS65090_INT2_MASK_OVERLOAD_FET2 2
# define TPS65090_INT2_MASK_OVERLOAD_FET3 3
# define TPS65090_INT2_MASK_OVERLOAD_FET4 4
# define TPS65090_INT2_MASK_OVERLOAD_FET5 5
# define TPS65090_INT2_MASK_OVERLOAD_FET6 6
# define TPS65090_INT2_MASK_OVERLOAD_FET7 7
2012-03-16 09:40:19 +04:00
static struct mfd_cell tps65090s [ ] = {
{
2012-07-18 17:03:42 +04:00
. name = " tps65090-pmic " ,
2012-03-16 09:40:19 +04:00
} ,
{
2012-11-20 07:14:45 +04:00
. name = " tps65090-charger " ,
2012-03-16 09:40:19 +04:00
} ,
} ;
2012-11-20 07:14:49 +04:00
static const struct regmap_irq tps65090_irqs [ ] = {
/* INT1 IRQs*/
[ TPS65090_IRQ_VAC_STATUS_CHANGE ] = {
. mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE ,
} ,
[ TPS65090_IRQ_VSYS_STATUS_CHANGE ] = {
. mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE ,
} ,
[ TPS65090_IRQ_BAT_STATUS_CHANGE ] = {
. mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE ,
} ,
[ TPS65090_IRQ_CHARGING_STATUS_CHANGE ] = {
. mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE ,
} ,
[ TPS65090_IRQ_CHARGING_COMPLETE ] = {
. mask = TPS65090_INT1_MASK_CHARGING_COMPLETE ,
} ,
[ TPS65090_IRQ_OVERLOAD_DCDC1 ] = {
. mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1 ,
} ,
[ TPS65090_IRQ_OVERLOAD_DCDC2 ] = {
. mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2 ,
} ,
/* INT2 IRQs*/
[ TPS65090_IRQ_OVERLOAD_DCDC3 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET1 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET1 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET2 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET2 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET3 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET3 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET4 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET4 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET5 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET5 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET6 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET6 ,
} ,
[ TPS65090_IRQ_OVERLOAD_FET7 ] = {
. reg_offset = 1 ,
. mask = TPS65090_INT2_MASK_OVERLOAD_FET7 ,
} ,
} ;
2012-03-16 09:40:19 +04:00
2012-11-20 07:14:49 +04:00
static struct regmap_irq_chip tps65090_irq_chip = {
. name = " tps65090 " ,
. irqs = tps65090_irqs ,
. num_irqs = ARRAY_SIZE ( tps65090_irqs ) ,
. num_regs = NUM_INT_REG ,
. status_base = TPS65090_INT_STS ,
. mask_base = TPS65090_INT_MSK ,
. mask_invert = true ,
} ;
2012-03-16 09:40:19 +04:00
static bool is_volatile_reg ( struct device * dev , unsigned int reg )
{
2012-11-20 07:14:49 +04:00
if ( ( reg = = TPS65090_INT_STS ) | | ( reg = = TPS65090_INT_STS2 ) )
2012-03-16 09:40:19 +04:00
return true ;
else
return false ;
}
static const struct regmap_config tps65090_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = TOTAL_NUM_REG ,
. num_reg_defaults_raw = TOTAL_NUM_REG ,
. cache_type = REGCACHE_RBTREE ,
. volatile_reg = is_volatile_reg ,
} ;
2012-11-19 22:23:04 +04:00
static int tps65090_i2c_probe ( struct i2c_client * client ,
2012-03-16 09:40:19 +04:00
const struct i2c_device_id * id )
{
struct tps65090_platform_data * pdata = client - > dev . platform_data ;
struct tps65090 * tps65090 ;
int ret ;
if ( ! pdata ) {
dev_err ( & client - > dev , " tps65090 requires platform data \n " ) ;
return - EINVAL ;
}
2012-11-20 07:14:46 +04:00
tps65090 = devm_kzalloc ( & client - > dev , sizeof ( * tps65090 ) , GFP_KERNEL ) ;
if ( ! tps65090 ) {
dev_err ( & client - > dev , " mem alloc for tps65090 failed \n " ) ;
2012-03-16 09:40:19 +04:00
return - ENOMEM ;
2012-11-20 07:14:46 +04:00
}
2012-03-16 09:40:19 +04:00
tps65090 - > dev = & client - > dev ;
i2c_set_clientdata ( client , tps65090 ) ;
2012-11-20 07:14:47 +04:00
tps65090 - > rmap = devm_regmap_init_i2c ( client , & tps65090_regmap_config ) ;
2012-03-16 09:40:19 +04:00
if ( IS_ERR ( tps65090 - > rmap ) ) {
2012-04-25 05:30:36 +04:00
ret = PTR_ERR ( tps65090 - > rmap ) ;
dev_err ( & client - > dev , " regmap_init failed with err: %d \n " , ret ) ;
2012-11-20 07:14:49 +04:00
return ret ;
}
if ( client - > irq ) {
ret = regmap_add_irq_chip ( tps65090 - > rmap , client - > irq ,
IRQF_ONESHOT | IRQF_TRIGGER_LOW , pdata - > irq_base ,
& tps65090_irq_chip , & tps65090 - > irq_data ) ;
if ( ret ) {
dev_err ( & client - > dev ,
" IRQ init failed with err: %d \n " , ret ) ;
return ret ;
}
2012-04-25 05:30:36 +04:00
}
2012-03-16 09:40:19 +04:00
ret = mfd_add_devices ( tps65090 - > dev , - 1 , tps65090s ,
2012-11-20 07:14:49 +04:00
ARRAY_SIZE ( tps65090s ) , NULL ,
regmap_irq_chip_get_base ( tps65090 - > irq_data ) , NULL ) ;
2012-03-16 09:40:19 +04:00
if ( ret ) {
dev_err ( & client - > dev , " add mfd devices failed with err: %d \n " ,
ret ) ;
2012-04-25 06:04:58 +04:00
goto err_irq_exit ;
2012-03-16 09:40:19 +04:00
}
return 0 ;
err_irq_exit :
if ( client - > irq )
2012-11-20 07:14:49 +04:00
regmap_del_irq_chip ( client - > irq , tps65090 - > irq_data ) ;
2012-03-16 09:40:19 +04:00
return ret ;
}
2012-11-19 22:26:01 +04:00
static int tps65090_i2c_remove ( struct i2c_client * client )
2012-03-16 09:40:19 +04:00
{
struct tps65090 * tps65090 = i2c_get_clientdata ( client ) ;
mfd_remove_devices ( tps65090 - > dev ) ;
if ( client - > irq )
2012-11-20 07:14:49 +04:00
regmap_del_irq_chip ( client - > irq , tps65090 - > irq_data ) ;
2012-03-16 09:40:19 +04:00
return 0 ;
}
2012-05-07 13:03:17 +04:00
# ifdef CONFIG_PM_SLEEP
2012-05-07 13:03:18 +04:00
static int tps65090_suspend ( struct device * dev )
2012-03-16 09:40:19 +04:00
{
2012-05-07 13:03:18 +04:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2012-03-16 09:40:19 +04:00
if ( client - > irq )
disable_irq ( client - > irq ) ;
return 0 ;
}
2012-05-07 13:03:18 +04:00
static int tps65090_resume ( struct device * dev )
2012-03-16 09:40:19 +04:00
{
2012-05-07 13:03:18 +04:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2012-03-16 09:40:19 +04:00
if ( client - > irq )
enable_irq ( client - > irq ) ;
return 0 ;
}
# endif
2012-05-07 13:03:18 +04:00
static const struct dev_pm_ops tps65090_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( tps65090_suspend , tps65090_resume )
} ;
2012-03-16 09:40:19 +04:00
static const struct i2c_device_id tps65090_id_table [ ] = {
{ " tps65090 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , tps65090_id_table ) ;
static struct i2c_driver tps65090_driver = {
. driver = {
. name = " tps65090 " ,
. owner = THIS_MODULE ,
2012-05-07 13:03:18 +04:00
. pm = & tps65090_pm_ops ,
2012-03-16 09:40:19 +04:00
} ,
. probe = tps65090_i2c_probe ,
2012-11-19 22:20:24 +04:00
. remove = tps65090_i2c_remove ,
2012-03-16 09:40:19 +04:00
. id_table = tps65090_id_table ,
} ;
static int __init tps65090_init ( void )
{
return i2c_add_driver ( & tps65090_driver ) ;
}
subsys_initcall ( tps65090_init ) ;
static void __exit tps65090_exit ( void )
{
i2c_del_driver ( & tps65090_driver ) ;
}
module_exit ( tps65090_exit ) ;
MODULE_DESCRIPTION ( " TPS65090 core driver " ) ;
MODULE_AUTHOR ( " Venu Byravarasu <vbyravarasu@nvidia.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;