2010-12-14 09:00:54 +03:00
/*
* Regulator Driver for Freescale MC13xxx PMIC
*
* Copyright 2010 Yong Shen < yong . shen @ linaro . org >
*
* Based on mc13783 regulator driver :
* Copyright ( C ) 2008 Sascha Hauer , Pengutronix < s . hauer @ pengutronix . de >
* Copyright 2009 Alberto Panizzo < maramaopercheseimorto @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Regs infos taken from mc13xxx drivers from freescale and mc13xxx . pdf file
* from freescale
*/
# include <linux/mfd/mc13xxx.h>
# include <linux/regulator/machine.h>
# include <linux/regulator/driver.h>
2011-12-21 19:00:46 +04:00
# include <linux/regulator/of_regulator.h>
2010-12-14 09:00:54 +03:00
# include <linux/platform_device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/err.h>
2011-07-18 00:28:23 +04:00
# include <linux/module.h>
2011-12-21 19:00:46 +04:00
# include <linux/of.h>
2010-12-14 09:00:54 +03:00
# include "mc13xxx.h"
static int mc13xxx_regulator_enable ( struct regulator_dev * rdev )
{
struct mc13xxx_regulator_priv * priv = rdev_get_drvdata ( rdev ) ;
struct mc13xxx_regulator * mc13xxx_regulators = priv - > mc13xxx_regulators ;
int id = rdev_get_id ( rdev ) ;
int ret ;
dev_dbg ( rdev_get_dev ( rdev ) , " %s id: %d \n " , __func__ , id ) ;
mc13xxx_lock ( priv - > mc13xxx ) ;
ret = mc13xxx_reg_rmw ( priv - > mc13xxx , mc13xxx_regulators [ id ] . reg ,
mc13xxx_regulators [ id ] . enable_bit ,
mc13xxx_regulators [ id ] . enable_bit ) ;
mc13xxx_unlock ( priv - > mc13xxx ) ;
return ret ;
}
static int mc13xxx_regulator_disable ( struct regulator_dev * rdev )
{
struct mc13xxx_regulator_priv * priv = rdev_get_drvdata ( rdev ) ;
struct mc13xxx_regulator * mc13xxx_regulators = priv - > mc13xxx_regulators ;
int id = rdev_get_id ( rdev ) ;
int ret ;
dev_dbg ( rdev_get_dev ( rdev ) , " %s id: %d \n " , __func__ , id ) ;
mc13xxx_lock ( priv - > mc13xxx ) ;
ret = mc13xxx_reg_rmw ( priv - > mc13xxx , mc13xxx_regulators [ id ] . reg ,
mc13xxx_regulators [ id ] . enable_bit , 0 ) ;
mc13xxx_unlock ( priv - > mc13xxx ) ;
return ret ;
}
static int mc13xxx_regulator_is_enabled ( struct regulator_dev * rdev )
{
struct mc13xxx_regulator_priv * priv = rdev_get_drvdata ( rdev ) ;
struct mc13xxx_regulator * mc13xxx_regulators = priv - > mc13xxx_regulators ;
int ret , id = rdev_get_id ( rdev ) ;
unsigned int val ;
mc13xxx_lock ( priv - > mc13xxx ) ;
ret = mc13xxx_reg_read ( priv - > mc13xxx , mc13xxx_regulators [ id ] . reg , & val ) ;
mc13xxx_unlock ( priv - > mc13xxx ) ;
if ( ret )
return ret ;
return ( val & mc13xxx_regulators [ id ] . enable_bit ) ! = 0 ;
}
2012-03-20 06:46:35 +04:00
static int mc13xxx_regulator_set_voltage_sel ( struct regulator_dev * rdev ,
unsigned selector )
2010-12-14 09:00:54 +03:00
{
struct mc13xxx_regulator_priv * priv = rdev_get_drvdata ( rdev ) ;
struct mc13xxx_regulator * mc13xxx_regulators = priv - > mc13xxx_regulators ;
2012-03-20 06:46:35 +04:00
int id = rdev_get_id ( rdev ) ;
2010-12-14 09:00:54 +03:00
int ret ;
mc13xxx_lock ( priv - > mc13xxx ) ;
ret = mc13xxx_reg_rmw ( priv - > mc13xxx , mc13xxx_regulators [ id ] . vsel_reg ,
mc13xxx_regulators [ id ] . vsel_mask ,
2012-03-20 06:46:35 +04:00
selector < < mc13xxx_regulators [ id ] . vsel_shift ) ;
2010-12-14 09:00:54 +03:00
mc13xxx_unlock ( priv - > mc13xxx ) ;
return ret ;
}
static int mc13xxx_regulator_get_voltage ( struct regulator_dev * rdev )
{
struct mc13xxx_regulator_priv * priv = rdev_get_drvdata ( rdev ) ;
struct mc13xxx_regulator * mc13xxx_regulators = priv - > mc13xxx_regulators ;
int ret , id = rdev_get_id ( rdev ) ;
unsigned int val ;
dev_dbg ( rdev_get_dev ( rdev ) , " %s id: %d \n " , __func__ , id ) ;
mc13xxx_lock ( priv - > mc13xxx ) ;
ret = mc13xxx_reg_read ( priv - > mc13xxx ,
mc13xxx_regulators [ id ] . vsel_reg , & val ) ;
mc13xxx_unlock ( priv - > mc13xxx ) ;
if ( ret )
return ret ;
val = ( val & mc13xxx_regulators [ id ] . vsel_mask )
> > mc13xxx_regulators [ id ] . vsel_shift ;
dev_dbg ( rdev_get_dev ( rdev ) , " %s id: %d val: %d \n " , __func__ , id , val ) ;
2011-05-18 16:56:45 +04:00
BUG_ON ( val > = mc13xxx_regulators [ id ] . desc . n_voltages ) ;
2010-12-14 09:00:54 +03:00
2012-06-08 11:41:48 +04:00
return rdev - > desc - > volt_table [ val ] ;
2010-12-14 09:00:54 +03:00
}
struct regulator_ops mc13xxx_regulator_ops = {
. enable = mc13xxx_regulator_enable ,
. disable = mc13xxx_regulator_disable ,
. is_enabled = mc13xxx_regulator_is_enabled ,
2012-06-08 11:41:48 +04:00
. list_voltage = regulator_list_voltage_table ,
2012-03-20 06:46:35 +04:00
. set_voltage_sel = mc13xxx_regulator_set_voltage_sel ,
2010-12-14 09:00:54 +03:00
. get_voltage = mc13xxx_regulator_get_voltage ,
} ;
2010-12-15 17:10:25 +03:00
EXPORT_SYMBOL_GPL ( mc13xxx_regulator_ops ) ;
2010-12-14 09:00:54 +03:00
int mc13xxx_fixed_regulator_set_voltage ( struct regulator_dev * rdev , int min_uV ,
int max_uV , unsigned * selector )
{
int id = rdev_get_id ( rdev ) ;
dev_dbg ( rdev_get_dev ( rdev ) , " %s id: %d min_uV: %d max_uV: %d \n " ,
__func__ , id , min_uV , max_uV ) ;
2012-06-08 11:41:48 +04:00
if ( min_uV < = rdev - > desc - > volt_table [ 0 ] & &
2012-07-13 19:01:14 +04:00
rdev - > desc - > volt_table [ 0 ] < = max_uV ) {
* selector = 0 ;
2010-12-14 09:00:54 +03:00
return 0 ;
2012-07-13 19:01:14 +04:00
} else {
2010-12-14 09:00:54 +03:00
return - EINVAL ;
2012-07-13 19:01:14 +04:00
}
2010-12-14 09:00:54 +03:00
}
2010-12-15 17:10:25 +03:00
EXPORT_SYMBOL_GPL ( mc13xxx_fixed_regulator_set_voltage ) ;
2010-12-14 09:00:54 +03:00
struct regulator_ops mc13xxx_fixed_regulator_ops = {
. enable = mc13xxx_regulator_enable ,
. disable = mc13xxx_regulator_disable ,
. is_enabled = mc13xxx_regulator_is_enabled ,
2012-06-08 11:41:48 +04:00
. list_voltage = regulator_list_voltage_table ,
2010-12-14 09:00:54 +03:00
. set_voltage = mc13xxx_fixed_regulator_set_voltage ,
} ;
2010-12-15 17:10:25 +03:00
EXPORT_SYMBOL_GPL ( mc13xxx_fixed_regulator_ops ) ;
2010-12-14 09:00:54 +03:00
2011-12-21 19:00:46 +04:00
# ifdef CONFIG_OF
2012-11-19 22:22:22 +04:00
int mc13xxx_get_num_regulators_dt ( struct platform_device * pdev )
2011-12-21 19:00:46 +04:00
{
struct device_node * parent , * child ;
int num = 0 ;
of_node_get ( pdev - > dev . parent - > of_node ) ;
parent = of_find_node_by_name ( pdev - > dev . parent - > of_node , " regulators " ) ;
if ( ! parent )
return - ENODEV ;
for_each_child_of_node ( parent , child )
num + + ;
return num ;
}
2012-02-10 01:43:01 +04:00
EXPORT_SYMBOL_GPL ( mc13xxx_get_num_regulators_dt ) ;
2011-12-21 19:00:46 +04:00
2012-11-19 22:22:22 +04:00
struct mc13xxx_regulator_init_data * mc13xxx_parse_regulators_dt (
2011-12-21 19:00:46 +04:00
struct platform_device * pdev , struct mc13xxx_regulator * regulators ,
2013-01-21 22:25:45 +04:00
int num_regulators , int * num_parsed )
2011-12-21 19:00:46 +04:00
{
struct mc13xxx_regulator_priv * priv = platform_get_drvdata ( pdev ) ;
struct mc13xxx_regulator_init_data * data , * p ;
struct device_node * parent , * child ;
2013-01-21 22:25:45 +04:00
int i , parsed = 0 ;
* num_parsed = 0 ;
2011-12-21 19:00:46 +04:00
of_node_get ( pdev - > dev . parent - > of_node ) ;
parent = of_find_node_by_name ( pdev - > dev . parent - > of_node , " regulators " ) ;
if ( ! parent )
return NULL ;
data = devm_kzalloc ( & pdev - > dev , sizeof ( * data ) * priv - > num_regulators ,
GFP_KERNEL ) ;
if ( ! data )
return NULL ;
p = data ;
for_each_child_of_node ( parent , child ) {
for ( i = 0 ; i < num_regulators ; i + + ) {
if ( ! of_node_cmp ( child - > name ,
regulators [ i ] . desc . name ) ) {
2013-01-21 22:25:45 +04:00
2011-12-21 19:00:46 +04:00
p - > id = i ;
p - > init_data = of_get_regulator_init_data (
& pdev - > dev , child ) ;
p - > node = child ;
p + + ;
2013-01-21 22:25:45 +04:00
parsed + + ;
2011-12-21 19:00:46 +04:00
break ;
}
}
}
2013-01-21 22:25:45 +04:00
* num_parsed = parsed ;
2011-12-21 19:00:46 +04:00
return data ;
}
2012-02-10 01:43:01 +04:00
EXPORT_SYMBOL_GPL ( mc13xxx_parse_regulators_dt ) ;
2011-12-21 19:00:46 +04:00
# endif
2010-12-14 09:00:54 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Yong Shen <yong.shen@linaro.org> " ) ;
MODULE_DESCRIPTION ( " Regulator Driver for Freescale MC13xxx PMIC " ) ;
MODULE_ALIAS ( " mc13xxx-regulator-core " ) ;