2011-05-03 01:20:08 +04:00
/*
* tps65910 . c - - TI tps65910
*
* Copyright 2010 Texas Instruments Inc .
*
* Author : Graeme Gregory < gg @ slimlogic . co . uk >
* Author : Jorge Eduardo Candelaria < jedu @ slimlogic . co . uk >
*
* 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/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/gpio.h>
# include <linux/mfd/tps65910.h>
# define TPS65910_SUPPLY_STATE_ENABLED 0x1
2012-01-28 13:37:57 +04:00
# define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \
2012-03-07 16:51:49 +04:00
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP )
2011-05-03 01:20:08 +04:00
/* supported VIO voltages in milivolts */
static const u16 VIO_VSEL_table [ ] = {
1500 , 1800 , 2500 , 3300 ,
} ;
2011-05-17 03:35:03 +04:00
/* VSEL tables for TPS65910 specific LDOs and dcdc's */
/* supported VDD3 voltages in milivolts */
2011-05-03 01:20:08 +04:00
static const u16 VDD3_VSEL_table [ ] = {
5000 ,
} ;
/* supported VDIG1 voltages in milivolts */
static const u16 VDIG1_VSEL_table [ ] = {
1200 , 1500 , 1800 , 2700 ,
} ;
/* supported VDIG2 voltages in milivolts */
static const u16 VDIG2_VSEL_table [ ] = {
1000 , 1100 , 1200 , 1800 ,
} ;
/* supported VPLL voltages in milivolts */
static const u16 VPLL_VSEL_table [ ] = {
1000 , 1100 , 1800 , 2500 ,
} ;
/* supported VDAC voltages in milivolts */
static const u16 VDAC_VSEL_table [ ] = {
1800 , 2600 , 2800 , 2850 ,
} ;
/* supported VAUX1 voltages in milivolts */
static const u16 VAUX1_VSEL_table [ ] = {
1800 , 2500 , 2800 , 2850 ,
} ;
/* supported VAUX2 voltages in milivolts */
static const u16 VAUX2_VSEL_table [ ] = {
1800 , 2800 , 2900 , 3300 ,
} ;
/* supported VAUX33 voltages in milivolts */
static const u16 VAUX33_VSEL_table [ ] = {
1800 , 2000 , 2800 , 3300 ,
} ;
/* supported VMMC voltages in milivolts */
static const u16 VMMC_VSEL_table [ ] = {
1800 , 2800 , 3000 , 3300 ,
} ;
struct tps_info {
const char * name ;
unsigned min_uV ;
unsigned max_uV ;
2012-01-20 15:06:22 +04:00
u8 n_voltages ;
const u16 * voltage_table ;
2012-03-13 10:05:20 +04:00
int enable_time_us ;
2011-05-03 01:20:08 +04:00
} ;
static struct tps_info tps65910_regs [ ] = {
{
. name = " VRTC " ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 2200 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VIO " ,
. min_uV = 1500000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VIO_VSEL_table ) ,
. voltage_table = VIO_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDD1 " ,
. min_uV = 600000 ,
. max_uV = 4500000 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDD2 " ,
. min_uV = 600000 ,
. max_uV = 4500000 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDD3 " ,
. min_uV = 5000000 ,
. max_uV = 5000000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VDD3_VSEL_table ) ,
. voltage_table = VDD3_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 200 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDIG1 " ,
. min_uV = 1200000 ,
. max_uV = 2700000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VDIG1_VSEL_table ) ,
. voltage_table = VDIG1_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDIG2 " ,
. min_uV = 1000000 ,
. max_uV = 1800000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VDIG2_VSEL_table ) ,
. voltage_table = VDIG2_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VPLL " ,
. min_uV = 1000000 ,
. max_uV = 2500000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VPLL_VSEL_table ) ,
. voltage_table = VPLL_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VDAC " ,
. min_uV = 1800000 ,
. max_uV = 2850000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VDAC_VSEL_table ) ,
. voltage_table = VDAC_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VAUX1 " ,
. min_uV = 1800000 ,
. max_uV = 2850000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VAUX1_VSEL_table ) ,
. voltage_table = VAUX1_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VAUX2 " ,
. min_uV = 1800000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VAUX2_VSEL_table ) ,
. voltage_table = VAUX2_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VAUX33 " ,
. min_uV = 1800000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VAUX33_VSEL_table ) ,
. voltage_table = VAUX33_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
{
. name = " VMMC " ,
. min_uV = 1800000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VMMC_VSEL_table ) ,
. voltage_table = VMMC_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 100 ,
2011-05-03 01:20:08 +04:00
} ,
} ;
2011-05-17 03:35:03 +04:00
static struct tps_info tps65911_regs [ ] = {
2012-01-18 19:16:56 +04:00
{
. name = " VRTC " ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 2200 ,
2012-01-18 19:16:56 +04:00
} ,
2011-05-17 03:35:03 +04:00
{
. name = " VIO " ,
. min_uV = 1500000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = ARRAY_SIZE ( VIO_VSEL_table ) ,
. voltage_table = VIO_VSEL_table ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " VDD1 " ,
. min_uV = 600000 ,
. max_uV = 4500000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 73 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " VDD2 " ,
. min_uV = 600000 ,
. max_uV = 4500000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 73 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " VDDCTRL " ,
. min_uV = 600000 ,
. max_uV = 1400000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 65 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 900 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO1 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 47 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 420 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO2 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 47 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 420 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO3 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 24 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO4 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 47 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO5 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 24 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO6 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 24 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO7 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 24 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
. name = " LDO8 " ,
. min_uV = 1000000 ,
. max_uV = 3300000 ,
2012-01-20 15:06:22 +04:00
. n_voltages = 24 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
} ;
2012-01-28 13:37:57 +04:00
# define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits))
static unsigned int tps65910_ext_sleep_control [ ] = {
0 ,
EXT_CONTROL_REG_BITS ( VIO , 1 , 0 ) ,
EXT_CONTROL_REG_BITS ( VDD1 , 1 , 1 ) ,
EXT_CONTROL_REG_BITS ( VDD2 , 1 , 2 ) ,
EXT_CONTROL_REG_BITS ( VDD3 , 1 , 3 ) ,
EXT_CONTROL_REG_BITS ( VDIG1 , 0 , 1 ) ,
EXT_CONTROL_REG_BITS ( VDIG2 , 0 , 2 ) ,
EXT_CONTROL_REG_BITS ( VPLL , 0 , 6 ) ,
EXT_CONTROL_REG_BITS ( VDAC , 0 , 7 ) ,
EXT_CONTROL_REG_BITS ( VAUX1 , 0 , 3 ) ,
EXT_CONTROL_REG_BITS ( VAUX2 , 0 , 4 ) ,
EXT_CONTROL_REG_BITS ( VAUX33 , 0 , 5 ) ,
EXT_CONTROL_REG_BITS ( VMMC , 0 , 0 ) ,
} ;
static unsigned int tps65911_ext_sleep_control [ ] = {
0 ,
EXT_CONTROL_REG_BITS ( VIO , 1 , 0 ) ,
EXT_CONTROL_REG_BITS ( VDD1 , 1 , 1 ) ,
EXT_CONTROL_REG_BITS ( VDD2 , 1 , 2 ) ,
EXT_CONTROL_REG_BITS ( VDDCTRL , 1 , 3 ) ,
EXT_CONTROL_REG_BITS ( LDO1 , 0 , 1 ) ,
EXT_CONTROL_REG_BITS ( LDO2 , 0 , 2 ) ,
EXT_CONTROL_REG_BITS ( LDO3 , 0 , 7 ) ,
EXT_CONTROL_REG_BITS ( LDO4 , 0 , 6 ) ,
EXT_CONTROL_REG_BITS ( LDO5 , 0 , 3 ) ,
EXT_CONTROL_REG_BITS ( LDO6 , 0 , 0 ) ,
EXT_CONTROL_REG_BITS ( LDO7 , 0 , 5 ) ,
EXT_CONTROL_REG_BITS ( LDO8 , 0 , 4 ) ,
} ;
2011-05-03 01:20:08 +04:00
struct tps65910_reg {
2011-07-11 05:57:43 +04:00
struct regulator_desc * desc ;
2011-05-03 01:20:08 +04:00
struct tps65910 * mfd ;
2011-07-11 05:57:43 +04:00
struct regulator_dev * * rdev ;
struct tps_info * * info ;
2011-05-03 01:20:08 +04:00
struct mutex mutex ;
2011-07-11 05:57:43 +04:00
int num_regulators ;
2011-05-03 01:20:08 +04:00
int mode ;
2011-05-17 03:35:03 +04:00
int ( * get_ctrl_reg ) ( int ) ;
2012-01-28 13:37:57 +04:00
unsigned int * ext_sleep_control ;
unsigned int board_ext_control [ TPS65910_NUM_REGS ] ;
2011-05-03 01:20:08 +04:00
} ;
static inline int tps65910_read ( struct tps65910_reg * pmic , u8 reg )
{
u8 val ;
int err ;
err = pmic - > mfd - > read ( pmic - > mfd , reg , 1 , & val ) ;
if ( err )
return err ;
return val ;
}
static inline int tps65910_write ( struct tps65910_reg * pmic , u8 reg , u8 val )
{
return pmic - > mfd - > write ( pmic - > mfd , reg , 1 , & val ) ;
}
static int tps65910_modify_bits ( struct tps65910_reg * pmic , u8 reg ,
u8 set_mask , u8 clear_mask )
{
int err , data ;
mutex_lock ( & pmic - > mutex ) ;
data = tps65910_read ( pmic , reg ) ;
if ( data < 0 ) {
dev_err ( pmic - > mfd - > dev , " Read from reg 0x%x failed \n " , reg ) ;
err = data ;
goto out ;
}
data & = ~ clear_mask ;
data | = set_mask ;
err = tps65910_write ( pmic , reg , data ) ;
if ( err )
dev_err ( pmic - > mfd - > dev , " Write for reg 0x%x failed \n " , reg ) ;
out :
mutex_unlock ( & pmic - > mutex ) ;
return err ;
}
static int tps65910_reg_read ( struct tps65910_reg * pmic , u8 reg )
{
int data ;
mutex_lock ( & pmic - > mutex ) ;
data = tps65910_read ( pmic , reg ) ;
if ( data < 0 )
dev_err ( pmic - > mfd - > dev , " Read from reg 0x%x failed \n " , reg ) ;
mutex_unlock ( & pmic - > mutex ) ;
return data ;
}
static int tps65910_reg_write ( struct tps65910_reg * pmic , u8 reg , u8 val )
{
int err ;
mutex_lock ( & pmic - > mutex ) ;
err = tps65910_write ( pmic , reg , val ) ;
if ( err < 0 )
dev_err ( pmic - > mfd - > dev , " Write for reg 0x%x failed \n " , reg ) ;
mutex_unlock ( & pmic - > mutex ) ;
return err ;
}
static int tps65910_get_ctrl_register ( int id )
{
switch ( id ) {
case TPS65910_REG_VRTC :
return TPS65910_VRTC ;
case TPS65910_REG_VIO :
return TPS65910_VIO ;
case TPS65910_REG_VDD1 :
return TPS65910_VDD1 ;
case TPS65910_REG_VDD2 :
return TPS65910_VDD2 ;
case TPS65910_REG_VDD3 :
return TPS65910_VDD3 ;
case TPS65910_REG_VDIG1 :
return TPS65910_VDIG1 ;
case TPS65910_REG_VDIG2 :
return TPS65910_VDIG2 ;
case TPS65910_REG_VPLL :
return TPS65910_VPLL ;
case TPS65910_REG_VDAC :
return TPS65910_VDAC ;
case TPS65910_REG_VAUX1 :
return TPS65910_VAUX1 ;
case TPS65910_REG_VAUX2 :
return TPS65910_VAUX2 ;
case TPS65910_REG_VAUX33 :
return TPS65910_VAUX33 ;
case TPS65910_REG_VMMC :
return TPS65910_VMMC ;
default :
return - EINVAL ;
}
}
2011-05-17 03:35:03 +04:00
static int tps65911_get_ctrl_register ( int id )
{
switch ( id ) {
case TPS65910_REG_VRTC :
return TPS65910_VRTC ;
case TPS65910_REG_VIO :
return TPS65910_VIO ;
case TPS65910_REG_VDD1 :
return TPS65910_VDD1 ;
case TPS65910_REG_VDD2 :
return TPS65910_VDD2 ;
case TPS65911_REG_VDDCTRL :
return TPS65911_VDDCTRL ;
case TPS65911_REG_LDO1 :
return TPS65911_LDO1 ;
case TPS65911_REG_LDO2 :
return TPS65911_LDO2 ;
case TPS65911_REG_LDO3 :
return TPS65911_LDO3 ;
case TPS65911_REG_LDO4 :
return TPS65911_LDO4 ;
case TPS65911_REG_LDO5 :
return TPS65911_LDO5 ;
case TPS65911_REG_LDO6 :
return TPS65911_LDO6 ;
case TPS65911_REG_LDO7 :
return TPS65911_LDO7 ;
case TPS65911_REG_LDO8 :
return TPS65911_LDO8 ;
default :
return - EINVAL ;
}
}
2011-05-03 01:20:08 +04:00
static int tps65910_is_enabled ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int reg , value , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
value = tps65910_reg_read ( pmic , reg ) ;
if ( value < 0 )
return value ;
return value & TPS65910_SUPPLY_STATE_ENABLED ;
}
static int tps65910_enable ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
struct tps65910 * mfd = pmic - > mfd ;
int reg , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
return tps65910_set_bits ( mfd , reg , TPS65910_SUPPLY_STATE_ENABLED ) ;
}
static int tps65910_disable ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
struct tps65910 * mfd = pmic - > mfd ;
int reg , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
return tps65910_clear_bits ( mfd , reg , TPS65910_SUPPLY_STATE_ENABLED ) ;
}
2012-03-13 10:05:20 +04:00
static int tps65910_enable_time ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int id = rdev_get_id ( dev ) ;
return pmic - > info [ id ] - > enable_time_us ;
}
2011-05-03 01:20:08 +04:00
static int tps65910_set_mode ( struct regulator_dev * dev , unsigned int mode )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
struct tps65910 * mfd = pmic - > mfd ;
int reg , value , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
switch ( mode ) {
case REGULATOR_MODE_NORMAL :
return tps65910_modify_bits ( pmic , reg , LDO_ST_ON_BIT ,
LDO_ST_MODE_BIT ) ;
case REGULATOR_MODE_IDLE :
value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT ;
return tps65910_set_bits ( mfd , reg , value ) ;
case REGULATOR_MODE_STANDBY :
return tps65910_clear_bits ( mfd , reg , LDO_ST_ON_BIT ) ;
}
return - EINVAL ;
}
static unsigned int tps65910_get_mode ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int reg , value , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
value = tps65910_reg_read ( pmic , reg ) ;
if ( value < 0 )
return value ;
2012-03-13 03:15:27 +04:00
if ( ! ( value & LDO_ST_ON_BIT ) )
2011-05-03 01:20:08 +04:00
return REGULATOR_MODE_STANDBY ;
else if ( value & LDO_ST_MODE_BIT )
return REGULATOR_MODE_IDLE ;
else
return REGULATOR_MODE_NORMAL ;
}
2012-03-14 11:30:58 +04:00
static int tps65910_get_voltage_dcdc_sel ( struct regulator_dev * dev )
2011-05-03 01:20:08 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
2012-03-14 11:30:58 +04:00
int id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
int opvsel = 0 , srvsel = 0 , vselmax = 0 , mult = 0 , sr = 0 ;
2011-05-03 01:20:08 +04:00
switch ( id ) {
case TPS65910_REG_VDD1 :
opvsel = tps65910_reg_read ( pmic , TPS65910_VDD1_OP ) ;
mult = tps65910_reg_read ( pmic , TPS65910_VDD1 ) ;
mult = ( mult & VDD1_VGAIN_SEL_MASK ) > > VDD1_VGAIN_SEL_SHIFT ;
srvsel = tps65910_reg_read ( pmic , TPS65910_VDD1_SR ) ;
sr = opvsel & VDD1_OP_CMD_MASK ;
opvsel & = VDD1_OP_SEL_MASK ;
srvsel & = VDD1_SR_SEL_MASK ;
2011-05-17 03:35:03 +04:00
vselmax = 75 ;
2011-05-03 01:20:08 +04:00
break ;
case TPS65910_REG_VDD2 :
opvsel = tps65910_reg_read ( pmic , TPS65910_VDD2_OP ) ;
mult = tps65910_reg_read ( pmic , TPS65910_VDD2 ) ;
mult = ( mult & VDD2_VGAIN_SEL_MASK ) > > VDD2_VGAIN_SEL_SHIFT ;
srvsel = tps65910_reg_read ( pmic , TPS65910_VDD2_SR ) ;
sr = opvsel & VDD2_OP_CMD_MASK ;
opvsel & = VDD2_OP_SEL_MASK ;
srvsel & = VDD2_SR_SEL_MASK ;
2011-05-17 03:35:03 +04:00
vselmax = 75 ;
break ;
case TPS65911_REG_VDDCTRL :
opvsel = tps65910_reg_read ( pmic , TPS65911_VDDCTRL_OP ) ;
srvsel = tps65910_reg_read ( pmic , TPS65911_VDDCTRL_SR ) ;
sr = opvsel & VDDCTRL_OP_CMD_MASK ;
opvsel & = VDDCTRL_OP_SEL_MASK ;
srvsel & = VDDCTRL_SR_SEL_MASK ;
vselmax = 64 ;
2011-05-03 01:20:08 +04:00
break ;
}
/* multiplier 0 == 1 but 2,3 normal */
if ( ! mult )
mult = 1 ;
if ( sr ) {
2011-05-17 03:35:03 +04:00
/* normalise to valid range */
if ( srvsel < 3 )
srvsel = 3 ;
if ( srvsel > vselmax )
srvsel = vselmax ;
2012-03-14 11:30:58 +04:00
return srvsel - 3 ;
2011-05-03 01:20:08 +04:00
} else {
2011-05-17 03:35:03 +04:00
/* normalise to valid range*/
if ( opvsel < 3 )
opvsel = 3 ;
if ( opvsel > vselmax )
opvsel = vselmax ;
2012-03-14 11:30:58 +04:00
return opvsel - 3 ;
2011-05-03 01:20:08 +04:00
}
2012-03-14 11:30:58 +04:00
return - EINVAL ;
2011-05-03 01:20:08 +04:00
}
static int tps65910_get_voltage ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int reg , value , id = rdev_get_id ( dev ) , voltage = 0 ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
value = tps65910_reg_read ( pmic , reg ) ;
if ( value < 0 )
return value ;
switch ( id ) {
case TPS65910_REG_VIO :
case TPS65910_REG_VDIG1 :
case TPS65910_REG_VDIG2 :
case TPS65910_REG_VPLL :
case TPS65910_REG_VDAC :
case TPS65910_REG_VAUX1 :
case TPS65910_REG_VAUX2 :
case TPS65910_REG_VAUX33 :
case TPS65910_REG_VMMC :
value & = LDO_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
break ;
default :
return - EINVAL ;
}
2012-01-20 15:06:22 +04:00
voltage = pmic - > info [ id ] - > voltage_table [ value ] * 1000 ;
2011-05-03 01:20:08 +04:00
return voltage ;
}
static int tps65910_get_voltage_vdd3 ( struct regulator_dev * dev )
{
return 5 * 1000 * 1000 ;
}
2011-05-17 03:35:03 +04:00
static int tps65911_get_voltage ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int step_mv , id = rdev_get_id ( dev ) ;
u8 value , reg ;
reg = pmic - > get_ctrl_reg ( id ) ;
value = tps65910_reg_read ( pmic , reg ) ;
switch ( id ) {
case TPS65911_REG_LDO1 :
case TPS65911_REG_LDO2 :
case TPS65911_REG_LDO4 :
value & = LDO1_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
/* The first 5 values of the selector correspond to 1V */
if ( value < 5 )
value = 0 ;
else
value - = 4 ;
step_mv = 50 ;
break ;
case TPS65911_REG_LDO3 :
case TPS65911_REG_LDO5 :
case TPS65911_REG_LDO6 :
case TPS65911_REG_LDO7 :
case TPS65911_REG_LDO8 :
value & = LDO3_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
/* The first 3 values of the selector correspond to 1V */
if ( value < 3 )
value = 0 ;
else
value - = 2 ;
step_mv = 100 ;
break ;
case TPS65910_REG_VIO :
2012-02-17 17:26:11 +04:00
value & = LDO_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
2012-01-20 15:06:22 +04:00
return pmic - > info [ id ] - > voltage_table [ value ] * 1000 ;
2011-05-17 03:35:03 +04:00
default :
return - EINVAL ;
}
return ( LDO_MIN_VOLT + value * step_mv ) * 1000 ;
}
2012-03-09 06:22:20 +04:00
static int tps65910_set_voltage_dcdc_sel ( struct regulator_dev * dev ,
unsigned selector )
2011-05-03 01:20:08 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int id = rdev_get_id ( dev ) , vsel ;
2011-05-17 03:35:03 +04:00
int dcdc_mult = 0 ;
2011-05-03 01:20:08 +04:00
2011-05-17 03:35:03 +04:00
switch ( id ) {
case TPS65910_REG_VDD1 :
2011-11-08 17:24:10 +04:00
dcdc_mult = ( selector / VDD1_2_NUM_VOLT_FINE ) + 1 ;
2011-05-17 03:35:03 +04:00
if ( dcdc_mult = = 1 )
dcdc_mult - - ;
2011-11-08 17:24:10 +04:00
vsel = ( selector % VDD1_2_NUM_VOLT_FINE ) + 3 ;
2011-05-03 01:20:08 +04:00
tps65910_modify_bits ( pmic , TPS65910_VDD1 ,
( dcdc_mult < < VDD1_VGAIN_SEL_SHIFT ) ,
VDD1_VGAIN_SEL_MASK ) ;
tps65910_reg_write ( pmic , TPS65910_VDD1_OP , vsel ) ;
2011-05-17 03:35:03 +04:00
break ;
case TPS65910_REG_VDD2 :
2011-11-08 17:24:10 +04:00
dcdc_mult = ( selector / VDD1_2_NUM_VOLT_FINE ) + 1 ;
2011-05-17 03:35:03 +04:00
if ( dcdc_mult = = 1 )
dcdc_mult - - ;
2011-11-08 17:24:10 +04:00
vsel = ( selector % VDD1_2_NUM_VOLT_FINE ) + 3 ;
2011-05-17 03:35:03 +04:00
2011-05-03 01:20:08 +04:00
tps65910_modify_bits ( pmic , TPS65910_VDD2 ,
( dcdc_mult < < VDD2_VGAIN_SEL_SHIFT ) ,
VDD1_VGAIN_SEL_MASK ) ;
tps65910_reg_write ( pmic , TPS65910_VDD2_OP , vsel ) ;
2011-05-17 03:35:03 +04:00
break ;
case TPS65911_REG_VDDCTRL :
2012-03-07 15:09:05 +04:00
vsel = selector + 3 ;
2011-05-17 03:35:03 +04:00
tps65910_reg_write ( pmic , TPS65911_VDDCTRL_OP , vsel ) ;
2011-05-03 01:20:08 +04:00
}
return 0 ;
}
2012-03-09 06:22:20 +04:00
static int tps65910_set_voltage_sel ( struct regulator_dev * dev ,
unsigned selector )
2011-05-03 01:20:08 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int reg , id = rdev_get_id ( dev ) ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2011-05-03 01:20:08 +04:00
if ( reg < 0 )
return reg ;
switch ( id ) {
case TPS65910_REG_VIO :
case TPS65910_REG_VDIG1 :
case TPS65910_REG_VDIG2 :
case TPS65910_REG_VPLL :
case TPS65910_REG_VDAC :
case TPS65910_REG_VAUX1 :
case TPS65910_REG_VAUX2 :
case TPS65910_REG_VAUX33 :
case TPS65910_REG_VMMC :
return tps65910_modify_bits ( pmic , reg ,
( selector < < LDO_SEL_SHIFT ) , LDO_SEL_MASK ) ;
}
return - EINVAL ;
}
2012-03-09 06:22:20 +04:00
static int tps65911_set_voltage_sel ( struct regulator_dev * dev ,
unsigned selector )
2011-05-17 03:35:03 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int reg , id = rdev_get_id ( dev ) ;
reg = pmic - > get_ctrl_reg ( id ) ;
if ( reg < 0 )
return reg ;
switch ( id ) {
case TPS65911_REG_LDO1 :
case TPS65911_REG_LDO2 :
case TPS65911_REG_LDO4 :
return tps65910_modify_bits ( pmic , reg ,
( selector < < LDO_SEL_SHIFT ) , LDO1_SEL_MASK ) ;
case TPS65911_REG_LDO3 :
case TPS65911_REG_LDO5 :
case TPS65911_REG_LDO6 :
case TPS65911_REG_LDO7 :
case TPS65911_REG_LDO8 :
return tps65910_modify_bits ( pmic , reg ,
( selector < < LDO_SEL_SHIFT ) , LDO3_SEL_MASK ) ;
2012-02-17 17:26:11 +04:00
case TPS65910_REG_VIO :
return tps65910_modify_bits ( pmic , reg ,
( selector < < LDO_SEL_SHIFT ) , LDO_SEL_MASK ) ;
2011-05-17 03:35:03 +04:00
}
return - EINVAL ;
}
2011-05-03 01:20:08 +04:00
static int tps65910_list_voltage_dcdc ( struct regulator_dev * dev ,
unsigned selector )
{
2011-05-17 03:35:03 +04:00
int volt , mult = 1 , id = rdev_get_id ( dev ) ;
2011-05-03 01:20:08 +04:00
2011-05-17 03:35:03 +04:00
switch ( id ) {
case TPS65910_REG_VDD1 :
case TPS65910_REG_VDD2 :
2011-11-08 17:24:10 +04:00
mult = ( selector / VDD1_2_NUM_VOLT_FINE ) + 1 ;
2011-05-17 03:35:03 +04:00
volt = VDD1_2_MIN_VOLT +
2011-11-08 17:24:10 +04:00
( selector % VDD1_2_NUM_VOLT_FINE ) * VDD1_2_OFFSET ;
2011-07-10 17:44:09 +04:00
break ;
2011-05-17 03:35:03 +04:00
case TPS65911_REG_VDDCTRL :
volt = VDDCTRL_MIN_VOLT + ( selector * VDDCTRL_OFFSET ) ;
2011-07-10 17:44:09 +04:00
break ;
default :
BUG ( ) ;
return - EINVAL ;
2011-05-17 03:35:03 +04:00
}
2011-05-03 01:20:08 +04:00
return volt * 100 * mult ;
}
static int tps65910_list_voltage ( struct regulator_dev * dev ,
unsigned selector )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int id = rdev_get_id ( dev ) , voltage ;
if ( id < TPS65910_REG_VIO | | id > TPS65910_REG_VMMC )
return - EINVAL ;
2012-01-20 15:06:22 +04:00
if ( selector > = pmic - > info [ id ] - > n_voltages )
2011-05-03 01:20:08 +04:00
return - EINVAL ;
else
2012-01-20 15:06:22 +04:00
voltage = pmic - > info [ id ] - > voltage_table [ selector ] * 1000 ;
2011-05-03 01:20:08 +04:00
return voltage ;
}
2011-05-17 03:35:03 +04:00
static int tps65911_list_voltage ( struct regulator_dev * dev , unsigned selector )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
int step_mv = 0 , id = rdev_get_id ( dev ) ;
switch ( id ) {
case TPS65911_REG_LDO1 :
case TPS65911_REG_LDO2 :
case TPS65911_REG_LDO4 :
/* The first 5 values of the selector correspond to 1V */
if ( selector < 5 )
selector = 0 ;
else
selector - = 4 ;
step_mv = 50 ;
break ;
case TPS65911_REG_LDO3 :
case TPS65911_REG_LDO5 :
case TPS65911_REG_LDO6 :
case TPS65911_REG_LDO7 :
case TPS65911_REG_LDO8 :
/* The first 3 values of the selector correspond to 1V */
if ( selector < 3 )
selector = 0 ;
else
selector - = 2 ;
step_mv = 100 ;
break ;
case TPS65910_REG_VIO :
2012-01-20 15:06:22 +04:00
return pmic - > info [ id ] - > voltage_table [ selector ] * 1000 ;
2011-05-17 03:35:03 +04:00
default :
return - EINVAL ;
}
return ( LDO_MIN_VOLT + selector * step_mv ) * 1000 ;
}
2012-03-14 11:30:58 +04:00
static int tps65910_set_voltage_dcdc_time_sel ( struct regulator_dev * dev ,
unsigned int old_selector , unsigned int new_selector )
{
int id = rdev_get_id ( dev ) ;
int old_volt , new_volt ;
old_volt = tps65910_list_voltage_dcdc ( dev , old_selector ) ;
if ( old_volt < 0 )
return old_volt ;
new_volt = tps65910_list_voltage_dcdc ( dev , new_selector ) ;
if ( new_volt < 0 )
return new_volt ;
/* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
switch ( id ) {
case TPS65910_REG_VDD1 :
case TPS65910_REG_VDD2 :
return DIV_ROUND_UP ( abs ( old_volt - new_volt ) , 12500 ) ;
case TPS65911_REG_VDDCTRL :
return DIV_ROUND_UP ( abs ( old_volt - new_volt ) , 5000 ) ;
}
return - EINVAL ;
}
2011-05-03 01:20:08 +04:00
/* Regulator ops (except VRTC) */
static struct regulator_ops tps65910_ops_dcdc = {
. is_enabled = tps65910_is_enabled ,
. enable = tps65910_enable ,
. disable = tps65910_disable ,
2012-03-13 10:05:20 +04:00
. enable_time = tps65910_enable_time ,
2011-05-03 01:20:08 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
2012-03-14 11:30:58 +04:00
. get_voltage_sel = tps65910_get_voltage_dcdc_sel ,
2012-03-09 06:22:20 +04:00
. set_voltage_sel = tps65910_set_voltage_dcdc_sel ,
2012-03-14 11:30:58 +04:00
. set_voltage_time_sel = tps65910_set_voltage_dcdc_time_sel ,
2011-05-03 01:20:08 +04:00
. list_voltage = tps65910_list_voltage_dcdc ,
} ;
static struct regulator_ops tps65910_ops_vdd3 = {
. is_enabled = tps65910_is_enabled ,
. enable = tps65910_enable ,
. disable = tps65910_disable ,
2012-03-13 10:05:20 +04:00
. enable_time = tps65910_enable_time ,
2011-05-03 01:20:08 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
. get_voltage = tps65910_get_voltage_vdd3 ,
. list_voltage = tps65910_list_voltage ,
} ;
static struct regulator_ops tps65910_ops = {
. is_enabled = tps65910_is_enabled ,
. enable = tps65910_enable ,
. disable = tps65910_disable ,
2012-03-13 10:05:20 +04:00
. enable_time = tps65910_enable_time ,
2011-05-03 01:20:08 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
. get_voltage = tps65910_get_voltage ,
2012-03-09 06:22:20 +04:00
. set_voltage_sel = tps65910_set_voltage_sel ,
2011-05-03 01:20:08 +04:00
. list_voltage = tps65910_list_voltage ,
} ;
2011-05-17 03:35:03 +04:00
static struct regulator_ops tps65911_ops = {
. is_enabled = tps65910_is_enabled ,
. enable = tps65910_enable ,
. disable = tps65910_disable ,
2012-03-13 10:05:20 +04:00
. enable_time = tps65910_enable_time ,
2011-05-17 03:35:03 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
. get_voltage = tps65911_get_voltage ,
2012-03-09 06:22:20 +04:00
. set_voltage_sel = tps65911_set_voltage_sel ,
2011-05-17 03:35:03 +04:00
. list_voltage = tps65911_list_voltage ,
} ;
2012-01-28 13:37:57 +04:00
static int tps65910_set_ext_sleep_config ( struct tps65910_reg * pmic ,
int id , int ext_sleep_config )
{
struct tps65910 * mfd = pmic - > mfd ;
u8 regoffs = ( pmic - > ext_sleep_control [ id ] > > 8 ) & 0xFF ;
u8 bit_pos = ( 1 < < pmic - > ext_sleep_control [ id ] & 0xFF ) ;
int ret ;
/*
* Regulator can not be control from multiple external input EN1 , EN2
* and EN3 together .
*/
if ( ext_sleep_config & EXT_SLEEP_CONTROL ) {
int en_count ;
en_count = ( ( ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 ) ! = 0 ) ;
en_count + = ( ( ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 ) ! = 0 ) ;
en_count + = ( ( ext_sleep_config &
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 ) ! = 0 ) ;
2012-03-07 16:51:49 +04:00
en_count + = ( ( ext_sleep_config &
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP ) ! = 0 ) ;
2012-01-28 13:37:57 +04:00
if ( en_count > 1 ) {
dev_err ( mfd - > dev ,
" External sleep control flag is not proper \n " ) ;
return - EINVAL ;
}
}
pmic - > board_ext_control [ id ] = ext_sleep_config ;
/* External EN1 control */
if ( ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 )
ret = tps65910_set_bits ( mfd ,
TPS65910_EN1_LDO_ASS + regoffs , bit_pos ) ;
else
ret = tps65910_clear_bits ( mfd ,
TPS65910_EN1_LDO_ASS + regoffs , bit_pos ) ;
if ( ret < 0 ) {
dev_err ( mfd - > dev ,
" Error in configuring external control EN1 \n " ) ;
return ret ;
}
/* External EN2 control */
if ( ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 )
ret = tps65910_set_bits ( mfd ,
TPS65910_EN2_LDO_ASS + regoffs , bit_pos ) ;
else
ret = tps65910_clear_bits ( mfd ,
TPS65910_EN2_LDO_ASS + regoffs , bit_pos ) ;
if ( ret < 0 ) {
dev_err ( mfd - > dev ,
" Error in configuring external control EN2 \n " ) ;
return ret ;
}
/* External EN3 control for TPS65910 LDO only */
if ( ( tps65910_chip_id ( mfd ) = = TPS65910 ) & &
( id > = TPS65910_REG_VDIG1 ) ) {
if ( ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 )
ret = tps65910_set_bits ( mfd ,
TPS65910_EN3_LDO_ASS + regoffs , bit_pos ) ;
else
ret = tps65910_clear_bits ( mfd ,
TPS65910_EN3_LDO_ASS + regoffs , bit_pos ) ;
if ( ret < 0 ) {
dev_err ( mfd - > dev ,
" Error in configuring external control EN3 \n " ) ;
return ret ;
}
}
/* Return if no external control is selected */
if ( ! ( ext_sleep_config & EXT_SLEEP_CONTROL ) ) {
/* Clear all sleep controls */
ret = tps65910_clear_bits ( mfd ,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs , bit_pos ) ;
if ( ! ret )
ret = tps65910_clear_bits ( mfd ,
TPS65910_SLEEP_SET_LDO_OFF + regoffs , bit_pos ) ;
if ( ret < 0 )
dev_err ( mfd - > dev ,
" Error in configuring SLEEP register \n " ) ;
return ret ;
}
/*
* For regulator that has separate operational and sleep register make
* sure that operational is used and clear sleep register to turn
* regulator off when external control is inactive
*/
if ( ( id = = TPS65910_REG_VDD1 ) | |
( id = = TPS65910_REG_VDD2 ) | |
( ( id = = TPS65911_REG_VDDCTRL ) & &
( tps65910_chip_id ( mfd ) = = TPS65911 ) ) ) {
int op_reg_add = pmic - > get_ctrl_reg ( id ) + 1 ;
int sr_reg_add = pmic - > get_ctrl_reg ( id ) + 2 ;
int opvsel = tps65910_reg_read ( pmic , op_reg_add ) ;
int srvsel = tps65910_reg_read ( pmic , sr_reg_add ) ;
if ( opvsel & VDD1_OP_CMD_MASK ) {
u8 reg_val = srvsel & VDD1_OP_SEL_MASK ;
ret = tps65910_reg_write ( pmic , op_reg_add , reg_val ) ;
if ( ret < 0 ) {
dev_err ( mfd - > dev ,
" Error in configuring op register \n " ) ;
return ret ;
}
}
ret = tps65910_reg_write ( pmic , sr_reg_add , 0 ) ;
if ( ret < 0 ) {
dev_err ( mfd - > dev , " Error in settting sr register \n " ) ;
return ret ;
}
}
ret = tps65910_clear_bits ( mfd ,
TPS65910_SLEEP_KEEP_LDO_ON + regoffs , bit_pos ) ;
2012-03-07 16:51:49 +04:00
if ( ! ret ) {
if ( ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP )
ret = tps65910_set_bits ( mfd ,
TPS65910_SLEEP_SET_LDO_OFF + regoffs , bit_pos ) ;
else
ret = tps65910_clear_bits ( mfd ,
TPS65910_SLEEP_SET_LDO_OFF + regoffs , bit_pos ) ;
}
2012-01-28 13:37:57 +04:00
if ( ret < 0 )
dev_err ( mfd - > dev ,
" Error in configuring SLEEP register \n " ) ;
2012-03-07 16:51:49 +04:00
2012-01-28 13:37:57 +04:00
return ret ;
}
2011-05-03 01:20:08 +04:00
static __devinit int tps65910_probe ( struct platform_device * pdev )
{
struct tps65910 * tps65910 = dev_get_drvdata ( pdev - > dev . parent ) ;
2011-05-17 03:35:03 +04:00
struct tps_info * info ;
2011-05-03 01:20:08 +04:00
struct regulator_init_data * reg_data ;
struct regulator_dev * rdev ;
struct tps65910_reg * pmic ;
struct tps65910_board * pmic_plat_data ;
int i , err ;
pmic_plat_data = dev_get_platdata ( tps65910 - > dev ) ;
if ( ! pmic_plat_data )
return - EINVAL ;
pmic = kzalloc ( sizeof ( * pmic ) , GFP_KERNEL ) ;
if ( ! pmic )
return - ENOMEM ;
mutex_init ( & pmic - > mutex ) ;
pmic - > mfd = tps65910 ;
platform_set_drvdata ( pdev , pmic ) ;
/* Give control of all register to control port */
tps65910_set_bits ( pmic - > mfd , TPS65910_DEVCTRL ,
DEVCTRL_SR_CTL_I2C_SEL_MASK ) ;
2011-05-17 03:35:03 +04:00
switch ( tps65910_chip_id ( tps65910 ) ) {
case TPS65910 :
pmic - > get_ctrl_reg = & tps65910_get_ctrl_register ;
2011-07-11 05:57:43 +04:00
pmic - > num_regulators = ARRAY_SIZE ( tps65910_regs ) ;
2012-01-28 13:37:57 +04:00
pmic - > ext_sleep_control = tps65910_ext_sleep_control ;
2011-05-17 03:35:03 +04:00
info = tps65910_regs ;
2011-07-10 17:44:09 +04:00
break ;
2011-05-17 03:35:03 +04:00
case TPS65911 :
pmic - > get_ctrl_reg = & tps65911_get_ctrl_register ;
2011-07-11 05:57:43 +04:00
pmic - > num_regulators = ARRAY_SIZE ( tps65911_regs ) ;
2012-01-28 13:37:57 +04:00
pmic - > ext_sleep_control = tps65911_ext_sleep_control ;
2011-05-17 03:35:03 +04:00
info = tps65911_regs ;
2011-07-10 17:44:09 +04:00
break ;
2011-05-17 03:35:03 +04:00
default :
pr_err ( " Invalid tps chip version \n " ) ;
2011-07-10 14:52:07 +04:00
kfree ( pmic ) ;
2011-05-17 03:35:03 +04:00
return - ENODEV ;
}
2011-07-11 05:57:43 +04:00
pmic - > desc = kcalloc ( pmic - > num_regulators ,
sizeof ( struct regulator_desc ) , GFP_KERNEL ) ;
if ( ! pmic - > desc ) {
err = - ENOMEM ;
goto err_free_pmic ;
}
pmic - > info = kcalloc ( pmic - > num_regulators ,
sizeof ( struct tps_info * ) , GFP_KERNEL ) ;
if ( ! pmic - > info ) {
err = - ENOMEM ;
goto err_free_desc ;
}
pmic - > rdev = kcalloc ( pmic - > num_regulators ,
sizeof ( struct regulator_dev * ) , GFP_KERNEL ) ;
if ( ! pmic - > rdev ) {
err = - ENOMEM ;
goto err_free_info ;
}
2011-11-03 21:08:06 +04:00
for ( i = 0 ; i < pmic - > num_regulators & & i < TPS65910_NUM_REGS ;
i + + , info + + ) {
reg_data = pmic_plat_data - > tps65910_pmic_init_data [ i ] ;
/* Regulator API handles empty constraints but not NULL
* constraints */
if ( ! reg_data )
continue ;
2011-05-03 01:20:08 +04:00
/* Register the regulators */
pmic - > info [ i ] = info ;
pmic - > desc [ i ] . name = info - > name ;
2011-05-12 09:47:50 +04:00
pmic - > desc [ i ] . id = i ;
2012-01-20 15:06:22 +04:00
pmic - > desc [ i ] . n_voltages = info - > n_voltages ;
2011-05-03 01:20:08 +04:00
2011-05-17 03:35:03 +04:00
if ( i = = TPS65910_REG_VDD1 | | i = = TPS65910_REG_VDD2 ) {
2011-05-03 01:20:08 +04:00
pmic - > desc [ i ] . ops = & tps65910_ops_dcdc ;
2011-11-08 17:24:10 +04:00
pmic - > desc [ i ] . n_voltages = VDD1_2_NUM_VOLT_FINE *
VDD1_2_NUM_VOLT_COARSE ;
2011-05-17 03:35:03 +04:00
} else if ( i = = TPS65910_REG_VDD3 ) {
if ( tps65910_chip_id ( tps65910 ) = = TPS65910 )
pmic - > desc [ i ] . ops = & tps65910_ops_vdd3 ;
else
pmic - > desc [ i ] . ops = & tps65910_ops_dcdc ;
} else {
if ( tps65910_chip_id ( tps65910 ) = = TPS65910 )
pmic - > desc [ i ] . ops = & tps65910_ops ;
else
pmic - > desc [ i ] . ops = & tps65911_ops ;
}
2011-05-03 01:20:08 +04:00
2012-01-28 13:37:57 +04:00
err = tps65910_set_ext_sleep_config ( pmic , i ,
pmic_plat_data - > regulator_ext_sleep_control [ i ] ) ;
/*
* Failing on regulator for configuring externally control
* is not a serious issue , just throw warning .
*/
if ( err < 0 )
dev_warn ( tps65910 - > dev ,
" Failed to initialise ext control config \n " ) ;
2011-05-03 01:20:08 +04:00
pmic - > desc [ i ] . type = REGULATOR_VOLTAGE ;
pmic - > desc [ i ] . owner = THIS_MODULE ;
rdev = regulator_register ( & pmic - > desc [ i ] ,
2011-11-18 15:17:19 +04:00
tps65910 - > dev , reg_data , pmic , NULL ) ;
2011-05-03 01:20:08 +04:00
if ( IS_ERR ( rdev ) ) {
dev_err ( tps65910 - > dev ,
" failed to register %s regulator \n " ,
pdev - > name ) ;
err = PTR_ERR ( rdev ) ;
2011-07-11 05:57:43 +04:00
goto err_unregister_regulator ;
2011-05-03 01:20:08 +04:00
}
/* Save regulator for cleanup */
pmic - > rdev [ i ] = rdev ;
}
return 0 ;
2011-07-11 05:57:43 +04:00
err_unregister_regulator :
2011-05-03 01:20:08 +04:00
while ( - - i > = 0 )
regulator_unregister ( pmic - > rdev [ i ] ) ;
2011-07-11 05:57:43 +04:00
kfree ( pmic - > rdev ) ;
err_free_info :
kfree ( pmic - > info ) ;
err_free_desc :
kfree ( pmic - > desc ) ;
err_free_pmic :
2011-05-03 01:20:08 +04:00
kfree ( pmic ) ;
return err ;
}
static int __devexit tps65910_remove ( struct platform_device * pdev )
{
2011-07-11 05:57:43 +04:00
struct tps65910_reg * pmic = platform_get_drvdata ( pdev ) ;
2011-05-03 01:20:08 +04:00
int i ;
2011-07-11 05:57:43 +04:00
for ( i = 0 ; i < pmic - > num_regulators ; i + + )
regulator_unregister ( pmic - > rdev [ i ] ) ;
2011-05-03 01:20:08 +04:00
2011-07-11 05:57:43 +04:00
kfree ( pmic - > rdev ) ;
kfree ( pmic - > info ) ;
kfree ( pmic - > desc ) ;
kfree ( pmic ) ;
2011-05-03 01:20:08 +04:00
return 0 ;
}
2012-01-28 13:37:57 +04:00
static void tps65910_shutdown ( struct platform_device * pdev )
{
struct tps65910_reg * pmic = platform_get_drvdata ( pdev ) ;
int i ;
/*
* Before bootloader jumps to kernel , it makes sure that required
* external control signals are in desired state so that given rails
* can be configure accordingly .
* If rails are configured to be controlled from external control
* then before shutting down / rebooting the system , the external
* control configuration need to be remove from the rails so that
* its output will be available as per register programming even
* if external controls are removed . This is require when the POR
* value of the control signals are not in active state and before
* bootloader initializes it , the system requires the rail output
* to be active for booting .
*/
for ( i = 0 ; i < pmic - > num_regulators ; i + + ) {
int err ;
if ( ! pmic - > rdev [ i ] )
continue ;
err = tps65910_set_ext_sleep_config ( pmic , i , 0 ) ;
if ( err < 0 )
dev_err ( & pdev - > dev ,
" Error in clearing external control \n " ) ;
}
}
2011-05-03 01:20:08 +04:00
static struct platform_driver tps65910_driver = {
. driver = {
. name = " tps65910-pmic " ,
. owner = THIS_MODULE ,
} ,
. probe = tps65910_probe ,
. remove = __devexit_p ( tps65910_remove ) ,
2012-01-28 13:37:57 +04:00
. shutdown = tps65910_shutdown ,
2011-05-03 01:20:08 +04:00
} ;
static int __init tps65910_init ( void )
{
return platform_driver_register ( & tps65910_driver ) ;
}
subsys_initcall ( tps65910_init ) ;
static void __exit tps65910_cleanup ( void )
{
platform_driver_unregister ( & tps65910_driver ) ;
}
module_exit ( tps65910_cleanup ) ;
MODULE_AUTHOR ( " Graeme Gregory <gg@slimlogic.co.uk> " ) ;
2012-02-21 06:14:55 +04:00
MODULE_DESCRIPTION ( " TPS65910/TPS65911 voltage regulator driver " ) ;
2011-05-03 01:20:08 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:tps65910-pmic " ) ;