2009-07-28 15:22:02 +01:00
/*
* wm831x - ldo . c - - LDO driver for the WM831x series
*
* Copyright 2009 Wolfson Microelectronics PLC .
*
* Author : Mark Brown < broonie @ opensource . wolfsonmicro . 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/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/bitops.h>
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/mfd/wm831x/core.h>
# include <linux/mfd/wm831x/regulator.h>
# include <linux/mfd/wm831x/pdata.h>
# define WM831X_LDO_MAX_NAME 6
# define WM831X_LDO_CONTROL 0
# define WM831X_LDO_ON_CONTROL 1
# define WM831X_LDO_SLEEP_CONTROL 2
# define WM831X_ALIVE_LDO_ON_CONTROL 0
# define WM831X_ALIVE_LDO_SLEEP_CONTROL 1
struct wm831x_ldo {
char name [ WM831X_LDO_MAX_NAME ] ;
struct regulator_desc desc ;
int base ;
struct wm831x * wm831x ;
struct regulator_dev * regulator ;
} ;
/*
* Shared
*/
static int wm831x_ldo_is_enabled ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
int reg ;
reg = wm831x_reg_read ( wm831x , WM831X_LDO_ENABLE ) ;
if ( reg < 0 )
return reg ;
if ( reg & mask )
return 1 ;
else
return 0 ;
}
static int wm831x_ldo_enable ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
return wm831x_set_bits ( wm831x , WM831X_LDO_ENABLE , mask , mask ) ;
}
static int wm831x_ldo_disable ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
return wm831x_set_bits ( wm831x , WM831X_LDO_ENABLE , mask , 0 ) ;
}
static irqreturn_t wm831x_ldo_uv_irq ( int irq , void * data )
{
struct wm831x_ldo * ldo = data ;
regulator_notifier_call_chain ( ldo - > regulator ,
REGULATOR_EVENT_UNDER_VOLTAGE ,
NULL ) ;
return IRQ_HANDLED ;
}
/*
* General purpose LDOs
*/
# define WM831X_GP_LDO_SELECTOR_LOW 0xe
# define WM831X_GP_LDO_MAX_SELECTOR 0x1f
static int wm831x_gp_ldo_list_voltage ( struct regulator_dev * rdev ,
unsigned int selector )
{
/* 0.9-1.6V in 50mV steps */
if ( selector < = WM831X_GP_LDO_SELECTOR_LOW )
return 900000 + ( selector * 50000 ) ;
/* 1.7-3.3V in 50mV steps */
if ( selector < = WM831X_GP_LDO_MAX_SELECTOR )
return 1600000 + ( ( selector - WM831X_GP_LDO_SELECTOR_LOW )
* 100000 ) ;
return - EINVAL ;
}
static int wm831x_gp_ldo_set_voltage_int ( struct regulator_dev * rdev , int reg ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int vsel , ret ;
if ( min_uV < 900000 )
vsel = 0 ;
else if ( min_uV < 1700000 )
vsel = ( ( min_uV - 900000 ) / 50000 ) ;
else
vsel = ( ( min_uV - 1700000 ) / 100000 )
+ WM831X_GP_LDO_SELECTOR_LOW + 1 ;
ret = wm831x_gp_ldo_list_voltage ( rdev , vsel ) ;
if ( ret < 0 )
return ret ;
if ( ret < min_uV | | ret > max_uV )
return - EINVAL ;
return wm831x_set_bits ( wm831x , reg , WM831X_LDO1_ON_VSEL_MASK , vsel ) ;
}
static int wm831x_gp_ldo_set_voltage ( struct regulator_dev * rdev ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
return wm831x_gp_ldo_set_voltage_int ( rdev , reg , min_uV , max_uV ) ;
}
static int wm831x_gp_ldo_set_suspend_voltage ( struct regulator_dev * rdev ,
int uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_LDO_SLEEP_CONTROL ;
return wm831x_gp_ldo_set_voltage_int ( rdev , reg , uV , uV ) ;
}
static int wm831x_gp_ldo_get_voltage ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
int ret ;
ret = wm831x_reg_read ( wm831x , reg ) ;
if ( ret < 0 )
return ret ;
ret & = WM831X_LDO1_ON_VSEL_MASK ;
return wm831x_gp_ldo_list_voltage ( rdev , ret ) ;
}
static unsigned int wm831x_gp_ldo_get_mode ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int ctrl_reg = ldo - > base + WM831X_LDO_CONTROL ;
int on_reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
2009-10-16 14:16:15 +02:00
int ret ;
2009-07-28 15:22:02 +01:00
ret = wm831x_reg_read ( wm831x , on_reg ) ;
if ( ret < 0 )
2009-10-16 14:16:15 +02:00
return ret ;
2009-07-28 15:22:02 +01:00
if ( ! ( ret & WM831X_LDO1_ON_MODE ) )
return REGULATOR_MODE_NORMAL ;
ret = wm831x_reg_read ( wm831x , ctrl_reg ) ;
if ( ret < 0 )
2009-10-16 14:16:15 +02:00
return ret ;
2009-07-28 15:22:02 +01:00
if ( ret & WM831X_LDO1_LP_MODE )
return REGULATOR_MODE_STANDBY ;
else
return REGULATOR_MODE_IDLE ;
}
static int wm831x_gp_ldo_set_mode ( struct regulator_dev * rdev ,
unsigned int mode )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int ctrl_reg = ldo - > base + WM831X_LDO_CONTROL ;
int on_reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
int ret ;
switch ( mode ) {
case REGULATOR_MODE_NORMAL :
ret = wm831x_set_bits ( wm831x , on_reg ,
WM831X_LDO1_ON_MODE , 0 ) ;
if ( ret < 0 )
return ret ;
break ;
case REGULATOR_MODE_IDLE :
ret = wm831x_set_bits ( wm831x , ctrl_reg ,
WM831X_LDO1_LP_MODE ,
WM831X_LDO1_LP_MODE ) ;
if ( ret < 0 )
return ret ;
ret = wm831x_set_bits ( wm831x , on_reg ,
WM831X_LDO1_ON_MODE ,
WM831X_LDO1_ON_MODE ) ;
if ( ret < 0 )
return ret ;
case REGULATOR_MODE_STANDBY :
ret = wm831x_set_bits ( wm831x , ctrl_reg ,
WM831X_LDO1_LP_MODE , 0 ) ;
if ( ret < 0 )
return ret ;
ret = wm831x_set_bits ( wm831x , on_reg ,
WM831X_LDO1_ON_MODE ,
WM831X_LDO1_ON_MODE ) ;
if ( ret < 0 )
return ret ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int wm831x_gp_ldo_get_status ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
int ret ;
/* Is the regulator on? */
ret = wm831x_reg_read ( wm831x , WM831X_LDO_STATUS ) ;
if ( ret < 0 )
return ret ;
if ( ! ( ret & mask ) )
return REGULATOR_STATUS_OFF ;
/* Is it reporting under voltage? */
ret = wm831x_reg_read ( wm831x , WM831X_LDO_UV_STATUS ) ;
if ( ret & mask )
return REGULATOR_STATUS_ERROR ;
ret = wm831x_gp_ldo_get_mode ( rdev ) ;
if ( ret < 0 )
return ret ;
else
return regulator_mode_to_status ( ret ) ;
}
static unsigned int wm831x_gp_ldo_get_optimum_mode ( struct regulator_dev * rdev ,
int input_uV ,
int output_uV , int load_uA )
{
if ( load_uA < 20000 )
return REGULATOR_MODE_STANDBY ;
if ( load_uA < 50000 )
return REGULATOR_MODE_IDLE ;
return REGULATOR_MODE_NORMAL ;
}
static struct regulator_ops wm831x_gp_ldo_ops = {
. list_voltage = wm831x_gp_ldo_list_voltage ,
. get_voltage = wm831x_gp_ldo_get_voltage ,
. set_voltage = wm831x_gp_ldo_set_voltage ,
. set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage ,
. get_mode = wm831x_gp_ldo_get_mode ,
. set_mode = wm831x_gp_ldo_set_mode ,
. get_status = wm831x_gp_ldo_get_status ,
. get_optimum_mode = wm831x_gp_ldo_get_optimum_mode ,
. is_enabled = wm831x_ldo_is_enabled ,
. enable = wm831x_ldo_enable ,
. disable = wm831x_ldo_disable ,
} ;
static __devinit int wm831x_gp_ldo_probe ( struct platform_device * pdev )
{
struct wm831x * wm831x = dev_get_drvdata ( pdev - > dev . parent ) ;
struct wm831x_pdata * pdata = wm831x - > dev - > platform_data ;
int id = pdev - > id % ARRAY_SIZE ( pdata - > ldo ) ;
struct wm831x_ldo * ldo ;
struct resource * res ;
int ret , irq ;
dev_dbg ( & pdev - > dev , " Probing LDO%d \n " , id + 1 ) ;
if ( pdata = = NULL | | pdata - > ldo [ id ] = = NULL )
return - ENODEV ;
ldo = kzalloc ( sizeof ( struct wm831x_ldo ) , GFP_KERNEL ) ;
if ( ldo = = NULL ) {
dev_err ( & pdev - > dev , " Unable to allocate private data \n " ) ;
return - ENOMEM ;
}
ldo - > wm831x = wm831x ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " No I/O resource \n " ) ;
ret = - EINVAL ;
goto err ;
}
ldo - > base = res - > start ;
snprintf ( ldo - > name , sizeof ( ldo - > name ) , " LDO%d " , id + 1 ) ;
ldo - > desc . name = ldo - > name ;
ldo - > desc . id = id ;
ldo - > desc . type = REGULATOR_VOLTAGE ;
ldo - > desc . n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1 ;
ldo - > desc . ops = & wm831x_gp_ldo_ops ;
ldo - > desc . owner = THIS_MODULE ;
ldo - > regulator = regulator_register ( & ldo - > desc , & pdev - > dev ,
pdata - > ldo [ id ] , ldo ) ;
if ( IS_ERR ( ldo - > regulator ) ) {
ret = PTR_ERR ( ldo - > regulator ) ;
dev_err ( wm831x - > dev , " Failed to register LDO%d: %d \n " ,
id + 1 , ret ) ;
goto err ;
}
irq = platform_get_irq_byname ( pdev , " UV " ) ;
ret = wm831x_request_irq ( wm831x , irq , wm831x_ldo_uv_irq ,
IRQF_TRIGGER_RISING , ldo - > name ,
ldo ) ;
if ( ret ! = 0 ) {
dev_err ( & pdev - > dev , " Failed to request UV IRQ %d: %d \n " ,
irq , ret ) ;
goto err_regulator ;
}
platform_set_drvdata ( pdev , ldo ) ;
return 0 ;
err_regulator :
regulator_unregister ( ldo - > regulator ) ;
err :
kfree ( ldo ) ;
return ret ;
}
static __devexit int wm831x_gp_ldo_remove ( struct platform_device * pdev )
{
struct wm831x_ldo * ldo = platform_get_drvdata ( pdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
2010-02-23 23:38:39 -08:00
platform_set_drvdata ( pdev , NULL ) ;
2009-07-28 15:22:02 +01:00
wm831x_free_irq ( wm831x , platform_get_irq_byname ( pdev , " UV " ) , ldo ) ;
regulator_unregister ( ldo - > regulator ) ;
kfree ( ldo ) ;
return 0 ;
}
static struct platform_driver wm831x_gp_ldo_driver = {
. probe = wm831x_gp_ldo_probe ,
. remove = __devexit_p ( wm831x_gp_ldo_remove ) ,
. driver = {
. name = " wm831x-ldo " ,
2010-02-23 23:38:39 -08:00
. owner = THIS_MODULE ,
2009-07-28 15:22:02 +01:00
} ,
} ;
/*
* Analogue LDOs
*/
# define WM831X_ALDO_SELECTOR_LOW 0xc
# define WM831X_ALDO_MAX_SELECTOR 0x1f
static int wm831x_aldo_list_voltage ( struct regulator_dev * rdev ,
unsigned int selector )
{
/* 1-1.6V in 50mV steps */
if ( selector < = WM831X_ALDO_SELECTOR_LOW )
return 1000000 + ( selector * 50000 ) ;
/* 1.7-3.5V in 50mV steps */
if ( selector < = WM831X_ALDO_MAX_SELECTOR )
return 1600000 + ( ( selector - WM831X_ALDO_SELECTOR_LOW )
* 100000 ) ;
return - EINVAL ;
}
static int wm831x_aldo_set_voltage_int ( struct regulator_dev * rdev , int reg ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int vsel , ret ;
if ( min_uV < 1000000 )
vsel = 0 ;
else if ( min_uV < 1700000 )
vsel = ( ( min_uV - 1000000 ) / 50000 ) ;
else
vsel = ( ( min_uV - 1700000 ) / 100000 )
+ WM831X_ALDO_SELECTOR_LOW + 1 ;
ret = wm831x_aldo_list_voltage ( rdev , vsel ) ;
if ( ret < 0 )
return ret ;
if ( ret < min_uV | | ret > max_uV )
return - EINVAL ;
return wm831x_set_bits ( wm831x , reg , WM831X_LDO7_ON_VSEL_MASK , vsel ) ;
}
static int wm831x_aldo_set_voltage ( struct regulator_dev * rdev ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
return wm831x_aldo_set_voltage_int ( rdev , reg , min_uV , max_uV ) ;
}
static int wm831x_aldo_set_suspend_voltage ( struct regulator_dev * rdev ,
int uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_LDO_SLEEP_CONTROL ;
return wm831x_aldo_set_voltage_int ( rdev , reg , uV , uV ) ;
}
static int wm831x_aldo_get_voltage ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
int ret ;
ret = wm831x_reg_read ( wm831x , reg ) ;
if ( ret < 0 )
return ret ;
ret & = WM831X_LDO7_ON_VSEL_MASK ;
return wm831x_aldo_list_voltage ( rdev , ret ) ;
}
static unsigned int wm831x_aldo_get_mode ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int on_reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
2009-12-15 20:07:31 +01:00
int ret ;
2009-07-28 15:22:02 +01:00
ret = wm831x_reg_read ( wm831x , on_reg ) ;
if ( ret < 0 )
return 0 ;
if ( ret & WM831X_LDO7_ON_MODE )
return REGULATOR_MODE_IDLE ;
else
return REGULATOR_MODE_NORMAL ;
}
static int wm831x_aldo_set_mode ( struct regulator_dev * rdev ,
unsigned int mode )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int ctrl_reg = ldo - > base + WM831X_LDO_CONTROL ;
int on_reg = ldo - > base + WM831X_LDO_ON_CONTROL ;
int ret ;
switch ( mode ) {
case REGULATOR_MODE_NORMAL :
ret = wm831x_set_bits ( wm831x , on_reg ,
WM831X_LDO7_ON_MODE , 0 ) ;
if ( ret < 0 )
return ret ;
break ;
case REGULATOR_MODE_IDLE :
ret = wm831x_set_bits ( wm831x , ctrl_reg ,
WM831X_LDO7_ON_MODE ,
WM831X_LDO7_ON_MODE ) ;
if ( ret < 0 )
return ret ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int wm831x_aldo_get_status ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
int ret ;
/* Is the regulator on? */
ret = wm831x_reg_read ( wm831x , WM831X_LDO_STATUS ) ;
if ( ret < 0 )
return ret ;
if ( ! ( ret & mask ) )
return REGULATOR_STATUS_OFF ;
/* Is it reporting under voltage? */
ret = wm831x_reg_read ( wm831x , WM831X_LDO_UV_STATUS ) ;
if ( ret & mask )
return REGULATOR_STATUS_ERROR ;
ret = wm831x_aldo_get_mode ( rdev ) ;
if ( ret < 0 )
return ret ;
else
return regulator_mode_to_status ( ret ) ;
}
static struct regulator_ops wm831x_aldo_ops = {
. list_voltage = wm831x_aldo_list_voltage ,
. get_voltage = wm831x_aldo_get_voltage ,
. set_voltage = wm831x_aldo_set_voltage ,
. set_suspend_voltage = wm831x_aldo_set_suspend_voltage ,
. get_mode = wm831x_aldo_get_mode ,
. set_mode = wm831x_aldo_set_mode ,
. get_status = wm831x_aldo_get_status ,
. is_enabled = wm831x_ldo_is_enabled ,
. enable = wm831x_ldo_enable ,
. disable = wm831x_ldo_disable ,
} ;
static __devinit int wm831x_aldo_probe ( struct platform_device * pdev )
{
struct wm831x * wm831x = dev_get_drvdata ( pdev - > dev . parent ) ;
struct wm831x_pdata * pdata = wm831x - > dev - > platform_data ;
int id = pdev - > id % ARRAY_SIZE ( pdata - > ldo ) ;
struct wm831x_ldo * ldo ;
struct resource * res ;
int ret , irq ;
dev_dbg ( & pdev - > dev , " Probing LDO%d \n " , id + 1 ) ;
if ( pdata = = NULL | | pdata - > ldo [ id ] = = NULL )
return - ENODEV ;
ldo = kzalloc ( sizeof ( struct wm831x_ldo ) , GFP_KERNEL ) ;
if ( ldo = = NULL ) {
dev_err ( & pdev - > dev , " Unable to allocate private data \n " ) ;
return - ENOMEM ;
}
ldo - > wm831x = wm831x ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " No I/O resource \n " ) ;
ret = - EINVAL ;
goto err ;
}
ldo - > base = res - > start ;
snprintf ( ldo - > name , sizeof ( ldo - > name ) , " LDO%d " , id + 1 ) ;
ldo - > desc . name = ldo - > name ;
ldo - > desc . id = id ;
ldo - > desc . type = REGULATOR_VOLTAGE ;
ldo - > desc . n_voltages = WM831X_ALDO_MAX_SELECTOR + 1 ;
ldo - > desc . ops = & wm831x_aldo_ops ;
ldo - > desc . owner = THIS_MODULE ;
ldo - > regulator = regulator_register ( & ldo - > desc , & pdev - > dev ,
pdata - > ldo [ id ] , ldo ) ;
if ( IS_ERR ( ldo - > regulator ) ) {
ret = PTR_ERR ( ldo - > regulator ) ;
dev_err ( wm831x - > dev , " Failed to register LDO%d: %d \n " ,
id + 1 , ret ) ;
goto err ;
}
irq = platform_get_irq_byname ( pdev , " UV " ) ;
ret = wm831x_request_irq ( wm831x , irq , wm831x_ldo_uv_irq ,
IRQF_TRIGGER_RISING , ldo - > name ,
ldo ) ;
if ( ret ! = 0 ) {
dev_err ( & pdev - > dev , " Failed to request UV IRQ %d: %d \n " ,
irq , ret ) ;
goto err_regulator ;
}
platform_set_drvdata ( pdev , ldo ) ;
return 0 ;
err_regulator :
regulator_unregister ( ldo - > regulator ) ;
err :
kfree ( ldo ) ;
return ret ;
}
static __devexit int wm831x_aldo_remove ( struct platform_device * pdev )
{
struct wm831x_ldo * ldo = platform_get_drvdata ( pdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
wm831x_free_irq ( wm831x , platform_get_irq_byname ( pdev , " UV " ) , ldo ) ;
regulator_unregister ( ldo - > regulator ) ;
kfree ( ldo ) ;
return 0 ;
}
static struct platform_driver wm831x_aldo_driver = {
. probe = wm831x_aldo_probe ,
. remove = __devexit_p ( wm831x_aldo_remove ) ,
. driver = {
. name = " wm831x-aldo " ,
2010-02-23 23:38:39 -08:00
. owner = THIS_MODULE ,
2009-07-28 15:22:02 +01:00
} ,
} ;
/*
* Alive LDO
*/
# define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
static int wm831x_alive_ldo_list_voltage ( struct regulator_dev * rdev ,
unsigned int selector )
{
/* 0.8-1.55V in 50mV steps */
if ( selector < = WM831X_ALIVE_LDO_MAX_SELECTOR )
return 800000 + ( selector * 50000 ) ;
return - EINVAL ;
}
static int wm831x_alive_ldo_set_voltage_int ( struct regulator_dev * rdev ,
int reg ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int vsel , ret ;
vsel = ( min_uV - 800000 ) / 50000 ;
ret = wm831x_alive_ldo_list_voltage ( rdev , vsel ) ;
if ( ret < 0 )
return ret ;
if ( ret < min_uV | | ret > max_uV )
return - EINVAL ;
return wm831x_set_bits ( wm831x , reg , WM831X_LDO11_ON_VSEL_MASK , vsel ) ;
}
static int wm831x_alive_ldo_set_voltage ( struct regulator_dev * rdev ,
int min_uV , int max_uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_ALIVE_LDO_ON_CONTROL ;
return wm831x_alive_ldo_set_voltage_int ( rdev , reg , min_uV , max_uV ) ;
}
static int wm831x_alive_ldo_set_suspend_voltage ( struct regulator_dev * rdev ,
int uV )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
int reg = ldo - > base + WM831X_ALIVE_LDO_SLEEP_CONTROL ;
return wm831x_alive_ldo_set_voltage_int ( rdev , reg , uV , uV ) ;
}
static int wm831x_alive_ldo_get_voltage ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int reg = ldo - > base + WM831X_ALIVE_LDO_ON_CONTROL ;
int ret ;
ret = wm831x_reg_read ( wm831x , reg ) ;
if ( ret < 0 )
return ret ;
ret & = WM831X_LDO11_ON_VSEL_MASK ;
return wm831x_alive_ldo_list_voltage ( rdev , ret ) ;
}
static int wm831x_alive_ldo_get_status ( struct regulator_dev * rdev )
{
struct wm831x_ldo * ldo = rdev_get_drvdata ( rdev ) ;
struct wm831x * wm831x = ldo - > wm831x ;
int mask = 1 < < rdev_get_id ( rdev ) ;
int ret ;
/* Is the regulator on? */
ret = wm831x_reg_read ( wm831x , WM831X_LDO_STATUS ) ;
if ( ret < 0 )
return ret ;
if ( ret & mask )
return REGULATOR_STATUS_ON ;
else
return REGULATOR_STATUS_OFF ;
}
static struct regulator_ops wm831x_alive_ldo_ops = {
. list_voltage = wm831x_alive_ldo_list_voltage ,
. get_voltage = wm831x_alive_ldo_get_voltage ,
. set_voltage = wm831x_alive_ldo_set_voltage ,
. set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage ,
. get_status = wm831x_alive_ldo_get_status ,
. is_enabled = wm831x_ldo_is_enabled ,
. enable = wm831x_ldo_enable ,
. disable = wm831x_ldo_disable ,
} ;
static __devinit int wm831x_alive_ldo_probe ( struct platform_device * pdev )
{
struct wm831x * wm831x = dev_get_drvdata ( pdev - > dev . parent ) ;
struct wm831x_pdata * pdata = wm831x - > dev - > platform_data ;
int id = pdev - > id % ARRAY_SIZE ( pdata - > ldo ) ;
struct wm831x_ldo * ldo ;
struct resource * res ;
int ret ;
dev_dbg ( & pdev - > dev , " Probing LDO%d \n " , id + 1 ) ;
if ( pdata = = NULL | | pdata - > ldo [ id ] = = NULL )
return - ENODEV ;
ldo = kzalloc ( sizeof ( struct wm831x_ldo ) , GFP_KERNEL ) ;
if ( ldo = = NULL ) {
dev_err ( & pdev - > dev , " Unable to allocate private data \n " ) ;
return - ENOMEM ;
}
ldo - > wm831x = wm831x ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " No I/O resource \n " ) ;
ret = - EINVAL ;
goto err ;
}
ldo - > base = res - > start ;
snprintf ( ldo - > name , sizeof ( ldo - > name ) , " LDO%d " , id + 1 ) ;
ldo - > desc . name = ldo - > name ;
ldo - > desc . id = id ;
ldo - > desc . type = REGULATOR_VOLTAGE ;
ldo - > desc . n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1 ;
ldo - > desc . ops = & wm831x_alive_ldo_ops ;
ldo - > desc . owner = THIS_MODULE ;
ldo - > regulator = regulator_register ( & ldo - > desc , & pdev - > dev ,
pdata - > ldo [ id ] , ldo ) ;
if ( IS_ERR ( ldo - > regulator ) ) {
ret = PTR_ERR ( ldo - > regulator ) ;
dev_err ( wm831x - > dev , " Failed to register LDO%d: %d \n " ,
id + 1 , ret ) ;
goto err ;
}
platform_set_drvdata ( pdev , ldo ) ;
return 0 ;
err :
kfree ( ldo ) ;
return ret ;
}
static __devexit int wm831x_alive_ldo_remove ( struct platform_device * pdev )
{
struct wm831x_ldo * ldo = platform_get_drvdata ( pdev ) ;
regulator_unregister ( ldo - > regulator ) ;
kfree ( ldo ) ;
return 0 ;
}
static struct platform_driver wm831x_alive_ldo_driver = {
. probe = wm831x_alive_ldo_probe ,
. remove = __devexit_p ( wm831x_alive_ldo_remove ) ,
. driver = {
. name = " wm831x-alive-ldo " ,
2010-02-23 23:38:39 -08:00
. owner = THIS_MODULE ,
2009-07-28 15:22:02 +01:00
} ,
} ;
static int __init wm831x_ldo_init ( void )
{
int ret ;
ret = platform_driver_register ( & wm831x_gp_ldo_driver ) ;
if ( ret ! = 0 )
pr_err ( " Failed to register WM831x GP LDO driver: %d \n " , ret ) ;
ret = platform_driver_register ( & wm831x_aldo_driver ) ;
if ( ret ! = 0 )
pr_err ( " Failed to register WM831x ALDO driver: %d \n " , ret ) ;
ret = platform_driver_register ( & wm831x_alive_ldo_driver ) ;
if ( ret ! = 0 )
pr_err ( " Failed to register WM831x alive LDO driver: %d \n " ,
ret ) ;
return 0 ;
}
subsys_initcall ( wm831x_ldo_init ) ;
static void __exit wm831x_ldo_exit ( void )
{
platform_driver_unregister ( & wm831x_alive_ldo_driver ) ;
platform_driver_unregister ( & wm831x_aldo_driver ) ;
platform_driver_unregister ( & wm831x_gp_ldo_driver ) ;
}
module_exit ( wm831x_ldo_exit ) ;
/* Module information */
MODULE_AUTHOR ( " Mark Brown <broonie@opensource.wolfsonmicro.com> " ) ;
MODULE_DESCRIPTION ( " WM831x LDO driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:wm831x-ldo " ) ;
MODULE_ALIAS ( " platform:wm831x-aldo " ) ;
MODULE_ALIAS ( " platform:wm831x-aliveldo " ) ;