2009-06-27 07:18:02 +04:00
/*
* PCAP2 Regulator Driver
*
* Copyright ( c ) 2009 Daniel Ribeiro < drwyrm @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/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/mfd/ezx-pcap.h>
2012-06-06 04:36:37 +04:00
static const unsigned int V1_table [ ] = {
2775000 , 1275000 , 1600000 , 1725000 , 1825000 , 1925000 , 2075000 , 2275000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V2_table [ ] = {
2500000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V3_table [ ] = {
1075000 , 1275000 , 1550000 , 1725000 , 1876000 , 1950000 , 2075000 , 2275000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V4_table [ ] = {
1275000 , 1550000 , 1725000 , 1875000 , 1950000 , 2075000 , 2275000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V5_table [ ] = {
1875000 , 2275000 , 2475000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V6_table [ ] = {
2475000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V7_table [ ] = {
1875000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
# define V8_table V4_table
2012-06-06 04:36:37 +04:00
static const unsigned int V9_table [ ] = {
1575000 , 1875000 , 2475000 , 2775000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int V10_table [ ] = {
5000000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int VAUX1_table [ ] = {
1875000 , 2475000 , 2775000 , 3000000 ,
2009-06-27 07:18:02 +04:00
} ;
# define VAUX2_table VAUX1_table
2012-06-06 04:36:37 +04:00
static const unsigned int VAUX3_table [ ] = {
1200000 , 1200000 , 1200000 , 1200000 , 1400000 , 1600000 , 1800000 , 2000000 ,
2200000 , 2400000 , 2600000 , 2800000 , 3000000 , 3200000 , 3400000 , 3600000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int VAUX4_table [ ] = {
1800000 , 1800000 , 3000000 , 5000000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int VSIM_table [ ] = {
1875000 , 3000000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int VSIM2_table [ ] = {
1875000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int VVIB_table [ ] = {
1300000 , 1800000 , 2000000 , 3000000 ,
2009-06-27 07:18:02 +04:00
} ;
2012-06-06 04:36:37 +04:00
static const unsigned int SW1_table [ ] = {
900000 , 950000 , 1000000 , 1050000 , 1100000 , 1150000 , 1200000 , 1250000 ,
1300000 , 1350000 , 1400000 , 1450000 , 1500000 , 1600000 , 1875000 , 2250000 ,
2009-06-27 07:18:02 +04:00
} ;
# define SW2_table SW1_table
2012-06-06 04:36:37 +04:00
static const unsigned int SW3_table [ ] = {
4000000 , 4500000 , 5000000 , 5500000 ,
2009-06-27 07:18:02 +04:00
} ;
struct pcap_regulator {
const u8 reg ;
const u8 en ;
const u8 index ;
const u8 stby ;
const u8 lowpwr ;
} ;
# define NA 0xff
# define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr) \
[ _vreg ] = { \
. reg = _reg , \
. en = _en , \
. index = _index , \
. stby = _stby , \
. lowpwr = _lowpwr , \
}
static struct pcap_regulator vreg_table [ ] = {
VREG_INFO ( V1 , PCAP_REG_VREG1 , 1 , 2 , 18 , 0 ) ,
VREG_INFO ( V2 , PCAP_REG_VREG1 , 5 , 6 , 19 , 22 ) ,
VREG_INFO ( V3 , PCAP_REG_VREG1 , 7 , 8 , 20 , 23 ) ,
VREG_INFO ( V4 , PCAP_REG_VREG1 , 11 , 12 , 21 , 24 ) ,
/* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */
VREG_INFO ( V5 , PCAP_REG_VREG1 , 15 , 16 , 12 , 19 ) ,
VREG_INFO ( V6 , PCAP_REG_VREG2 , 1 , 2 , 14 , 20 ) ,
VREG_INFO ( V7 , PCAP_REG_VREG2 , 3 , 4 , 15 , 21 ) ,
VREG_INFO ( V8 , PCAP_REG_VREG2 , 5 , 6 , 16 , 22 ) ,
VREG_INFO ( V9 , PCAP_REG_VREG2 , 9 , 10 , 17 , 23 ) ,
VREG_INFO ( V10 , PCAP_REG_VREG2 , 10 , NA , 18 , 24 ) ,
VREG_INFO ( VAUX1 , PCAP_REG_AUXVREG , 1 , 2 , 22 , 23 ) ,
/* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */
VREG_INFO ( VAUX2 , PCAP_REG_AUXVREG , 4 , 5 , 0 , 1 ) ,
VREG_INFO ( VAUX3 , PCAP_REG_AUXVREG , 7 , 8 , 2 , 3 ) ,
VREG_INFO ( VAUX4 , PCAP_REG_AUXVREG , 12 , 13 , 4 , 5 ) ,
VREG_INFO ( VSIM , PCAP_REG_AUXVREG , 17 , 18 , NA , 6 ) ,
VREG_INFO ( VSIM2 , PCAP_REG_AUXVREG , 16 , NA , NA , 7 ) ,
VREG_INFO ( VVIB , PCAP_REG_AUXVREG , 19 , 20 , NA , NA ) ,
VREG_INFO ( SW1 , PCAP_REG_SWCTRL , 1 , 2 , NA , NA ) ,
VREG_INFO ( SW2 , PCAP_REG_SWCTRL , 6 , 7 , NA , NA ) ,
/* SW3 STBY is on PCAP_REG_AUXVREG */
VREG_INFO ( SW3 , PCAP_REG_SWCTRL , 11 , 12 , 24 , NA ) ,
/* SWxS used to control SWx voltage on standby */
/* VREG_INFO(SW1S, PCAP_REG_LOWPWR, NA, 12, NA, NA),
VREG_INFO ( SW2S , PCAP_REG_LOWPWR , NA , 20 , NA , NA ) , */
} ;
2012-03-23 12:49:22 +04:00
static int pcap_regulator_set_voltage_sel ( struct regulator_dev * rdev ,
unsigned selector )
2009-06-27 07:18:02 +04:00
{
struct pcap_regulator * vreg = & vreg_table [ rdev_get_id ( rdev ) ] ;
void * pcap = rdev_get_drvdata ( rdev ) ;
/* the regulator doesn't support voltage switching */
2012-06-06 04:36:37 +04:00
if ( rdev - > desc - > n_voltages = = 1 )
2009-06-27 07:18:02 +04:00
return - EINVAL ;
2012-03-23 12:49:22 +04:00
return ezx_pcap_set_bits ( pcap , vreg - > reg ,
2012-06-06 04:36:37 +04:00
( rdev - > desc - > n_voltages - 1 ) < < vreg - > index ,
2012-03-23 12:49:22 +04:00
selector < < vreg - > index ) ;
2009-06-27 07:18:02 +04:00
}
2012-03-23 12:50:40 +04:00
static int pcap_regulator_get_voltage_sel ( struct regulator_dev * rdev )
2009-06-27 07:18:02 +04:00
{
struct pcap_regulator * vreg = & vreg_table [ rdev_get_id ( rdev ) ] ;
void * pcap = rdev_get_drvdata ( rdev ) ;
u32 tmp ;
2012-06-06 04:36:37 +04:00
if ( rdev - > desc - > n_voltages = = 1 )
2012-03-23 12:50:40 +04:00
return 0 ;
2009-06-27 07:18:02 +04:00
ezx_pcap_read ( pcap , vreg - > reg , & tmp ) ;
2012-06-06 04:36:37 +04:00
tmp = ( ( tmp > > vreg - > index ) & ( rdev - > desc - > n_voltages - 1 ) ) ;
2012-03-23 12:50:40 +04:00
return tmp ;
2009-06-27 07:18:02 +04:00
}
static int pcap_regulator_enable ( struct regulator_dev * rdev )
{
struct pcap_regulator * vreg = & vreg_table [ rdev_get_id ( rdev ) ] ;
void * pcap = rdev_get_drvdata ( rdev ) ;
if ( vreg - > en = = NA )
return - EINVAL ;
return ezx_pcap_set_bits ( pcap , vreg - > reg , 1 < < vreg - > en , 1 < < vreg - > en ) ;
}
static int pcap_regulator_disable ( struct regulator_dev * rdev )
{
struct pcap_regulator * vreg = & vreg_table [ rdev_get_id ( rdev ) ] ;
void * pcap = rdev_get_drvdata ( rdev ) ;
if ( vreg - > en = = NA )
return - EINVAL ;
return ezx_pcap_set_bits ( pcap , vreg - > reg , 1 < < vreg - > en , 0 ) ;
}
static int pcap_regulator_is_enabled ( struct regulator_dev * rdev )
{
struct pcap_regulator * vreg = & vreg_table [ rdev_get_id ( rdev ) ] ;
void * pcap = rdev_get_drvdata ( rdev ) ;
u32 tmp ;
if ( vreg - > en = = NA )
return - EINVAL ;
ezx_pcap_read ( pcap , vreg - > reg , & tmp ) ;
return ( tmp > > vreg - > en ) & 1 ;
}
static struct regulator_ops pcap_regulator_ops = {
2012-06-06 04:36:37 +04:00
. list_voltage = regulator_list_voltage_table ,
2012-03-23 12:49:22 +04:00
. set_voltage_sel = pcap_regulator_set_voltage_sel ,
2012-03-23 12:50:40 +04:00
. get_voltage_sel = pcap_regulator_get_voltage_sel ,
2009-06-27 07:18:02 +04:00
. enable = pcap_regulator_enable ,
. disable = pcap_regulator_disable ,
. is_enabled = pcap_regulator_is_enabled ,
} ;
# define VREG(_vreg) \
[ _vreg ] = { \
. name = # _vreg , \
. id = _vreg , \
. n_voltages = ARRAY_SIZE ( _vreg # # _table ) , \
2012-06-06 04:36:37 +04:00
. volt_table = _vreg # # _table , \
2009-06-27 07:18:02 +04:00
. ops = & pcap_regulator_ops , \
. type = REGULATOR_VOLTAGE , \
. owner = THIS_MODULE , \
}
2012-04-05 08:01:33 +04:00
static const struct regulator_desc pcap_regulators [ ] = {
2009-06-27 07:18:02 +04:00
VREG ( V1 ) , VREG ( V2 ) , VREG ( V3 ) , VREG ( V4 ) , VREG ( V5 ) , VREG ( V6 ) , VREG ( V7 ) ,
VREG ( V8 ) , VREG ( V9 ) , VREG ( V10 ) , VREG ( VAUX1 ) , VREG ( VAUX2 ) , VREG ( VAUX3 ) ,
VREG ( VAUX4 ) , VREG ( VSIM ) , VREG ( VSIM2 ) , VREG ( VVIB ) , VREG ( SW1 ) , VREG ( SW2 ) ,
} ;
2012-11-19 22:22:22 +04:00
static int pcap_regulator_probe ( struct platform_device * pdev )
2009-06-27 07:18:02 +04:00
{
struct regulator_dev * rdev ;
2009-08-08 01:18:41 +04:00
void * pcap = dev_get_drvdata ( pdev - > dev . parent ) ;
2012-04-04 03:50:22 +04:00
struct regulator_config config = { } ;
2009-06-27 07:18:02 +04:00
2012-04-04 03:50:22 +04:00
config . dev = & pdev - > dev ;
2013-07-30 12:20:47 +04:00
config . init_data = dev_get_platdata ( & pdev - > dev ) ;
2012-04-04 03:50:22 +04:00
config . driver_data = pcap ;
2013-09-30 04:56:55 +04:00
rdev = devm_regulator_register ( & pdev - > dev , & pcap_regulators [ pdev - > id ] ,
& config ) ;
2009-06-27 07:18:02 +04:00
if ( IS_ERR ( rdev ) )
return PTR_ERR ( rdev ) ;
platform_set_drvdata ( pdev , rdev ) ;
return 0 ;
}
static struct platform_driver pcap_regulator_driver = {
. driver = {
2010-02-24 10:38:33 +03:00
. name = " pcap-regulator " ,
2009-06-27 07:18:02 +04:00
} ,
2010-02-24 10:38:33 +03:00
. probe = pcap_regulator_probe ,
2009-06-27 07:18:02 +04:00
} ;
static int __init pcap_regulator_init ( void )
{
return platform_driver_register ( & pcap_regulator_driver ) ;
}
static void __exit pcap_regulator_exit ( void )
{
platform_driver_unregister ( & pcap_regulator_driver ) ;
}
2009-08-07 03:08:52 +04:00
subsys_initcall ( pcap_regulator_init ) ;
2009-06-27 07:18:02 +04:00
module_exit ( pcap_regulator_exit ) ;
MODULE_AUTHOR ( " Daniel Ribeiro <drwyrm@gmail.com> " ) ;
MODULE_DESCRIPTION ( " PCAP2 Regulator Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;