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/slab.h>
# include <linux/gpio.h>
# include <linux/mfd/tps65910.h>
2012-05-08 22:42:41 +04:00
# include <linux/regulator/of_regulator.h>
2011-05-03 01:20:08 +04:00
# 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
2012-06-21 14:48:00 +04:00
/* supported VIO voltages in microvolts */
static const unsigned int VIO_VSEL_table [ ] = {
1500000 , 1800000 , 2500000 , 3300000 ,
2011-05-03 01:20:08 +04:00
} ;
2011-05-17 03:35:03 +04:00
/* VSEL tables for TPS65910 specific LDOs and dcdc's */
2012-06-21 14:48:00 +04:00
/* supported VDD3 voltages in microvolts */
static const unsigned int VDD3_VSEL_table [ ] = {
5000000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VDIG1 voltages in microvolts */
static const unsigned int VDIG1_VSEL_table [ ] = {
1200000 , 1500000 , 1800000 , 2700000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VDIG2 voltages in microvolts */
static const unsigned int VDIG2_VSEL_table [ ] = {
1000000 , 1100000 , 1200000 , 1800000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VPLL voltages in microvolts */
static const unsigned int VPLL_VSEL_table [ ] = {
1000000 , 1100000 , 1800000 , 2500000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VDAC voltages in microvolts */
static const unsigned int VDAC_VSEL_table [ ] = {
1800000 , 2600000 , 2800000 , 2850000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VAUX1 voltages in microvolts */
static const unsigned int VAUX1_VSEL_table [ ] = {
1800000 , 2500000 , 2800000 , 2850000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VAUX2 voltages in microvolts */
static const unsigned int VAUX2_VSEL_table [ ] = {
1800000 , 2800000 , 2900000 , 3300000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VAUX33 voltages in microvolts */
static const unsigned int VAUX33_VSEL_table [ ] = {
1800000 , 2000000 , 2800000 , 3300000 ,
2011-05-03 01:20:08 +04:00
} ;
2012-06-21 14:48:00 +04:00
/* supported VMMC voltages in microvolts */
static const unsigned int VMMC_VSEL_table [ ] = {
1800000 , 2800000 , 3000000 , 3300000 ,
2011-05-03 01:20:08 +04:00
} ;
struct tps_info {
const char * name ;
2012-07-06 12:43:12 +04:00
const char * vin_name ;
2012-01-20 15:06:22 +04:00
u8 n_voltages ;
2012-06-21 14:48:00 +04:00
const unsigned int * 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 [ ] = {
{
2012-05-19 18:34:06 +04:00
. name = " vrtc " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc7 " ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 2200 ,
2011-05-03 01:20:08 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vio " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vccio " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdd1 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc1 " ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-03 01:20:08 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdd2 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc2 " ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-03 01:20:08 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdd3 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdig1 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc6 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdig2 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc6 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vpll " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc5 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdac " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc5 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vaux1 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc4 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vaux2 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc4 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vaux33 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc3 " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vmmc " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc3 " ,
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
{
2012-05-19 18:34:06 +04:00
. name = " vrtc " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc7 " ,
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
{
2012-05-19 18:34:06 +04:00
. name = " vio " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vccio " ,
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
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdd1 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc1 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x4C ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vdd2 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc2 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x4C ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 350 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " vddctrl " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x44 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 900 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo1 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc6 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x33 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 420 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo2 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc6 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x33 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 420 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo3 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc5 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x1A ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo4 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc5 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x33 ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo5 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc4 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x1A ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo6 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc3 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x1A ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo7 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc3 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x1A ,
2012-03-13 10:05:20 +04:00
. enable_time_us = 230 ,
2011-05-17 03:35:03 +04:00
} ,
{
2012-05-19 18:34:06 +04:00
. name = " ldo8 " ,
2012-07-06 12:43:12 +04:00
. vin_name = " vcc3 " ,
2012-07-09 18:57:13 +04:00
. n_voltages = 0x1A ,
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 ;
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 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_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 :
2012-07-11 15:44:13 +04:00
return tps65910_reg_update_bits ( pmic - > mfd , reg ,
LDO_ST_MODE_BIT | LDO_ST_ON_BIT ,
LDO_ST_ON_BIT ) ;
2011-05-03 01:20:08 +04:00
case REGULATOR_MODE_IDLE :
value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT ;
2012-05-08 22:42:38 +04:00
return tps65910_reg_set_bits ( mfd , reg , value ) ;
2011-05-03 01:20:08 +04:00
case REGULATOR_MODE_STANDBY :
2012-05-08 22:42:38 +04:00
return tps65910_reg_clear_bits ( mfd , reg , LDO_ST_ON_BIT ) ;
2011-05-03 01:20:08 +04:00
}
return - EINVAL ;
}
static unsigned int tps65910_get_mode ( struct regulator_dev * dev )
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
2012-07-11 15:44:13 +04:00
int ret , reg , value , id = rdev_get_id ( dev ) ;
2011-05-03 01:20:08 +04:00
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 ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , reg , & value ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
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-07-11 15:44:13 +04:00
int ret , 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 :
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD1_OP , & opvsel ) ;
if ( ret < 0 )
return ret ;
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD1 , & mult ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
mult = ( mult & VDD1_VGAIN_SEL_MASK ) > > VDD1_VGAIN_SEL_SHIFT ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD1_SR , & srvsel ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
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 :
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD2_OP , & opvsel ) ;
if ( ret < 0 )
return ret ;
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD2 , & mult ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
mult = ( mult & VDD2_VGAIN_SEL_MASK ) > > VDD2_VGAIN_SEL_SHIFT ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , TPS65910_VDD2_SR , & srvsel ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
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 :
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , TPS65911_VDDCTRL_OP ,
& opvsel ) ;
if ( ret < 0 )
return ret ;
ret = tps65910_reg_read ( pmic - > mfd , TPS65911_VDDCTRL_SR ,
& srvsel ) ;
if ( ret < 0 )
return ret ;
2011-05-17 03:35:03 +04:00
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
}
2012-05-09 05:22:47 +04:00
static int tps65910_get_voltage_sel ( struct regulator_dev * dev )
2011-05-03 01:20:08 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
2012-07-11 15:44:13 +04:00
int ret , reg , value , id = rdev_get_id ( dev ) ;
2011-05-03 01:20:08 +04:00
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 ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , reg , & value ) ;
if ( ret < 0 )
return ret ;
2011-05-03 01:20:08 +04:00
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-05-09 05:22:47 +04:00
return value ;
2011-05-03 01:20:08 +04:00
}
static int tps65910_get_voltage_vdd3 ( struct regulator_dev * dev )
{
2012-06-21 14:48:00 +04:00
return dev - > desc - > volt_table [ 0 ] ;
2011-05-03 01:20:08 +04:00
}
2012-05-09 05:22:47 +04:00
static int tps65911_get_voltage_sel ( struct regulator_dev * dev )
2011-05-17 03:35:03 +04:00
{
struct tps65910_reg * pmic = rdev_get_drvdata ( dev ) ;
2012-07-11 15:44:13 +04:00
int ret , id = rdev_get_id ( dev ) ;
unsigned int value , reg ;
2011-05-17 03:35:03 +04:00
reg = pmic - > get_ctrl_reg ( id ) ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_read ( pmic - > mfd , reg , & value ) ;
if ( ret < 0 )
return ret ;
2011-05-17 03:35:03 +04:00
switch ( id ) {
case TPS65911_REG_LDO1 :
case TPS65911_REG_LDO2 :
case TPS65911_REG_LDO4 :
value & = LDO1_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
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 ;
break ;
case TPS65910_REG_VIO :
2012-02-17 17:26:11 +04:00
value & = LDO_SEL_MASK ;
value > > = LDO_SEL_SHIFT ;
2012-05-09 05:22:47 +04:00
break ;
2011-05-17 03:35:03 +04:00
default :
return - EINVAL ;
}
2012-05-09 05:22:47 +04:00
return value ;
2011-05-17 03:35:03 +04:00
}
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
2012-07-11 15:44:13 +04:00
tps65910_reg_update_bits ( pmic - > mfd , TPS65910_VDD1 ,
VDD1_VGAIN_SEL_MASK ,
dcdc_mult < < VDD1_VGAIN_SEL_SHIFT ) ;
tps65910_reg_write ( pmic - > mfd , 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
2012-07-11 15:44:13 +04:00
tps65910_reg_update_bits ( pmic - > mfd , TPS65910_VDD2 ,
VDD1_VGAIN_SEL_MASK ,
dcdc_mult < < VDD2_VGAIN_SEL_SHIFT ) ;
tps65910_reg_write ( pmic - > mfd , 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 ;
2012-07-11 15:44:13 +04:00
tps65910_reg_write ( pmic - > mfd , 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 :
2012-07-11 15:44:13 +04:00
return tps65910_reg_update_bits ( pmic - > mfd , reg , LDO_SEL_MASK ,
selector < < LDO_SEL_SHIFT ) ;
2011-05-03 01:20:08 +04:00
}
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 :
2012-07-11 15:44:13 +04:00
return tps65910_reg_update_bits ( pmic - > mfd , reg , LDO1_SEL_MASK ,
selector < < LDO_SEL_SHIFT ) ;
2011-05-17 03:35:03 +04:00
case TPS65911_REG_LDO3 :
case TPS65911_REG_LDO5 :
case TPS65911_REG_LDO6 :
case TPS65911_REG_LDO7 :
case TPS65911_REG_LDO8 :
2012-07-11 15:44:13 +04:00
return tps65910_reg_update_bits ( pmic - > mfd , reg , LDO3_SEL_MASK ,
selector < < LDO_SEL_SHIFT ) ;
2012-02-17 17:26:11 +04:00
case TPS65910_REG_VIO :
2012-07-11 15:44:13 +04:00
return tps65910_reg_update_bits ( pmic - > mfd , reg , LDO_SEL_MASK ,
selector < < LDO_SEL_SHIFT ) ;
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 ;
}
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-06-21 14:48:00 +04:00
return pmic - > info [ id ] - > voltage_table [ selector ] ;
2011-05-17 03:35:03 +04:00
default :
return - EINVAL ;
}
return ( LDO_MIN_VOLT + selector * step_mv ) * 1000 ;
}
2011-05-03 01:20:08 +04:00
/* Regulator ops (except VRTC) */
static struct regulator_ops tps65910_ops_dcdc = {
2012-04-17 10:34:46 +04:00
. is_enabled = regulator_is_enabled_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
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-06-20 18:40:10 +04:00
. set_voltage_time_sel = regulator_set_voltage_time_sel ,
2011-05-03 01:20:08 +04:00
. list_voltage = tps65910_list_voltage_dcdc ,
} ;
static struct regulator_ops tps65910_ops_vdd3 = {
2012-04-17 10:34:46 +04:00
. is_enabled = regulator_is_enabled_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
2011-05-03 01:20:08 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
. get_voltage = tps65910_get_voltage_vdd3 ,
2012-06-21 14:48:00 +04:00
. list_voltage = regulator_list_voltage_table ,
2011-05-03 01:20:08 +04:00
} ;
static struct regulator_ops tps65910_ops = {
2012-04-17 10:34:46 +04:00
. is_enabled = regulator_is_enabled_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
2011-05-03 01:20:08 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
2012-05-09 05:22:47 +04:00
. get_voltage_sel = tps65910_get_voltage_sel ,
2012-03-09 06:22:20 +04:00
. set_voltage_sel = tps65910_set_voltage_sel ,
2012-06-21 14:48:00 +04:00
. list_voltage = regulator_list_voltage_table ,
2011-05-03 01:20:08 +04:00
} ;
2011-05-17 03:35:03 +04:00
static struct regulator_ops tps65911_ops = {
2012-04-17 10:34:46 +04:00
. is_enabled = regulator_is_enabled_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
2011-05-17 03:35:03 +04:00
. set_mode = tps65910_set_mode ,
. get_mode = tps65910_get_mode ,
2012-05-09 05:22:47 +04:00
. get_voltage_sel = tps65911_get_voltage_sel ,
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 )
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_set_bits ( mfd ,
2012-01-28 13:37:57 +04:00
TPS65910_EN1_LDO_ASS + regoffs , bit_pos ) ;
else
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
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 )
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_set_bits ( mfd ,
2012-01-28 13:37:57 +04:00
TPS65910_EN2_LDO_ASS + regoffs , bit_pos ) ;
else
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
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 )
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_set_bits ( mfd ,
2012-01-28 13:37:57 +04:00
TPS65910_EN3_LDO_ASS + regoffs , bit_pos ) ;
else
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
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 */
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
TPS65910_SLEEP_KEEP_LDO_ON + regoffs , bit_pos ) ;
if ( ! ret )
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
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 ;
2012-07-11 15:44:13 +04:00
int opvsel , srvsel ;
ret = tps65910_reg_read ( pmic - > mfd , op_reg_add , & opvsel ) ;
if ( ret < 0 )
return ret ;
ret = tps65910_reg_read ( pmic - > mfd , sr_reg_add , & srvsel ) ;
if ( ret < 0 )
return ret ;
2012-01-28 13:37:57 +04:00
if ( opvsel & VDD1_OP_CMD_MASK ) {
u8 reg_val = srvsel & VDD1_OP_SEL_MASK ;
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_write ( pmic - > mfd , op_reg_add ,
reg_val ) ;
2012-01-28 13:37:57 +04:00
if ( ret < 0 ) {
dev_err ( mfd - > dev ,
" Error in configuring op register \n " ) ;
return ret ;
}
}
2012-07-11 15:44:13 +04:00
ret = tps65910_reg_write ( pmic - > mfd , sr_reg_add , 0 ) ;
2012-01-28 13:37:57 +04:00
if ( ret < 0 ) {
dev_err ( mfd - > dev , " Error in settting sr register \n " ) ;
return ret ;
}
}
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-01-28 13:37:57 +04:00
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 )
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_set_bits ( mfd ,
2012-03-07 16:51:49 +04:00
TPS65910_SLEEP_SET_LDO_OFF + regoffs , bit_pos ) ;
else
2012-05-08 22:42:38 +04:00
ret = tps65910_reg_clear_bits ( mfd ,
2012-03-07 16:51:49 +04:00
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 ;
}
2012-05-08 22:42:41 +04:00
# ifdef CONFIG_OF
static struct of_regulator_match tps65910_matches [ ] = {
2012-05-19 18:34:06 +04:00
{ . name = " vrtc " , . driver_data = ( void * ) & tps65910_regs [ 0 ] } ,
{ . name = " vio " , . driver_data = ( void * ) & tps65910_regs [ 1 ] } ,
{ . name = " vdd1 " , . driver_data = ( void * ) & tps65910_regs [ 2 ] } ,
{ . name = " vdd2 " , . driver_data = ( void * ) & tps65910_regs [ 3 ] } ,
{ . name = " vdd3 " , . driver_data = ( void * ) & tps65910_regs [ 4 ] } ,
{ . name = " vdig1 " , . driver_data = ( void * ) & tps65910_regs [ 5 ] } ,
{ . name = " vdig2 " , . driver_data = ( void * ) & tps65910_regs [ 6 ] } ,
{ . name = " vpll " , . driver_data = ( void * ) & tps65910_regs [ 7 ] } ,
{ . name = " vdac " , . driver_data = ( void * ) & tps65910_regs [ 8 ] } ,
{ . name = " vaux1 " , . driver_data = ( void * ) & tps65910_regs [ 9 ] } ,
{ . name = " vaux2 " , . driver_data = ( void * ) & tps65910_regs [ 10 ] } ,
{ . name = " vaux33 " , . driver_data = ( void * ) & tps65910_regs [ 11 ] } ,
{ . name = " vmmc " , . driver_data = ( void * ) & tps65910_regs [ 12 ] } ,
2012-05-08 22:42:41 +04:00
} ;
static struct of_regulator_match tps65911_matches [ ] = {
2012-05-19 18:34:06 +04:00
{ . name = " vrtc " , . driver_data = ( void * ) & tps65911_regs [ 0 ] } ,
{ . name = " vio " , . driver_data = ( void * ) & tps65911_regs [ 1 ] } ,
{ . name = " vdd1 " , . driver_data = ( void * ) & tps65911_regs [ 2 ] } ,
{ . name = " vdd2 " , . driver_data = ( void * ) & tps65911_regs [ 3 ] } ,
{ . name = " vddctrl " , . driver_data = ( void * ) & tps65911_regs [ 4 ] } ,
{ . name = " ldo1 " , . driver_data = ( void * ) & tps65911_regs [ 5 ] } ,
{ . name = " ldo2 " , . driver_data = ( void * ) & tps65911_regs [ 6 ] } ,
{ . name = " ldo3 " , . driver_data = ( void * ) & tps65911_regs [ 7 ] } ,
{ . name = " ldo4 " , . driver_data = ( void * ) & tps65911_regs [ 8 ] } ,
{ . name = " ldo5 " , . driver_data = ( void * ) & tps65911_regs [ 9 ] } ,
{ . name = " ldo6 " , . driver_data = ( void * ) & tps65911_regs [ 10 ] } ,
{ . name = " ldo7 " , . driver_data = ( void * ) & tps65911_regs [ 11 ] } ,
{ . name = " ldo8 " , . driver_data = ( void * ) & tps65911_regs [ 12 ] } ,
2012-05-08 22:42:41 +04:00
} ;
static struct tps65910_board * tps65910_parse_dt_reg_data (
2012-05-20 20:18:50 +04:00
struct platform_device * pdev ,
struct of_regulator_match * * tps65910_reg_matches )
2012-05-08 22:42:41 +04:00
{
struct tps65910_board * pmic_plat_data ;
struct tps65910 * tps65910 = dev_get_drvdata ( pdev - > dev . parent ) ;
struct device_node * np = pdev - > dev . parent - > of_node ;
struct device_node * regulators ;
struct of_regulator_match * matches ;
unsigned int prop ;
int idx = 0 , ret , count ;
pmic_plat_data = devm_kzalloc ( & pdev - > dev , sizeof ( * pmic_plat_data ) ,
GFP_KERNEL ) ;
if ( ! pmic_plat_data ) {
dev_err ( & pdev - > dev , " Failure to alloc pdata for regulators. \n " ) ;
return NULL ;
}
regulators = of_find_node_by_name ( np , " regulators " ) ;
2012-05-20 20:18:49 +04:00
if ( ! regulators ) {
dev_err ( & pdev - > dev , " regulator node not found \n " ) ;
return NULL ;
}
2012-05-08 22:42:41 +04:00
switch ( tps65910_chip_id ( tps65910 ) ) {
case TPS65910 :
count = ARRAY_SIZE ( tps65910_matches ) ;
matches = tps65910_matches ;
break ;
case TPS65911 :
count = ARRAY_SIZE ( tps65911_matches ) ;
matches = tps65911_matches ;
break ;
default :
2012-05-20 20:18:48 +04:00
dev_err ( & pdev - > dev , " Invalid tps chip version \n " ) ;
2012-05-08 22:42:41 +04:00
return NULL ;
}
ret = of_regulator_match ( pdev - > dev . parent , regulators , matches , count ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Error parsing regulator init data: %d \n " ,
ret ) ;
return NULL ;
}
2012-05-20 20:18:50 +04:00
* tps65910_reg_matches = matches ;
2012-05-08 22:42:41 +04:00
for ( idx = 0 ; idx < count ; idx + + ) {
if ( ! matches [ idx ] . init_data | | ! matches [ idx ] . of_node )
continue ;
pmic_plat_data - > tps65910_pmic_init_data [ idx ] =
matches [ idx ] . init_data ;
ret = of_property_read_u32 ( matches [ idx ] . of_node ,
" ti,regulator-ext-sleep-control " , & prop ) ;
if ( ! ret )
pmic_plat_data - > regulator_ext_sleep_control [ idx ] = prop ;
2012-07-06 12:43:12 +04:00
2012-05-08 22:42:41 +04:00
}
return pmic_plat_data ;
}
# else
static inline struct tps65910_board * tps65910_parse_dt_reg_data (
2012-05-20 20:18:50 +04:00
struct platform_device * pdev ,
struct of_regulator_match * * tps65910_reg_matches )
2012-05-08 22:42:41 +04:00
{
2012-05-20 20:18:50 +04:00
* tps65910_reg_matches = NULL ;
2012-06-15 22:04:33 +04:00
return NULL ;
2012-05-08 22:42:41 +04:00
}
# endif
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 ) ;
2012-04-04 03:50:22 +04:00
struct regulator_config config = { } ;
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 ;
2012-05-20 20:18:50 +04:00
struct of_regulator_match * tps65910_reg_matches = NULL ;
2011-05-03 01:20:08 +04:00
int i , err ;
pmic_plat_data = dev_get_platdata ( tps65910 - > dev ) ;
2012-05-08 22:42:41 +04:00
if ( ! pmic_plat_data & & tps65910 - > dev - > of_node )
2012-05-20 20:18:50 +04:00
pmic_plat_data = tps65910_parse_dt_reg_data ( pdev ,
& tps65910_reg_matches ) ;
2012-05-08 22:42:41 +04:00
2012-05-20 20:18:48 +04:00
if ( ! pmic_plat_data ) {
dev_err ( & pdev - > dev , " Platform data not found \n " ) ;
2011-05-03 01:20:08 +04:00
return - EINVAL ;
2012-05-20 20:18:48 +04:00
}
2011-05-03 01:20:08 +04:00
2012-04-11 10:40:18 +04:00
pmic = devm_kzalloc ( & pdev - > dev , sizeof ( * pmic ) , GFP_KERNEL ) ;
2012-05-20 20:18:48 +04:00
if ( ! pmic ) {
dev_err ( & pdev - > dev , " Memory allocation failed for pmic \n " ) ;
2011-05-03 01:20:08 +04:00
return - ENOMEM ;
2012-05-20 20:18:48 +04:00
}
2011-05-03 01:20:08 +04:00
pmic - > mfd = tps65910 ;
platform_set_drvdata ( pdev , pmic ) ;
/* Give control of all register to control port */
2012-05-08 22:42:38 +04:00
tps65910_reg_set_bits ( pmic - > mfd , TPS65910_DEVCTRL ,
2011-05-03 01:20:08 +04:00
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 :
2012-05-20 20:18:48 +04:00
dev_err ( & pdev - > dev , " Invalid tps chip version \n " ) ;
2011-05-17 03:35:03 +04:00
return - ENODEV ;
}
2012-05-19 18:34:09 +04:00
pmic - > desc = devm_kzalloc ( & pdev - > dev , pmic - > num_regulators *
2011-07-11 05:57:43 +04:00
sizeof ( struct regulator_desc ) , GFP_KERNEL ) ;
if ( ! pmic - > desc ) {
2012-05-19 18:34:09 +04:00
dev_err ( & pdev - > dev , " Memory alloc fails for desc \n " ) ;
return - ENOMEM ;
2011-07-11 05:57:43 +04:00
}
2012-05-19 18:34:09 +04:00
pmic - > info = devm_kzalloc ( & pdev - > dev , pmic - > num_regulators *
2011-07-11 05:57:43 +04:00
sizeof ( struct tps_info * ) , GFP_KERNEL ) ;
if ( ! pmic - > info ) {
2012-05-19 18:34:09 +04:00
dev_err ( & pdev - > dev , " Memory alloc fails for info \n " ) ;
return - ENOMEM ;
2011-07-11 05:57:43 +04:00
}
2012-05-19 18:34:09 +04:00
pmic - > rdev = devm_kzalloc ( & pdev - > dev , pmic - > num_regulators *
2011-07-11 05:57:43 +04:00
sizeof ( struct regulator_dev * ) , GFP_KERNEL ) ;
if ( ! pmic - > rdev ) {
2012-05-19 18:34:09 +04:00
dev_err ( & pdev - > dev , " Memory alloc fails for rdev \n " ) ;
return - ENOMEM ;
2011-07-11 05:57:43 +04:00
}
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 ;
2012-07-17 10:04:06 +04:00
pmic - > desc [ i ] . supply_name = info - > vin_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 ;
2012-07-04 05:59:17 +04:00
pmic - > desc [ i ] . enable_time = info - > enable_time_us ;
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 ;
2012-06-20 18:40:10 +04:00
pmic - > desc [ i ] . ramp_delay = 12500 ;
2011-05-17 03:35:03 +04:00
} else if ( i = = TPS65910_REG_VDD3 ) {
2012-06-20 18:40:10 +04:00
if ( tps65910_chip_id ( tps65910 ) = = TPS65910 ) {
2011-05-17 03:35:03 +04:00
pmic - > desc [ i ] . ops = & tps65910_ops_vdd3 ;
2012-06-21 14:48:00 +04:00
pmic - > desc [ i ] . volt_table = info - > voltage_table ;
2012-06-20 18:40:10 +04:00
} else {
2011-05-17 03:35:03 +04:00
pmic - > desc [ i ] . ops = & tps65910_ops_dcdc ;
2012-06-20 18:40:10 +04:00
pmic - > desc [ i ] . ramp_delay = 5000 ;
}
2011-05-17 03:35:03 +04:00
} else {
2012-06-21 14:48:00 +04:00
if ( tps65910_chip_id ( tps65910 ) = = TPS65910 ) {
2011-05-17 03:35:03 +04:00
pmic - > desc [ i ] . ops = & tps65910_ops ;
2012-06-21 14:48:00 +04:00
pmic - > desc [ i ] . volt_table = info - > voltage_table ;
} else {
2011-05-17 03:35:03 +04:00
pmic - > desc [ i ] . ops = & tps65911_ops ;
2012-06-21 14:48:00 +04:00
}
2011-05-17 03:35:03 +04:00
}
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 ;
2012-04-17 10:34:46 +04:00
pmic - > desc [ i ] . enable_reg = pmic - > get_ctrl_reg ( i ) ;
pmic - > desc [ i ] . enable_mask = TPS65910_SUPPLY_STATE_ENABLED ;
2011-05-03 01:20:08 +04:00
2012-04-04 03:50:22 +04:00
config . dev = tps65910 - > dev ;
config . init_data = reg_data ;
config . driver_data = pmic ;
2012-04-17 10:34:46 +04:00
config . regmap = tps65910 - > regmap ;
2012-04-04 03:50:22 +04:00
2012-05-20 20:18:50 +04:00
if ( tps65910_reg_matches )
config . of_node = tps65910_reg_matches [ i ] . of_node ;
2012-05-08 22:42:41 +04:00
2012-04-04 03:50:22 +04:00
rdev = regulator_register ( & pmic - > desc [ i ] , & config ) ;
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 ] ) ;
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
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 " ) ;