2013-12-24 06:34:28 +04:00
/*
2014-07-05 17:20:54 +04:00
* act8865 - regulator . c - Voltage regulation for active - semi ACT88xx PMUs
*
* http : //www.active-semi.com/products/power-management-units/act88xx/
2013-12-24 06:34:28 +04:00
*
* Copyright ( C ) 2013 Atmel Corporation
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/i2c.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/act8865.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/regulator/of_regulator.h>
# include <linux/regmap.h>
2015-02-27 20:04:04 +03:00
/*
* ACT8600 Global Register Map .
*/
# define ACT8600_SYS_MODE 0x00
# define ACT8600_SYS_CTRL 0x01
# define ACT8600_DCDC1_VSET 0x10
# define ACT8600_DCDC1_CTRL 0x12
# define ACT8600_DCDC2_VSET 0x20
# define ACT8600_DCDC2_CTRL 0x22
# define ACT8600_DCDC3_VSET 0x30
# define ACT8600_DCDC3_CTRL 0x32
# define ACT8600_SUDCDC4_VSET 0x40
# define ACT8600_SUDCDC4_CTRL 0x41
# define ACT8600_LDO5_VSET 0x50
# define ACT8600_LDO5_CTRL 0x51
# define ACT8600_LDO6_VSET 0x60
# define ACT8600_LDO6_CTRL 0x61
# define ACT8600_LDO7_VSET 0x70
# define ACT8600_LDO7_CTRL 0x71
# define ACT8600_LDO8_VSET 0x80
# define ACT8600_LDO8_CTRL 0x81
# define ACT8600_LDO910_CTRL 0x91
# define ACT8600_APCH0 0xA1
# define ACT8600_APCH1 0xA8
# define ACT8600_APCH2 0xA9
# define ACT8600_APCH_STAT 0xAA
# define ACT8600_OTG0 0xB0
# define ACT8600_OTG1 0xB2
2014-07-05 17:20:55 +04:00
/*
* ACT8846 Global Register Map .
*/
# define ACT8846_SYS0 0x00
# define ACT8846_SYS1 0x01
# define ACT8846_REG1_VSET 0x10
# define ACT8846_REG1_CTRL 0x12
# define ACT8846_REG2_VSET0 0x20
# define ACT8846_REG2_VSET1 0x21
# define ACT8846_REG2_CTRL 0x22
# define ACT8846_REG3_VSET0 0x30
# define ACT8846_REG3_VSET1 0x31
# define ACT8846_REG3_CTRL 0x32
# define ACT8846_REG4_VSET0 0x40
# define ACT8846_REG4_VSET1 0x41
# define ACT8846_REG4_CTRL 0x42
# define ACT8846_REG5_VSET 0x50
# define ACT8846_REG5_CTRL 0x51
# define ACT8846_REG6_VSET 0x58
# define ACT8846_REG6_CTRL 0x59
# define ACT8846_REG7_VSET 0x60
# define ACT8846_REG7_CTRL 0x61
# define ACT8846_REG8_VSET 0x68
# define ACT8846_REG8_CTRL 0x69
# define ACT8846_REG9_VSET 0x70
# define ACT8846_REG9_CTRL 0x71
# define ACT8846_REG10_VSET 0x80
# define ACT8846_REG10_CTRL 0x81
# define ACT8846_REG11_VSET 0x90
# define ACT8846_REG11_CTRL 0x91
# define ACT8846_REG12_VSET 0xa0
# define ACT8846_REG12_CTRL 0xa1
# define ACT8846_REG13_CTRL 0xb1
2014-10-14 10:31:10 +04:00
# define ACT8846_GLB_OFF_CTRL 0xc3
# define ACT8846_OFF_SYSMASK 0x18
2014-07-05 17:20:55 +04:00
2013-12-24 06:34:28 +04:00
/*
* ACT8865 Global Register Map .
*/
# define ACT8865_SYS_MODE 0x00
# define ACT8865_SYS_CTRL 0x01
# define ACT8865_DCDC1_VSET1 0x20
# define ACT8865_DCDC1_VSET2 0x21
# define ACT8865_DCDC1_CTRL 0x22
# define ACT8865_DCDC2_VSET1 0x30
# define ACT8865_DCDC2_VSET2 0x31
# define ACT8865_DCDC2_CTRL 0x32
# define ACT8865_DCDC3_VSET1 0x40
# define ACT8865_DCDC3_VSET2 0x41
# define ACT8865_DCDC3_CTRL 0x42
# define ACT8865_LDO1_VSET 0x50
# define ACT8865_LDO1_CTRL 0x51
# define ACT8865_LDO2_VSET 0x54
# define ACT8865_LDO2_CTRL 0x55
# define ACT8865_LDO3_VSET 0x60
# define ACT8865_LDO3_CTRL 0x61
# define ACT8865_LDO4_VSET 0x64
# define ACT8865_LDO4_CTRL 0x65
2014-10-14 10:31:10 +04:00
# define ACT8865_MSTROFF 0x20
2013-12-24 06:34:28 +04:00
/*
* Field Definitions .
*/
# define ACT8865_ENA 0x80 /* ON - [7] */
# define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */
2015-02-27 20:04:04 +03:00
# define ACT8600_LDO10_ENA 0x40 /* ON - [6] */
# define ACT8600_SUDCDC_VSEL_MASK 0xFF /* SUDCDC VSET - [7:0] */
2013-12-24 06:34:28 +04:00
/*
* ACT8865 voltage number
*/
# define ACT8865_VOLTAGE_NUM 64
2015-02-27 20:04:04 +03:00
# define ACT8600_SUDCDC_VOLTAGE_NUM 255
2013-12-24 06:34:28 +04:00
struct act8865 {
struct regmap * regmap ;
2014-10-14 10:31:10 +04:00
int off_reg ;
int off_mask ;
2013-12-24 06:34:28 +04:00
} ;
2016-03-17 17:05:08 +03:00
static const struct regmap_range act8600_reg_ranges [ ] = {
regmap_reg_range ( 0x00 , 0x01 ) ,
regmap_reg_range ( 0x10 , 0x10 ) ,
regmap_reg_range ( 0x12 , 0x12 ) ,
regmap_reg_range ( 0x20 , 0x20 ) ,
regmap_reg_range ( 0x22 , 0x22 ) ,
regmap_reg_range ( 0x30 , 0x30 ) ,
regmap_reg_range ( 0x32 , 0x32 ) ,
regmap_reg_range ( 0x40 , 0x41 ) ,
regmap_reg_range ( 0x50 , 0x51 ) ,
regmap_reg_range ( 0x60 , 0x61 ) ,
regmap_reg_range ( 0x70 , 0x71 ) ,
regmap_reg_range ( 0x80 , 0x81 ) ,
regmap_reg_range ( 0x91 , 0x91 ) ,
regmap_reg_range ( 0xA1 , 0xA1 ) ,
regmap_reg_range ( 0xA8 , 0xAA ) ,
regmap_reg_range ( 0xB0 , 0xB0 ) ,
regmap_reg_range ( 0xB2 , 0xB2 ) ,
regmap_reg_range ( 0xC1 , 0xC1 ) ,
} ;
static const struct regmap_range act8600_reg_ro_ranges [ ] = {
regmap_reg_range ( 0xAA , 0xAA ) ,
regmap_reg_range ( 0xC1 , 0xC1 ) ,
} ;
static const struct regmap_range act8600_reg_volatile_ranges [ ] = {
regmap_reg_range ( 0x00 , 0x01 ) ,
regmap_reg_range ( 0x12 , 0x12 ) ,
regmap_reg_range ( 0x22 , 0x22 ) ,
regmap_reg_range ( 0x32 , 0x32 ) ,
regmap_reg_range ( 0x41 , 0x41 ) ,
regmap_reg_range ( 0x51 , 0x51 ) ,
regmap_reg_range ( 0x61 , 0x61 ) ,
regmap_reg_range ( 0x71 , 0x71 ) ,
regmap_reg_range ( 0x81 , 0x81 ) ,
regmap_reg_range ( 0xA8 , 0xA8 ) ,
regmap_reg_range ( 0xAA , 0xAA ) ,
regmap_reg_range ( 0xB0 , 0xB0 ) ,
regmap_reg_range ( 0xC1 , 0xC1 ) ,
} ;
static const struct regmap_access_table act8600_write_ranges_table = {
. yes_ranges = act8600_reg_ranges ,
. n_yes_ranges = ARRAY_SIZE ( act8600_reg_ranges ) ,
. no_ranges = act8600_reg_ro_ranges ,
. n_no_ranges = ARRAY_SIZE ( act8600_reg_ro_ranges ) ,
} ;
static const struct regmap_access_table act8600_read_ranges_table = {
. yes_ranges = act8600_reg_ranges ,
. n_yes_ranges = ARRAY_SIZE ( act8600_reg_ranges ) ,
} ;
static const struct regmap_access_table act8600_volatile_ranges_table = {
. yes_ranges = act8600_reg_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( act8600_reg_volatile_ranges ) ,
} ;
static const struct regmap_config act8600_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = 0xFF ,
. wr_table = & act8600_write_ranges_table ,
. rd_table = & act8600_read_ranges_table ,
. volatile_table = & act8600_volatile_ranges_table ,
} ;
2013-12-24 06:34:28 +04:00
static const struct regmap_config act8865_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2014-07-05 17:20:54 +04:00
static const struct regulator_linear_range act8865_voltage_ranges [ ] = {
2013-12-24 06:34:28 +04:00
REGULATOR_LINEAR_RANGE ( 600000 , 0 , 23 , 25000 ) ,
REGULATOR_LINEAR_RANGE ( 1200000 , 24 , 47 , 50000 ) ,
REGULATOR_LINEAR_RANGE ( 2400000 , 48 , 63 , 100000 ) ,
} ;
2015-02-27 20:04:04 +03:00
static const struct regulator_linear_range act8600_sudcdc_voltage_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 3000000 , 0 , 63 , 0 ) ,
REGULATOR_LINEAR_RANGE ( 3000000 , 64 , 159 , 100000 ) ,
REGULATOR_LINEAR_RANGE ( 12600000 , 160 , 191 , 200000 ) ,
REGULATOR_LINEAR_RANGE ( 19000000 , 191 , 255 , 400000 ) ,
} ;
2013-12-24 06:34:28 +04:00
static struct regulator_ops act8865_ops = {
. list_voltage = regulator_list_voltage_linear_range ,
. map_voltage = regulator_map_voltage_linear_range ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
} ;
2015-02-27 20:04:04 +03:00
static struct regulator_ops act8865_ldo_ops = {
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
} ;
2015-03-07 18:33:53 +03:00
# define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \
2014-07-05 17:20:54 +04:00
[ _family # # _ID_ # # _id ] = { \
. name = _name , \
2015-03-07 18:33:53 +03:00
. supply_name = _supply , \
2014-07-05 17:20:54 +04:00
. id = _family # # _ID_ # # _id , \
. type = REGULATOR_VOLTAGE , \
. ops = & act8865_ops , \
. n_voltages = ACT8865_VOLTAGE_NUM , \
. linear_ranges = act8865_voltage_ranges , \
. n_linear_ranges = ARRAY_SIZE ( act8865_voltage_ranges ) , \
. vsel_reg = _family # # _ # # _id # # _ # # _vsel_reg , \
. vsel_mask = ACT8865_VSEL_MASK , \
. enable_reg = _family # # _ # # _id # # _CTRL , \
. enable_mask = ACT8865_ENA , \
. owner = THIS_MODULE , \
}
2015-02-27 20:04:04 +03:00
static const struct regulator_desc act8600_regulators [ ] = {
2015-03-07 18:33:53 +03:00
ACT88xx_REG ( " DCDC1 " , ACT8600 , DCDC1 , VSET , " vp1 " ) ,
ACT88xx_REG ( " DCDC2 " , ACT8600 , DCDC2 , VSET , " vp2 " ) ,
ACT88xx_REG ( " DCDC3 " , ACT8600 , DCDC3 , VSET , " vp3 " ) ,
2015-02-27 20:04:04 +03:00
{
. name = " SUDCDC_REG4 " ,
. id = ACT8600_ID_SUDCDC4 ,
. ops = & act8865_ops ,
. type = REGULATOR_VOLTAGE ,
. n_voltages = ACT8600_SUDCDC_VOLTAGE_NUM ,
. linear_ranges = act8600_sudcdc_voltage_ranges ,
. n_linear_ranges = ARRAY_SIZE ( act8600_sudcdc_voltage_ranges ) ,
. vsel_reg = ACT8600_SUDCDC4_VSET ,
. vsel_mask = ACT8600_SUDCDC_VSEL_MASK ,
. enable_reg = ACT8600_SUDCDC4_CTRL ,
. enable_mask = ACT8865_ENA ,
. owner = THIS_MODULE ,
} ,
2015-03-07 18:33:53 +03:00
ACT88xx_REG ( " LDO5 " , ACT8600 , LDO5 , VSET , " inl " ) ,
ACT88xx_REG ( " LDO6 " , ACT8600 , LDO6 , VSET , " inl " ) ,
ACT88xx_REG ( " LDO7 " , ACT8600 , LDO7 , VSET , " inl " ) ,
ACT88xx_REG ( " LDO8 " , ACT8600 , LDO8 , VSET , " inl " ) ,
2015-02-27 20:04:04 +03:00
{
. name = " LDO_REG9 " ,
. id = ACT8600_ID_LDO9 ,
. ops = & act8865_ldo_ops ,
. type = REGULATOR_VOLTAGE ,
. n_voltages = 1 ,
2016-02-28 18:53:28 +03:00
. fixed_uV = 3300000 ,
2015-02-27 20:04:04 +03:00
. enable_reg = ACT8600_LDO910_CTRL ,
. enable_mask = ACT8865_ENA ,
. owner = THIS_MODULE ,
} ,
{
. name = " LDO_REG10 " ,
. id = ACT8600_ID_LDO10 ,
. ops = & act8865_ldo_ops ,
. type = REGULATOR_VOLTAGE ,
. n_voltages = 1 ,
. fixed_uV = 1200000 ,
. enable_reg = ACT8600_LDO910_CTRL ,
. enable_mask = ACT8600_LDO10_ENA ,
. owner = THIS_MODULE ,
} ,
} ;
2014-07-05 17:20:55 +04:00
static const struct regulator_desc act8846_regulators [ ] = {
2015-03-07 18:33:53 +03:00
ACT88xx_REG ( " REG1 " , ACT8846 , REG1 , VSET , " vp1 " ) ,
ACT88xx_REG ( " REG2 " , ACT8846 , REG2 , VSET0 , " vp2 " ) ,
ACT88xx_REG ( " REG3 " , ACT8846 , REG3 , VSET0 , " vp3 " ) ,
ACT88xx_REG ( " REG4 " , ACT8846 , REG4 , VSET0 , " vp4 " ) ,
ACT88xx_REG ( " REG5 " , ACT8846 , REG5 , VSET , " inl1 " ) ,
ACT88xx_REG ( " REG6 " , ACT8846 , REG6 , VSET , " inl1 " ) ,
ACT88xx_REG ( " REG7 " , ACT8846 , REG7 , VSET , " inl1 " ) ,
ACT88xx_REG ( " REG8 " , ACT8846 , REG8 , VSET , " inl2 " ) ,
ACT88xx_REG ( " REG9 " , ACT8846 , REG9 , VSET , " inl2 " ) ,
ACT88xx_REG ( " REG10 " , ACT8846 , REG10 , VSET , " inl3 " ) ,
ACT88xx_REG ( " REG11 " , ACT8846 , REG11 , VSET , " inl3 " ) ,
ACT88xx_REG ( " REG12 " , ACT8846 , REG12 , VSET , " inl3 " ) ,
2014-07-05 17:20:55 +04:00
} ;
2014-07-05 17:20:54 +04:00
static const struct regulator_desc act8865_regulators [ ] = {
2015-03-07 18:33:53 +03:00
ACT88xx_REG ( " DCDC_REG1 " , ACT8865 , DCDC1 , VSET1 , " vp1 " ) ,
ACT88xx_REG ( " DCDC_REG2 " , ACT8865 , DCDC2 , VSET1 , " vp2 " ) ,
ACT88xx_REG ( " DCDC_REG3 " , ACT8865 , DCDC3 , VSET1 , " vp3 " ) ,
ACT88xx_REG ( " LDO_REG1 " , ACT8865 , LDO1 , VSET , " inl45 " ) ,
ACT88xx_REG ( " LDO_REG2 " , ACT8865 , LDO2 , VSET , " inl45 " ) ,
ACT88xx_REG ( " LDO_REG3 " , ACT8865 , LDO3 , VSET , " inl67 " ) ,
ACT88xx_REG ( " LDO_REG4 " , ACT8865 , LDO4 , VSET , " inl67 " ) ,
2013-12-24 06:34:28 +04:00
} ;
2015-09-30 10:25:49 +03:00
static const struct regulator_desc act8865_alt_regulators [ ] = {
ACT88xx_REG ( " DCDC_REG1 " , ACT8865 , DCDC1 , VSET2 , " vp1 " ) ,
ACT88xx_REG ( " DCDC_REG2 " , ACT8865 , DCDC2 , VSET2 , " vp2 " ) ,
ACT88xx_REG ( " DCDC_REG3 " , ACT8865 , DCDC3 , VSET2 , " vp3 " ) ,
ACT88xx_REG ( " LDO_REG1 " , ACT8865 , LDO1 , VSET , " inl45 " ) ,
ACT88xx_REG ( " LDO_REG2 " , ACT8865 , LDO2 , VSET , " inl45 " ) ,
ACT88xx_REG ( " LDO_REG3 " , ACT8865 , LDO3 , VSET , " inl67 " ) ,
ACT88xx_REG ( " LDO_REG4 " , ACT8865 , LDO4 , VSET , " inl67 " ) ,
} ;
2013-12-24 06:34:28 +04:00
# ifdef CONFIG_OF
static const struct of_device_id act8865_dt_ids [ ] = {
2015-02-27 20:04:04 +03:00
{ . compatible = " active-semi,act8600 " , . data = ( void * ) ACT8600 } ,
2014-07-05 17:20:55 +04:00
{ . compatible = " active-semi,act8846 " , . data = ( void * ) ACT8846 } ,
2014-07-05 17:20:54 +04:00
{ . compatible = " active-semi,act8865 " , . data = ( void * ) ACT8865 } ,
2013-12-24 06:34:28 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , act8865_dt_ids ) ;
2014-07-05 17:20:55 +04:00
static struct of_regulator_match act8846_matches [ ] = {
[ ACT8846_ID_REG1 ] = { . name = " REG1 " } ,
[ ACT8846_ID_REG2 ] = { . name = " REG2 " } ,
[ ACT8846_ID_REG3 ] = { . name = " REG3 " } ,
[ ACT8846_ID_REG4 ] = { . name = " REG4 " } ,
[ ACT8846_ID_REG5 ] = { . name = " REG5 " } ,
[ ACT8846_ID_REG6 ] = { . name = " REG6 " } ,
[ ACT8846_ID_REG7 ] = { . name = " REG7 " } ,
[ ACT8846_ID_REG8 ] = { . name = " REG8 " } ,
[ ACT8846_ID_REG9 ] = { . name = " REG9 " } ,
[ ACT8846_ID_REG10 ] = { . name = " REG10 " } ,
[ ACT8846_ID_REG11 ] = { . name = " REG11 " } ,
[ ACT8846_ID_REG12 ] = { . name = " REG12 " } ,
} ;
2013-12-24 06:34:28 +04:00
static struct of_regulator_match act8865_matches [ ] = {
[ ACT8865_ID_DCDC1 ] = { . name = " DCDC_REG1 " } ,
[ ACT8865_ID_DCDC2 ] = { . name = " DCDC_REG2 " } ,
[ ACT8865_ID_DCDC3 ] = { . name = " DCDC_REG3 " } ,
[ ACT8865_ID_LDO1 ] = { . name = " LDO_REG1 " } ,
[ ACT8865_ID_LDO2 ] = { . name = " LDO_REG2 " } ,
[ ACT8865_ID_LDO3 ] = { . name = " LDO_REG3 " } ,
[ ACT8865_ID_LDO4 ] = { . name = " LDO_REG4 " } ,
} ;
2015-02-27 20:04:04 +03:00
static struct of_regulator_match act8600_matches [ ] = {
[ ACT8600_ID_DCDC1 ] = { . name = " DCDC_REG1 " } ,
[ ACT8600_ID_DCDC2 ] = { . name = " DCDC_REG2 " } ,
[ ACT8600_ID_DCDC3 ] = { . name = " DCDC_REG3 " } ,
[ ACT8600_ID_SUDCDC4 ] = { . name = " SUDCDC_REG4 " } ,
[ ACT8600_ID_LDO5 ] = { . name = " LDO_REG5 " } ,
[ ACT8600_ID_LDO6 ] = { . name = " LDO_REG6 " } ,
[ ACT8600_ID_LDO7 ] = { . name = " LDO_REG7 " } ,
[ ACT8600_ID_LDO8 ] = { . name = " LDO_REG8 " } ,
[ ACT8600_ID_LDO9 ] = { . name = " LDO_REG9 " } ,
[ ACT8600_ID_LDO10 ] = { . name = " LDO_REG10 " } ,
} ;
2013-12-24 06:34:28 +04:00
static int act8865_pdata_from_dt ( struct device * dev ,
2014-07-05 17:20:54 +04:00
struct act8865_platform_data * pdata ,
2014-07-08 01:40:47 +04:00
unsigned long type )
2013-12-24 06:34:28 +04:00
{
2014-07-08 01:40:47 +04:00
int matched , i , num_matches ;
2013-12-24 06:34:28 +04:00
struct device_node * np ;
struct act8865_regulator_data * regulator ;
2014-07-08 01:40:47 +04:00
struct of_regulator_match * matches ;
2013-12-24 06:34:28 +04:00
2014-07-08 01:40:47 +04:00
switch ( type ) {
2015-02-27 20:04:04 +03:00
case ACT8600 :
matches = act8600_matches ;
num_matches = ARRAY_SIZE ( act8600_matches ) ;
break ;
2014-07-08 01:40:47 +04:00
case ACT8846 :
matches = act8846_matches ;
num_matches = ARRAY_SIZE ( act8846_matches ) ;
break ;
case ACT8865 :
matches = act8865_matches ;
num_matches = ARRAY_SIZE ( act8865_matches ) ;
break ;
default :
dev_err ( dev , " invalid device id %lu \n " , type ) ;
return - EINVAL ;
}
2016-07-12 14:23:50 +03:00
np = of_get_child_by_name ( dev - > of_node , " regulators " ) ;
if ( ! np ) {
dev_err ( dev , " missing 'regulators' subnode in DT \n " ) ;
return - EINVAL ;
}
2014-07-05 17:20:54 +04:00
matched = of_regulator_match ( dev , np , matches , num_matches ) ;
2014-02-17 13:03:29 +04:00
of_node_put ( np ) ;
2013-12-24 06:34:28 +04:00
if ( matched < = 0 )
return matched ;
pdata - > regulators = devm_kzalloc ( dev ,
2014-07-05 17:20:54 +04:00
sizeof ( struct act8865_regulator_data ) *
num_matches , GFP_KERNEL ) ;
2014-02-18 14:41:08 +04:00
if ( ! pdata - > regulators )
2013-12-24 06:34:28 +04:00
return - ENOMEM ;
2014-07-05 17:20:54 +04:00
pdata - > num_regulators = num_matches ;
2013-12-24 06:34:28 +04:00
regulator = pdata - > regulators ;
2014-07-05 17:20:54 +04:00
for ( i = 0 ; i < num_matches ; i + + ) {
2013-12-24 06:34:28 +04:00
regulator - > id = i ;
2014-07-05 17:20:54 +04:00
regulator - > name = matches [ i ] . name ;
2016-02-28 18:53:26 +03:00
regulator - > init_data = matches [ i ] . init_data ;
2016-03-17 17:05:07 +03:00
regulator - > of_node = matches [ i ] . of_node ;
2013-12-24 06:34:28 +04:00
regulator + + ;
}
return 0 ;
}
# else
static inline int act8865_pdata_from_dt ( struct device * dev ,
2014-07-08 01:40:47 +04:00
struct act8865_platform_data * pdata ,
unsigned long type )
2013-12-24 06:34:28 +04:00
{
return 0 ;
}
# endif
2016-03-17 17:05:07 +03:00
static struct act8865_regulator_data * act8865_get_regulator_data (
int id , struct act8865_platform_data * pdata )
2014-06-22 19:31:41 +04:00
{
int i ;
if ( ! pdata )
return NULL ;
for ( i = 0 ; i < pdata - > num_regulators ; i + + ) {
if ( pdata - > regulators [ i ] . id = = id )
2016-03-17 17:05:07 +03:00
return & pdata - > regulators [ i ] ;
2014-06-22 19:31:41 +04:00
}
return NULL ;
}
2014-10-14 10:31:10 +04:00
static struct i2c_client * act8865_i2c_client ;
static void act8865_power_off ( void )
{
struct act8865 * act8865 ;
act8865 = i2c_get_clientdata ( act8865_i2c_client ) ;
regmap_write ( act8865 - > regmap , act8865 - > off_reg , act8865 - > off_mask ) ;
while ( 1 ) ;
}
2013-12-24 06:34:28 +04:00
static int act8865_pmic_probe ( struct i2c_client * client ,
2014-07-05 17:20:54 +04:00
const struct i2c_device_id * i2c_id )
2013-12-24 06:34:28 +04:00
{
2016-02-28 18:53:25 +03:00
const struct regulator_desc * regulators ;
2014-07-05 17:20:54 +04:00
struct act8865_platform_data pdata_of , * pdata ;
2013-12-24 06:34:28 +04:00
struct device * dev = & client - > dev ;
2014-07-05 17:20:54 +04:00
int i , ret , num_regulators ;
2013-12-24 06:34:28 +04:00
struct act8865 * act8865 ;
2016-03-17 17:05:08 +03:00
const struct regmap_config * regmap_config ;
2014-07-05 17:20:54 +04:00
unsigned long type ;
2014-10-14 10:31:10 +04:00
int off_reg , off_mask ;
2015-09-30 10:25:49 +03:00
int voltage_select = 0 ;
2014-07-05 17:20:54 +04:00
pdata = dev_get_platdata ( dev ) ;
2013-12-24 06:34:28 +04:00
if ( dev - > of_node & & ! pdata ) {
const struct of_device_id * id ;
id = of_match_device ( of_match_ptr ( act8865_dt_ids ) , dev ) ;
if ( ! id )
return - ENODEV ;
2014-07-05 17:20:54 +04:00
type = ( unsigned long ) id - > data ;
2015-09-30 10:25:49 +03:00
voltage_select = ! ! of_get_property ( dev - > of_node ,
" active-semi,vsel-high " ,
NULL ) ;
2014-07-05 17:20:54 +04:00
} else {
type = i2c_id - > driver_data ;
}
switch ( type ) {
2015-02-27 20:04:04 +03:00
case ACT8600 :
regulators = act8600_regulators ;
num_regulators = ARRAY_SIZE ( act8600_regulators ) ;
2016-03-17 17:05:08 +03:00
regmap_config = & act8600_regmap_config ;
2015-02-27 20:04:04 +03:00
off_reg = - 1 ;
off_mask = - 1 ;
break ;
2014-07-05 17:20:55 +04:00
case ACT8846 :
regulators = act8846_regulators ;
num_regulators = ARRAY_SIZE ( act8846_regulators ) ;
2016-03-17 17:05:08 +03:00
regmap_config = & act8865_regmap_config ;
2014-10-14 10:31:10 +04:00
off_reg = ACT8846_GLB_OFF_CTRL ;
off_mask = ACT8846_OFF_SYSMASK ;
2014-07-05 17:20:55 +04:00
break ;
2014-07-05 17:20:54 +04:00
case ACT8865 :
2015-09-30 10:25:49 +03:00
if ( voltage_select ) {
regulators = act8865_alt_regulators ;
num_regulators = ARRAY_SIZE ( act8865_alt_regulators ) ;
} else {
regulators = act8865_regulators ;
num_regulators = ARRAY_SIZE ( act8865_regulators ) ;
}
2016-03-17 17:05:08 +03:00
regmap_config = & act8865_regmap_config ;
2014-10-14 10:31:10 +04:00
off_reg = ACT8865_SYS_CTRL ;
off_mask = ACT8865_MSTROFF ;
2014-07-05 17:20:54 +04:00
break ;
default :
dev_err ( dev , " invalid device id %lu \n " , type ) ;
return - EINVAL ;
}
if ( dev - > of_node & & ! pdata ) {
2016-03-17 17:05:07 +03:00
ret = act8865_pdata_from_dt ( dev , & pdata_of , type ) ;
2013-12-24 06:34:28 +04:00
if ( ret < 0 )
return ret ;
pdata = & pdata_of ;
}
2013-12-26 10:52:43 +04:00
act8865 = devm_kzalloc ( dev , sizeof ( struct act8865 ) , GFP_KERNEL ) ;
2013-12-24 06:34:28 +04:00
if ( ! act8865 )
return - ENOMEM ;
2016-03-17 17:05:08 +03:00
act8865 - > regmap = devm_regmap_init_i2c ( client , regmap_config ) ;
2013-12-24 06:34:28 +04:00
if ( IS_ERR ( act8865 - > regmap ) ) {
2014-06-30 11:32:09 +04:00
ret = PTR_ERR ( act8865 - > regmap ) ;
2016-03-17 17:05:05 +03:00
dev_err ( dev , " Failed to allocate register map: %d \n " , ret ) ;
2014-06-30 11:32:09 +04:00
return ret ;
2013-12-24 06:34:28 +04:00
}
2014-11-25 15:28:25 +03:00
if ( of_device_is_system_power_controller ( dev - > of_node ) ) {
2015-02-27 20:04:04 +03:00
if ( ! pm_power_off & & ( off_reg > 0 ) ) {
2014-10-14 10:31:10 +04:00
act8865_i2c_client = client ;
act8865 - > off_reg = off_reg ;
act8865 - > off_mask = off_mask ;
pm_power_off = act8865_power_off ;
} else {
dev_err ( dev , " Failed to set poweroff capability, already defined \n " ) ;
}
}
2013-12-24 06:34:28 +04:00
/* Finally register devices */
2014-07-05 17:20:54 +04:00
for ( i = 0 ; i < num_regulators ; i + + ) {
const struct regulator_desc * desc = & regulators [ i ] ;
struct regulator_config config = { } ;
2016-03-17 17:05:07 +03:00
struct act8865_regulator_data * rdata ;
2014-07-05 17:20:54 +04:00
struct regulator_dev * rdev ;
2013-12-24 06:34:28 +04:00
config . dev = dev ;
config . driver_data = act8865 ;
config . regmap = act8865 - > regmap ;
2016-03-17 17:05:07 +03:00
rdata = act8865_get_regulator_data ( desc - > id , pdata ) ;
if ( rdata ) {
config . init_data = rdata - > init_data ;
config . of_node = rdata - > of_node ;
}
2016-03-17 17:05:05 +03:00
rdev = devm_regulator_register ( dev , desc , & config ) ;
2014-03-08 17:19:07 +04:00
if ( IS_ERR ( rdev ) ) {
2014-06-22 19:31:41 +04:00
dev_err ( dev , " failed to register %s \n " , desc - > name ) ;
2014-03-08 17:19:07 +04:00
return PTR_ERR ( rdev ) ;
2013-12-24 06:34:28 +04:00
}
}
i2c_set_clientdata ( client , act8865 ) ;
return 0 ;
}
static const struct i2c_device_id act8865_ids [ ] = {
2015-02-27 20:04:04 +03:00
{ . name = " act8600 " , . driver_data = ACT8600 } ,
2014-07-05 17:20:55 +04:00
{ . name = " act8846 " , . driver_data = ACT8846 } ,
2014-07-05 17:20:54 +04:00
{ . name = " act8865 " , . driver_data = ACT8865 } ,
2013-12-24 06:34:28 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , act8865_ids ) ;
static struct i2c_driver act8865_pmic_driver = {
. driver = {
. name = " act8865 " ,
} ,
. probe = act8865_pmic_probe ,
. id_table = act8865_ids ,
} ;
module_i2c_driver ( act8865_pmic_driver ) ;
2014-07-05 17:20:54 +04:00
MODULE_DESCRIPTION ( " active-semi act88xx voltage regulator driver " ) ;
2013-12-24 06:34:28 +04:00
MODULE_AUTHOR ( " Wenyou Yang <wenyou.yang@atmel.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;