Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
55a71bc2
Commit
55a71bc2
authored
Sep 15, 2009
by
Stephen Rothwell
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'voltage/for-next'
Conflicts: drivers/regulator/Kconfig
parents
54b59c6a
23b0b60d
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1922 additions
and
160 deletions
+1922
-160
Documentation/power/regulator/overview.txt
Documentation/power/regulator/overview.txt
+2
-2
Documentation/power/regulator/regulator.txt
Documentation/power/regulator/regulator.txt
+3
-2
drivers/regulator/Kconfig
drivers/regulator/Kconfig
+17
-1
drivers/regulator/Makefile
drivers/regulator/Makefile
+3
-0
drivers/regulator/core.c
drivers/regulator/core.c
+218
-67
drivers/regulator/da903x.c
drivers/regulator/da903x.c
+66
-9
drivers/regulator/fixed.c
drivers/regulator/fixed.c
+89
-2
drivers/regulator/pcf50633-regulator.c
drivers/regulator/pcf50633-regulator.c
+65
-33
drivers/regulator/tps65023-regulator.c
drivers/regulator/tps65023-regulator.c
+632
-0
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps6507x-regulator.c
+714
-0
drivers/regulator/userspace-consumer.c
drivers/regulator/userspace-consumer.c
+23
-22
drivers/regulator/virtual.c
drivers/regulator/virtual.c
+36
-20
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8350-regulator.c
+2
-0
include/linux/mfd/da903x.h
include/linux/mfd/da903x.h
+3
-1
include/linux/regulator/consumer.h
include/linux/regulator/consumer.h
+4
-0
include/linux/regulator/driver.h
include/linux/regulator/driver.h
+2
-0
include/linux/regulator/fixed.h
include/linux/regulator/fixed.h
+24
-0
include/linux/regulator/machine.h
include/linux/regulator/machine.h
+19
-1
No files found.
Documentation/power/regulator/overview.txt
View file @
55a71bc2
...
...
@@ -29,7 +29,7 @@ Some terms used in this document:-
o PMIC - Power Management IC. An IC that contains numerous regulators
and often contains other su
s
bsystems.
and often contains other subsystems.
o Consumer - Electronic device that is supplied power by a regulator.
...
...
@@ -168,4 +168,4 @@ relevant to non SoC devices and is split into the following four interfaces:-
userspace via sysfs. This could be used to help monitor device power
consumption and status.
See Documentation/ABI/testing/
regulator-sysfs.txt
See Documentation/ABI/testing/
sysfs-class-regulator
Documentation/power/regulator/regulator.txt
View file @
55a71bc2
...
...
@@ -10,8 +10,9 @@ Registration
Drivers can register a regulator by calling :-
struct regulator_dev *regulator_register(struct device *dev,
struct regulator_desc *regulator_desc);
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, struct regulator_init_data *init_data,
void *driver_data);
This will register the regulators capabilities and operations to the regulator
core.
...
...
drivers/regulator/Kconfig
View file @
55a71bc2
...
...
@@ -52,7 +52,7 @@ config REGULATOR_USERSPACE_CONSUMER
default n
help
There are some classes of devices that are controlled entirely
from user space. Users
ap
ce consumer driver provides ability to
from user space. Users
pa
ce consumer driver provides ability to
control power supplies for such devices.
If unsure, say no.
...
...
@@ -147,5 +147,21 @@ config REGULATOR_AB3100
AB3100 analog baseband dealing with power regulators
for the system.
config REGULATOR_TPS65023
tristate "TI TPS65023 Power regulators"
depends on I2C
help
This driver supports TPS65023 voltage regulator chips. TPS65023 provides
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
config REGULATOR_TPS6507X
tristate "TI TPS6507X Power regulators"
depends on I2C
help
This driver supports TPS6507X voltage regulator chips. TPS6507X provides
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
endif
drivers/regulator/Makefile
View file @
55a71bc2
...
...
@@ -23,4 +23,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_MC13783)
+=
mc13783.o
obj-$(CONFIG_REGULATOR_AB3100)
+=
ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023)
+=
tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X)
+=
tps6507x-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG)
+=
-DDEBUG
drivers/regulator/core.c
View file @
55a71bc2
...
...
@@ -37,7 +37,7 @@ static int has_full_constraints;
*/
struct
regulator_map
{
struct
list_head
list
;
struct
device
*
dev
;
const
char
*
dev_name
;
/* The dev_name() for the consumer */
const
char
*
supply
;
struct
regulator_dev
*
regulator
;
};
...
...
@@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev,
struct
regulator_dev
*
rdev
=
dev_get_drvdata
(
dev
);
const
char
*
name
;
if
(
rdev
->
constraints
->
name
)
if
(
rdev
->
constraints
&&
rdev
->
constraints
->
name
)
name
=
rdev
->
constraints
->
name
;
else
if
(
rdev
->
desc
->
name
)
name
=
rdev
->
desc
->
name
;
...
...
@@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
regulator_dev
*
rdev
=
dev_get_drvdata
(
dev
);
ssize_t
ret
;
mutex_lock
(
&
rdev
->
mutex
);
ret
=
regulator_print_state
(
buf
,
_regulator_is_enabled
(
rdev
));
mutex_unlock
(
&
rdev
->
mutex
);
return
re
gulator_print_state
(
buf
,
_regulator_is_enabled
(
rdev
))
;
return
re
t
;
}
static
DEVICE_ATTR
(
state
,
0444
,
regulator_state_show
,
NULL
);
...
...
@@ -857,23 +862,39 @@ out:
* set_consumer_device_supply: Bind a regulator to a symbolic supply
* @rdev: regulator source
* @consumer_dev: device the supply applies to
* @consumer_dev_name: dev_name() string for device supply applies to
* @supply: symbolic name for supply
*
* Allows platform initialisation code to map physical regulator
* sources to symbolic names for supplies for use by devices. Devices
* should use these symbolic names to request regulators, avoiding the
* need to provide board-specific regulator names as platform data.
*
* Only one of consumer_dev and consumer_dev_name may be specified.
*/
static
int
set_consumer_device_supply
(
struct
regulator_dev
*
rdev
,
struct
device
*
consumer_dev
,
const
char
*
supply
)
struct
device
*
consumer_dev
,
const
char
*
consumer_dev_name
,
const
char
*
supply
)
{
struct
regulator_map
*
node
;
int
has_dev
;
if
(
consumer_dev
&&
consumer_dev_name
)
return
-
EINVAL
;
if
(
!
consumer_dev_name
&&
consumer_dev
)
consumer_dev_name
=
dev_name
(
consumer_dev
);
if
(
supply
==
NULL
)
return
-
EINVAL
;
if
(
consumer_dev_name
!=
NULL
)
has_dev
=
1
;
else
has_dev
=
0
;
list_for_each_entry
(
node
,
&
regulator_map_list
,
list
)
{
if
(
consumer_dev
!=
node
->
dev
)
if
(
consumer_dev
_name
!=
node
->
dev_name
)
continue
;
if
(
strcmp
(
node
->
supply
,
supply
)
!=
0
)
continue
;
...
...
@@ -886,30 +907,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
return
-
EBUSY
;
}
node
=
k
m
alloc
(
sizeof
(
struct
regulator_map
),
GFP_KERNEL
);
node
=
k
z
alloc
(
sizeof
(
struct
regulator_map
),
GFP_KERNEL
);
if
(
node
==
NULL
)
return
-
ENOMEM
;
node
->
regulator
=
rdev
;
node
->
dev
=
consumer_dev
;
node
->
supply
=
supply
;
if
(
has_dev
)
{
node
->
dev_name
=
kstrdup
(
consumer_dev_name
,
GFP_KERNEL
);
if
(
node
->
dev_name
==
NULL
)
{
kfree
(
node
);
return
-
ENOMEM
;
}
}
list_add
(
&
node
->
list
,
&
regulator_map_list
);
return
0
;
}
static
void
unset_consumer_device_supply
(
struct
regulator_dev
*
rdev
,
struct
device
*
consumer_dev
)
const
char
*
consumer_dev_name
,
struct
device
*
consumer_dev
)
{
struct
regulator_map
*
node
,
*
n
;
if
(
consumer_dev
&&
!
consumer_dev_name
)
consumer_dev_name
=
dev_name
(
consumer_dev
);
list_for_each_entry_safe
(
node
,
n
,
&
regulator_map_list
,
list
)
{
if
(
rdev
==
node
->
regulator
&&
consumer_dev
==
node
->
dev
)
{
list_del
(
&
node
->
list
);
kfree
(
node
);
return
;
}
if
(
rdev
!=
node
->
regulator
)
continue
;
if
(
consumer_dev_name
&&
node
->
dev_name
&&
strcmp
(
consumer_dev_name
,
node
->
dev_name
))
continue
;
list_del
(
&
node
->
list
);
kfree
(
node
->
dev_name
);
kfree
(
node
);
return
;
}
}
...
...
@@ -920,6 +956,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
list_for_each_entry_safe
(
node
,
n
,
&
regulator_map_list
,
list
)
{
if
(
rdev
==
node
->
regulator
)
{
list_del
(
&
node
->
list
);
kfree
(
node
->
dev_name
);
kfree
(
node
);
return
;
}
...
...
@@ -1001,35 +1038,33 @@ overflow_err:
return
NULL
;
}
/**
* regulator_get - lookup and obtain a reference to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct
regulator
*
regulator_get
(
struct
device
*
dev
,
const
char
*
id
)
/* Internal regulator request function */
static
struct
regulator
*
_regulator_get
(
struct
device
*
dev
,
const
char
*
id
,
int
exclusive
)
{
struct
regulator_dev
*
rdev
;
struct
regulator_map
*
map
;
struct
regulator
*
regulator
=
ERR_PTR
(
-
ENODEV
);
const
char
*
devname
=
NULL
;
int
ret
;
if
(
id
==
NULL
)
{
printk
(
KERN_ERR
"regulator: get() with no identifier
\n
"
);
return
regulator
;
}
if
(
dev
)
devname
=
dev_name
(
dev
);
mutex_lock
(
&
regulator_list_mutex
);
list_for_each_entry
(
map
,
&
regulator_map_list
,
list
)
{
if
(
dev
==
map
->
dev
&&
strcmp
(
map
->
supply
,
id
)
==
0
)
{
/* If the mapping has a device set up it must match */
if
(
map
->
dev_name
&&
(
!
devname
||
strcmp
(
map
->
dev_name
,
devname
)))
continue
;
if
(
strcmp
(
map
->
supply
,
id
)
==
0
)
{
rdev
=
map
->
regulator
;
goto
found
;
}
...
...
@@ -1038,6 +1073,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return
regulator
;
found:
if
(
rdev
->
exclusive
)
{
regulator
=
ERR_PTR
(
-
EPERM
);
goto
out
;
}
if
(
exclusive
&&
rdev
->
open_count
)
{
regulator
=
ERR_PTR
(
-
EBUSY
);
goto
out
;
}
if
(
!
try_module_get
(
rdev
->
owner
))
goto
out
;
...
...
@@ -1047,12 +1092,69 @@ found:
module_put
(
rdev
->
owner
);
}
rdev
->
open_count
++
;
if
(
exclusive
)
{
rdev
->
exclusive
=
1
;
ret
=
_regulator_is_enabled
(
rdev
);
if
(
ret
>
0
)
rdev
->
use_count
=
1
;
else
rdev
->
use_count
=
0
;
}
out:
mutex_unlock
(
&
regulator_list_mutex
);
return
regulator
;
}
/**
* regulator_get - lookup and obtain a reference to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct
regulator
*
regulator_get
(
struct
device
*
dev
,
const
char
*
id
)
{
return
_regulator_get
(
dev
,
id
,
0
);
}
EXPORT_SYMBOL_GPL
(
regulator_get
);
/**
* regulator_get_exclusive - obtain exclusive access to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno. Other consumers will be
* unable to obtain this reference is held and the use count for the
* regulator will be initialised to reflect the current state of the
* regulator.
*
* This is intended for use by consumers which cannot tolerate shared
* use of the regulator such as those which need to force the
* regulator off for correct operation of the hardware they are
* controlling.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct
regulator
*
regulator_get_exclusive
(
struct
device
*
dev
,
const
char
*
id
)
{
return
_regulator_get
(
dev
,
id
,
1
);
}
EXPORT_SYMBOL_GPL
(
regulator_get_exclusive
);
/**
* regulator_put - "free" the regulator source
* @regulator: regulator source
...
...
@@ -1081,21 +1183,29 @@ void regulator_put(struct regulator *regulator)
list_del
(
&
regulator
->
list
);
kfree
(
regulator
);
rdev
->
open_count
--
;
rdev
->
exclusive
=
0
;
module_put
(
rdev
->
owner
);
mutex_unlock
(
&
regulator_list_mutex
);
}
EXPORT_SYMBOL_GPL
(
regulator_put
);
static
int
_regulator_can_change_status
(
struct
regulator_dev
*
rdev
)
{
if
(
!
rdev
->
constraints
)
return
0
;
if
(
rdev
->
constraints
->
valid_ops_mask
&
REGULATOR_CHANGE_STATUS
)
return
1
;
else
return
0
;
}
/* locks held by regulator_enable() */
static
int
_regulator_enable
(
struct
regulator_dev
*
rdev
)
{
int
ret
=
-
EINVAL
;
if
(
!
rdev
->
constraints
)
{
printk
(
KERN_ERR
"%s: %s has no constraints
\n
"
,
__func__
,
rdev
->
desc
->
name
);
return
ret
;
}
int
ret
;
/* do we need to enable the supply regulator first */
if
(
rdev
->
supply
)
{
...
...
@@ -1108,24 +1218,35 @@ static int _regulator_enable(struct regulator_dev *rdev)
}
/* check voltage and requested load before enabling */
if
(
rdev
->
desc
->
ops
->
enable
)
{
if
(
rdev
->
constraints
&&
(
rdev
->
constraints
->
valid_ops_mask
&
REGULATOR_CHANGE_DRMS
))
drms_uA_update
(
rdev
);
ret
=
rdev
->
desc
->
ops
->
enable
(
rdev
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"%s: failed to enable %s: %d
\n
"
,
if
(
rdev
->
constraints
&&
(
rdev
->
constraints
->
valid_ops_mask
&
REGULATOR_CHANGE_DRMS
))
drms_uA_update
(
rdev
);
if
(
rdev
->
use_count
==
0
)
{
/* The regulator may on if it's not switchable or left on */
ret
=
_regulator_is_enabled
(
rdev
);
if
(
ret
==
-
EINVAL
||
ret
==
0
)
{
if
(
!
_regulator_can_change_status
(
rdev
))
return
-
EPERM
;
if
(
rdev
->
desc
->
ops
->
enable
)
{
ret
=
rdev
->
desc
->
ops
->
enable
(
rdev
);
if
(
ret
<
0
)
return
ret
;
}
else
{
return
-
EINVAL
;
}
}
else
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"%s: is_enabled() failed for %s: %d
\n
"
,
__func__
,
rdev
->
desc
->
name
,
ret
);
return
ret
;
}
rdev
->
use_count
++
;
return
ret
;
/* Fallthrough on positive return values - already enabled */
}
return
ret
;
rdev
->
use_count
++
;
return
0
;
}
/**
...
...
@@ -1165,7 +1286,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
if
(
rdev
->
use_count
==
1
&&
!
rdev
->
constraints
->
always_on
)
{
/* we are last user */
if
(
rdev
->
desc
->
ops
->
disable
)
{
if
(
_regulator_can_change_status
(
rdev
)
&&
rdev
->
desc
->
ops
->
disable
)
{
ret
=
rdev
->
desc
->
ops
->
disable
(
rdev
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"%s: failed to disable %s
\n
"
,
...
...
@@ -1265,20 +1387,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
static
int
_regulator_is_enabled
(
struct
regulator_dev
*
rdev
)
{
int
ret
;
mutex_lock
(
&
rdev
->
mutex
);
/* sanity check */
if
(
!
rdev
->
desc
->
ops
->
is_enabled
)
{
ret
=
-
EINVAL
;
goto
out
;
}
if
(
!
rdev
->
desc
->
ops
->
is_enabled
)
return
-
EINVAL
;
ret
=
rdev
->
desc
->
ops
->
is_enabled
(
rdev
);
out:
mutex_unlock
(
&
rdev
->
mutex
);
return
ret
;
return
rdev
->
desc
->
ops
->
is_enabled
(
rdev
);
}
/**
...
...
@@ -1295,7 +1408,13 @@ out:
*/
int
regulator_is_enabled
(
struct
regulator
*
regulator
)
{
return
_regulator_is_enabled
(
regulator
->
rdev
);
int
ret
;
mutex_lock
(
&
regulator
->
rdev
->
mutex
);
ret
=
_regulator_is_enabled
(
regulator
->
rdev
);
mutex_unlock
(
&
regulator
->
rdev
->
mutex
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regulator_is_enabled
);
...
...
@@ -1349,6 +1468,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
}
EXPORT_SYMBOL_GPL
(
regulator_list_voltage
);
/**
* regulator_is_supported_voltage - check if a voltage range can be supported
*
* @regulator: Regulator to check.
* @min_uV: Minimum required voltage in uV.
* @max_uV: Maximum required voltage in uV.
*
* Returns a boolean or a negative error code.
*/
int
regulator_is_supported_voltage
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
)
{
int
i
,
voltages
,
ret
;
ret
=
regulator_count_voltages
(
regulator
);
if
(
ret
<
0
)
return
ret
;
voltages
=
ret
;
for
(
i
=
0
;
i
<
voltages
;
i
++
)
{
ret
=
regulator_list_voltage
(
regulator
,
i
);
if
(
ret
>=
min_uV
&&
ret
<=
max_uV
)
return
1
;
}
return
0
;
}
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
...
...
@@ -2091,11 +2239,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
for
(
i
=
0
;
i
<
init_data
->
num_consumer_supplies
;
i
++
)
{
ret
=
set_consumer_device_supply
(
rdev
,
init_data
->
consumer_supplies
[
i
].
dev
,
init_data
->
consumer_supplies
[
i
].
dev_name
,
init_data
->
consumer_supplies
[
i
].
supply
);
if
(
ret
<
0
)
{
for
(
--
i
;
i
>=
0
;
i
--
)
unset_consumer_device_supply
(
rdev
,
init_data
->
consumer_supplies
[
i
].
dev
);
init_data
->
consumer_supplies
[
i
].
dev_name
,
init_data
->
consumer_supplies
[
i
].
dev
);
goto
scrub
;
}
}
...
...
@@ -2130,6 +2280,7 @@ void regulator_unregister(struct regulator_dev *rdev)
return
;
mutex_lock
(
&
regulator_list_mutex
);
WARN_ON
(
rdev
->
open_count
);
unset_regulator_supplies
(
rdev
);
list_del
(
&
rdev
->
list
);
if
(
rdev
->
supply
)
...
...
@@ -2277,14 +2428,14 @@ static int __init regulator_init_complete(void)
ops
=
rdev
->
desc
->
ops
;
c
=
rdev
->
constraints
;
if
(
c
->
name
)
if
(
c
&&
c
->
name
)
name
=
c
->
name
;
else
if
(
rdev
->
desc
->
name
)
name
=
rdev
->
desc
->
name
;
else
name
=
"regulator"
;
if
(
!
ops
->
disable
||
c
->
always_on
)
if
(
!
ops
->
disable
||
(
c
&&
c
->
always_on
)
)
continue
;
mutex_lock
(
&
rdev
->
mutex
);
...
...
drivers/regulator/da903x.c
View file @
55a71bc2
...
...
@@ -64,6 +64,14 @@
#define DA9034_MDTV2 (0x33)
#define DA9034_MVRC (0x34)
/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */
#define DA9035_OVER3 (0x12)
#define DA9035_VCC2 (0x1f)
#define DA9035_3DTV1 (0x2c)
#define DA9035_3DTV2 (0x2d)
#define DA9035_3VRC (0x2e)
#define DA9035_AUTOSKIP (0x2f)
struct
da903x_regulator_info
{
struct
regulator_desc
desc
;
...
...
@@ -79,6 +87,10 @@ struct da903x_regulator_info {
int
enable_bit
;
};
static
int
da9034_ldo12_data
[]
=
{
1700
,
1750
,
1800
,
1850
,
1900
,
1950
,
2000
,
2050
,
2700
,
2750
,
2800
,
2850
,
2900
,
2950
,
3000
,
3050
};
static
inline
struct
device
*
to_da903x_dev
(
struct
regulator_dev
*
rdev
)
{
return
rdev_get_dev
(
rdev
)
->
parent
->
parent
;
...
...
@@ -162,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
return
!!
(
reg_val
&
(
1
<<
info
->
enable_bit
));
}
static
int
da903x_list_voltage
(
struct
regulator_dev
*
rdev
,
unsigned
selector
)
{
struct
da903x_regulator_info
*
info
=
rdev_get_drvdata
(
rdev
);
int
ret
;
ret
=
info
->
min_uV
+
info
->
step_uV
*
selector
;
if
(
ret
>
info
->
max_uV
)
return
-
EINVAL
;
return
ret
;
}
/* DA9030 specific operations */
static
int
da9030_set_ldo1_15_voltage
(
struct
regulator_dev
*
rdev
,
int
min_uV
,
int
max_uV
)
...
...
@@ -305,9 +328,18 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
return
info
->
min_uV
+
info
->
step_uV
*
val
;
}
static
int
da9034_list_ldo12_voltage
(
struct
regulator_dev
*
rdev
,
unsigned
selector
)
{
if
(
selector
>
ARRAY_SIZE
(
da9034_ldo12_data
))
return
-
EINVAL
;
return
da9034_ldo12_data
[
selector
]
*
1000
;
}
static
struct
regulator_ops
da903x_regulator_ldo_ops
=
{
.
set_voltage
=
da903x_set_ldo_voltage
,
.
get_voltage
=
da903x_get_voltage
,
.
list_voltage
=
da903x_list_voltage
,
.
enable
=
da903x_enable
,
.
disable
=
da903x_disable
,
.
is_enabled
=
da903x_is_enabled
,
...
...
@@ -317,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
static
struct
regulator_ops
da9030_regulator_ldo14_ops
=
{
.
set_voltage
=
da9030_set_ldo14_voltage
,
.
get_voltage
=
da9030_get_ldo14_voltage
,
.
list_voltage
=
da903x_list_voltage
,
.
enable
=
da903x_enable
,
.
disable
=
da903x_disable
,
.
is_enabled
=
da903x_is_enabled
,
...
...
@@ -326,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
static
struct
regulator_ops
da9030_regulator_ldo1_15_ops
=
{
.
set_voltage
=
da9030_set_ldo1_15_voltage
,
.
get_voltage
=
da903x_get_voltage
,
.
list_voltage
=
da903x_list_voltage
,
.
enable
=
da903x_enable
,
.
disable
=
da903x_disable
,
.
is_enabled
=
da903x_is_enabled
,
...
...
@@ -334,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
static
struct
regulator_ops
da9034_regulator_dvc_ops
=
{
.
set_voltage
=
da9034_set_dvc_voltage
,
.
get_voltage
=
da903x_get_voltage
,
.
list_voltage
=
da903x_list_voltage
,
.
enable
=
da903x_enable
,
.
disable
=
da903x_disable
,
.
is_enabled
=
da903x_is_enabled
,
...
...
@@ -343,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
static
struct
regulator_ops
da9034_regulator_ldo12_ops
=
{
.
set_voltage
=
da9034_set_ldo12_voltage
,
.
get_voltage
=
da9034_get_ldo12_voltage
,
.
list_voltage
=
da9034_list_ldo12_voltage
,
.
enable
=
da903x_enable
,
.
disable
=
da903x_disable
,
.
is_enabled
=
da903x_is_enabled
,
...
...
@@ -355,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.ops = &da903x_regulator_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.id = _pmic##_ID_LDO##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
}, \
.min_uV = (min) * 1000, \
...
...
@@ -367,24 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.enable_bit = (ebit), \
}
#define DA903
4_DVC(
_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
#define DA903
x_DVC(_pmic,
_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
{ \
.desc = { \
.name = #_id, \
.ops = &da9034_regulator_dvc_ops, \
.type = REGULATOR_VOLTAGE, \
.id = DA9034_ID_##_id, \
.id = _pmic##_ID_##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
}, \
.min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \
.step_uV = (step) * 1000, \
.vol_reg =
DA9034
_##vreg, \
.vol_reg =
_pmic##
_##vreg, \
.vol_shift = (0), \
.vol_nbits = (nbits), \
.update_reg =
DA9034
_##ureg, \
.update_reg =
_pmic##
_##ureg, \
.update_bit = (ubit), \
.enable_reg =
DA9034
_##ereg, \
.enable_reg =
_pmic##
_##ereg, \
.enable_bit = (ebit), \
}
...
...
@@ -394,8 +432,22 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
static
struct
da903x_regulator_info
da903x_regulator_info
[]
=
{
/* DA9030 */
DA9030_DVC
(
BUCK2
,
850
,
1625
,
25
,
BUCK2DVM1
,
5
,
BUCK2DVM1
,
7
,
RCTL11
,
0
),
DA9030_LDO
(
1
,
1200
,
3200
,
100
,
LDO1
,
0
,
5
,
RCTL12
,
1
),
DA9030_LDO
(
2
,
1800
,
3200
,
100
,
LDO23
,
0
,
4
,
RCTL12
,
2
),
DA9030_LDO
(
3
,
1800
,
3200
,
100
,
LDO23
,
4
,
4
,
RCTL12
,
3
),
...
...
@@ -417,9 +469,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9030_LDO
(
13
,
2100
,
2100
,
0
,
INVAL
,
0
,
0
,
RCTL11
,
3
),
/* fixed @2.1V */
/* DA9034 */
DA9034_DVC
(
BUCK1
,
725
,
1500
,
25
,
ADTV
1
,
5
,
VCC1
,
0
,
OVER1
,
0
),
DA9034_DVC
(
BUCK2
,
725
,
1500
,
25
,
CDTV
1
,
5
,
VCC1
,
2
,
OVER1
,
1
),
DA9034_DVC
(
LDO2
,
725
,
1500
,
25
,
SDTV
1
,
5
,
VCC1
,
4
,
OVER1
,
2
),
DA9034_DVC
(
BUCK1
,
725
,
1500
,
25
,
ADTV
2
,
5
,
VCC1
,
0
,
OVER1
,
0
),
DA9034_DVC
(
BUCK2
,
725
,
1500
,
25
,
CDTV
2
,
5
,
VCC1
,
2
,
OVER1
,
1
),
DA9034_DVC
(
LDO2
,
725
,
1500
,
25
,
SDTV
2
,
5
,
VCC1
,
4
,
OVER1
,
2
),
DA9034_DVC
(
LDO1
,
1700
,
2075
,
25
,
MDTV1
,
4
,
VCC1
,
6
,
OVER3
,
4
),
DA9034_LDO
(
3
,
1800
,
3300
,
100
,
LDO643
,
0
,
4
,
OVER3
,
5
),
...
...
@@ -435,6 +487,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9034_LDO
(
14
,
1800
,
3300
,
100
,
LDO1514
,
0
,
4
,
OVER3
,
0
),
DA9034_LDO
(
15
,
1800
,
3300
,
100
,
LDO1514
,
4
,
4
,
OVER3
,
1
),
DA9034_LDO
(
5
,
3100
,
3100
,
0
,
INVAL
,
0
,
0
,
OVER3
,
7
),
/* fixed @3.1V */
/* DA9035 */
DA9035_DVC
(
BUCK3
,
1800
,
2200
,
100
,
3
DTV1
,
3
,
VCC2
,
0
,
OVER3
,
3
),
};
static
inline
struct
da903x_regulator_info
*
find_regulator_info
(
int
id
)
...
...
@@ -462,8 +517,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
}
/* Workaround for the weird LDO12 voltage setting */
if
(
ri
->
desc
.
id
==
DA9034_ID_LDO12
)
if
(
ri
->
desc
.
id
==
DA9034_ID_LDO12
)
{
ri
->
desc
.
ops
=
&
da9034_regulator_ldo12_ops
;
ri
->
desc
.
n_voltages
=
ARRAY_SIZE
(
da9034_ldo12_data
);
}
if
(
ri
->
desc
.
id
==
DA9030_ID_LDO14
)
ri
->
desc
.
ops
=
&
da9030_regulator_ldo14_ops
;
...
...
drivers/regulator/fixed.c
View file @
55a71bc2
...
...
@@ -5,6 +5,9 @@
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.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
...
...
@@ -20,20 +23,45 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
#include <linux/gpio.h>
struct
fixed_voltage_data
{
struct
regulator_desc
desc
;
struct
regulator_dev
*
dev
;
int
microvolts
;
int
gpio
;
unsigned
enable_high
:
1
;
unsigned
is_enabled
:
1
;
};
static
int
fixed_voltage_is_enabled
(
struct
regulator_dev
*
dev
)
{
return
1
;
struct
fixed_voltage_data
*
data
=
rdev_get_drvdata
(
dev
);
return
data
->
is_enabled
;
}
static
int
fixed_voltage_enable
(
struct
regulator_dev
*
dev
)
{
struct
fixed_voltage_data
*
data
=
rdev_get_drvdata
(
dev
);
if
(
gpio_is_valid
(
data
->
gpio
))
{
gpio_set_value_cansleep
(
data
->
gpio
,
data
->
enable_high
);
data
->
is_enabled
=
1
;
}
return
0
;
}
static
int
fixed_voltage_disable
(
struct
regulator_dev
*
dev
)
{
struct
fixed_voltage_data
*
data
=
rdev_get_drvdata
(
dev
);
if
(
gpio_is_valid
(
data
->
gpio
))
{
gpio_set_value_cansleep
(
data
->
gpio
,
!
data
->
enable_high
);
data
->
is_enabled
=
0
;
}
return
0
;
}
...
...
@@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
static
struct
regulator_ops
fixed_voltage_ops
=
{
.
is_enabled
=
fixed_voltage_is_enabled
,
.
enable
=
fixed_voltage_enable
,
.
disable
=
fixed_voltage_disable
,
.
get_voltage
=
fixed_voltage_get_voltage
,
.
list_voltage
=
fixed_voltage_list_voltage
,
};
...
...
@@ -70,12 +99,14 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata
=
kzalloc
(
sizeof
(
struct
fixed_voltage_data
),
GFP_KERNEL
);
if
(
drvdata
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to allocate device data
\n
"
);
ret
=
-
ENOMEM
;
goto
err
;
}
drvdata
->
desc
.
name
=
kstrdup
(
config
->
supply_name
,
GFP_KERNEL
);
if
(
drvdata
->
desc
.
name
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to allocate supply name
\n
"
);
ret
=
-
ENOMEM
;
goto
err
;
}
...
...
@@ -85,12 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata
->
desc
.
n_voltages
=
1
;
drvdata
->
microvolts
=
config
->
microvolts
;
drvdata
->
gpio
=
config
->
gpio
;
if
(
gpio_is_valid
(
config
->
gpio
))
{
drvdata
->
enable_high
=
config
->
enable_high
;
/* FIXME: Remove below print warning
*
* config->gpio must be set to -EINVAL by platform code if
* GPIO control is not required. However, early adopters
* not requiring GPIO control may forget to initialize
* config->gpio to -EINVAL. This will cause GPIO 0 to be used
* for GPIO control.
*
* This warning will be removed once there are a couple of users
* for this driver.
*/
if
(
!
config
->
gpio
)
dev_warn
(
&
pdev
->
dev
,
"using GPIO 0 for regulator enable control
\n
"
);
ret
=
gpio_request
(
config
->
gpio
,
config
->
supply_name
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Could not obtain regulator enable GPIO %d: %d
\n
"
,
config
->
gpio
,
ret
);
goto
err_name
;
}
/* set output direction without changing state
* to prevent glitch
*/
drvdata
->
is_enabled
=
config
->
enabled_at_boot
;
ret
=
drvdata
->
is_enabled
?
config
->
enable_high
:
!
config
->
enable_high
;
ret
=
gpio_direction_output
(
config
->
gpio
,
ret
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Could not configure regulator enable GPIO %d direction: %d
\n
"
,
config
->
gpio
,
ret
);
goto
err_gpio
;
}
}
else
{
/* Regulator without GPIO control is considered
* always enabled
*/
drvdata
->
is_enabled
=
1
;
}
drvdata
->
dev
=
regulator_register
(
&
drvdata
->
desc
,
&
pdev
->
dev
,
config
->
init_data
,
drvdata
);
if
(
IS_ERR
(
drvdata
->
dev
))
{
ret
=
PTR_ERR
(
drvdata
->
dev
);
goto
err_name
;
dev_err
(
&
pdev
->
dev
,
"Failed to register regulator: %d
\n
"
,
ret
);
goto
err_gpio
;
}
platform_set_drvdata
(
pdev
,
drvdata
);
...
...
@@ -100,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
return
0
;
err_gpio:
if
(
gpio_is_valid
(
config
->
gpio
))
gpio_free
(
config
->
gpio
);
err_name:
kfree
(
drvdata
->
desc
.
name
);
err:
...
...
@@ -115,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)
kfree
(
drvdata
->
desc
.
name
);
kfree
(
drvdata
);
if
(
gpio_is_valid
(
drvdata
->
gpio
))
gpio_free
(
drvdata
->
gpio
);
return
0
;
}
...
...
drivers/regulator/pcf50633-regulator.c
View file @
55a71bc2
...
...
@@ -24,11 +24,12 @@
#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/pmic.h>
#define PCF50633_REGULATOR(_name, _id) \
#define PCF50633_REGULATOR(_name, _id
, _n
) \
{ \
.name = _name, \
.id = _id, \
.ops = &pcf50633_regulator_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
...
...
@@ -149,33 +150,20 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
return
pcf50633_reg_write
(
pcf
,
regnr
,
volt_bits
);
}
static
int
pcf50633_regulator_get_voltage
(
struct
regulator_dev
*
rdev
)
static
int
pcf50633_regulator_voltage_value
(
enum
pcf50633_regulator_id
id
,
u8
bits
)
{
struct
pcf50633
*
pcf
;
int
regulator_id
,
millivolts
,
volt_bits
;
u8
regnr
;
pcf
=
rdev_get_drvdata
(
rdev
);;
int
millivolts
;
regulator_id
=
rdev_get_id
(
rdev
);
if
(
regulator_id
>=
PCF50633_NUM_REGULATORS
)
return
-
EINVAL
;
regnr
=
pcf50633_regulator_registers
[
regulator_id
];
volt_bits
=
pcf50633_reg_read
(
pcf
,
regnr
);
if
(
volt_bits
<
0
)
return
-
1
;
switch
(
regulator_id
)
{
switch
(
id
)
{
case
PCF50633_REGULATOR_AUTO
:
millivolts
=
auto_voltage_value
(
volt_
bits
);
millivolts
=
auto_voltage_value
(
bits
);
break
;
case
PCF50633_REGULATOR_DOWN1
:
millivolts
=
down_voltage_value
(
volt_
bits
);
millivolts
=
down_voltage_value
(
bits
);
break
;
case
PCF50633_REGULATOR_DOWN2
:
millivolts
=
down_voltage_value
(
volt_
bits
);
millivolts
=
down_voltage_value
(
bits
);
break
;
case
PCF50633_REGULATOR_LDO1
:
case
PCF50633_REGULATOR_LDO2
:
...
...
@@ -184,7 +172,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
case
PCF50633_REGULATOR_LDO5
:
case
PCF50633_REGULATOR_LDO6
:
case
PCF50633_REGULATOR_HCLDO
:
millivolts
=
ldo_voltage_value
(
volt_
bits
);
millivolts
=
ldo_voltage_value
(
bits
);
break
;
default:
return
-
EINVAL
;
...
...
@@ -193,6 +181,49 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
return
millivolts
*
1000
;
}
static
int
pcf50633_regulator_get_voltage
(
struct
regulator_dev
*
rdev
)
{
struct
pcf50633
*
pcf
;
int
regulator_id
;
u8
volt_bits
,
regnr
;
pcf
=
rdev_get_drvdata
(
rdev
);
regulator_id
=
rdev_get_id
(
rdev
);
if
(
regulator_id
>=
PCF50633_NUM_REGULATORS
)
return
-
EINVAL
;
regnr
=
pcf50633_regulator_registers
[
regulator_id
];
volt_bits
=
pcf50633_reg_read
(
pcf
,
regnr
);
return
pcf50633_regulator_voltage_value
(
regulator_id
,
volt_bits
);
}
static
int
pcf50633_regulator_list_voltage
(
struct
regulator_dev
*
rdev
,
unsigned
int
index
)
{
struct
pcf50633
*
pcf
;
int
regulator_id
;
pcf
=
rdev_get_drvdata
(
rdev
);
regulator_id
=
rdev_get_id
(
rdev
);
switch
(
regulator_id
)
{
case
PCF50633_REGULATOR_AUTO
:
index
+=
0x2f
;
break
;
case
PCF50633_REGULATOR_HCLDO
:
index
+=
0x01
;
break
;
default:
break
;
}
return
pcf50633_regulator_voltage_value
(
regulator_id
,
index
);
}
static
int
pcf50633_regulator_enable
(
struct
regulator_dev
*
rdev
)
{
struct
pcf50633
*
pcf
=
rdev_get_drvdata
(
rdev
);
...
...
@@ -246,6 +277,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
static
struct
regulator_ops
pcf50633_regulator_ops
=
{
.
set_voltage
=
pcf50633_regulator_set_voltage
,
.
get_voltage
=
pcf50633_regulator_get_voltage
,
.
list_voltage
=
pcf50633_regulator_list_voltage
,
.
enable
=
pcf50633_regulator_enable
,
.
disable
=
pcf50633_regulator_disable
,
.
is_enabled
=
pcf50633_regulator_is_enabled
,
...
...
@@ -253,27 +285,27 @@ static struct regulator_ops pcf50633_regulator_ops = {
static
struct
regulator_desc
regulators
[]
=
{
[
PCF50633_REGULATOR_AUTO
]
=
PCF50633_REGULATOR
(
"auto"
,
PCF50633_REGULATOR_AUTO
),
PCF50633_REGULATOR
(
"auto"
,
PCF50633_REGULATOR_AUTO
,
80
),
[
PCF50633_REGULATOR_DOWN1
]
=
PCF50633_REGULATOR
(
"down1"
,
PCF50633_REGULATOR_DOWN1
),
PCF50633_REGULATOR
(
"down1"
,
PCF50633_REGULATOR_DOWN1
,
95
),
[
PCF50633_REGULATOR_DOWN2
]
=
PCF50633_REGULATOR
(
"down2"
,
PCF50633_REGULATOR_DOWN2
),
PCF50633_REGULATOR
(
"down2"
,
PCF50633_REGULATOR_DOWN2
,
95
),
[
PCF50633_REGULATOR_LDO1
]
=
PCF50633_REGULATOR
(
"ldo1"
,
PCF50633_REGULATOR_LDO1
),
PCF50633_REGULATOR
(
"ldo1"
,
PCF50633_REGULATOR_LDO1
,
27
),
[
PCF50633_REGULATOR_LDO2
]
=
PCF50633_REGULATOR
(
"ldo2"
,
PCF50633_REGULATOR_LDO2
),
PCF50633_REGULATOR
(
"ldo2"
,
PCF50633_REGULATOR_LDO2
,
27
),
[
PCF50633_REGULATOR_LDO3
]
=
PCF50633_REGULATOR
(
"ldo3"
,
PCF50633_REGULATOR_LDO3
),
PCF50633_REGULATOR
(
"ldo3"
,
PCF50633_REGULATOR_LDO3
,
27
),
[
PCF50633_REGULATOR_LDO4
]
=
PCF50633_REGULATOR
(
"ldo4"
,
PCF50633_REGULATOR_LDO4
),
PCF50633_REGULATOR
(
"ldo4"
,
PCF50633_REGULATOR_LDO4
,
27
),
[
PCF50633_REGULATOR_LDO5
]
=
PCF50633_REGULATOR
(
"ldo5"
,
PCF50633_REGULATOR_LDO5
),
PCF50633_REGULATOR
(
"ldo5"
,
PCF50633_REGULATOR_LDO5
,
27
),
[
PCF50633_REGULATOR_LDO6
]
=
PCF50633_REGULATOR
(
"ldo6"
,
PCF50633_REGULATOR_LDO6
),
PCF50633_REGULATOR
(
"ldo6"
,
PCF50633_REGULATOR_LDO6
,
27
),
[
PCF50633_REGULATOR_HCLDO
]
=
PCF50633_REGULATOR
(
"hcldo"
,
PCF50633_REGULATOR_HCLDO
),
PCF50633_REGULATOR
(
"hcldo"
,
PCF50633_REGULATOR_HCLDO
,
26
),
[
PCF50633_REGULATOR_MEMLDO
]
=
PCF50633_REGULATOR
(
"memldo"
,
PCF50633_REGULATOR_MEMLDO
),
PCF50633_REGULATOR
(
"memldo"
,
PCF50633_REGULATOR_MEMLDO
,
0
),
};
static
int
__devinit
pcf50633_regulator_probe
(
struct
platform_device
*
pdev
)
...
...
drivers/regulator/tps65023-regulator.c
0 → 100644
View file @
55a71bc2
/*
* tps65023-regulator.c
*
* Supports TPS65023 Regulator
*
* Copyright (C) 2009 Texas Instrument 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/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c.h>
#include <linux/delay.h>
/* Register definitions */
#define TPS65023_REG_VERSION 0
#define TPS65023_REG_PGOODZ 1
#define TPS65023_REG_MASK 2
#define TPS65023_REG_REG_CTRL 3
#define TPS65023_REG_CON_CTRL 4
#define TPS65023_REG_CON_CTRL2 5
#define TPS65023_REG_DEF_CORE 6
#define TPS65023_REG_DEFSLEW 7
#define TPS65023_REG_LDO_CTRL 8
/* PGOODZ bitfields */
#define TPS65023_PGOODZ_PWRFAILZ BIT(7)
#define TPS65023_PGOODZ_LOWBATTZ BIT(6)
#define TPS65023_PGOODZ_VDCDC1 BIT(5)
#define TPS65023_PGOODZ_VDCDC2 BIT(4)
#define TPS65023_PGOODZ_VDCDC3 BIT(3)
#define TPS65023_PGOODZ_LDO2 BIT(2)
#define TPS65023_PGOODZ_LDO1 BIT(1)
/* MASK bitfields */
#define TPS65023_MASK_PWRFAILZ BIT(7)
#define TPS65023_MASK_LOWBATTZ BIT(6)
#define TPS65023_MASK_VDCDC1 BIT(5)
#define TPS65023_MASK_VDCDC2 BIT(4)
#define TPS65023_MASK_VDCDC3 BIT(3)
#define TPS65023_MASK_LDO2 BIT(2)
#define TPS65023_MASK_LDO1 BIT(1)
/* REG_CTRL bitfields */
#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5)
#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4)
#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3)
#define TPS65023_REG_CTRL_LDO2_EN BIT(2)
#define TPS65023_REG_CTRL_LDO1_EN BIT(1)
/* LDO_CTRL bitfields */
#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4))
/* Number of step-down converters available */
#define TPS65023_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS65023_NUM_LDO 2
/* Number of total regulators available */
#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
/* DCDCs */
#define TPS65023_DCDC_1 0
#define TPS65023_DCDC_2 1
#define TPS65023_DCDC_3 2
/* LDOs */
#define TPS65023_LDO_1 3
#define TPS65023_LDO_2 4
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
/* Supported voltage values for regulators */
static
const
u16
VDCDC1_VSEL_table
[]
=
{
800
,
825
,
850
,
875
,
900
,
925
,
950
,
975
,
1000
,
1025
,
1050
,
1075
,
1100
,
1125
,
1150
,
1175
,
1200
,
1225
,
1250
,
1275
,
1300
,
1325
,
1350
,
1375
,
1400
,
1425
,
1450
,
1475
,
1500
,
1525
,
1550
,
1600
,
};
static
const
u16
LDO1_VSEL_table
[]
=
{
1000
,
1100
,
1300
,
1800
,
2200
,
2600
,
2800
,
3150
,
};
static
const
u16
LDO2_VSEL_table
[]
=
{
1050
,
1200
,
1300
,
1800
,
2500
,
2800
,
3000
,
3300
,
};
static
unsigned
int
num_voltages
[]
=
{
ARRAY_SIZE
(
VDCDC1_VSEL_table
),
0
,
0
,
ARRAY_SIZE
(
LDO1_VSEL_table
),
ARRAY_SIZE
(
LDO2_VSEL_table
)};
/* Regulator specific details */
struct
tps_info
{
const
char
*
name
;
unsigned
min_uV
;
unsigned
max_uV
;
bool
fixed
;
u8
table_len
;
const
u16
*
table
;
};
/* PMIC details */
struct
tps_pmic
{
struct
regulator_desc
desc
[
TPS65023_NUM_REGULATOR
];
struct
i2c_client
*
client
;
struct
regulator_dev
*
rdev
[
TPS65023_NUM_REGULATOR
];
const
struct
tps_info
*
info
[
TPS65023_NUM_REGULATOR
];
struct
mutex
io_lock
;
};
static
inline
int
tps_65023_read
(
struct
tps_pmic
*
tps
,
u8
reg
)
{
return
i2c_smbus_read_byte_data
(
tps
->
client
,
reg
);
}
static
inline
int
tps_65023_write
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
val
)
{
return
i2c_smbus_write_byte_data
(
tps
->
client
,
reg
,
val
);
}
static
int
tps_65023_set_bits
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
mask
)
{
int
err
,
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_65023_read
(
tps
,
reg
);
if
(
data
<
0
)
{
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
err
=
data
;
goto
out
;
}
data
|=
mask
;
err
=
tps_65023_write
(
tps
,
reg
,
data
);
if
(
err
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
out:
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps_65023_clear_bits
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
mask
)
{
int
err
,
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_65023_read
(
tps
,
reg
);
if
(
data
<
0
)
{
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
err
=
data
;
goto
out
;
}
data
&=
~
mask
;
err
=
tps_65023_write
(
tps
,
reg
,
data
);
if
(
err
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
out:
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps_65023_reg_read
(
struct
tps_pmic
*
tps
,
u8
reg
)
{
int
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_65023_read
(
tps
,
reg
);
if
(
data
<
0
)
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
mutex_unlock
(
&
tps
->
io_lock
);
return
data
;
}
static
int
tps_65023_reg_write
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
val
)
{
int
err
;
mutex_lock
(
&
tps
->
io_lock
);
err
=
tps_65023_write
(
tps
,
reg
,
val
);
if
(
err
<
0
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps65023_dcdc_is_enabled
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS65023_DCDC_1
||
dcdc
>
TPS65023_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS65023_NUM_REGULATOR
-
dcdc
;
data
=
tps_65023_reg_read
(
tps
,
TPS65023_REG_REG_CTRL
);
if
(
data
<
0
)
return
data
;
else
return
(
data
&
1
<<
shift
)
?
1
:
0
;
}
static
int
tps65023_ldo_is_enabled
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
return
-
EINVAL
;
shift
=
(
ldo
==
TPS65023_LDO_1
?
1
:
2
);
data
=
tps_65023_reg_read
(
tps
,
TPS65023_REG_REG_CTRL
);
if
(
data
<
0
)
return
data
;
else
return
(
data
&
1
<<
shift
)
?
1
:
0
;
}
static
int
tps65023_dcdc_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS65023_DCDC_1
||
dcdc
>
TPS65023_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS65023_NUM_REGULATOR
-
dcdc
;
return
tps_65023_set_bits
(
tps
,
TPS65023_REG_REG_CTRL
,
1
<<
shift
);
}
static
int
tps65023_dcdc_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS65023_DCDC_1
||
dcdc
>
TPS65023_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS65023_NUM_REGULATOR
-
dcdc
;
return
tps_65023_clear_bits
(
tps
,
TPS65023_REG_REG_CTRL
,
1
<<
shift
);
}
static
int
tps65023_ldo_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
return
-
EINVAL
;
shift
=
(
ldo
==
TPS65023_LDO_1
?
1
:
2
);
return
tps_65023_set_bits
(
tps
,
TPS65023_REG_REG_CTRL
,
1
<<
shift
);
}
static
int
tps65023_ldo_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
return
-
EINVAL
;
shift
=
(
ldo
==
TPS65023_LDO_1
?
1
:
2
);
return
tps_65023_clear_bits
(
tps
,
TPS65023_REG_REG_CTRL
,
1
<<
shift
);
}
static
int
tps65023_dcdc_get_voltage
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65023_DCDC_1
||
dcdc
>
TPS65023_DCDC_3
)
return
-
EINVAL
;
if
(
dcdc
==
TPS65023_DCDC_1
)
{
data
=
tps_65023_reg_read
(
tps
,
TPS65023_REG_DEF_CORE
);
if
(
data
<
0
)
return
data
;
data
&=
(
tps
->
info
[
dcdc
]
->
table_len
-
1
);
return
tps
->
info
[
dcdc
]
->
table
[
data
]
*
1000
;
}
else
return
tps
->
info
[
dcdc
]
->
min_uV
;
}
static
int
tps65023_dcdc_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
int
vsel
;
if
(
dcdc
!=
TPS65023_DCDC_1
)
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
;
for
(
vsel
=
0
;
vsel
<
tps
->
info
[
dcdc
]
->
table_len
;
vsel
++
)
{
int
mV
=
tps
->
info
[
dcdc
]
->
table
[
vsel
];
int
uV
=
mV
*
1000
;
/* Break at the first in-range value */
if
(
min_uV
<=
uV
&&
uV
<=
max_uV
)
break
;
}
/* write to the register in case we found a match */
if
(
vsel
==
tps
->
info
[
dcdc
]
->
table_len
)
return
-
EINVAL
;
else
return
tps_65023_reg_write
(
tps
,
TPS65023_REG_DEF_CORE
,
vsel
);
}
static
int
tps65023_ldo_get_voltage
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
return
-
EINVAL
;
data
=
tps_65023_reg_read
(
tps
,
TPS65023_REG_LDO_CTRL
);
if
(
data
<
0
)
return
data
;
data
>>=
(
TPS65023_LDO_CTRL_LDOx_SHIFT
(
ldo
-
TPS65023_LDO_1
));
data
&=
(
tps
->
info
[
ldo
]
->
table_len
-
1
);
return
tps
->
info
[
ldo
]
->
table
[
data
]
*
1000
;
}
static
int
tps65023_ldo_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
vsel
,
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
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
;
for
(
vsel
=
0
;
vsel
<
tps
->
info
[
ldo
]
->
table_len
;
vsel
++
)
{
int
mV
=
tps
->
info
[
ldo
]
->
table
[
vsel
];
int
uV
=
mV
*
1000
;
/* Break at the first in-range value */
if
(
min_uV
<=
uV
&&
uV
<=
max_uV
)
break
;
}
if
(
vsel
==
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
data
=
tps_65023_reg_read
(
tps
,
TPS65023_REG_LDO_CTRL
);
if
(
data
<
0
)
return
data
;
data
&=
TPS65023_LDO_CTRL_LDOx_MASK
(
ldo
-
TPS65023_LDO_1
);
data
|=
(
vsel
<<
(
TPS65023_LDO_CTRL_LDOx_SHIFT
(
ldo
-
TPS65023_LDO_1
)));
return
tps_65023_reg_write
(
tps
,
TPS65023_REG_LDO_CTRL
,
data
);
}
static
int
tps65023_dcdc_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS65023_DCDC_1
||
dcdc
>
TPS65023_DCDC_3
)
return
-
EINVAL
;
if
(
dcdc
==
TPS65023_DCDC_1
)
{
if
(
selector
>=
tps
->
info
[
dcdc
]
->
table_len
)
return
-
EINVAL
;
else
return
tps
->
info
[
dcdc
]
->
table
[
selector
]
*
1000
;
}
else
return
tps
->
info
[
dcdc
]
->
min_uV
;
}
static
int
tps65023_ldo_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS65023_LDO_1
||
ldo
>
TPS65023_LDO_2
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
else
return
tps
->
info
[
ldo
]
->
table
[
selector
]
*
1000
;
}
/* Operations permitted on VDCDCx */
static
struct
regulator_ops
tps65023_dcdc_ops
=
{
.
is_enabled
=
tps65023_dcdc_is_enabled
,
.
enable
=
tps65023_dcdc_enable
,
.
disable
=
tps65023_dcdc_disable
,
.
get_voltage
=
tps65023_dcdc_get_voltage
,
.
set_voltage
=
tps65023_dcdc_set_voltage
,
.
list_voltage
=
tps65023_dcdc_list_voltage
,
};
/* Operations permitted on LDOx */
static
struct
regulator_ops
tps65023_ldo_ops
=
{
.
is_enabled
=
tps65023_ldo_is_enabled
,
.
enable
=
tps65023_ldo_enable
,
.
disable
=
tps65023_ldo_disable
,
.
get_voltage
=
tps65023_ldo_get_voltage
,
.
set_voltage
=
tps65023_ldo_set_voltage
,
.
list_voltage
=
tps65023_ldo_list_voltage
,
};
static
int
tps_65023_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
static
int
desc_id
;
const
struct
tps_info
*
info
=
(
void
*
)
id
->
driver_data
;
struct
regulator_init_data
*
init_data
;
struct
regulator_dev
*
rdev
;
struct
tps_pmic
*
tps
;
int
i
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_BYTE_DATA
))
return
-
EIO
;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data
=
client
->
dev
.
platform_data
;
if
(
!
init_data
)
return
-
EIO
;
tps
=
kzalloc
(
sizeof
(
*
tps
),
GFP_KERNEL
);
if
(
!
tps
)
return
-
ENOMEM
;
mutex_init
(
&
tps
->
io_lock
);
/* common for all regulators */
tps
->
client
=
client
;
for
(
i
=
0
;
i
<
TPS65023_NUM_REGULATOR
;
i
++
,
info
++
,
init_data
++
)
{
/* Store regulator specific information */
tps
->
info
[
i
]
=
info
;
tps
->
desc
[
i
].
name
=
info
->
name
;
tps
->
desc
[
i
].
id
=
desc_id
++
;
tps
->
desc
[
i
].
n_voltages
=
num_voltages
[
i
];
tps
->
desc
[
i
].
ops
=
(
i
>
TPS65023_DCDC_3
?
&
tps65023_ldo_ops
:
&
tps65023_dcdc_ops
);
tps
->
desc
[
i
].
type
=
REGULATOR_VOLTAGE
;
tps
->
desc
[
i
].
owner
=
THIS_MODULE
;
/* Register the regulators */
rdev
=
regulator_register
(
&
tps
->
desc
[
i
],
&
client
->
dev
,
init_data
,
tps
);
if
(
IS_ERR
(
rdev
))
{
dev_err
(
&
client
->
dev
,
"failed to register %s
\n
"
,
id
->
name
);
/* Unregister */
while
(
i
)
regulator_unregister
(
tps
->
rdev
[
--
i
]);
tps
->
client
=
NULL
;
/* clear the client data in i2c */
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
tps
);
return
PTR_ERR
(
rdev
);
}
/* Save regulator for cleanup */
tps
->
rdev
[
i
]
=
rdev
;
}
i2c_set_clientdata
(
client
,
tps
);
return
0
;
}
/**
* tps_65023_remove - TPS65023 driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister TPS driver as an i2c client device driver
*/
static
int
__devexit
tps_65023_remove
(
struct
i2c_client
*
client
)
{
struct
tps_pmic
*
tps
=
i2c_get_clientdata
(
client
);
int
i
;
for
(
i
=
0
;
i
<
TPS65023_NUM_REGULATOR
;
i
++
)
regulator_unregister
(
tps
->
rdev
[
i
]);
tps
->
client
=
NULL
;
/* clear the client data in i2c */
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
tps
);
return
0
;
}
static
const
struct
tps_info
tps65023_regs
[]
=
{
{
.
name
=
"VDCDC1"
,
.
min_uV
=
800000
,
.
max_uV
=
1600000
,
.
table_len
=
ARRAY_SIZE
(
VDCDC1_VSEL_table
),
.
table
=
VDCDC1_VSEL_table
,
},
{
.
name
=
"VDCDC2"
,
.
min_uV
=
3300000
,
.
max_uV
=
3300000
,
.
fixed
=
1
,
},
{
.
name
=
"VDCDC3"
,
.
min_uV
=
1800000
,
.
max_uV
=
1800000
,
.
fixed
=
1
,
},
{
.
name
=
"LDO1"
,
.
min_uV
=
1000000
,
.
max_uV
=
3150000
,
.
table_len
=
ARRAY_SIZE
(
LDO1_VSEL_table
),
.
table
=
LDO1_VSEL_table
,
},
{
.
name
=
"LDO2"
,
.
min_uV
=
1050000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
LDO2_VSEL_table
),
.
table
=
LDO2_VSEL_table
,
},
};
static
const
struct
i2c_device_id
tps_65023_id
[]
=
{
{.
name
=
"tps65023"
,
.
driver_data
=
(
unsigned
long
)
tps65023_regs
,},
{
},
};
MODULE_DEVICE_TABLE
(
i2c
,
tps_65023_id
);
static
struct
i2c_driver
tps_65023_i2c_driver
=
{
.
driver
=
{
.
name
=
"tps65023"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
tps_65023_probe
,
.
remove
=
__devexit_p
(
tps_65023_remove
),
.
id_table
=
tps_65023_id
,
};
/**
* tps_65023_init
*
* Module init function
*/
static
int
__init
tps_65023_init
(
void
)
{
return
i2c_add_driver
(
&
tps_65023_i2c_driver
);
}
subsys_initcall
(
tps_65023_init
);
/**
* tps_65023_cleanup
*
* Module exit function
*/
static
void
__exit
tps_65023_cleanup
(
void
)
{
i2c_del_driver
(
&
tps_65023_i2c_driver
);
}
module_exit
(
tps_65023_cleanup
);
MODULE_AUTHOR
(
"Texas Instruments"
);
MODULE_DESCRIPTION
(
"TPS65023 voltage regulator driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/tps6507x-regulator.c
0 → 100644
View file @
55a71bc2
/*
* tps6507x-regulator.c
*
* Regulator driver for TPS65073 PMIC
*
* Copyright (C) 2009 Texas Instrument 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/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c.h>
#include <linux/delay.h>
/* Register definitions */
#define TPS6507X_REG_PPATH1 0X01
#define TPS6507X_REG_INT 0X02
#define TPS6507X_REG_CHGCONFIG0 0X03
#define TPS6507X_REG_CHGCONFIG1 0X04
#define TPS6507X_REG_CHGCONFIG2 0X05
#define TPS6507X_REG_CHGCONFIG3 0X06
#define TPS6507X_REG_REG_ADCONFIG 0X07
#define TPS6507X_REG_TSCMODE 0X08
#define TPS6507X_REG_ADRESULT_1 0X09
#define TPS6507X_REG_ADRESULT_2 0X0A
#define TPS6507X_REG_PGOOD 0X0B
#define TPS6507X_REG_PGOODMASK 0X0C
#define TPS6507X_REG_CON_CTRL1 0X0D
#define TPS6507X_REG_CON_CTRL2 0X0E
#define TPS6507X_REG_CON_CTRL3 0X0F
#define TPS6507X_REG_DEFDCDC1 0X10
#define TPS6507X_REG_DEFDCDC2_LOW 0X11
#define TPS6507X_REG_DEFDCDC2_HIGH 0X12
#define TPS6507X_REG_DEFDCDC3_LOW 0X13
#define TPS6507X_REG_DEFDCDC3_HIGH 0X14
#define TPS6507X_REG_DEFSLEW 0X15
#define TPS6507X_REG_LDO_CTRL1 0X16
#define TPS6507X_REG_DEFLDO2 0X17
#define TPS6507X_REG_WLED_CTRL1 0X18
#define TPS6507X_REG_WLED_CTRL2 0X19
/* CON_CTRL1 bitfields */
#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4)
#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3)
#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2)
#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1)
#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0)
/* DEFDCDC1 bitfields */
#define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN BIT(7)
#define TPS6507X_DEFDCDC1_DCDC1_MASK 0X3F
/* DEFDCDC2_LOW bitfields */
#define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK 0X3F
/* DEFDCDC2_HIGH bitfields */
#define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK 0X3F
/* DEFDCDC3_LOW bitfields */
#define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK 0X3F
/* DEFDCDC3_HIGH bitfields */
#define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK 0X3F
/* TPS6507X_REG_LDO_CTRL1 bitfields */
#define TPS6507X_REG_LDO_CTRL1_LDO1_MASK 0X0F
/* TPS6507X_REG_DEFLDO2 bitfields */
#define TPS6507X_REG_DEFLDO2_LDO2_MASK 0X3F
/* VDCDC MASK */
#define TPS6507X_DEFDCDCX_DCDC_MASK 0X3F
/* DCDC's */
#define TPS6507X_DCDC_1 0
#define TPS6507X_DCDC_2 1
#define TPS6507X_DCDC_3 2
/* LDOs */
#define TPS6507X_LDO_1 3
#define TPS6507X_LDO_2 4
#define TPS6507X_MAX_REG_ID TPS6507X_LDO_2
/* Number of step-down converters available */
#define TPS6507X_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS6507X_NUM_LDO 2
/* Number of total regulators available */
#define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
/* Supported voltage values for regulators (in milliVolts) */
static
const
u16
VDCDCx_VSEL_table
[]
=
{
725
,
750
,
775
,
800
,
825
,
850
,
875
,
900
,
925
,
950
,
975
,
1000
,
1025
,
1050
,
1075
,
1100
,
1125
,
1150
,
1175
,
1200
,
1225
,
1250
,
1275
,
1300
,
1325
,
1350
,
1375
,
1400
,
1425
,
1450
,
1475
,
1500
,
1550
,
1600
,
1650
,
1700
,
1750
,
1800
,
1850
,
1900
,
1950
,
2000
,
2050
,
2100
,
2150
,
2200
,
2250
,
2300
,
2350
,
2400
,
2450
,
2500
,
2550
,
2600
,
2650
,
2700
,
2750
,
2800
,
2850
,
2900
,
3000
,
3100
,
3200
,
3300
,
};
static
const
u16
LDO1_VSEL_table
[]
=
{
1000
,
1100
,
1200
,
1250
,
1300
,
1350
,
1400
,
1500
,
1600
,
1800
,
2500
,
2750
,
2800
,
3000
,
3100
,
3300
,
};
static
const
u16
LDO2_VSEL_table
[]
=
{
725
,
750
,
775
,
800
,
825
,
850
,
875
,
900
,
925
,
950
,
975
,
1000
,
1025
,
1050
,
1075
,
1100
,
1125
,
1150
,
1175
,
1200
,
1225
,
1250
,
1275
,
1300
,
1325
,
1350
,
1375
,
1400
,
1425
,
1450
,
1475
,
1500
,
1550
,
1600
,
1650
,
1700
,
1750
,
1800
,
1850
,
1900
,
1950
,
2000
,
2050
,
2100
,
2150
,
2200
,
2250
,
2300
,
2350
,
2400
,
2450
,
2500
,
2550
,
2600
,
2650
,
2700
,
2750
,
2800
,
2850
,
2900
,
3000
,
3100
,
3200
,
3300
,
};
static
unsigned
int
num_voltages
[]
=
{
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
ARRAY_SIZE
(
LDO1_VSEL_table
),
ARRAY_SIZE
(
LDO2_VSEL_table
)};
struct
tps_info
{
const
char
*
name
;
unsigned
min_uV
;
unsigned
max_uV
;
u8
table_len
;
const
u16
*
table
;
};
struct
tps_pmic
{
struct
regulator_desc
desc
[
TPS6507X_NUM_REGULATOR
];
struct
i2c_client
*
client
;
struct
regulator_dev
*
rdev
[
TPS6507X_NUM_REGULATOR
];
const
struct
tps_info
*
info
[
TPS6507X_NUM_REGULATOR
];
struct
mutex
io_lock
;
};
static
inline
int
tps_6507x_read
(
struct
tps_pmic
*
tps
,
u8
reg
)
{
return
i2c_smbus_read_byte_data
(
tps
->
client
,
reg
);
}
static
inline
int
tps_6507x_write
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
val
)
{
return
i2c_smbus_write_byte_data
(
tps
->
client
,
reg
,
val
);
}
static
int
tps_6507x_set_bits
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
mask
)
{
int
err
,
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_6507x_read
(
tps
,
reg
);
if
(
data
<
0
)
{
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
err
=
data
;
goto
out
;
}
data
|=
mask
;
err
=
tps_6507x_write
(
tps
,
reg
,
data
);
if
(
err
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
out:
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps_6507x_clear_bits
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
mask
)
{
int
err
,
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_6507x_read
(
tps
,
reg
);
if
(
data
<
0
)
{
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
err
=
data
;
goto
out
;
}
data
&=
~
mask
;
err
=
tps_6507x_write
(
tps
,
reg
,
data
);
if
(
err
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
out:
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps_6507x_reg_read
(
struct
tps_pmic
*
tps
,
u8
reg
)
{
int
data
;
mutex_lock
(
&
tps
->
io_lock
);
data
=
tps_6507x_read
(
tps
,
reg
);
if
(
data
<
0
)
dev_err
(
&
tps
->
client
->
dev
,
"Read from reg 0x%x failed
\n
"
,
reg
);
mutex_unlock
(
&
tps
->
io_lock
);
return
data
;
}
static
int
tps_6507x_reg_write
(
struct
tps_pmic
*
tps
,
u8
reg
,
u8
val
)
{
int
err
;
mutex_lock
(
&
tps
->
io_lock
);
err
=
tps_6507x_write
(
tps
,
reg
,
val
);
if
(
err
<
0
)
dev_err
(
&
tps
->
client
->
dev
,
"Write for reg 0x%x failed
\n
"
,
reg
);
mutex_unlock
(
&
tps
->
io_lock
);
return
err
;
}
static
int
tps6507x_dcdc_is_enabled
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS6507X_DCDC_1
||
dcdc
>
TPS6507X_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
dcdc
;
data
=
tps_6507x_reg_read
(
tps
,
TPS6507X_REG_CON_CTRL1
);
if
(
data
<
0
)
return
data
;
else
return
(
data
&
1
<<
shift
)
?
1
:
0
;
}
static
int
tps6507x_ldo_is_enabled
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
ldo
;
data
=
tps_6507x_reg_read
(
tps
,
TPS6507X_REG_CON_CTRL1
);
if
(
data
<
0
)
return
data
;
else
return
(
data
&
1
<<
shift
)
?
1
:
0
;
}
static
int
tps6507x_dcdc_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS6507X_DCDC_1
||
dcdc
>
TPS6507X_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
dcdc
;
return
tps_6507x_set_bits
(
tps
,
TPS6507X_REG_CON_CTRL1
,
1
<<
shift
);
}
static
int
tps6507x_dcdc_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
dcdc
<
TPS6507X_DCDC_1
||
dcdc
>
TPS6507X_DCDC_3
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
dcdc
;
return
tps_6507x_clear_bits
(
tps
,
TPS6507X_REG_CON_CTRL1
,
1
<<
shift
);
}
static
int
tps6507x_ldo_enable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
ldo
;
return
tps_6507x_set_bits
(
tps
,
TPS6507X_REG_CON_CTRL1
,
1
<<
shift
);
}
static
int
tps6507x_ldo_disable
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
u8
shift
;
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
shift
=
TPS6507X_MAX_REG_ID
-
ldo
;
return
tps_6507x_clear_bits
(
tps
,
TPS6507X_REG_CON_CTRL1
,
1
<<
shift
);
}
static
int
tps6507x_dcdc_get_voltage
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
dcdc
=
rdev_get_id
(
dev
);
u8
reg
;
switch
(
dcdc
)
{
case
TPS6507X_DCDC_1
:
reg
=
TPS6507X_REG_DEFDCDC1
;
break
;
case
TPS6507X_DCDC_2
:
reg
=
TPS6507X_REG_DEFDCDC2_LOW
;
break
;
case
TPS6507X_DCDC_3
:
reg
=
TPS6507X_REG_DEFDCDC3_LOW
;
break
;
default:
return
-
EINVAL
;
}
data
=
tps_6507x_reg_read
(
tps
,
reg
);
if
(
data
<
0
)
return
data
;
data
&=
TPS6507X_DEFDCDCX_DCDC_MASK
;
return
tps
->
info
[
dcdc
]
->
table
[
data
]
*
1000
;
}
static
int
tps6507x_dcdc_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
vsel
,
dcdc
=
rdev_get_id
(
dev
);
u8
reg
;
switch
(
dcdc
)
{
case
TPS6507X_DCDC_1
:
reg
=
TPS6507X_REG_DEFDCDC1
;
break
;
case
TPS6507X_DCDC_2
:
reg
=
TPS6507X_REG_DEFDCDC2_LOW
;
break
;
case
TPS6507X_DCDC_3
:
reg
=
TPS6507X_REG_DEFDCDC3_LOW
;
break
;
default:
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
;
for
(
vsel
=
0
;
vsel
<
tps
->
info
[
dcdc
]
->
table_len
;
vsel
++
)
{
int
mV
=
tps
->
info
[
dcdc
]
->
table
[
vsel
];
int
uV
=
mV
*
1000
;
/* Break at the first in-range value */
if
(
min_uV
<=
uV
&&
uV
<=
max_uV
)
break
;
}
/* write to the register in case we found a match */
if
(
vsel
==
tps
->
info
[
dcdc
]
->
table_len
)
return
-
EINVAL
;
data
=
tps_6507x_reg_read
(
tps
,
reg
);
if
(
data
<
0
)
return
data
;
data
&=
~
TPS6507X_DEFDCDCX_DCDC_MASK
;
data
|=
vsel
;
return
tps_6507x_reg_write
(
tps
,
reg
,
data
);
}
static
int
tps6507x_ldo_get_voltage
(
struct
regulator_dev
*
dev
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
ldo
=
rdev_get_id
(
dev
);
u8
reg
,
mask
;
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
else
{
reg
=
(
ldo
==
TPS6507X_LDO_1
?
TPS6507X_REG_LDO_CTRL1
:
TPS6507X_REG_DEFLDO2
);
mask
=
(
ldo
==
TPS6507X_LDO_1
?
TPS6507X_REG_LDO_CTRL1_LDO1_MASK
:
TPS6507X_REG_DEFLDO2_LDO2_MASK
);
}
data
=
tps_6507x_reg_read
(
tps
,
reg
);
if
(
data
<
0
)
return
data
;
data
&=
mask
;
return
tps
->
info
[
ldo
]
->
table
[
data
]
*
1000
;
}
static
int
tps6507x_ldo_set_voltage
(
struct
regulator_dev
*
dev
,
int
min_uV
,
int
max_uV
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
data
,
vsel
,
ldo
=
rdev_get_id
(
dev
);
u8
reg
,
mask
;
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
else
{
reg
=
(
ldo
==
TPS6507X_LDO_1
?
TPS6507X_REG_LDO_CTRL1
:
TPS6507X_REG_DEFLDO2
);
mask
=
(
ldo
==
TPS6507X_LDO_1
?
TPS6507X_REG_LDO_CTRL1_LDO1_MASK
:
TPS6507X_REG_DEFLDO2_LDO2_MASK
);
}
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
;
for
(
vsel
=
0
;
vsel
<
tps
->
info
[
ldo
]
->
table_len
;
vsel
++
)
{
int
mV
=
tps
->
info
[
ldo
]
->
table
[
vsel
];
int
uV
=
mV
*
1000
;
/* Break at the first in-range value */
if
(
min_uV
<=
uV
&&
uV
<=
max_uV
)
break
;
}
if
(
vsel
==
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
data
=
tps_6507x_reg_read
(
tps
,
reg
);
if
(
data
<
0
)
return
data
;
data
&=
~
mask
;
data
|=
vsel
;
return
tps_6507x_reg_write
(
tps
,
reg
,
data
);
}
static
int
tps6507x_dcdc_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
dcdc
=
rdev_get_id
(
dev
);
if
(
dcdc
<
TPS6507X_DCDC_1
||
dcdc
>
TPS6507X_DCDC_3
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
dcdc
]
->
table_len
)
return
-
EINVAL
;
else
return
tps
->
info
[
dcdc
]
->
table
[
selector
]
*
1000
;
}
static
int
tps6507x_ldo_list_voltage
(
struct
regulator_dev
*
dev
,
unsigned
selector
)
{
struct
tps_pmic
*
tps
=
rdev_get_drvdata
(
dev
);
int
ldo
=
rdev_get_id
(
dev
);
if
(
ldo
<
TPS6507X_LDO_1
||
ldo
>
TPS6507X_LDO_2
)
return
-
EINVAL
;
if
(
selector
>=
tps
->
info
[
ldo
]
->
table_len
)
return
-
EINVAL
;
else
return
tps
->
info
[
ldo
]
->
table
[
selector
]
*
1000
;
}
/* Operations permitted on VDCDCx */
static
struct
regulator_ops
tps6507x_dcdc_ops
=
{
.
is_enabled
=
tps6507x_dcdc_is_enabled
,
.
enable
=
tps6507x_dcdc_enable
,
.
disable
=
tps6507x_dcdc_disable
,
.
get_voltage
=
tps6507x_dcdc_get_voltage
,
.
set_voltage
=
tps6507x_dcdc_set_voltage
,
.
list_voltage
=
tps6507x_dcdc_list_voltage
,
};
/* Operations permitted on LDOx */
static
struct
regulator_ops
tps6507x_ldo_ops
=
{
.
is_enabled
=
tps6507x_ldo_is_enabled
,
.
enable
=
tps6507x_ldo_enable
,
.
disable
=
tps6507x_ldo_disable
,
.
get_voltage
=
tps6507x_ldo_get_voltage
,
.
set_voltage
=
tps6507x_ldo_set_voltage
,
.
list_voltage
=
tps6507x_ldo_list_voltage
,
};
static
int
tps_6507x_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
static
int
desc_id
;
const
struct
tps_info
*
info
=
(
void
*
)
id
->
driver_data
;
struct
regulator_init_data
*
init_data
;
struct
regulator_dev
*
rdev
;
struct
tps_pmic
*
tps
;
int
i
;
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_BYTE_DATA
))
return
-
EIO
;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data
=
client
->
dev
.
platform_data
;
if
(
!
init_data
)
return
-
EIO
;
tps
=
kzalloc
(
sizeof
(
*
tps
),
GFP_KERNEL
);
if
(
!
tps
)
return
-
ENOMEM
;
mutex_init
(
&
tps
->
io_lock
);
/* common for all regulators */
tps
->
client
=
client
;
for
(
i
=
0
;
i
<
TPS6507X_NUM_REGULATOR
;
i
++
,
info
++
,
init_data
++
)
{
/* Register the regulators */
tps
->
info
[
i
]
=
info
;
tps
->
desc
[
i
].
name
=
info
->
name
;
tps
->
desc
[
i
].
id
=
desc_id
++
;
tps
->
desc
[
i
].
n_voltages
=
num_voltages
[
i
];
tps
->
desc
[
i
].
ops
=
(
i
>
TPS6507X_DCDC_3
?
&
tps6507x_ldo_ops
:
&
tps6507x_dcdc_ops
);
tps
->
desc
[
i
].
type
=
REGULATOR_VOLTAGE
;
tps
->
desc
[
i
].
owner
=
THIS_MODULE
;
rdev
=
regulator_register
(
&
tps
->
desc
[
i
],
&
client
->
dev
,
init_data
,
tps
);
if
(
IS_ERR
(
rdev
))
{
dev_err
(
&
client
->
dev
,
"failed to register %s
\n
"
,
id
->
name
);
/* Unregister */
while
(
i
)
regulator_unregister
(
tps
->
rdev
[
--
i
]);
tps
->
client
=
NULL
;
/* clear the client data in i2c */
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
tps
);
return
PTR_ERR
(
rdev
);
}
/* Save regulator for cleanup */
tps
->
rdev
[
i
]
=
rdev
;
}
i2c_set_clientdata
(
client
,
tps
);
return
0
;
}
/**
* tps_6507x_remove - TPS6507x driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister TPS driver as an i2c client device driver
*/
static
int
__devexit
tps_6507x_remove
(
struct
i2c_client
*
client
)
{
struct
tps_pmic
*
tps
=
i2c_get_clientdata
(
client
);
int
i
;
for
(
i
=
0
;
i
<
TPS6507X_NUM_REGULATOR
;
i
++
)
regulator_unregister
(
tps
->
rdev
[
i
]);
tps
->
client
=
NULL
;
/* clear the client data in i2c */
i2c_set_clientdata
(
client
,
NULL
);
kfree
(
tps
);
return
0
;
}
static
const
struct
tps_info
tps6507x_regs
[]
=
{
{
.
name
=
"VDCDC1"
,
.
min_uV
=
725000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
.
table
=
VDCDCx_VSEL_table
,
},
{
.
name
=
"VDCDC2"
,
.
min_uV
=
725000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
.
table
=
VDCDCx_VSEL_table
,
},
{
.
name
=
"VDCDC3"
,
.
min_uV
=
725000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
VDCDCx_VSEL_table
),
.
table
=
VDCDCx_VSEL_table
,
},
{
.
name
=
"LDO1"
,
.
min_uV
=
1000000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
LDO1_VSEL_table
),
.
table
=
LDO1_VSEL_table
,
},
{
.
name
=
"LDO2"
,
.
min_uV
=
725000
,
.
max_uV
=
3300000
,
.
table_len
=
ARRAY_SIZE
(
LDO2_VSEL_table
),
.
table
=
LDO2_VSEL_table
,
},
};
static
const
struct
i2c_device_id
tps_6507x_id
[]
=
{
{.
name
=
"tps6507x"
,
.
driver_data
=
(
unsigned
long
)
tps6507x_regs
,},
{
},
};
MODULE_DEVICE_TABLE
(
i2c
,
tps_6507x_id
);
static
struct
i2c_driver
tps_6507x_i2c_driver
=
{
.
driver
=
{
.
name
=
"tps6507x"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
tps_6507x_probe
,
.
remove
=
__devexit_p
(
tps_6507x_remove
),
.
id_table
=
tps_6507x_id
,
};
/**
* tps_6507x_init
*
* Module init function
*/
static
int
__init
tps_6507x_init
(
void
)
{
return
i2c_add_driver
(
&
tps_6507x_i2c_driver
);
}
subsys_initcall
(
tps_6507x_init
);
/**
* tps_6507x_cleanup
*
* Module exit function
*/
static
void
__exit
tps_6507x_cleanup
(
void
)
{
i2c_del_driver
(
&
tps_6507x_i2c_driver
);
}
module_exit
(
tps_6507x_cleanup
);
MODULE_AUTHOR
(
"Texas Instruments"
);
MODULE_DESCRIPTION
(
"TPS6507x voltage regulator driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/userspace-consumer.c
View file @
55a71bc2
...
...
@@ -93,16 +93,21 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
static
DEVICE_ATTR
(
name
,
0444
,
reg_show_name
,
NULL
);
static
DEVICE_ATTR
(
state
,
0644
,
reg_show_state
,
reg_set_state
);
static
struct
device_attribute
*
attributes
[]
=
{
&
dev_attr_name
,
&
dev_attr_state
,
static
struct
attribute
*
attributes
[]
=
{
&
dev_attr_name
.
attr
,
&
dev_attr_state
.
attr
,
NULL
,
};
static
const
struct
attribute_group
attr_group
=
{
.
attrs
=
attributes
,
};
static
int
regulator_userspace_consumer_probe
(
struct
platform_device
*
pdev
)
{
struct
regulator_userspace_consumer_data
*
pdata
;
struct
userspace_consumer_data
*
drvdata
;
int
ret
,
i
;
int
ret
;
pdata
=
pdev
->
dev
.
platform_data
;
if
(
!
pdata
)
...
...
@@ -125,31 +130,29 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
goto
err_alloc_supplies
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
attributes
);
i
++
)
{
ret
=
device_create_file
(
&
pdev
->
dev
,
attributes
[
i
]);
if
(
ret
!=
0
)
goto
err_create_attrs
;
}
ret
=
sysfs_create_group
(
&
pdev
->
dev
.
kobj
,
&
attr_group
);
if
(
ret
!=
0
)
goto
err_create_attrs
;
if
(
pdata
->
init_on
)
if
(
pdata
->
init_on
)
{
ret
=
regulator_bulk_enable
(
drvdata
->
num_supplies
,
drvdata
->
supplies
);
drvdata
->
enabled
=
pdata
->
init_on
;
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to set initial state: %d
\n
"
,
ret
);
goto
err_create_attrs
;
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to set initial state: %d
\n
"
,
ret
);
goto
err_enable
;
}
}
drvdata
->
enabled
=
pdata
->
init_on
;
platform_set_drvdata
(
pdev
,
drvdata
);
return
0
;
err_create_attrs:
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
attributes
);
i
++
)
device_remove_file
(
&
pdev
->
dev
,
attributes
[
i
]);
err_enable:
sysfs_remove_group
(
&
pdev
->
dev
.
kobj
,
&
attr_group
);
err_create_attrs:
regulator_bulk_free
(
drvdata
->
num_supplies
,
drvdata
->
supplies
);
err_alloc_supplies:
...
...
@@ -160,10 +163,8 @@ err_alloc_supplies:
static
int
regulator_userspace_consumer_remove
(
struct
platform_device
*
pdev
)
{
struct
userspace_consumer_data
*
data
=
platform_get_drvdata
(
pdev
);
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
attributes
);
i
++
)
device_remove_file
(
&
pdev
->
dev
,
attributes
[
i
]);
sysfs_remove_group
(
&
pdev
->
dev
.
kobj
,
&
attr_group
);
if
(
data
->
enabled
)
regulator_bulk_disable
(
data
->
num_supplies
,
data
->
supplies
);
...
...
drivers/regulator/virtual.c
View file @
55a71bc2
...
...
@@ -27,71 +27,81 @@ struct virtual_consumer_data {
unsigned
int
mode
;
};
static
void
update_voltage_constraints
(
struct
virtual_consumer_data
*
data
)
static
void
update_voltage_constraints
(
struct
device
*
dev
,
struct
virtual_consumer_data
*
data
)
{
int
ret
;
if
(
data
->
min_uV
&&
data
->
max_uV
&&
data
->
min_uV
<=
data
->
max_uV
)
{
dev_dbg
(
dev
,
"Requesting %d-%duV
\n
"
,
data
->
min_uV
,
data
->
max_uV
);
ret
=
regulator_set_voltage
(
data
->
regulator
,
data
->
min_uV
,
data
->
max_uV
);
data
->
min_uV
,
data
->
max_uV
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
"regulator_set_voltage() failed: %d
\n
"
,
ret
);
dev_err
(
dev
,
"regulator_set_voltage() failed: %d
\n
"
,
ret
);
return
;
}
}
if
(
data
->
min_uV
&&
data
->
max_uV
&&
!
data
->
enabled
)
{
dev_dbg
(
dev
,
"Enabling regulator
\n
"
);
ret
=
regulator_enable
(
data
->
regulator
);
if
(
ret
==
0
)
data
->
enabled
=
1
;
else
printk
(
KERN_ERR
"regulator_enable() failed: %d
\n
"
,
dev_err
(
dev
,
"regulator_enable() failed: %d
\n
"
,
ret
);
}
if
(
!
(
data
->
min_uV
&&
data
->
max_uV
)
&&
data
->
enabled
)
{
dev_dbg
(
dev
,
"Disabling regulator
\n
"
);
ret
=
regulator_disable
(
data
->
regulator
);
if
(
ret
==
0
)
data
->
enabled
=
0
;
else
printk
(
KERN_ERR
"regulator_disable() failed: %d
\n
"
,
dev_err
(
dev
,
"regulator_disable() failed: %d
\n
"
,
ret
);
}
}
static
void
update_current_limit_constraints
(
struct
virtual_consumer_data
*
data
)
static
void
update_current_limit_constraints
(
struct
device
*
dev
,
struct
virtual_consumer_data
*
data
)
{
int
ret
;
if
(
data
->
max_uA
&&
data
->
min_uA
<=
data
->
max_uA
)
{
dev_dbg
(
dev
,
"Requesting %d-%duA
\n
"
,
data
->
min_uA
,
data
->
max_uA
);
ret
=
regulator_set_current_limit
(
data
->
regulator
,
data
->
min_uA
,
data
->
max_uA
);
if
(
ret
!=
0
)
{
pr_err
(
"regulator_set_current_limit() failed: %d
\n
"
,
ret
);
dev_err
(
dev
,
"regulator_set_current_limit() failed: %d
\n
"
,
ret
);
return
;
}
}
if
(
data
->
max_uA
&&
!
data
->
enabled
)
{
dev_dbg
(
dev
,
"Enabling regulator
\n
"
);
ret
=
regulator_enable
(
data
->
regulator
);
if
(
ret
==
0
)
data
->
enabled
=
1
;
else
printk
(
KERN_ERR
"regulator_enable() failed: %d
\n
"
,
dev_err
(
dev
,
"regulator_enable() failed: %d
\n
"
,
ret
);
}
if
(
!
(
data
->
min_uA
&&
data
->
max_uA
)
&&
data
->
enabled
)
{
dev_dbg
(
dev
,
"Disabling regulator
\n
"
);
ret
=
regulator_disable
(
data
->
regulator
);
if
(
ret
==
0
)
data
->
enabled
=
0
;
else
printk
(
KERN_ERR
"regulator_disable() failed: %d
\n
"
,
dev_err
(
dev
,
"regulator_disable() failed: %d
\n
"
,
ret
);
}
}
...
...
@@ -115,7 +125,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
data
->
lock
);
data
->
min_uV
=
val
;
update_voltage_constraints
(
data
);
update_voltage_constraints
(
d
ev
,
d
ata
);
mutex_unlock
(
&
data
->
lock
);
...
...
@@ -141,7 +151,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
data
->
lock
);
data
->
max_uV
=
val
;
update_voltage_constraints
(
data
);
update_voltage_constraints
(
d
ev
,
d
ata
);
mutex_unlock
(
&
data
->
lock
);
...
...
@@ -167,7 +177,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
data
->
lock
);
data
->
min_uA
=
val
;
update_current_limit_constraints
(
data
);
update_current_limit_constraints
(
d
ev
,
d
ata
);
mutex_unlock
(
&
data
->
lock
);
...
...
@@ -193,7 +203,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
data
->
lock
);
data
->
max_uA
=
val
;
update_current_limit_constraints
(
data
);
update_current_limit_constraints
(
d
ev
,
d
ata
);
mutex_unlock
(
&
data
->
lock
);
...
...
@@ -276,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata
=
kzalloc
(
sizeof
(
struct
virtual_consumer_data
),
GFP_KERNEL
);
if
(
drvdata
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
err
;
return
-
ENOMEM
;
}
mutex_init
(
&
drvdata
->
lock
);
...
...
@@ -285,13 +294,18 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata
->
regulator
=
regulator_get
(
&
pdev
->
dev
,
reg_id
);
if
(
IS_ERR
(
drvdata
->
regulator
))
{
ret
=
PTR_ERR
(
drvdata
->
regulator
);
dev_err
(
&
pdev
->
dev
,
"Failed to obtain supply '%s': %d
\n
"
,
reg_id
,
ret
);
goto
err
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
attributes
);
i
++
)
{
ret
=
device_create_file
(
&
pdev
->
dev
,
attributes
[
i
]);
if
(
ret
!=
0
)
goto
err
;
if
(
ret
!=
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to create attr %d: %d
\n
"
,
i
,
ret
);
goto
err_regulator
;
}
}
drvdata
->
mode
=
regulator_get_mode
(
drvdata
->
regulator
);
...
...
@@ -300,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
return
0
;
err_regulator:
regulator_put
(
drvdata
->
regulator
);
err:
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
attributes
);
i
++
)
device_remove_file
(
&
pdev
->
dev
,
attributes
[
i
]);
...
...
drivers/regulator/wm8350-regulator.c
View file @
55a71bc2
...
...
@@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
{
struct
platform_device
*
pdev
;
int
ret
;
if
(
reg
<
0
||
reg
>=
NUM_WM8350_REGULATORS
)
return
-
EINVAL
;
if
(
wm8350
->
pmic
.
pdev
[
reg
])
return
-
EBUSY
;
...
...
include/linux/mfd/da903x.h
View file @
55a71bc2
#ifndef __LINUX_PMIC_DA903X_H
#define __LINUX_PMIC_DA903X_H
/* Unified sub device IDs for DA9030/DA9034 */
/* Unified sub device IDs for DA9030/DA9034
/DA9035
*/
enum
{
DA9030_ID_LED_1
,
DA9030_ID_LED_2
,
...
...
@@ -57,6 +57,8 @@ enum {
DA9034_ID_LDO13
,
DA9034_ID_LDO14
,
DA9034_ID_LDO15
,
DA9035_ID_BUCK3
,
};
/*
...
...
include/linux/regulator/consumer.h
View file @
55a71bc2
...
...
@@ -125,6 +125,8 @@ struct regulator_bulk_data {
/* regulator get and put */
struct
regulator
*
__must_check
regulator_get
(
struct
device
*
dev
,
const
char
*
id
);
struct
regulator
*
__must_check
regulator_get_exclusive
(
struct
device
*
dev
,
const
char
*
id
);
void
regulator_put
(
struct
regulator
*
regulator
);
/* regulator output control and status */
...
...
@@ -144,6 +146,8 @@ void regulator_bulk_free(int num_consumers,
int
regulator_count_voltages
(
struct
regulator
*
regulator
);
int
regulator_list_voltage
(
struct
regulator
*
regulator
,
unsigned
selector
);
int
regulator_is_supported_voltage
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
);
int
regulator_set_voltage
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
);
int
regulator_get_voltage
(
struct
regulator
*
regulator
);
int
regulator_set_current_limit
(
struct
regulator
*
regulator
,
...
...
include/linux/regulator/driver.h
View file @
55a71bc2
...
...
@@ -162,6 +162,8 @@ struct regulator_desc {
struct
regulator_dev
{
struct
regulator_desc
*
desc
;
int
use_count
;
int
open_count
;
int
exclusive
;
/* lists we belong to */
struct
list_head
list
;
/* list of all regulators */
...
...
include/linux/regulator/fixed.h
View file @
55a71bc2
...
...
@@ -5,6 +5,9 @@
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.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
...
...
@@ -16,9 +19,30 @@
struct
regulator_init_data
;
/**
* struct fixed_voltage_config - fixed_voltage_config structure
* @supply_name: Name of the regulator supply
* @microvolts: Output voltage of regulator
* @gpio: GPIO to use for enable control
* set to -EINVAL if not used
* @enable_high: Polarity of enable GPIO
* 1 = Active high, 0 = Active low
* @enabled_at_boot: Whether regulator has been enabled at
* boot or not. 1 = Yes, 0 = No
* This is used to keep the regulator at
* the default state
* @init_data: regulator_init_data
*
* This structure contains fixed voltage regulator configuration
* information that must be passed by platform code to the fixed
* voltage regulator driver.
*/
struct
fixed_voltage_config
{
const
char
*
supply_name
;
int
microvolts
;
int
gpio
;
unsigned
enable_high
:
1
;
unsigned
enabled_at_boot
:
1
;
struct
regulator_init_data
*
init_data
;
};
...
...
include/linux/regulator/machine.h
View file @
55a71bc2
...
...
@@ -126,16 +126,28 @@ struct regulation_constraints {
/**
* struct regulator_consumer_supply - supply -> device mapping
*
* This maps a supply name to a device.
* This maps a supply name to a device. Only one of dev or dev_name
* can be specified. Use of dev_name allows support for buses which
* make struct device available late such as I2C and is the preferred
* form.
*
* @dev: Device structure for the consumer.
* @dev_name: Result of dev_name() for the consumer.
* @supply: Name for the supply.
*/
struct
regulator_consumer_supply
{
struct
device
*
dev
;
/* consumer */
const
char
*
dev_name
;
/* dev_name() for consumer */
const
char
*
supply
;
/* consumer supply - e.g. "vcc" */
};
/* Initialize struct regulator_consumer_supply */
#define REGULATOR_SUPPLY(_name, _dev_name) \
{ \
.supply = _name, \
.dev_name = _dev_name, \
}
/**
* struct regulator_init_data - regulator platform initialisation data.
*
...
...
@@ -166,6 +178,12 @@ struct regulator_init_data {
int
regulator_suspend_prepare
(
suspend_state_t
state
);
#ifdef CONFIG_REGULATOR
void
regulator_has_full_constraints
(
void
);
#else
static
inline
void
regulator_has_full_constraints
(
void
)
{
}
#endif
#endif
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