Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
fb87ef1a
Commit
fb87ef1a
authored
Feb 02, 2012
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'regulator-drivers' into regulator-supply
parents
62aa2b53
20a14b84
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2492 additions
and
122 deletions
+2492
-122
drivers/regulator/Kconfig
drivers/regulator/Kconfig
+31
-0
drivers/regulator/Makefile
drivers/regulator/Makefile
+5
-0
drivers/regulator/db8500-prcmu.c
drivers/regulator/db8500-prcmu.c
+32
-86
drivers/regulator/dbx500-prcmu.c
drivers/regulator/dbx500-prcmu.c
+241
-0
drivers/regulator/dbx500-prcmu.h
drivers/regulator/dbx500-prcmu.h
+63
-0
drivers/regulator/max8997.c
drivers/regulator/max8997.c
+4
-4
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/mc13xxx-regulator-core.c
+2
-0
drivers/regulator/s5m8767.c
drivers/regulator/s5m8767.c
+832
-0
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps62360-regulator.c
+472
-0
drivers/regulator/tps65217-regulator.c
drivers/regulator/tps65217-regulator.c
+493
-0
drivers/regulator/tps65910-regulator.c
drivers/regulator/tps65910-regulator.c
+250
-30
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8350-regulator.c
+2
-2
include/linux/mfd/tps65910.h
include/linux/mfd/tps65910.h
+8
-0
include/linux/regulator/tps62360.h
include/linux/regulator/tps62360.h
+57
-0
No files found.
drivers/regulator/Kconfig
View file @
fb87ef1a
...
...
@@ -136,6 +136,14 @@ config REGULATOR_MAX8998
via I2C bus. The provided regulator is suitable for S3C6410
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
depends on MFD_S5M_CORE
help
This driver supports a Samsung S5M8767A voltage output regulator
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
supports DVS mode with 8bits of output voltage control.
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
depends on TWL4030_CORE
...
...
@@ -267,6 +275,15 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
config REGULATOR_TPS65217
tristate "TI TPS65217 Power regulators"
depends on MFD_TPS65217
help
This driver supports TPS65217 voltage regulator chips. TPS65217
provides three step-down converters and four general-purpose LDO
voltage regulators. It supports software based voltage control
for different voltage domains
config REGULATOR_TPS65912
tristate "TI TPS65912 Power regulator"
depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
...
...
@@ -299,9 +316,13 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
config REGULATOR_DBX500_PRCMU
bool
config REGULATOR_DB8500_PRCMU
bool "ST-Ericsson DB8500 Voltage Domain Regulators"
depends on MFD_DB8500_PRCMU
select REGULATOR_DBX500_PRCMU
help
This driver supports the voltage domain regulators controlled by the
DB8500 PRCMU
...
...
@@ -328,6 +349,16 @@ config REGULATOR_TPS65910
help
This driver supports TPS65910 voltage regulator chips.
config REGULATOR_TPS62360
tristate "TI TPS62360 Power Regulator"
depends on I2C
select REGMAP_I2C
help
This driver supports TPS62360 voltage regulator chip. This
regulator is meant for processor core supply. This chip is
high-frequency synchronous step down dc-dc converter optimized
for battery-powered portable applications.
config REGULATOR_AAT2870
tristate "AnalogicTech AAT2870 Regulators"
depends on MFD_AAT2870_CORE
...
...
drivers/regulator/Makefile
View file @
fb87ef1a
...
...
@@ -40,13 +40,18 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS6105X)
+=
tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023)
+=
tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X)
+=
tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217)
+=
tps65217-regulator.o
obj-$(CONFIG_REGULATOR_TPS6524X)
+=
tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912)
+=
tps65912-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607)
+=
88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A)
+=
isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500)
+=
ab8500.o
obj-$(CONFIG_REGULATOR_DBX500_PRCMU)
+=
dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU)
+=
db8500-prcmu.o
obj-$(CONFIG_REGULATOR_TPS65910)
+=
tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360)
+=
tps62360-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870)
+=
aat2870-regulator.o
obj-$(CONFIG_REGULATOR_S5M8767)
+=
s5m8767.o
ccflags-$(CONFIG_REGULATOR_DEBUG)
+=
-DDEBUG
drivers/regulator/db8500-prcmu.c
View file @
fb87ef1a
...
...
@@ -18,74 +18,11 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/module.h>
/*
* power state reference count
*/
static
int
power_state_active_cnt
;
/* will initialize to zero */
static
DEFINE_SPINLOCK
(
power_state_active_lock
);
static
void
power_state_active_enable
(
void
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
power_state_active_lock
,
flags
);
power_state_active_cnt
++
;
spin_unlock_irqrestore
(
&
power_state_active_lock
,
flags
);
}
static
int
power_state_active_disable
(
void
)
{
int
ret
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
power_state_active_lock
,
flags
);
if
(
power_state_active_cnt
<=
0
)
{
pr_err
(
"power state: unbalanced enable/disable calls
\n
"
);
ret
=
-
EINVAL
;
goto
out
;
}
power_state_active_cnt
--
;
out:
spin_unlock_irqrestore
(
&
power_state_active_lock
,
flags
);
return
ret
;
}
/*
* Exported interface for CPUIdle only. This function is called when interrupts
* are turned off. Hence, no locking.
*/
int
power_state_active_is_enabled
(
void
)
{
return
(
power_state_active_cnt
>
0
);
}
/**
* struct db8500_regulator_info - db8500 regulator information
* @dev: device pointer
* @desc: regulator description
* @rdev: regulator device pointer
* @is_enabled: status of the regulator
* @epod_id: id for EPOD (power domain)
* @is_ramret: RAM retention switch for EPOD (power domain)
* @operating_point: operating point (only for vape, to be removed)
*
*/
struct
db8500_regulator_info
{
struct
device
*
dev
;
struct
regulator_desc
desc
;
struct
regulator_dev
*
rdev
;
bool
is_enabled
;
u16
epod_id
;
bool
is_ramret
;
bool
exclude_from_power_state
;
unsigned
int
operating_point
;
};
#include "dbx500-prcmu.h"
static
int
db8500_regulator_enable
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
if
(
info
==
NULL
)
return
-
EINVAL
;
...
...
@@ -93,16 +30,18 @@ static int db8500_regulator_enable(struct regulator_dev *rdev)
dev_vdbg
(
rdev_get_dev
(
rdev
),
"regulator-%s-enable
\n
"
,
info
->
desc
.
name
);
info
->
is_enabled
=
true
;
if
(
!
info
->
exclude_from_power_state
)
power_state_active_enable
();
if
(
!
info
->
is_enabled
)
{
info
->
is_enabled
=
true
;
if
(
!
info
->
exclude_from_power_state
)
power_state_active_enable
();
}
return
0
;
}
static
int
db8500_regulator_disable
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
int
ret
=
0
;
if
(
info
==
NULL
)
...
...
@@ -111,16 +50,18 @@ static int db8500_regulator_disable(struct regulator_dev *rdev)
dev_vdbg
(
rdev_get_dev
(
rdev
),
"regulator-%s-disable
\n
"
,
info
->
desc
.
name
);
info
->
is_enabled
=
false
;
if
(
!
info
->
exclude_from_power_state
)
ret
=
power_state_active_disable
();
if
(
info
->
is_enabled
)
{
info
->
is_enabled
=
false
;
if
(
!
info
->
exclude_from_power_state
)
ret
=
power_state_active_disable
();
}
return
ret
;
}
static
int
db8500_regulator_is_enabled
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
if
(
info
==
NULL
)
return
-
EINVAL
;
...
...
@@ -197,7 +138,7 @@ static int disable_epod(u16 epod_id, bool ramret)
*/
static
int
db8500_regulator_switch_enable
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
int
ret
;
if
(
info
==
NULL
)
...
...
@@ -221,7 +162,7 @@ static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
static
int
db8500_regulator_switch_disable
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
int
ret
;
if
(
info
==
NULL
)
...
...
@@ -245,7 +186,7 @@ static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
static
int
db8500_regulator_switch_is_enabled
(
struct
regulator_dev
*
rdev
)
{
struct
db
8
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
struct
db
x
500_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
if
(
info
==
NULL
)
return
-
EINVAL
;
...
...
@@ -266,8 +207,8 @@ static struct regulator_ops db8500_regulator_switch_ops = {
/*
* Regulator information
*/
static
struct
db
8
500_regulator_info
db
8
500_regulator_info
[
DB8500_NUM_REGULATORS
]
=
{
static
struct
db
x
500_regulator_info
db
x
500_regulator_info
[
DB8500_NUM_REGULATORS
]
=
{
[
DB8500_REGULATOR_VAPE
]
=
{
.
desc
=
{
.
name
=
"db8500-vape"
,
...
...
@@ -476,12 +417,12 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
int
i
,
err
;
/* register all regulators */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
db
8
500_regulator_info
);
i
++
)
{
struct
db
8
500_regulator_info
*
info
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
db
x
500_regulator_info
);
i
++
)
{
struct
db
x
500_regulator_info
*
info
;
struct
regulator_init_data
*
init_data
=
&
db8500_init_data
[
i
];
/* assign per-regulator data */
info
=
&
db
8
500_regulator_info
[
i
];
info
=
&
db
x
500_regulator_info
[
i
];
info
->
dev
=
&
pdev
->
dev
;
/* register with the regulator framework */
...
...
@@ -494,7 +435,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
/* if failing, unregister all earlier regulators */
while
(
--
i
>=
0
)
{
info
=
&
db
8
500_regulator_info
[
i
];
info
=
&
db
x
500_regulator_info
[
i
];
regulator_unregister
(
info
->
rdev
);
}
return
err
;
...
...
@@ -503,17 +444,22 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev)
dev_dbg
(
rdev_get_dev
(
info
->
rdev
),
"regulator-%s-probed
\n
"
,
info
->
desc
.
name
);
}
err
=
ux500_regulator_debug_init
(
pdev
,
dbx500_regulator_info
,
ARRAY_SIZE
(
dbx500_regulator_info
));
return
0
;
return
err
;
}
static
int
__exit
db8500_regulator_remove
(
struct
platform_device
*
pdev
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
db8500_regulator_info
);
i
++
)
{
struct
db8500_regulator_info
*
info
;
info
=
&
db8500_regulator_info
[
i
];
ux500_regulator_debug_exit
();
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dbx500_regulator_info
);
i
++
)
{
struct
dbx500_regulator_info
*
info
;
info
=
&
dbx500_regulator_info
[
i
];
dev_vdbg
(
rdev_get_dev
(
info
->
rdev
),
"regulator-%s-remove
\n
"
,
info
->
desc
.
name
);
...
...
drivers/regulator/dbx500-prcmu.c
0 → 100644
View file @
fb87ef1a
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
*
* UX500 common part of Power domain regulators
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/regulator/driver.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include "dbx500-prcmu.h"
/*
* power state reference count
*/
static
int
power_state_active_cnt
;
/* will initialize to zero */
static
DEFINE_SPINLOCK
(
power_state_active_lock
);
int
power_state_active_get
(
void
)
{
unsigned
long
flags
;
int
cnt
;
spin_lock_irqsave
(
&
power_state_active_lock
,
flags
);
cnt
=
power_state_active_cnt
;
spin_unlock_irqrestore
(
&
power_state_active_lock
,
flags
);
return
cnt
;
}
void
power_state_active_enable
(
void
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
power_state_active_lock
,
flags
);
power_state_active_cnt
++
;
spin_unlock_irqrestore
(
&
power_state_active_lock
,
flags
);
}
int
power_state_active_disable
(
void
)
{
int
ret
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
power_state_active_lock
,
flags
);
if
(
power_state_active_cnt
<=
0
)
{
pr_err
(
"power state: unbalanced enable/disable calls
\n
"
);
ret
=
-
EINVAL
;
goto
out
;
}
power_state_active_cnt
--
;
out:
spin_unlock_irqrestore
(
&
power_state_active_lock
,
flags
);
return
ret
;
}
#ifdef CONFIG_REGULATOR_DEBUG
static
struct
ux500_regulator_debug
{
struct
dentry
*
dir
;
struct
dentry
*
status_file
;
struct
dentry
*
power_state_cnt_file
;
struct
dbx500_regulator_info
*
regulator_array
;
int
num_regulators
;
u8
*
state_before_suspend
;
u8
*
state_after_suspend
;
}
rdebug
;
void
ux500_regulator_suspend_debug
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
rdebug
.
num_regulators
;
i
++
)
rdebug
.
state_before_suspend
[
i
]
=
rdebug
.
regulator_array
[
i
].
is_enabled
;
}
void
ux500_regulator_resume_debug
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
rdebug
.
num_regulators
;
i
++
)
rdebug
.
state_after_suspend
[
i
]
=
rdebug
.
regulator_array
[
i
].
is_enabled
;
}
static
int
ux500_regulator_power_state_cnt_print
(
struct
seq_file
*
s
,
void
*
p
)
{
struct
device
*
dev
=
s
->
private
;
int
err
;
/* print power state count */
err
=
seq_printf
(
s
,
"ux500-regulator power state count: %i
\n
"
,
power_state_active_get
());
if
(
err
<
0
)
dev_err
(
dev
,
"seq_printf overflow
\n
"
);
return
0
;
}
static
int
ux500_regulator_power_state_cnt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ux500_regulator_power_state_cnt_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ux500_regulator_power_state_cnt_fops
=
{
.
open
=
ux500_regulator_power_state_cnt_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ux500_regulator_status_print
(
struct
seq_file
*
s
,
void
*
p
)
{
struct
device
*
dev
=
s
->
private
;
int
err
;
int
i
;
/* print dump header */
err
=
seq_printf
(
s
,
"ux500-regulator status:
\n
"
);
if
(
err
<
0
)
dev_err
(
dev
,
"seq_printf overflow
\n
"
);
err
=
seq_printf
(
s
,
"%31s : %8s : %8s
\n
"
,
"current"
,
"before"
,
"after"
);
if
(
err
<
0
)
dev_err
(
dev
,
"seq_printf overflow
\n
"
);
for
(
i
=
0
;
i
<
rdebug
.
num_regulators
;
i
++
)
{
struct
dbx500_regulator_info
*
info
;
/* Access per-regulator data */
info
=
&
rdebug
.
regulator_array
[
i
];
/* print status */
err
=
seq_printf
(
s
,
"%20s : %8s : %8s : %8s
\n
"
,
info
->
desc
.
name
,
info
->
is_enabled
?
"enabled"
:
"disabled"
,
rdebug
.
state_before_suspend
[
i
]
?
"enabled"
:
"disabled"
,
rdebug
.
state_after_suspend
[
i
]
?
"enabled"
:
"disabled"
);
if
(
err
<
0
)
dev_err
(
dev
,
"seq_printf overflow
\n
"
);
}
return
0
;
}
static
int
ux500_regulator_status_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ux500_regulator_status_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ux500_regulator_status_fops
=
{
.
open
=
ux500_regulator_status_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
int
__attribute__
((
weak
))
dbx500_regulator_testcase
(
struct
dbx500_regulator_info
*
regulator_info
,
int
num_regulators
)
{
return
0
;
}
int
__devinit
ux500_regulator_debug_init
(
struct
platform_device
*
pdev
,
struct
dbx500_regulator_info
*
regulator_info
,
int
num_regulators
)
{
/* create directory */
rdebug
.
dir
=
debugfs_create_dir
(
"ux500-regulator"
,
NULL
);
if
(
!
rdebug
.
dir
)
goto
exit_no_debugfs
;
/* create "status" file */
rdebug
.
status_file
=
debugfs_create_file
(
"status"
,
S_IRUGO
,
rdebug
.
dir
,
&
pdev
->
dev
,
&
ux500_regulator_status_fops
);
if
(
!
rdebug
.
status_file
)
goto
exit_destroy_dir
;
/* create "power-state-count" file */
rdebug
.
power_state_cnt_file
=
debugfs_create_file
(
"power-state-count"
,
S_IRUGO
,
rdebug
.
dir
,
&
pdev
->
dev
,
&
ux500_regulator_power_state_cnt_fops
);
if
(
!
rdebug
.
power_state_cnt_file
)
goto
exit_destroy_status
;
rdebug
.
regulator_array
=
regulator_info
;
rdebug
.
num_regulators
=
num_regulators
;
rdebug
.
state_before_suspend
=
kzalloc
(
num_regulators
,
GFP_KERNEL
);
if
(
!
rdebug
.
state_before_suspend
)
{
dev_err
(
&
pdev
->
dev
,
"could not allocate memory for saving state
\n
"
);
goto
exit_destroy_power_state
;
}
rdebug
.
state_after_suspend
=
kzalloc
(
num_regulators
,
GFP_KERNEL
);
if
(
!
rdebug
.
state_after_suspend
)
{
dev_err
(
&
pdev
->
dev
,
"could not allocate memory for saving state
\n
"
);
goto
exit_free
;
}
dbx500_regulator_testcase
(
regulator_info
,
num_regulators
);
return
0
;
exit_free:
kfree
(
rdebug
.
state_before_suspend
);
exit_destroy_power_state:
debugfs_remove
(
rdebug
.
power_state_cnt_file
);
exit_destroy_status:
debugfs_remove
(
rdebug
.
status_file
);
exit_destroy_dir:
debugfs_remove
(
rdebug
.
dir
);
exit_no_debugfs:
dev_err
(
&
pdev
->
dev
,
"failed to create debugfs entries.
\n
"
);
return
-
ENOMEM
;
}
int
__devexit
ux500_regulator_debug_exit
(
void
)
{
debugfs_remove_recursive
(
rdebug
.
dir
);
kfree
(
rdebug
.
state_after_suspend
);
kfree
(
rdebug
.
state_before_suspend
);
return
0
;
}
#endif
drivers/regulator/dbx500-prcmu.h
0 → 100644
View file @
fb87ef1a
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson,
* Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
*
* License Terms: GNU General Public License v2
*
*/
#ifndef DBX500_REGULATOR_H
#define DBX500_REGULATOR_H
#include <linux/platform_device.h>
/**
* struct dbx500_regulator_info - dbx500 regulator information
* @dev: device pointer
* @desc: regulator description
* @rdev: regulator device pointer
* @is_enabled: status of the regulator
* @epod_id: id for EPOD (power domain)
* @is_ramret: RAM retention switch for EPOD (power domain)
* @operating_point: operating point (only for vape, to be removed)
*
*/
struct
dbx500_regulator_info
{
struct
device
*
dev
;
struct
regulator_desc
desc
;
struct
regulator_dev
*
rdev
;
bool
is_enabled
;
u16
epod_id
;
bool
is_ramret
;
bool
exclude_from_power_state
;
unsigned
int
operating_point
;
};
void
power_state_active_enable
(
void
);
int
power_state_active_disable
(
void
);
#ifdef CONFIG_REGULATOR_DEBUG
int
ux500_regulator_debug_init
(
struct
platform_device
*
pdev
,
struct
dbx500_regulator_info
*
regulator_info
,
int
num_regulators
);
int
ux500_regulator_debug_exit
(
void
);
#else
static
inline
int
ux500_regulator_debug_init
(
struct
platform_device
*
pdev
,
struct
dbx500_regulator_info
*
regulator_info
,
int
num_regulators
)
{
return
0
;
}
static
inline
int
ux500_regulator_debug_exit
(
void
)
{
return
0
;
}
#endif
#endif
drivers/regulator/max8997.c
View file @
fb87ef1a
...
...
@@ -908,13 +908,13 @@ static struct regulator_desc regulators[] = {
},
regulator_desc_buck
(
7
),
{
.
name
=
"EN32KHz
AP"
,
.
name
=
"EN32KHz
_
AP"
,
.
id
=
MAX8997_EN32KHZ_AP
,
.
ops
=
&
max8997_fixedvolt_ops
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
},
{
.
name
=
"EN32KHz
CP"
,
.
name
=
"EN32KHz
_
CP"
,
.
id
=
MAX8997_EN32KHZ_CP
,
.
ops
=
&
max8997_fixedvolt_ops
,
.
type
=
REGULATOR_VOLTAGE
,
...
...
@@ -938,7 +938,7 @@ static struct regulator_desc regulators[] = {
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
},
{
.
name
=
"CHARGER
CV"
,
.
name
=
"CHARGER
_
CV"
,
.
id
=
MAX8997_CHARGER_CV
,
.
ops
=
&
max8997_fixedstate_ops
,
.
type
=
REGULATOR_VOLTAGE
,
...
...
@@ -950,7 +950,7 @@ static struct regulator_desc regulators[] = {
.
type
=
REGULATOR_CURRENT
,
.
owner
=
THIS_MODULE
,
},
{
.
name
=
"CHARGER
TOPOFF"
,
.
name
=
"CHARGER
_
TOPOFF"
,
.
id
=
MAX8997_CHARGER_TOPOFF
,
.
ops
=
&
max8997_charger_fixedstate_ops
,
.
type
=
REGULATOR_CURRENT
,
...
...
drivers/regulator/mc13xxx-regulator-core.c
View file @
fb87ef1a
...
...
@@ -254,6 +254,7 @@ int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
return
num
;
}
EXPORT_SYMBOL_GPL
(
mc13xxx_get_num_regulators_dt
);
struct
mc13xxx_regulator_init_data
*
__devinit
mc13xxx_parse_regulators_dt
(
struct
platform_device
*
pdev
,
struct
mc13xxx_regulator
*
regulators
,
...
...
@@ -291,6 +292,7 @@ struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt(
return
data
;
}
EXPORT_SYMBOL_GPL
(
mc13xxx_parse_regulators_dt
);
#endif
MODULE_LICENSE
(
"GPL v2"
);
...
...
drivers/regulator/s5m8767.c
0 → 100644
View file @
fb87ef1a
/*
* s5m8767.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.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/bug.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/s5m87xx/s5m-core.h>
#include <linux/mfd/s5m87xx/s5m-pmic.h>
struct
s5m8767_info
{
struct
device
*
dev
;
struct
s5m87xx_dev
*
iodev
;
int
num_regulators
;
struct
regulator_dev
**
rdev
;
int
ramp_delay
;
bool
buck2_ramp
;
bool
buck3_ramp
;
bool
buck4_ramp
;
bool
buck2_gpiodvs
;
bool
buck3_gpiodvs
;
bool
buck4_gpiodvs
;
u8
buck2_vol
[
8
];
u8
buck3_vol
[
8
];
u8
buck4_vol
[
8
];
int
buck_gpios
[
3
];
int
buck_gpioindex
;
};
struct
s5m_voltage_desc
{
int
max
;
int
min
;
int
step
;
};
static
const
struct
s5m_voltage_desc
buck_voltage_val1
=
{
.
max
=
2225000
,
.
min
=
650000
,
.
step
=
6250
,
};
static
const
struct
s5m_voltage_desc
buck_voltage_val2
=
{
.
max
=
1600000
,
.
min
=
600000
,
.
step
=
6250
,
};
static
const
struct
s5m_voltage_desc
buck_voltage_val3
=
{
.
max
=
3000000
,
.
min
=
750000
,
.
step
=
12500
,
};
static
const
struct
s5m_voltage_desc
ldo_voltage_val1
=
{
.
max
=
3950000
,
.
min
=
800000
,
.
step
=
50000
,
};
static
const
struct
s5m_voltage_desc
ldo_voltage_val2
=
{
.
max
=
2375000
,
.
min
=
800000
,
.
step
=
25000
,
};
static
const
struct
s5m_voltage_desc
*
reg_voltage_map
[]
=
{
[
S5M8767_LDO1
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO2
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO3
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO4
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO5
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO6
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO7
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO8
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO9
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO10
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO11
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO12
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO13
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO14
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO15
]
=
&
ldo_voltage_val2
,
[
S5M8767_LDO16
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO17
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO18
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO19
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO20
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO21
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO22
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO23
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO24
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO25
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO26
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO27
]
=
&
ldo_voltage_val1
,
[
S5M8767_LDO28
]
=
&
ldo_voltage_val1
,
[
S5M8767_BUCK1
]
=
&
buck_voltage_val1
,
[
S5M8767_BUCK2
]
=
&
buck_voltage_val2
,
[
S5M8767_BUCK3
]
=
&
buck_voltage_val2
,
[
S5M8767_BUCK4
]
=
&
buck_voltage_val2
,
[
S5M8767_BUCK5
]
=
&
buck_voltage_val1
,
[
S5M8767_BUCK6
]
=
&
buck_voltage_val1
,
[
S5M8767_BUCK7
]
=
NULL
,
[
S5M8767_BUCK8
]
=
NULL
,
[
S5M8767_BUCK9
]
=
&
buck_voltage_val3
,
};
static
int
s5m8767_list_voltage
(
struct
regulator_dev
*
rdev
,
unsigned
int
selector
)
{
const
struct
s5m_voltage_desc
*
desc
;
int
reg_id
=
rdev_get_id
(
rdev
);
int
val
;
if
(
reg_id
>=
ARRAY_SIZE
(
reg_voltage_map
)
||
reg_id
<
0
)
return
-
EINVAL
;
desc
=
reg_voltage_map
[
reg_id
];
if
(
desc
==
NULL
)
return
-
EINVAL
;
val
=
desc
->
min
+
desc
->
step
*
selector
;
if
(
val
>
desc
->
max
)
return
-
EINVAL
;
return
val
;
}
static
int
s5m8767_get_register
(
struct
regulator_dev
*
rdev
,
int
*
reg
)
{
int
reg_id
=
rdev_get_id
(
rdev
);
switch
(
reg_id
)
{
case
S5M8767_LDO1
...
S5M8767_LDO2
:
*
reg
=
S5M8767_REG_LDO1CTRL
+
(
reg_id
-
S5M8767_LDO1
);
break
;
case
S5M8767_LDO3
...
S5M8767_LDO28
:
*
reg
=
S5M8767_REG_LDO3CTRL
+
(
reg_id
-
S5M8767_LDO3
);
break
;
case
S5M8767_BUCK1
:
*
reg
=
S5M8767_REG_BUCK1CTRL1
;
break
;
case
S5M8767_BUCK2
...
S5M8767_BUCK4
:
*
reg
=
S5M8767_REG_BUCK2CTRL
+
(
reg_id
-
S5M8767_BUCK2
)
*
9
;
break
;
case
S5M8767_BUCK5
:
*
reg
=
S5M8767_REG_BUCK5CTRL1
;
break
;
case
S5M8767_BUCK6
...
S5M8767_BUCK9
:
*
reg
=
S5M8767_REG_BUCK6CTRL1
+
(
reg_id
-
S5M8767_BUCK6
)
*
2
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
static
int
s5m8767_reg_is_enabled
(
struct
regulator_dev
*
rdev
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
ret
,
reg
;
int
mask
=
0xc0
,
pattern
=
0xc0
;
u8
val
;
ret
=
s5m8767_get_register
(
rdev
,
&
reg
);
if
(
ret
==
-
EINVAL
)
return
1
;
else
if
(
ret
)
return
ret
;
ret
=
s5m_reg_read
(
s5m8767
->
iodev
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
return
(
val
&
mask
)
==
pattern
;
}
static
int
s5m8767_reg_enable
(
struct
regulator_dev
*
rdev
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
ret
,
reg
;
int
mask
=
0xc0
,
pattern
=
0xc0
;
ret
=
s5m8767_get_register
(
rdev
,
&
reg
);
if
(
ret
)
return
ret
;
return
s5m_reg_update
(
s5m8767
->
iodev
,
reg
,
pattern
,
mask
);
}
static
int
s5m8767_reg_disable
(
struct
regulator_dev
*
rdev
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
ret
,
reg
;
int
mask
=
0xc0
,
pattern
=
0xc0
;
ret
=
s5m8767_get_register
(
rdev
,
&
reg
);
if
(
ret
)
return
ret
;
return
s5m_reg_update
(
s5m8767
->
iodev
,
reg
,
~
pattern
,
mask
);
}
static
int
s5m8767_get_voltage_register
(
struct
regulator_dev
*
rdev
,
int
*
_reg
)
{
int
reg_id
=
rdev_get_id
(
rdev
);
int
reg
;
switch
(
reg_id
)
{
case
S5M8767_LDO1
...
S5M8767_LDO2
:
reg
=
S5M8767_REG_LDO1CTRL
+
(
reg_id
-
S5M8767_LDO1
);
break
;
case
S5M8767_LDO3
...
S5M8767_LDO28
:
reg
=
S5M8767_REG_LDO3CTRL
+
(
reg_id
-
S5M8767_LDO3
);
break
;
case
S5M8767_BUCK1
:
reg
=
S5M8767_REG_BUCK1CTRL2
;
break
;
case
S5M8767_BUCK2
:
reg
=
S5M8767_REG_BUCK2DVS1
;
break
;
case
S5M8767_BUCK3
:
reg
=
S5M8767_REG_BUCK3DVS1
;
break
;
case
S5M8767_BUCK4
:
reg
=
S5M8767_REG_BUCK4DVS1
;
break
;
case
S5M8767_BUCK5
:
reg
=
S5M8767_REG_BUCK5CTRL2
;
break
;
case
S5M8767_BUCK6
...
S5M8767_BUCK9
:
reg
=
S5M8767_REG_BUCK6CTRL2
+
(
reg_id
-
S5M8767_BUCK6
)
*
2
;
break
;
default:
return
-
EINVAL
;
}
*
_reg
=
reg
;
return
0
;
}
static
int
s5m8767_get_voltage_sel
(
struct
regulator_dev
*
rdev
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
reg
,
mask
=
0xff
,
ret
;
int
reg_id
=
rdev_get_id
(
rdev
);
u8
val
;
ret
=
s5m8767_get_voltage_register
(
rdev
,
&
reg
);
if
(
ret
)
return
ret
;
switch
(
reg_id
)
{
case
S5M8767_LDO1
...
S5M8767_LDO28
:
mask
=
0x3f
;
break
;
case
S5M8767_BUCK2
:
if
(
s5m8767
->
buck2_gpiodvs
)
reg
+=
s5m8767
->
buck_gpioindex
;
break
;
case
S5M8767_BUCK3
:
if
(
s5m8767
->
buck3_gpiodvs
)
reg
+=
s5m8767
->
buck_gpioindex
;
break
;
case
S5M8767_BUCK4
:
if
(
s5m8767
->
buck4_gpiodvs
)
reg
+=
s5m8767
->
buck_gpioindex
;
break
;
}
ret
=
s5m_reg_read
(
s5m8767
->
iodev
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
val
&=
mask
;
return
val
;
}
static
inline
int
s5m8767_convert_voltage
(
const
struct
s5m_voltage_desc
*
desc
,
int
min_vol
,
int
max_vol
)
{
int
out_vol
=
0
;
if
(
desc
==
NULL
)
return
-
EINVAL
;
if
(
max_vol
<
desc
->
min
||
min_vol
>
desc
->
max
)
return
-
EINVAL
;
out_vol
=
(
min_vol
-
desc
->
min
)
/
desc
->
step
;
if
(
desc
->
min
+
desc
->
step
*
out_vol
>
max_vol
)
return
-
EINVAL
;
return
out_vol
;
}
static
int
s5m8767_set_voltage
(
struct
regulator_dev
*
rdev
,
int
min_uV
,
int
max_uV
,
unsigned
*
selector
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
min_vol
=
min_uV
,
max_vol
=
max_uV
;
const
struct
s5m_voltage_desc
*
desc
;
int
reg_id
=
rdev_get_id
(
rdev
);
int
reg
,
mask
,
ret
;
int
i
;
u8
val
;
switch
(
reg_id
)
{
case
S5M8767_LDO1
...
S5M8767_LDO28
:
mask
=
0x3f
;
break
;
case
S5M8767_BUCK1
...
S5M8767_BUCK6
:
mask
=
0xff
;
break
;
case
S5M8767_BUCK7
...
S5M8767_BUCK8
:
return
-
EINVAL
;
case
S5M8767_BUCK9
:
mask
=
0xff
;
break
;
default:
return
-
EINVAL
;
}
desc
=
reg_voltage_map
[
reg_id
];
i
=
s5m8767_convert_voltage
(
desc
,
min_vol
,
max_vol
);
if
(
i
<
0
)
return
i
;
ret
=
s5m8767_get_voltage_register
(
rdev
,
&
reg
);
if
(
ret
)
return
ret
;
s5m_reg_read
(
s5m8767
->
iodev
,
reg
,
&
val
);
val
=
val
&
mask
;
ret
=
s5m_reg_write
(
s5m8767
->
iodev
,
reg
,
val
);
*
selector
=
i
;
return
ret
;
}
static
inline
void
s5m8767_set_high
(
struct
s5m8767_info
*
s5m8767
)
{
int
temp_index
=
s5m8767
->
buck_gpioindex
;
gpio_set_value
(
s5m8767
->
buck_gpios
[
0
],
(
temp_index
>>
2
)
&
0x1
);
gpio_set_value
(
s5m8767
->
buck_gpios
[
1
],
(
temp_index
>>
1
)
&
0x1
);
gpio_set_value
(
s5m8767
->
buck_gpios
[
2
],
temp_index
&
0x1
);
}
static
inline
void
s5m8767_set_low
(
struct
s5m8767_info
*
s5m8767
)
{
int
temp_index
=
s5m8767
->
buck_gpioindex
;
gpio_set_value
(
s5m8767
->
buck_gpios
[
2
],
temp_index
&
0x1
);
gpio_set_value
(
s5m8767
->
buck_gpios
[
1
],
(
temp_index
>>
1
)
&
0x1
);
gpio_set_value
(
s5m8767
->
buck_gpios
[
0
],
(
temp_index
>>
2
)
&
0x1
);
}
static
int
s5m8767_set_voltage_buck
(
struct
regulator_dev
*
rdev
,
int
min_uV
,
int
max_uV
,
unsigned
*
selector
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
int
reg_id
=
rdev_get_id
(
rdev
);
const
struct
s5m_voltage_desc
*
desc
;
int
new_val
,
old_val
,
i
=
0
;
int
min_vol
=
min_uV
,
max_vol
=
max_uV
;
if
(
reg_id
<
S5M8767_BUCK1
||
reg_id
>
S5M8767_BUCK6
)
return
-
EINVAL
;
switch
(
reg_id
)
{
case
S5M8767_BUCK1
:
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
case
S5M8767_BUCK2
...
S5M8767_BUCK4
:
break
;
case
S5M8767_BUCK5
...
S5M8767_BUCK6
:
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
case
S5M8767_BUCK9
:
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
}
desc
=
reg_voltage_map
[
reg_id
];
new_val
=
s5m8767_convert_voltage
(
desc
,
min_vol
,
max_vol
);
if
(
new_val
<
0
)
return
new_val
;
switch
(
reg_id
)
{
case
S5M8767_BUCK2
:
if
(
s5m8767
->
buck2_gpiodvs
)
{
while
(
s5m8767
->
buck2_vol
[
i
]
!=
new_val
)
i
++
;
}
else
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
break
;
case
S5M8767_BUCK3
:
if
(
s5m8767
->
buck3_gpiodvs
)
{
while
(
s5m8767
->
buck3_vol
[
i
]
!=
new_val
)
i
++
;
}
else
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
break
;
case
S5M8767_BUCK4
:
if
(
s5m8767
->
buck3_gpiodvs
)
{
while
(
s5m8767
->
buck4_vol
[
i
]
!=
new_val
)
i
++
;
}
else
return
s5m8767_set_voltage
(
rdev
,
min_uV
,
max_uV
,
selector
);
break
;
}
old_val
=
s5m8767
->
buck_gpioindex
;
s5m8767
->
buck_gpioindex
=
i
;
if
(
i
>
old_val
)
s5m8767_set_high
(
s5m8767
);
else
s5m8767_set_low
(
s5m8767
);
*
selector
=
new_val
;
return
0
;
}
static
int
s5m8767_set_voltage_time_sel
(
struct
regulator_dev
*
rdev
,
unsigned
int
old_sel
,
unsigned
int
new_sel
)
{
struct
s5m8767_info
*
s5m8767
=
rdev_get_drvdata
(
rdev
);
const
struct
s5m_voltage_desc
*
desc
;
int
reg_id
=
rdev_get_id
(
rdev
);
int
mask
;
int
new_val
,
old_val
;
switch
(
reg_id
)
{
case
S5M8767_LDO1
...
S5M8767_LDO28
:
mask
=
0x3f
;
break
;
case
S5M8767_BUCK1
...
S5M8767_BUCK6
:
mask
=
0xff
;
break
;
case
S5M8767_BUCK7
...
S5M8767_BUCK8
:
return
-
EINVAL
;
case
S5M8767_BUCK9
:
mask
=
0xff
;
break
;
default:
return
-
EINVAL
;
}
desc
=
reg_voltage_map
[
reg_id
];
new_val
=
s5m8767_convert_voltage
(
desc
,
new_sel
,
new_sel
);
if
(
new_val
<
0
)
return
new_val
;
old_val
=
s5m8767_convert_voltage
(
desc
,
old_sel
,
old_sel
);
if
(
old_val
<
0
)
return
old_val
;
if
(
old_sel
<
new_sel
)
return
DIV_ROUND_UP
(
desc
->
step
*
(
new_val
-
old_val
),
s5m8767
->
ramp_delay
);
else
return
0
;
}
static
struct
regulator_ops
s5m8767_ldo_ops
=
{
.
list_voltage
=
s5m8767_list_voltage
,
.
is_enabled
=
s5m8767_reg_is_enabled
,
.
enable
=
s5m8767_reg_enable
,
.
disable
=
s5m8767_reg_disable
,
.
get_voltage_sel
=
s5m8767_get_voltage_sel
,
.
set_voltage
=
s5m8767_set_voltage
,
.
set_voltage_time_sel
=
s5m8767_set_voltage_time_sel
,
};
static
struct
regulator_ops
s5m8767_buck_ops
=
{
.
list_voltage
=
s5m8767_list_voltage
,
.
is_enabled
=
s5m8767_reg_is_enabled
,
.
enable
=
s5m8767_reg_enable
,
.
disable
=
s5m8767_reg_disable
,
.
get_voltage_sel
=
s5m8767_get_voltage_sel
,
.
set_voltage
=
s5m8767_set_voltage_buck
,
.
set_voltage_time_sel
=
s5m8767_set_voltage_time_sel
,
};
#define regulator_desc_ldo(num) { \
.name = "LDO"#num, \
.id = S5M8767_LDO##num, \
.ops = &s5m8767_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
#define regulator_desc_buck(num) { \
.name = "BUCK"#num, \
.id = S5M8767_BUCK##num, \
.ops = &s5m8767_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
static
struct
regulator_desc
regulators
[]
=
{
regulator_desc_ldo
(
1
),
regulator_desc_ldo
(
2
),
regulator_desc_ldo
(
3
),
regulator_desc_ldo
(
4
),
regulator_desc_ldo
(
5
),
regulator_desc_ldo
(
6
),
regulator_desc_ldo
(
7
),
regulator_desc_ldo
(
8
),
regulator_desc_ldo
(
9
),
regulator_desc_ldo
(
10
),
regulator_desc_ldo
(
11
),
regulator_desc_ldo
(
12
),
regulator_desc_ldo
(
13
),
regulator_desc_ldo
(
14
),
regulator_desc_ldo
(
15
),
regulator_desc_ldo
(
16
),
regulator_desc_ldo
(
17
),
regulator_desc_ldo
(
18
),
regulator_desc_ldo
(
19
),
regulator_desc_ldo
(
20
),
regulator_desc_ldo
(
21
),
regulator_desc_ldo
(
22
),
regulator_desc_ldo
(
23
),
regulator_desc_ldo
(
24
),
regulator_desc_ldo
(
25
),
regulator_desc_ldo
(
26
),
regulator_desc_ldo
(
27
),
regulator_desc_ldo
(
28
),
regulator_desc_buck
(
1
),
regulator_desc_buck
(
2
),
regulator_desc_buck
(
3
),
regulator_desc_buck
(
4
),
regulator_desc_buck
(
5
),
regulator_desc_buck
(
6
),
regulator_desc_buck
(
7
),
regulator_desc_buck
(
8
),
regulator_desc_buck
(
9
),
};
static
__devinit
int
s5m8767_pmic_probe
(
struct
platform_device
*
pdev
)
{
struct
s5m87xx_dev
*
iodev
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
s5m_platform_data
*
pdata
=
dev_get_platdata
(
iodev
->
dev
);
struct
regulator_dev
**
rdev
;
struct
s5m8767_info
*
s5m8767
;
struct
i2c_client
*
i2c
;
int
i
,
ret
,
size
,
reg
;
if
(
!
pdata
)
{
dev_err
(
pdev
->
dev
.
parent
,
"Platform data not supplied
\n
"
);
return
-
ENODEV
;
}
s5m8767
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
s5m8767_info
),
GFP_KERNEL
);
if
(
!
s5m8767
)
return
-
ENOMEM
;
size
=
sizeof
(
struct
regulator_dev
*
)
*
(
S5M8767_REG_MAX
-
2
);
s5m8767
->
rdev
=
devm_kzalloc
(
&
pdev
->
dev
,
size
,
GFP_KERNEL
);
if
(
!
s5m8767
->
rdev
)
return
-
ENOMEM
;
rdev
=
s5m8767
->
rdev
;
s5m8767
->
dev
=
&
pdev
->
dev
;
s5m8767
->
iodev
=
iodev
;
s5m8767
->
num_regulators
=
S5M8767_REG_MAX
-
2
;
platform_set_drvdata
(
pdev
,
s5m8767
);
i2c
=
s5m8767
->
iodev
->
i2c
;
s5m8767
->
buck_gpioindex
=
pdata
->
buck_default_idx
;
s5m8767
->
buck2_gpiodvs
=
pdata
->
buck2_gpiodvs
;
s5m8767
->
buck3_gpiodvs
=
pdata
->
buck3_gpiodvs
;
s5m8767
->
buck4_gpiodvs
=
pdata
->
buck4_gpiodvs
;
s5m8767
->
buck_gpios
[
0
]
=
pdata
->
buck_gpios
[
0
];
s5m8767
->
buck_gpios
[
1
]
=
pdata
->
buck_gpios
[
1
];
s5m8767
->
buck_gpios
[
2
]
=
pdata
->
buck_gpios
[
2
];
s5m8767
->
ramp_delay
=
pdata
->
buck_ramp_delay
;
s5m8767
->
buck2_ramp
=
pdata
->
buck2_ramp_enable
;
s5m8767
->
buck3_ramp
=
pdata
->
buck3_ramp_enable
;
s5m8767
->
buck4_ramp
=
pdata
->
buck4_ramp_enable
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
s5m8767
->
buck2_gpiodvs
)
{
s5m8767
->
buck2_vol
[
i
]
=
s5m8767_convert_voltage
(
&
buck_voltage_val2
,
pdata
->
buck2_voltage
[
i
],
pdata
->
buck2_voltage
[
i
]
+
buck_voltage_val2
.
step
);
}
if
(
s5m8767
->
buck3_gpiodvs
)
{
s5m8767
->
buck3_vol
[
i
]
=
s5m8767_convert_voltage
(
&
buck_voltage_val2
,
pdata
->
buck3_voltage
[
i
],
pdata
->
buck3_voltage
[
i
]
+
buck_voltage_val2
.
step
);
}
if
(
s5m8767
->
buck4_gpiodvs
)
{
s5m8767
->
buck4_vol
[
i
]
=
s5m8767_convert_voltage
(
&
buck_voltage_val2
,
pdata
->
buck4_voltage
[
i
],
pdata
->
buck4_voltage
[
i
]
+
buck_voltage_val2
.
step
);
}
}
if
(
pdata
->
buck2_gpiodvs
||
pdata
->
buck3_gpiodvs
||
pdata
->
buck4_gpiodvs
)
{
if
(
gpio_is_valid
(
pdata
->
buck_gpios
[
0
])
&&
gpio_is_valid
(
pdata
->
buck_gpios
[
1
])
&&
gpio_is_valid
(
pdata
->
buck_gpios
[
2
]))
{
ret
=
gpio_request
(
pdata
->
buck_gpios
[
0
],
"S5M8767 SET1"
);
if
(
ret
==
-
EBUSY
)
dev_warn
(
&
pdev
->
dev
,
"Duplicated gpio request for SET1
\n
"
);
ret
=
gpio_request
(
pdata
->
buck_gpios
[
1
],
"S5M8767 SET2"
);
if
(
ret
==
-
EBUSY
)
dev_warn
(
&
pdev
->
dev
,
"Duplicated gpio request for SET2
\n
"
);
ret
=
gpio_request
(
pdata
->
buck_gpios
[
2
],
"S5M8767 SET3"
);
if
(
ret
==
-
EBUSY
)
dev_warn
(
&
pdev
->
dev
,
"Duplicated gpio request for SET3
\n
"
);
/* SET1 GPIO */
gpio_direction_output
(
pdata
->
buck_gpios
[
0
],
(
s5m8767
->
buck_gpioindex
>>
2
)
&
0x1
);
/* SET2 GPIO */
gpio_direction_output
(
pdata
->
buck_gpios
[
1
],
(
s5m8767
->
buck_gpioindex
>>
1
)
&
0x1
);
/* SET3 GPIO */
gpio_direction_output
(
pdata
->
buck_gpios
[
2
],
(
s5m8767
->
buck_gpioindex
>>
0
)
&
0x1
);
ret
=
0
;
}
else
{
dev_err
(
&
pdev
->
dev
,
"GPIO NOT VALID
\n
"
);
ret
=
-
EINVAL
;
return
ret
;
}
}
if
(
pdata
->
buck2_gpiodvs
)
{
if
(
pdata
->
buck3_gpiodvs
||
pdata
->
buck4_gpiodvs
)
{
dev_err
(
&
pdev
->
dev
,
"S5M8767 GPIO DVS NOT VALID
\n
"
);
ret
=
-
EINVAL
;
return
ret
;
}
}
if
(
pdata
->
buck3_gpiodvs
)
{
if
(
pdata
->
buck2_gpiodvs
||
pdata
->
buck4_gpiodvs
)
{
dev_err
(
&
pdev
->
dev
,
"S5M8767 GPIO DVS NOT VALID
\n
"
);
ret
=
-
EINVAL
;
return
ret
;
}
}
if
(
pdata
->
buck4_gpiodvs
)
{
if
(
pdata
->
buck2_gpiodvs
||
pdata
->
buck3_gpiodvs
)
{
dev_err
(
&
pdev
->
dev
,
"S5M8767 GPIO DVS NOT VALID
\n
"
);
ret
=
-
EINVAL
;
return
ret
;
}
}
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK2CTRL
,
(
pdata
->
buck2_gpiodvs
)
?
(
1
<<
1
)
:
(
0
<<
1
),
1
<<
1
);
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK3CTRL
,
(
pdata
->
buck3_gpiodvs
)
?
(
1
<<
1
)
:
(
0
<<
1
),
1
<<
1
);
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK4CTRL
,
(
pdata
->
buck4_gpiodvs
)
?
(
1
<<
1
)
:
(
0
<<
1
),
1
<<
1
);
/* Initialize GPIO DVS registers */
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
s5m8767
->
buck2_gpiodvs
)
{
s5m_reg_write
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK2DVS1
+
i
,
s5m8767
->
buck2_vol
[
i
]);
}
if
(
s5m8767
->
buck3_gpiodvs
)
{
s5m_reg_write
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK3DVS1
+
i
,
s5m8767
->
buck3_vol
[
i
]);
}
if
(
s5m8767
->
buck4_gpiodvs
)
{
s5m_reg_write
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK4DVS1
+
i
,
s5m8767
->
buck4_vol
[
i
]);
}
}
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK2CTRL
,
0x78
,
0xff
);
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK3CTRL
,
0x58
,
0xff
);
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_BUCK4CTRL
,
0x78
,
0xff
);
if
(
s5m8767
->
buck2_ramp
)
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0x08
,
0x08
);
if
(
s5m8767
->
buck3_ramp
)
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0x04
,
0x04
);
if
(
s5m8767
->
buck4_ramp
)
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0x02
,
0x02
);
if
(
s5m8767
->
buck2_ramp
||
s5m8767
->
buck3_ramp
||
s5m8767
->
buck4_ramp
)
{
switch
(
s5m8767
->
ramp_delay
)
{
case
15
:
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0xc0
,
0xf0
);
break
;
case
25
:
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0xd0
,
0xf0
);
break
;
case
50
:
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0xe0
,
0xf0
);
break
;
case
100
:
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0xf0
,
0xf0
);
break
;
default:
s5m_reg_update
(
s5m8767
->
iodev
,
S5M8767_REG_DVSRAMP
,
0x90
,
0xf0
);
}
}
for
(
i
=
0
;
i
<
pdata
->
num_regulators
;
i
++
)
{
const
struct
s5m_voltage_desc
*
desc
;
int
id
=
pdata
->
regulators
[
i
].
id
;
desc
=
reg_voltage_map
[
id
];
if
(
desc
)
regulators
[
id
].
n_voltages
=
(
desc
->
max
-
desc
->
min
)
/
desc
->
step
+
1
;
rdev
[
i
]
=
regulator_register
(
&
regulators
[
id
],
s5m8767
->
dev
,
pdata
->
regulators
[
i
].
initdata
,
s5m8767
,
NULL
);
if
(
IS_ERR
(
rdev
[
i
]))
{
ret
=
PTR_ERR
(
rdev
[
i
]);
dev_err
(
s5m8767
->
dev
,
"regulator init failed for %d
\n
"
,
id
);
rdev
[
i
]
=
NULL
;
goto
err
;
}
}
return
0
;
err:
for
(
i
=
0
;
i
<
s5m8767
->
num_regulators
;
i
++
)
if
(
rdev
[
i
])
regulator_unregister
(
rdev
[
i
]);
return
ret
;
}
static
int
__devexit
s5m8767_pmic_remove
(
struct
platform_device
*
pdev
)
{
struct
s5m8767_info
*
s5m8767
=
platform_get_drvdata
(
pdev
);
struct
regulator_dev
**
rdev
=
s5m8767
->
rdev
;
int
i
;
for
(
i
=
0
;
i
<
s5m8767
->
num_regulators
;
i
++
)
if
(
rdev
[
i
])
regulator_unregister
(
rdev
[
i
]);
return
0
;
}
static
const
struct
platform_device_id
s5m8767_pmic_id
[]
=
{
{
"s5m8767-pmic"
,
0
},
{
},
};
MODULE_DEVICE_TABLE
(
platform
,
s5m8767_pmic_id
);
static
struct
platform_driver
s5m8767_pmic_driver
=
{
.
driver
=
{
.
name
=
"s5m8767-pmic"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
s5m8767_pmic_probe
,
.
remove
=
__devexit_p
(
s5m8767_pmic_remove
),
.
id_table
=
s5m8767_pmic_id
,
};
static
int
__init
s5m8767_pmic_init
(
void
)
{
return
platform_driver_register
(
&
s5m8767_pmic_driver
);
}
subsys_initcall
(
s5m8767_pmic_init
);
static
void
__exit
s5m8767_pmic_exit
(
void
)
{
platform_driver_unregister
(
&
s5m8767_pmic_driver
);
}
module_exit
(
s5m8767_pmic_exit
);
/* Module information */
MODULE_AUTHOR
(
"Sangbeom Kim <sbkim73@samsung.com>"
);
MODULE_DESCRIPTION
(
"SAMSUNG S5M8767 Regulator Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/regulator/tps62360-regulator.c
0 → 100644
View file @
fb87ef1a
/*
* tps62360.c -- TI tps62360
*
* Driver for processor core supply tps62360 and tps62361B
*
* Copyright (c) 2012, NVIDIA Corporation.
*
* Author: Laxman Dewangan <ldewangan@nvidia.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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
#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/regulator/tps62360.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/regmap.h>
/* Register definitions */
#define REG_VSET0 0
#define REG_VSET1 1
#define REG_VSET2 2
#define REG_VSET3 3
#define REG_CONTROL 4
#define REG_TEMP 5
#define REG_RAMPCTRL 6
#define REG_CHIPID 8
enum
chips
{
TPS62360
,
TPS62361
};
#define TPS62360_BASE_VOLTAGE 770
#define TPS62360_N_VOLTAGES 64
#define TPS62361_BASE_VOLTAGE 500
#define TPS62361_N_VOLTAGES 128
/* tps 62360 chip information */
struct
tps62360_chip
{
const
char
*
name
;
struct
device
*
dev
;
struct
regulator_desc
desc
;
struct
i2c_client
*
client
;
struct
regulator_dev
*
rdev
;
struct
regmap
*
regmap
;
int
chip_id
;
int
vsel0_gpio
;
int
vsel1_gpio
;
int
voltage_base
;
u8
voltage_reg_mask
;
bool
en_internal_pulldn
;
bool
en_force_pwm
;
bool
en_discharge
;
bool
valid_gpios
;
int
lru_index
[
4
];
int
curr_vset_vsel
[
4
];
int
curr_vset_id
;
};
/*
* find_voltage_set_register: Find new voltage configuration register
* (VSET) id.
* The finding of the new VSET register will be based on the LRU mechanism.
* Each VSET register will have different voltage configured . This
* Function will look if any of the VSET register have requested voltage set
* or not.
* - If it is already there then it will make that register as most
* recently used and return as found so that caller need not to set
* the VSET register but need to set the proper gpios to select this
* VSET register.
* - If requested voltage is not found then it will use the least
* recently mechanism to get new VSET register for new configuration
* and will return not_found so that caller need to set new VSET
* register and then gpios (both).
*/
static
bool
find_voltage_set_register
(
struct
tps62360_chip
*
tps
,
int
req_vsel
,
int
*
vset_reg_id
)
{
int
i
;
bool
found
=
false
;
int
new_vset_reg
=
tps
->
lru_index
[
3
];
int
found_index
=
3
;
for
(
i
=
0
;
i
<
4
;
++
i
)
{
if
(
tps
->
curr_vset_vsel
[
tps
->
lru_index
[
i
]]
==
req_vsel
)
{
new_vset_reg
=
tps
->
lru_index
[
i
];
found_index
=
i
;
found
=
true
;
goto
update_lru_index
;
}
}
update_lru_index:
for
(
i
=
found_index
;
i
>
0
;
i
--
)
tps
->
lru_index
[
i
]
=
tps
->
lru_index
[
i
-
1
];
tps
->
lru_index
[
0
]
=
new_vset_reg
;
*
vset_reg_id
=
new_vset_reg
;
return
found
;
}
static
int
tps62360_dcdc_get_voltage
(
struct
regulator_dev
*
dev
)
{
struct
tps62360_chip
*
tps
=
rdev_get_drvdata
(
dev
);
int
vsel
;
unsigned
int
data
;
int
ret
;
ret
=
regmap_read
(
tps
->
regmap
,
REG_VSET0
+
tps
->
curr_vset_id
,
&
data
);
if
(
ret
<
0
)
{
dev_err
(
tps
->
dev
,
"%s: Error in reading register %d
\n
"
,
__func__
,
REG_VSET0
+
tps
->
curr_vset_id
);
return
ret
;
}
vsel
=
(
int
)
data
&
tps
->
voltage_reg_mask
;
return
(
tps
->
voltage_base
+
vsel
*
10
)
*
1000
;
}
static
int
tps62360_dcdc_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
,
unsigned
*
selector
)
{
struct
tps62360_chip
*
tps
=
rdev_get_drvdata
(
dev
);
int
vsel
;
int
ret
;
bool
found
=
false
;
int
new_vset_id
=
tps
->
curr_vset_id
;
if
(
max_uV
<
min_uV
)
return
-
EINVAL
;
if
(
min_uV
>
((
tps
->
voltage_base
+
(
tps
->
desc
.
n_voltages
-
1
)
*
10
)
*
1000
))
return
-
EINVAL
;
if
(
max_uV
<
tps
->
voltage_base
*
1000
)
return
-
EINVAL
;
vsel
=
DIV_ROUND_UP
(
min_uV
-
(
tps
->
voltage_base
*
1000
),
10000
);
if
(
selector
)
*
selector
=
(
vsel
&
tps
->
voltage_reg_mask
);
/*
* If gpios are available to select the VSET register then least
* recently used register for new configuration.
*/
if
(
tps
->
valid_gpios
)
found
=
find_voltage_set_register
(
tps
,
vsel
,
&
new_vset_id
);
if
(
!
found
)
{
ret
=
regmap_update_bits
(
tps
->
regmap
,
REG_VSET0
+
new_vset_id
,
tps
->
voltage_reg_mask
,
vsel
);
if
(
ret
<
0
)
{
dev_err
(
tps
->
dev
,
"%s: Error in updating register %d
\n
"
,
__func__
,
REG_VSET0
+
new_vset_id
);
return
ret
;
}
tps
->
curr_vset_id
=
new_vset_id
;
tps
->
curr_vset_vsel
[
new_vset_id
]
=
vsel
;
}
/* Select proper VSET register vio gpios */
if
(
tps
->
valid_gpios
)
{
gpio_set_value_cansleep
(
tps
->
vsel0_gpio
,
new_vset_id
&
0x1
);
gpio_set_value_cansleep
(
tps
->
vsel1_gpio
,
(
new_vset_id
>>
1
)
&
0x1
);
}
return
0
;
}
static
int
tps62360_dcdc_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps62360_chip
*
tps
=
rdev_get_drvdata
(
dev
);
if
((
selector
<
0
)
||
(
selector
>=
tps
->
desc
.
n_voltages
))
return
-
EINVAL
;
return
(
tps
->
voltage_base
+
selector
*
10
)
*
1000
;
}
static
struct
regulator_ops
tps62360_dcdc_ops
=
{
.
get_voltage
=
tps62360_dcdc_get_voltage
,
.
set_voltage
=
tps62360_dcdc_set_voltage
,
.
list_voltage
=
tps62360_dcdc_list_voltage
,
};
static
int
tps62360_init_force_pwm
(
struct
tps62360_chip
*
tps
,
struct
tps62360_regulator_platform_data
*
pdata
,
int
vset_id
)
{
unsigned
int
data
;
int
ret
;
ret
=
regmap_read
(
tps
->
regmap
,
REG_VSET0
+
vset_id
,
&
data
);
if
(
ret
<
0
)
{
dev_err
(
tps
->
dev
,
"%s() fails in writing reg %d
\n
"
,
__func__
,
REG_VSET0
+
vset_id
);
return
ret
;
}
tps
->
curr_vset_vsel
[
vset_id
]
=
data
&
tps
->
voltage_reg_mask
;
if
(
pdata
->
en_force_pwm
)
data
|=
BIT
(
7
);
else
data
&=
~
BIT
(
7
);
ret
=
regmap_write
(
tps
->
regmap
,
REG_VSET0
+
vset_id
,
data
);
if
(
ret
<
0
)
dev_err
(
tps
->
dev
,
"%s() fails in writing reg %d
\n
"
,
__func__
,
REG_VSET0
+
vset_id
);
return
ret
;
}
static
int
tps62360_init_dcdc
(
struct
tps62360_chip
*
tps
,
struct
tps62360_regulator_platform_data
*
pdata
)
{
int
ret
;
int
i
;
/* Initailize internal pull up/down control */
if
(
tps
->
en_internal_pulldn
)
ret
=
regmap_write
(
tps
->
regmap
,
REG_CONTROL
,
0xE0
);
else
ret
=
regmap_write
(
tps
->
regmap
,
REG_CONTROL
,
0x0
);
if
(
ret
<
0
)
{
dev_err
(
tps
->
dev
,
"%s() fails in writing reg %d
\n
"
,
__func__
,
REG_CONTROL
);
return
ret
;
}
/* Initailize force PWM mode */
if
(
tps
->
valid_gpios
)
{
for
(
i
=
0
;
i
<
4
;
++
i
)
{
ret
=
tps62360_init_force_pwm
(
tps
,
pdata
,
i
);
if
(
ret
<
0
)
return
ret
;
}
}
else
{
ret
=
tps62360_init_force_pwm
(
tps
,
pdata
,
tps
->
curr_vset_id
);
if
(
ret
<
0
)
return
ret
;
}
/* Reset output discharge path to reduce power consumption */
ret
=
regmap_update_bits
(
tps
->
regmap
,
REG_RAMPCTRL
,
BIT
(
2
),
0
);
if
(
ret
<
0
)
dev_err
(
tps
->
dev
,
"%s() fails in updating reg %d
\n
"
,
__func__
,
REG_RAMPCTRL
);
return
ret
;
}
static
const
struct
regmap_config
tps62360_regmap_config
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
};
static
int
__devinit
tps62360_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
tps62360_regulator_platform_data
*
pdata
;
struct
regulator_dev
*
rdev
;
struct
tps62360_chip
*
tps
;
int
ret
;
int
i
;
pdata
=
client
->
dev
.
platform_data
;
if
(
!
pdata
)
{
dev_err
(
&
client
->
dev
,
"%s() Err: Platform data not found
\n
"
,
__func__
);
return
-
EIO
;
}
tps
=
devm_kzalloc
(
&
client
->
dev
,
sizeof
(
*
tps
),
GFP_KERNEL
);
if
(
!
tps
)
{
dev_err
(
&
client
->
dev
,
"%s() Err: Memory allocation fails
\n
"
,
__func__
);
return
-
ENOMEM
;
}
tps
->
en_force_pwm
=
pdata
->
en_force_pwm
;
tps
->
en_discharge
=
pdata
->
en_discharge
;
tps
->
en_internal_pulldn
=
pdata
->
en_internal_pulldn
;
tps
->
vsel0_gpio
=
pdata
->
vsel0_gpio
;
tps
->
vsel1_gpio
=
pdata
->
vsel1_gpio
;
tps
->
client
=
client
;
tps
->
dev
=
&
client
->
dev
;
tps
->
name
=
id
->
name
;
tps
->
voltage_base
=
(
id
->
driver_data
==
TPS62360
)
?
TPS62360_BASE_VOLTAGE
:
TPS62361_BASE_VOLTAGE
;
tps
->
voltage_reg_mask
=
(
id
->
driver_data
==
TPS62360
)
?
0x3F
:
0x7F
;
tps
->
desc
.
name
=
id
->
name
;
tps
->
desc
.
id
=
0
;
tps
->
desc
.
n_voltages
=
(
id
->
driver_data
==
TPS62360
)
?
TPS62360_N_VOLTAGES
:
TPS62361_N_VOLTAGES
;
tps
->
desc
.
ops
=
&
tps62360_dcdc_ops
;
tps
->
desc
.
type
=
REGULATOR_VOLTAGE
;
tps
->
desc
.
owner
=
THIS_MODULE
;
tps
->
regmap
=
regmap_init_i2c
(
client
,
&
tps62360_regmap_config
);
if
(
IS_ERR
(
tps
->
regmap
))
{
ret
=
PTR_ERR
(
tps
->
regmap
);
dev_err
(
&
client
->
dev
,
"%s() Err: Failed to allocate register"
"map: %d
\n
"
,
__func__
,
ret
);
return
ret
;
}
i2c_set_clientdata
(
client
,
tps
);
tps
->
curr_vset_id
=
(
pdata
->
vsel1_def_state
&
1
)
*
2
+
(
pdata
->
vsel0_def_state
&
1
);
tps
->
lru_index
[
0
]
=
tps
->
curr_vset_id
;
tps
->
valid_gpios
=
false
;
if
(
gpio_is_valid
(
tps
->
vsel0_gpio
)
&&
gpio_is_valid
(
tps
->
vsel1_gpio
))
{
ret
=
gpio_request
(
tps
->
vsel0_gpio
,
"tps62360-vsel0"
);
if
(
ret
)
{
dev_err
(
&
client
->
dev
,
"Err: Could not obtain vsel0 GPIO %d: %d
\n
"
,
tps
->
vsel0_gpio
,
ret
);
goto
err_gpio0
;
}
ret
=
gpio_direction_output
(
tps
->
vsel0_gpio
,
pdata
->
vsel0_def_state
);
if
(
ret
)
{
dev_err
(
&
client
->
dev
,
"Err: Could not set direction of"
"vsel0 GPIO %d: %d
\n
"
,
tps
->
vsel0_gpio
,
ret
);
gpio_free
(
tps
->
vsel0_gpio
);
goto
err_gpio0
;
}
ret
=
gpio_request
(
tps
->
vsel1_gpio
,
"tps62360-vsel1"
);
if
(
ret
)
{
dev_err
(
&
client
->
dev
,
"Err: Could not obtain vsel1 GPIO %d: %d
\n
"
,
tps
->
vsel1_gpio
,
ret
);
goto
err_gpio1
;
}
ret
=
gpio_direction_output
(
tps
->
vsel1_gpio
,
pdata
->
vsel1_def_state
);
if
(
ret
)
{
dev_err
(
&
client
->
dev
,
"Err: Could not set direction of"
"vsel1 GPIO %d: %d
\n
"
,
tps
->
vsel1_gpio
,
ret
);
gpio_free
(
tps
->
vsel1_gpio
);
goto
err_gpio1
;
}
tps
->
valid_gpios
=
true
;
/*
* Initialize the lru index with vset_reg id
* The index 0 will be most recently used and
* set with the tps->curr_vset_id */
for
(
i
=
0
;
i
<
4
;
++
i
)
tps
->
lru_index
[
i
]
=
i
;
tps
->
lru_index
[
0
]
=
tps
->
curr_vset_id
;
tps
->
lru_index
[
tps
->
curr_vset_id
]
=
0
;
}
ret
=
tps62360_init_dcdc
(
tps
,
pdata
);
if
(
ret
<
0
)
{
dev_err
(
tps
->
dev
,
"%s() Err: Init fails with = %d
\n
"
,
__func__
,
ret
);
goto
err_init
;
}
/* Register the regulators */
rdev
=
regulator_register
(
&
tps
->
desc
,
&
client
->
dev
,
&
pdata
->
reg_init_data
,
tps
,
NULL
);
if
(
IS_ERR
(
rdev
))
{
dev_err
(
tps
->
dev
,
"%s() Err: Failed to register %s
\n
"
,
__func__
,
id
->
name
);
ret
=
PTR_ERR
(
rdev
);
goto
err_init
;
}
tps
->
rdev
=
rdev
;
return
0
;
err_init:
if
(
gpio_is_valid
(
tps
->
vsel1_gpio
))
gpio_free
(
tps
->
vsel1_gpio
);
err_gpio1:
if
(
gpio_is_valid
(
tps
->
vsel0_gpio
))
gpio_free
(
tps
->
vsel0_gpio
);
err_gpio0:
regmap_exit
(
tps
->
regmap
);
return
ret
;
}
/**
* tps62360_remove - tps62360 driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister TPS driver as an i2c client device driver
*/
static
int
__devexit
tps62360_remove
(
struct
i2c_client
*
client
)
{
struct
tps62360_chip
*
tps
=
i2c_get_clientdata
(
client
);
if
(
gpio_is_valid
(
tps
->
vsel1_gpio
))
gpio_free
(
tps
->
vsel1_gpio
);
if
(
gpio_is_valid
(
tps
->
vsel0_gpio
))
gpio_free
(
tps
->
vsel0_gpio
);
regulator_unregister
(
tps
->
rdev
);
regmap_exit
(
tps
->
regmap
);
return
0
;
}
static
void
tps62360_shutdown
(
struct
i2c_client
*
client
)
{
struct
tps62360_chip
*
tps
=
i2c_get_clientdata
(
client
);
int
st
;
if
(
!
tps
->
en_discharge
)
return
;
/* Configure the output discharge path */
st
=
regmap_update_bits
(
tps
->
regmap
,
REG_RAMPCTRL
,
BIT
(
2
),
BIT
(
2
));
if
(
st
<
0
)
dev_err
(
tps
->
dev
,
"%s() fails in updating reg %d
\n
"
,
__func__
,
REG_RAMPCTRL
);
}
static
const
struct
i2c_device_id
tps62360_id
[]
=
{
{.
name
=
"tps62360"
,
.
driver_data
=
TPS62360
},
{.
name
=
"tps62361"
,
.
driver_data
=
TPS62361
},
{},
};
MODULE_DEVICE_TABLE
(
i2c
,
tps62360_id
);
static
struct
i2c_driver
tps62360_i2c_driver
=
{
.
driver
=
{
.
name
=
"tps62360"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
tps62360_probe
,
.
remove
=
__devexit_p
(
tps62360_remove
),
.
shutdown
=
tps62360_shutdown
,
.
id_table
=
tps62360_id
,
};
static
int
__init
tps62360_init
(
void
)
{
return
i2c_add_driver
(
&
tps62360_i2c_driver
);
}
subsys_initcall
(
tps62360_init
);
static
void
__exit
tps62360_cleanup
(
void
)
{
i2c_del_driver
(
&
tps62360_i2c_driver
);
}
module_exit
(
tps62360_cleanup
);
MODULE_AUTHOR
(
"Laxman Dewangan <ldewangan@nvidia.com>"
);
MODULE_DESCRIPTION
(
"TPS62360 voltage regulator driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/tps65217-regulator.c
0 → 100644
View file @
fb87ef1a
/*
* tps65217-regulator.c
*
* Regulator driver for TPS65217 PMIC
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.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/tps65217.h>
#define TPS65217_REGULATOR(_name, _id, _ops, _n) \
{ \
.name = _name, \
.id = _id, \
.ops = &_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
} \
#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm) \
{ \
.name = _nm, \
.min_uV = _min, \
.max_uV = _max, \
.vsel_to_uv = _f1, \
.uv_to_vsel = _f2, \
.table = _t, \
.table_len = _n, \
.enable_mask = _em, \
.set_vout_reg = _vr, \
.set_vout_mask = _vm, \
}
static
const
int
LDO1_VSEL_table
[]
=
{
1000000
,
1100000
,
1200000
,
1250000
,
1300000
,
1350000
,
1400000
,
1500000
,
1600000
,
1800000
,
2500000
,
2750000
,
2800000
,
3000000
,
3100000
,
3300000
,
};
static
int
tps65217_vsel_to_uv1
(
unsigned
int
vsel
)
{
int
uV
=
0
;
if
(
vsel
>
63
)
return
-
EINVAL
;
if
(
vsel
<=
24
)
uV
=
vsel
*
25000
+
900000
;
else
if
(
vsel
<=
52
)
uV
=
(
vsel
-
24
)
*
50000
+
1500000
;
else
if
(
vsel
<
56
)
uV
=
(
vsel
-
52
)
*
100000
+
2900000
;
else
uV
=
3300000
;
return
uV
;
}
static
int
tps65217_uv_to_vsel1
(
int
uV
,
unsigned
int
*
vsel
)
{
if
((
uV
<
0
)
&&
(
uV
>
3300000
))
return
-
EINVAL
;
if
(
uV
<=
1500000
)
*
vsel
=
(
uV
-
875001
)
/
25000
;
else
if
(
uV
<=
2900000
)
*
vsel
=
24
+
(
uV
-
1450001
)
/
50000
;
else
if
(
uV
<
3300000
)
*
vsel
=
52
+
(
uV
-
2800001
)
/
100000
;
else
*
vsel
=
56
;
return
0
;
}
static
int
tps65217_vsel_to_uv2
(
unsigned
int
vsel
)
{
int
uV
=
0
;
if
(
vsel
>
31
)
return
-
EINVAL
;
if
(
vsel
<=
8
)
uV
=
vsel
*
50000
+
1500000
;
else
if
(
vsel
<=
13
)
uV
=
(
vsel
-
8
)
*
100000
+
1900000
;
else
uV
=
(
vsel
-
13
)
*
50000
+
2400000
;
return
uV
;
}
static
int
tps65217_uv_to_vsel2
(
int
uV
,
unsigned
int
*
vsel
)
{
if
((
uV
<
0
)
&&
(
uV
>
3300000
))
return
-
EINVAL
;
if
(
uV
<=
1900000
)
*
vsel
=
(
uV
-
1450001
)
/
50000
;
else
if
(
uV
<=
2400000
)
*
vsel
=
8
+
(
uV
-
1800001
)
/
100000
;
else
*
vsel
=
13
+
(
uV
-
2350001
)
/
50000
;
return
0
;
}
static
struct
tps_info
tps65217_pmic_regs
[]
=
{
TPS65217_INFO
(
"DCDC1"
,
900000
,
1800000
,
tps65217_vsel_to_uv1
,
tps65217_uv_to_vsel1
,
NULL
,
64
,
TPS65217_ENABLE_DC1_EN
,
TPS65217_REG_DEFDCDC1
,
TPS65217_DEFDCDCX_DCDC_MASK
),
TPS65217_INFO
(
"DCDC2"
,
900000
,
3300000
,
tps65217_vsel_to_uv1
,
tps65217_uv_to_vsel1
,
NULL
,
64
,
TPS65217_ENABLE_DC2_EN
,
TPS65217_REG_DEFDCDC2
,
TPS65217_DEFDCDCX_DCDC_MASK
),
TPS65217_INFO
(
"DCDC3"
,
900000
,
1500000
,
tps65217_vsel_to_uv1
,
tps65217_uv_to_vsel1
,
NULL
,
64
,
TPS65217_ENABLE_DC3_EN
,
TPS65217_REG_DEFDCDC3
,
TPS65217_DEFDCDCX_DCDC_MASK
),
TPS65217_INFO
(
"LDO1"
,
1000000
,
3300000
,
NULL
,
NULL
,
LDO1_VSEL_table
,
16
,
TPS65217_ENABLE_LDO1_EN
,
TPS65217_REG_DEFLDO1
,
TPS65217_DEFLDO1_LDO1_MASK
),
TPS65217_INFO
(
"LDO2"
,
900000
,
3300000
,
tps65217_vsel_to_uv1
,
tps65217_uv_to_vsel1
,
NULL
,
64
,
TPS65217_ENABLE_LDO2_EN
,
TPS65217_REG_DEFLDO2
,
TPS65217_DEFLDO2_LDO2_MASK
),
TPS65217_INFO
(
"LDO3"
,
1800000
,
3300000
,
tps65217_vsel_to_uv2
,
tps65217_uv_to_vsel2
,
NULL
,
32
,
TPS65217_ENABLE_LS1_EN
|
TPS65217_DEFLDO3_LDO3_EN
,
TPS65217_REG_DEFLS1
,
TPS65217_DEFLDO3_LDO3_MASK
),
TPS65217_INFO
(
"LDO4"
,
1800000
,
3300000
,
tps65217_vsel_to_uv2
,
tps65217_uv_to_vsel2
,
NULL
,
32
,
TPS65217_ENABLE_LS2_EN
|
TPS65217_DEFLDO4_LDO4_EN
,
TPS65217_REG_DEFLS2
,
TPS65217_DEFLDO4_LDO4_MASK
),
};
static
int
tps65217_pmic_dcdc_is_enabled
(
struct
regulator_dev
*
dev
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
data
,
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
ret
=
tps65217_reg_read
(
tps
,
TPS65217_REG_ENABLE
,
&
data
);
if
(
ret
)
return
ret
;
return
(
data
&
tps
->
info
[
dcdc
]
->
enable_mask
)
?
1
:
0
;
}
static
int
tps65217_pmic_ldo_is_enabled
(
struct
regulator_dev
*
dev
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
data
,
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_1
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
ret
=
tps65217_reg_read
(
tps
,
TPS65217_REG_ENABLE
,
&
data
);
if
(
ret
)
return
ret
;
return
(
data
&
tps
->
info
[
ldo
]
->
enable_mask
)
?
1
:
0
;
}
static
int
tps65217_pmic_dcdc_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
/* Enable the regulator and password protection is level 1 */
return
tps65217_set_bits
(
tps
,
TPS65217_REG_ENABLE
,
tps
->
info
[
dcdc
]
->
enable_mask
,
tps
->
info
[
dcdc
]
->
enable_mask
,
TPS65217_PROTECT_L1
);
}
static
int
tps65217_pmic_dcdc_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
/* Disable the regulator and password protection is level 1 */
return
tps65217_clear_bits
(
tps
,
TPS65217_REG_ENABLE
,
tps
->
info
[
dcdc
]
->
enable_mask
,
TPS65217_PROTECT_L1
);
}
static
int
tps65217_pmic_ldo_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_1
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
/* Enable the regulator and password protection is level 1 */
return
tps65217_set_bits
(
tps
,
TPS65217_REG_ENABLE
,
tps
->
info
[
ldo
]
->
enable_mask
,
tps
->
info
[
ldo
]
->
enable_mask
,
TPS65217_PROTECT_L1
);
}
static
int
tps65217_pmic_ldo_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_1
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
/* Disable the regulator and password protection is level 1 */
return
tps65217_clear_bits
(
tps
,
TPS65217_REG_ENABLE
,
tps
->
info
[
ldo
]
->
enable_mask
,
TPS65217_PROTECT_L1
);
}
static
int
tps65217_pmic_dcdc_get_voltage_sel
(
struct
regulator_dev
*
dev
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
selector
,
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
ret
=
tps65217_reg_read
(
tps
,
tps
->
info
[
dcdc
]
->
set_vout_reg
,
&
selector
);
if
(
ret
)
return
ret
;
selector
&=
tps
->
info
[
dcdc
]
->
set_vout_mask
;
return
selector
;
}
static
int
tps65217_pmic_dcdc_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
,
unsigned
*
selector
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
if
(
min_uV
<
tps
->
info
[
dcdc
]
->
min_uV
||
min_uV
>
tps
->
info
[
dcdc
]
->
max_uV
)
return
-
EINVAL
;
if
(
max_uV
<
tps
->
info
[
dcdc
]
->
min_uV
||
max_uV
>
tps
->
info
[
dcdc
]
->
max_uV
)
return
-
EINVAL
;
ret
=
tps
->
info
[
dcdc
]
->
uv_to_vsel
(
min_uV
,
selector
);
if
(
ret
)
return
ret
;
/* Set the voltage based on vsel value and write protect level is 2 */
ret
=
tps65217_set_bits
(
tps
,
tps
->
info
[
dcdc
]
->
set_vout_reg
,
tps
->
info
[
dcdc
]
->
set_vout_mask
,
*
selector
,
TPS65217_PROTECT_L2
);
if
(
ret
)
return
ret
;
/* Set GO bit to initiate voltage transistion */
return
tps65217_set_bits
(
tps
,
TPS65217_REG_DEFSLEW
,
TPS65217_DEFSLEW_GO
,
TPS65217_DEFSLEW_GO
,
TPS65217_PROTECT_L2
);
}
static
int
tps65217_pmic_ldo_get_voltage_sel
(
struct
regulator_dev
*
dev
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
selector
,
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_1
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
ret
=
tps65217_reg_read
(
tps
,
tps
->
info
[
ldo
]
->
set_vout_reg
,
&
selector
);
if
(
ret
)
return
ret
;
selector
&=
tps
->
info
[
ldo
]
->
set_vout_mask
;
return
selector
;
}
static
int
tps65217_pmic_ldo_set_voltage_sel
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
!=
TPS65217_LDO_1
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
/* Set the voltage based on vsel value and write protect level is 2 */
return
tps65217_set_bits
(
tps
,
tps
->
info
[
ldo
]
->
set_vout_reg
,
tps
->
info
[
ldo
]
->
set_vout_mask
,
selector
,
TPS65217_PROTECT_L2
);
}
static
int
tps65217_pmic_ldo_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
,
unsigned
*
selector
)
{
int
ret
;
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_2
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
if
(
min_uV
<
tps
->
info
[
ldo
]
->
min_uV
||
min_uV
>
tps
->
info
[
ldo
]
->
max_uV
)
return
-
EINVAL
;
if
(
max_uV
<
tps
->
info
[
ldo
]
->
min_uV
||
max_uV
>
tps
->
info
[
ldo
]
->
max_uV
)
return
-
EINVAL
;
ret
=
tps
->
info
[
ldo
]
->
uv_to_vsel
(
min_uV
,
selector
);
if
(
ret
)
return
ret
;
/* Set the voltage based on vsel value and write protect level is 2 */
return
tps65217_set_bits
(
tps
,
tps
->
info
[
ldo
]
->
set_vout_reg
,
tps
->
info
[
ldo
]
->
set_vout_mask
,
*
selector
,
TPS65217_PROTECT_L2
);
}
static
int
tps65217_pmic_dcdc_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65217_DCDC_1
||
dcdc
>
TPS65217_DCDC_3
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
dcdc
]
->
table_len
)
return
-
EINVAL
;
return
tps
->
info
[
dcdc
]
->
vsel_to_uv
(
selector
);
}
static
int
tps65217_pmic_ldo_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps65217
*
tps
=
rdev_get_drvdata
(
dev
);
unsigned
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65217_LDO_1
||
ldo
>
TPS65217_LDO_4
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
if
(
tps
->
info
[
ldo
]
->
table
)
return
tps
->
info
[
ldo
]
->
table
[
selector
];
return
tps
->
info
[
ldo
]
->
vsel_to_uv
(
selector
);
}
/* Operations permitted on DCDCx */
static
struct
regulator_ops
tps65217_pmic_dcdc_ops
=
{
.
is_enabled
=
tps65217_pmic_dcdc_is_enabled
,
.
enable
=
tps65217_pmic_dcdc_enable
,
.
disable
=
tps65217_pmic_dcdc_disable
,
.
get_voltage_sel
=
tps65217_pmic_dcdc_get_voltage_sel
,
.
set_voltage
=
tps65217_pmic_dcdc_set_voltage
,
.
list_voltage
=
tps65217_pmic_dcdc_list_voltage
,
};
/* Operations permitted on LDO1 */
static
struct
regulator_ops
tps65217_pmic_ldo1_ops
=
{
.
is_enabled
=
tps65217_pmic_ldo_is_enabled
,
.
enable
=
tps65217_pmic_ldo_enable
,
.
disable
=
tps65217_pmic_ldo_disable
,
.
get_voltage_sel
=
tps65217_pmic_ldo_get_voltage_sel
,
.
set_voltage_sel
=
tps65217_pmic_ldo_set_voltage_sel
,
.
list_voltage
=
tps65217_pmic_ldo_list_voltage
,
};
/* Operations permitted on LDO2, LDO3 and LDO4 */
static
struct
regulator_ops
tps65217_pmic_ldo234_ops
=
{
.
is_enabled
=
tps65217_pmic_ldo_is_enabled
,
.
enable
=
tps65217_pmic_ldo_enable
,
.
disable
=
tps65217_pmic_ldo_disable
,
.
get_voltage_sel
=
tps65217_pmic_ldo_get_voltage_sel
,
.
set_voltage
=
tps65217_pmic_ldo_set_voltage
,
.
list_voltage
=
tps65217_pmic_ldo_list_voltage
,
};
static
struct
regulator_desc
regulators
[]
=
{
TPS65217_REGULATOR
(
"DCDC1"
,
TPS65217_DCDC_1
,
tps65217_pmic_dcdc_ops
,
64
),
TPS65217_REGULATOR
(
"DCDC2"
,
TPS65217_DCDC_2
,
tps65217_pmic_dcdc_ops
,
64
),
TPS65217_REGULATOR
(
"DCDC3"
,
TPS65217_DCDC_3
,
tps65217_pmic_dcdc_ops
,
64
),
TPS65217_REGULATOR
(
"LDO1"
,
TPS65217_LDO_1
,
tps65217_pmic_ldo1_ops
,
16
),
TPS65217_REGULATOR
(
"LDO2"
,
TPS65217_LDO_2
,
tps65217_pmic_ldo234_ops
,
64
),
TPS65217_REGULATOR
(
"LDO3"
,
TPS65217_LDO_3
,
tps65217_pmic_ldo234_ops
,
32
),
TPS65217_REGULATOR
(
"LDO4"
,
TPS65217_LDO_4
,
tps65217_pmic_ldo234_ops
,
32
),
};
static
int
__devinit
tps65217_regulator_probe
(
struct
platform_device
*
pdev
)
{
struct
regulator_dev
*
rdev
;
struct
tps65217
*
tps
;
struct
tps_info
*
info
=
&
tps65217_pmic_regs
[
pdev
->
id
];
/* Already set by core driver */
tps
=
dev_to_tps65217
(
pdev
->
dev
.
parent
);
tps
->
info
[
pdev
->
id
]
=
info
;
rdev
=
regulator_register
(
&
regulators
[
pdev
->
id
],
&
pdev
->
dev
,
pdev
->
dev
.
platform_data
,
tps
,
NULL
);
if
(
IS_ERR
(
rdev
))
return
PTR_ERR
(
rdev
);
platform_set_drvdata
(
pdev
,
rdev
);
return
0
;
}
static
int
__devexit
tps65217_regulator_remove
(
struct
platform_device
*
pdev
)
{
struct
regulator_dev
*
rdev
=
platform_get_drvdata
(
pdev
);
platform_set_drvdata
(
pdev
,
NULL
);
regulator_unregister
(
rdev
);
return
0
;
}
static
struct
platform_driver
tps65217_regulator_driver
=
{
.
driver
=
{
.
name
=
"tps65217-pmic"
,
},
.
probe
=
tps65217_regulator_probe
,
.
remove
=
__devexit_p
(
tps65217_regulator_remove
),
};
static
int
__init
tps65217_regulator_init
(
void
)
{
return
platform_driver_register
(
&
tps65217_regulator_driver
);
}
subsys_initcall
(
tps65217_regulator_init
);
static
void
__exit
tps65217_regulator_exit
(
void
)
{
platform_driver_unregister
(
&
tps65217_regulator_driver
);
}
module_exit
(
tps65217_regulator_exit
);
MODULE_AUTHOR
(
"AnilKumar Ch <anilkumar@ti.com>"
);
MODULE_DESCRIPTION
(
"TPS65217 voltage regulator driver"
);
MODULE_ALIAS
(
"platform:tps65217-pmic"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/tps65910-regulator.c
View file @
fb87ef1a
...
...
@@ -26,6 +26,9 @@
#include <linux/mfd/tps65910.h>
#define TPS65910_SUPPLY_STATE_ENABLED 0x1
#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3)
/* supported VIO voltages in milivolts */
static
const
u16
VIO_VSEL_table
[]
=
{
...
...
@@ -83,8 +86,8 @@ struct tps_info {
const
char
*
name
;
unsigned
min_uV
;
unsigned
max_uV
;
u8
table_len
;
const
u16
*
table
;
u8
n_voltages
;
const
u16
*
voltage_
table
;
};
static
struct
tps_info
tps65910_regs
[]
=
{
...
...
@@ -95,8 +98,8 @@ static struct tps_info tps65910_regs[] = {
.
name
=
"VIO"
,
.
min_uV
=
1500000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VIO_VSEL_table
),
.
table
=
VIO_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VIO_VSEL_table
),
.
voltage_
table
=
VIO_VSEL_table
,
},
{
.
name
=
"VDD1"
,
...
...
@@ -112,132 +115,179 @@ static struct tps_info tps65910_regs[] = {
.
name
=
"VDD3"
,
.
min_uV
=
5000000
,
.
max_uV
=
5000000
,
.
table_len
=
ARRAY_SIZE
(
VDD3_VSEL_table
),
.
table
=
VDD3_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VDD3_VSEL_table
),
.
voltage_
table
=
VDD3_VSEL_table
,
},
{
.
name
=
"VDIG1"
,
.
min_uV
=
1200000
,
.
max_uV
=
2700000
,
.
table_len
=
ARRAY_SIZE
(
VDIG1_VSEL_table
),
.
table
=
VDIG1_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VDIG1_VSEL_table
),
.
voltage_
table
=
VDIG1_VSEL_table
,
},
{
.
name
=
"VDIG2"
,
.
min_uV
=
1000000
,
.
max_uV
=
1800000
,
.
table_len
=
ARRAY_SIZE
(
VDIG2_VSEL_table
),
.
table
=
VDIG2_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VDIG2_VSEL_table
),
.
voltage_
table
=
VDIG2_VSEL_table
,
},
{
.
name
=
"VPLL"
,
.
min_uV
=
1000000
,
.
max_uV
=
2500000
,
.
table_len
=
ARRAY_SIZE
(
VPLL_VSEL_table
),
.
table
=
VPLL_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VPLL_VSEL_table
),
.
voltage_
table
=
VPLL_VSEL_table
,
},
{
.
name
=
"VDAC"
,
.
min_uV
=
1800000
,
.
max_uV
=
2850000
,
.
table_len
=
ARRAY_SIZE
(
VDAC_VSEL_table
),
.
table
=
VDAC_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VDAC_VSEL_table
),
.
voltage_
table
=
VDAC_VSEL_table
,
},
{
.
name
=
"VAUX1"
,
.
min_uV
=
1800000
,
.
max_uV
=
2850000
,
.
table_len
=
ARRAY_SIZE
(
VAUX1_VSEL_table
),
.
table
=
VAUX1_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VAUX1_VSEL_table
),
.
voltage_
table
=
VAUX1_VSEL_table
,
},
{
.
name
=
"VAUX2"
,
.
min_uV
=
1800000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VAUX2_VSEL_table
),
.
table
=
VAUX2_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VAUX2_VSEL_table
),
.
voltage_
table
=
VAUX2_VSEL_table
,
},
{
.
name
=
"VAUX33"
,
.
min_uV
=
1800000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VAUX33_VSEL_table
),
.
table
=
VAUX33_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VAUX33_VSEL_table
),
.
voltage_
table
=
VAUX33_VSEL_table
,
},
{
.
name
=
"VMMC"
,
.
min_uV
=
1800000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VMMC_VSEL_table
),
.
table
=
VMMC_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VMMC_VSEL_table
),
.
voltage_
table
=
VMMC_VSEL_table
,
},
};
static
struct
tps_info
tps65911_regs
[]
=
{
{
.
name
=
"VRTC"
,
},
{
.
name
=
"VIO"
,
.
min_uV
=
1500000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VIO_VSEL_table
),
.
table
=
VIO_VSEL_table
,
.
n_voltages
=
ARRAY_SIZE
(
VIO_VSEL_table
),
.
voltage_
table
=
VIO_VSEL_table
,
},
{
.
name
=
"VDD1"
,
.
min_uV
=
600000
,
.
max_uV
=
4500000
,
.
n_voltages
=
73
,
},
{
.
name
=
"VDD2"
,
.
min_uV
=
600000
,
.
max_uV
=
4500000
,
.
n_voltages
=
73
,
},
{
.
name
=
"VDDCTRL"
,
.
min_uV
=
600000
,
.
max_uV
=
1400000
,
.
n_voltages
=
65
,
},
{
.
name
=
"LDO1"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
47
,
},
{
.
name
=
"LDO2"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
47
,
},
{
.
name
=
"LDO3"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
24
,
},
{
.
name
=
"LDO4"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
47
,
},
{
.
name
=
"LDO5"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
24
,
},
{
.
name
=
"LDO6"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
24
,
},
{
.
name
=
"LDO7"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
24
,
},
{
.
name
=
"LDO8"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
n_voltages
=
24
,
},
};
#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
),
};
struct
tps65910_reg
{
struct
regulator_desc
*
desc
;
struct
tps65910
*
mfd
;
...
...
@@ -247,6 +297,8 @@ struct tps65910_reg {
int
num_regulators
;
int
mode
;
int
(
*
get_ctrl_reg
)(
int
);
unsigned
int
*
ext_sleep_control
;
unsigned
int
board_ext_control
[
TPS65910_NUM_REGS
];
};
static
inline
int
tps65910_read
(
struct
tps65910_reg
*
pmic
,
u8
reg
)
...
...
@@ -572,7 +624,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
return
-
EINVAL
;
}
voltage
=
pmic
->
info
[
id
]
->
table
[
value
]
*
1000
;
voltage
=
pmic
->
info
[
id
]
->
voltage_
table
[
value
]
*
1000
;
return
voltage
;
}
...
...
@@ -622,7 +674,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
step_mv
=
100
;
break
;
case
TPS65910_REG_VIO
:
return
pmic
->
info
[
id
]
->
table
[
value
]
*
1000
;
return
pmic
->
info
[
id
]
->
voltage_
table
[
value
]
*
1000
;
break
;
default:
return
-
EINVAL
;
...
...
@@ -756,10 +808,10 @@ static int tps65910_list_voltage(struct regulator_dev *dev,
if
(
id
<
TPS65910_REG_VIO
||
id
>
TPS65910_REG_VMMC
)
return
-
EINVAL
;
if
(
selector
>=
pmic
->
info
[
id
]
->
table_len
)
if
(
selector
>=
pmic
->
info
[
id
]
->
n_voltages
)
return
-
EINVAL
;
else
voltage
=
pmic
->
info
[
id
]
->
table
[
selector
]
*
1000
;
voltage
=
pmic
->
info
[
id
]
->
voltage_
table
[
selector
]
*
1000
;
return
voltage
;
}
...
...
@@ -795,7 +847,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
step_mv
=
100
;
break
;
case
TPS65910_REG_VIO
:
return
pmic
->
info
[
id
]
->
table
[
selector
]
*
1000
;
return
pmic
->
info
[
id
]
->
voltage_
table
[
selector
]
*
1000
;
default:
return
-
EINVAL
;
}
...
...
@@ -847,6 +899,131 @@ static struct regulator_ops tps65911_ops = {
.
list_voltage
=
tps65911_list_voltage
,
};
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
);
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
)
ret
=
tps65910_set_bits
(
mfd
,
TPS65910_EN1_LDO_ASS
+
regoffs
,
bit_pos
);
else
ret
=
tps65910_clear_bits
(
mfd
,
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
)
ret
=
tps65910_set_bits
(
mfd
,
TPS65910_EN2_LDO_ASS
+
regoffs
,
bit_pos
);
else
ret
=
tps65910_clear_bits
(
mfd
,
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
)
ret
=
tps65910_set_bits
(
mfd
,
TPS65910_EN3_LDO_ASS
+
regoffs
,
bit_pos
);
else
ret
=
tps65910_clear_bits
(
mfd
,
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 */
ret
=
tps65910_clear_bits
(
mfd
,
TPS65910_SLEEP_KEEP_LDO_ON
+
regoffs
,
bit_pos
);
if
(
!
ret
)
ret
=
tps65910_clear_bits
(
mfd
,
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
;
int
opvsel
=
tps65910_reg_read
(
pmic
,
op_reg_add
);
int
srvsel
=
tps65910_reg_read
(
pmic
,
sr_reg_add
);
if
(
opvsel
&
VDD1_OP_CMD_MASK
)
{
u8
reg_val
=
srvsel
&
VDD1_OP_SEL_MASK
;
ret
=
tps65910_reg_write
(
pmic
,
op_reg_add
,
reg_val
);
if
(
ret
<
0
)
{
dev_err
(
mfd
->
dev
,
"Error in configuring op register
\n
"
);
return
ret
;
}
}
ret
=
tps65910_reg_write
(
pmic
,
sr_reg_add
,
0
);
if
(
ret
<
0
)
{
dev_err
(
mfd
->
dev
,
"Error in settting sr register
\n
"
);
return
ret
;
}
}
ret
=
tps65910_clear_bits
(
mfd
,
TPS65910_SLEEP_KEEP_LDO_ON
+
regoffs
,
bit_pos
);
if
(
!
ret
)
ret
=
tps65910_set_bits
(
mfd
,
TPS65910_SLEEP_SET_LDO_OFF
+
regoffs
,
bit_pos
);
if
(
ret
<
0
)
dev_err
(
mfd
->
dev
,
"Error in configuring SLEEP register
\n
"
);
return
ret
;
}
static
__devinit
int
tps65910_probe
(
struct
platform_device
*
pdev
)
{
struct
tps65910
*
tps65910
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
...
...
@@ -877,11 +1054,13 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
case
TPS65910
:
pmic
->
get_ctrl_reg
=
&
tps65910_get_ctrl_register
;
pmic
->
num_regulators
=
ARRAY_SIZE
(
tps65910_regs
);
pmic
->
ext_sleep_control
=
tps65910_ext_sleep_control
;
info
=
tps65910_regs
;
break
;
case
TPS65911
:
pmic
->
get_ctrl_reg
=
&
tps65911_get_ctrl_register
;
pmic
->
num_regulators
=
ARRAY_SIZE
(
tps65911_regs
);
pmic
->
ext_sleep_control
=
tps65911_ext_sleep_control
;
info
=
tps65911_regs
;
break
;
default:
...
...
@@ -926,7 +1105,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
pmic
->
desc
[
i
].
name
=
info
->
name
;
pmic
->
desc
[
i
].
id
=
i
;
pmic
->
desc
[
i
].
n_voltages
=
info
->
table_len
;
pmic
->
desc
[
i
].
n_voltages
=
info
->
n_voltages
;
if
(
i
==
TPS65910_REG_VDD1
||
i
==
TPS65910_REG_VDD2
)
{
pmic
->
desc
[
i
].
ops
=
&
tps65910_ops_dcdc
;
...
...
@@ -944,6 +1123,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
pmic
->
desc
[
i
].
ops
=
&
tps65911_ops
;
}
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
"
);
pmic
->
desc
[
i
].
type
=
REGULATOR_VOLTAGE
;
pmic
->
desc
[
i
].
owner
=
THIS_MODULE
;
...
...
@@ -990,6 +1179,36 @@ static int __devexit tps65910_remove(struct platform_device *pdev)
return
0
;
}
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
"
);
}
}
static
struct
platform_driver
tps65910_driver
=
{
.
driver
=
{
.
name
=
"tps65910-pmic"
,
...
...
@@ -997,6 +1216,7 @@ static struct platform_driver tps65910_driver = {
},
.
probe
=
tps65910_probe
,
.
remove
=
__devexit_p
(
tps65910_remove
),
.
shutdown
=
tps65910_shutdown
,
};
static
int
__init
tps65910_init
(
void
)
...
...
drivers/regulator/wm8350-regulator.c
View file @
fb87ef1a
...
...
@@ -1544,7 +1544,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
return
-
ENOMEM
;
}
led
->
isink_consumer
.
dev
=
&
pdev
->
dev
;
led
->
isink_consumer
.
dev
_name
=
dev_name
(
&
pdev
->
dev
)
;
led
->
isink_consumer
.
supply
=
"led_isink"
;
led
->
isink_init
.
num_consumer_supplies
=
1
;
led
->
isink_init
.
consumer_supplies
=
&
led
->
isink_consumer
;
...
...
@@ -1559,7 +1559,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
return
ret
;
}
led
->
dcdc_consumer
.
dev
=
&
pdev
->
dev
;
led
->
dcdc_consumer
.
dev
_name
=
dev_name
(
&
pdev
->
dev
)
;
led
->
dcdc_consumer
.
supply
=
"led_vcc"
;
led
->
dcdc_init
.
num_consumer_supplies
=
1
;
led
->
dcdc_init
.
consumer_supplies
=
&
led
->
dcdc_consumer
;
...
...
include/linux/mfd/tps65910.h
View file @
fb87ef1a
...
...
@@ -768,6 +768,13 @@
/* Max number of TPS65910/11 regulators */
#define TPS65910_NUM_REGS 13
/* External sleep controls through EN1/EN2/EN3 inputs*/
#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 0x1
#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 0x2
#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4
/* TPS65911 names the EN3 signal as SLEEP */
#define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x4
/**
* struct tps65910_board
* Board platform data may be used to initialize regulators.
...
...
@@ -779,6 +786,7 @@ struct tps65910_board {
int
irq_base
;
int
vmbch_threshold
;
int
vmbch2_threshold
;
unsigned
long
regulator_ext_sleep_control
[
TPS65910_NUM_REGS
];
struct
regulator_init_data
*
tps65910_pmic_init_data
[
TPS65910_NUM_REGS
];
};
...
...
include/linux/regulator/tps62360.h
0 → 100644
View file @
fb87ef1a
/*
* tps62360.h -- TI tps62360
*
* Interface for regulator driver for TI TPS62360 Processor core supply
*
* Copyright (C) 2012 NVIDIA Corporation
* Author: Laxman Dewangan <ldewangan@nvidia.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.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef __LINUX_REGULATOR_TPS62360_H
#define __LINUX_REGULATOR_TPS62360_H
#include <linux/regulator/machine.h>
/*
* struct tps62360_regulator_platform_data - tps62360 regulator platform data.
*
* @reg_init_data: The regulator init data.
* @en_force_pwm: Enable force pwm or not.
* @en_discharge: Enable discharge the output capacitor via internal
* register.
* @en_internal_pulldn: internal pull down enable or not.
* @vsel0_gpio: Gpio number for vsel0. It should be -1 if this is tied with
* fixed logic.
* @vsel1_gpio: Gpio number for vsel1. It should be -1 if this is tied with
* fixed logic.
* @vsel0_def_state: Default state of vsel0. 1 if it is high else 0.
* @vsel1_def_state: Default state of vsel1. 1 if it is high else 0.
*/
struct
tps62360_regulator_platform_data
{
struct
regulator_init_data
reg_init_data
;
bool
en_force_pwm
;
bool
en_discharge
;
bool
en_internal_pulldn
;
int
vsel0_gpio
;
int
vsel1_gpio
;
int
vsel0_def_state
;
int
vsel1_def_state
;
};
#endif
/* __LINUX_REGULATOR_TPS62360_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment