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
73d80037
Commit
73d80037
authored
Jan 26, 2018
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regulator/topic/core' into regulator-next
parents
0c5b9b5d
00cb9f4f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
340 additions
and
155 deletions
+340
-155
Documentation/devicetree/bindings/regulator/regulator.txt
Documentation/devicetree/bindings/regulator/regulator.txt
+10
-2
drivers/regulator/core.c
drivers/regulator/core.c
+244
-139
drivers/regulator/internal.h
drivers/regulator/internal.h
+25
-2
drivers/regulator/of_regulator.c
drivers/regulator/of_regulator.c
+32
-2
include/linux/regulator/driver.h
include/linux/regulator/driver.h
+2
-0
include/linux/regulator/machine.h
include/linux/regulator/machine.h
+27
-10
No files found.
Documentation/devicetree/bindings/regulator/regulator.txt
View file @
73d80037
...
...
@@ -42,8 +42,16 @@ Optional properties:
- regulator-state-[mem/disk] node has following common properties:
- regulator-on-in-suspend: regulator should be on in suspend state.
- regulator-off-in-suspend: regulator should be off in suspend state.
- regulator-suspend-microvolt: regulator should be set to this voltage
in suspend.
- regulator-suspend-min-microvolt: minimum voltage may be set in
suspend state.
- regulator-suspend-max-microvolt: maximum voltage may be set in
suspend state.
- regulator-suspend-microvolt: the default voltage which regulator
would be set in suspend. This property is now deprecated, instead
setting voltage for suspend mode via the API which regulator
driver provides is recommended.
- regulator-changeable-in-suspend: whether the default voltage and
the regulator on/off in suspend can be changed in runtime.
- regulator-mode: operating mode in the given suspend state.
The set of possible operating modes depends on the capabilities of
every hardware so the valid modes are documented on each regulator
...
...
drivers/regulator/core.c
View file @
73d80037
...
...
@@ -58,8 +58,6 @@ static bool has_full_constraints;
static
struct
dentry
*
debugfs_root
;
static
struct
class
regulator_class
;
/*
* struct regulator_map
*
...
...
@@ -112,11 +110,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
const
char
*
supply_name
);
static
void
_regulator_put
(
struct
regulator
*
regulator
);
static
struct
regulator_dev
*
dev_to_rdev
(
struct
device
*
dev
)
{
return
container_of
(
dev
,
struct
regulator_dev
,
dev
);
}
static
const
char
*
rdev_get_name
(
struct
regulator_dev
*
rdev
)
{
if
(
rdev
->
constraints
&&
rdev
->
constraints
->
name
)
...
...
@@ -236,26 +229,35 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
return
0
;
}
/* return 0 if the state is valid */
static
int
regulator_check_states
(
suspend_state_t
state
)
{
return
(
state
>
PM_SUSPEND_MAX
||
state
==
PM_SUSPEND_TO_IDLE
);
}
/* Make sure we select a voltage that suits the needs of all
* regulator consumers
*/
static
int
regulator_check_consumers
(
struct
regulator_dev
*
rdev
,
int
*
min_uV
,
int
*
max_uV
)
int
*
min_uV
,
int
*
max_uV
,
suspend_state_t
state
)
{
struct
regulator
*
regulator
;
struct
regulator_voltage
*
voltage
;
list_for_each_entry
(
regulator
,
&
rdev
->
consumer_list
,
list
)
{
voltage
=
&
regulator
->
voltage
[
state
];
/*
* Assume consumers that didn't say anything are OK
* with anything in the constraint range.
*/
if
(
!
regulator
->
min_uV
&&
!
regulator
->
max_uV
)
if
(
!
voltage
->
min_uV
&&
!
voltage
->
max_uV
)
continue
;
if
(
*
max_uV
>
regulator
->
max_uV
)
*
max_uV
=
regulator
->
max_uV
;
if
(
*
min_uV
<
regulator
->
min_uV
)
*
min_uV
=
regulator
->
min_uV
;
if
(
*
max_uV
>
voltage
->
max_uV
)
*
max_uV
=
voltage
->
max_uV
;
if
(
*
min_uV
<
voltage
->
min_uV
)
*
min_uV
=
voltage
->
min_uV
;
}
if
(
*
min_uV
>
*
max_uV
)
{
...
...
@@ -324,6 +326,24 @@ static int regulator_mode_constrain(struct regulator_dev *rdev,
return
-
EINVAL
;
}
static
inline
struct
regulator_state
*
regulator_get_suspend_state
(
struct
regulator_dev
*
rdev
,
suspend_state_t
state
)
{
if
(
rdev
->
constraints
==
NULL
)
return
NULL
;
switch
(
state
)
{
case
PM_SUSPEND_STANDBY
:
return
&
rdev
->
constraints
->
state_standby
;
case
PM_SUSPEND_MEM
:
return
&
rdev
->
constraints
->
state_mem
;
case
PM_SUSPEND_MAX
:
return
&
rdev
->
constraints
->
state_disk
;
default:
return
NULL
;
}
}
static
ssize_t
regulator_uV_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
...
...
@@ -731,29 +751,32 @@ static int drms_uA_update(struct regulator_dev *rdev)
}
static
int
suspend_set_state
(
struct
regulator_dev
*
rdev
,
struct
regulator_state
*
r
state
)
suspend_state_t
state
)
{
int
ret
=
0
;
struct
regulator_state
*
rstate
;
rstate
=
regulator_get_suspend_state
(
rdev
,
state
);
if
(
rstate
==
NULL
)
return
-
EINVAL
;
/* If we have no suspend mode configration don't set anything;
* only warn if the driver implements set_suspend_voltage or
* set_suspend_mode callback.
*/
if
(
!
rstate
->
enabled
&&
!
rstate
->
disabled
)
{
if
(
rstate
->
enabled
!=
ENABLE_IN_SUSPEND
&&
rstate
->
enabled
!=
DISABLE_IN_SUSPEND
)
{
if
(
rdev
->
desc
->
ops
->
set_suspend_voltage
||
rdev
->
desc
->
ops
->
set_suspend_mode
)
rdev_warn
(
rdev
,
"No configuration
\n
"
);
return
0
;
}
if
(
rstate
->
enabled
&&
rstate
->
disabled
)
{
rdev_err
(
rdev
,
"invalid configuration
\n
"
);
return
-
EINVAL
;
}
if
(
rstate
->
enabled
&&
rdev
->
desc
->
ops
->
set_suspend_enable
)
if
(
rstate
->
enabled
==
ENABLE_IN_SUSPEND
&&
rdev
->
desc
->
ops
->
set_suspend_enable
)
ret
=
rdev
->
desc
->
ops
->
set_suspend_enable
(
rdev
);
else
if
(
rstate
->
disabled
&&
rdev
->
desc
->
ops
->
set_suspend_disable
)
else
if
(
rstate
->
enabled
==
DISABLE_IN_SUSPEND
&&
rdev
->
desc
->
ops
->
set_suspend_disable
)
ret
=
rdev
->
desc
->
ops
->
set_suspend_disable
(
rdev
);
else
/* OK if set_suspend_enable or set_suspend_disable is NULL */
ret
=
0
;
...
...
@@ -778,28 +801,8 @@ static int suspend_set_state(struct regulator_dev *rdev,
return
ret
;
}
}
return
ret
;
}
/* locks held by caller */
static
int
suspend_prepare
(
struct
regulator_dev
*
rdev
,
suspend_state_t
state
)
{
if
(
!
rdev
->
constraints
)
return
-
EINVAL
;
switch
(
state
)
{
case
PM_SUSPEND_STANDBY
:
return
suspend_set_state
(
rdev
,
&
rdev
->
constraints
->
state_standby
);
case
PM_SUSPEND_MEM
:
return
suspend_set_state
(
rdev
,
&
rdev
->
constraints
->
state_mem
);
case
PM_SUSPEND_MAX
:
return
suspend_set_state
(
rdev
,
&
rdev
->
constraints
->
state_disk
);
default:
return
-
EINVAL
;
}
return
ret
;
}
static
void
print_constraints
(
struct
regulator_dev
*
rdev
)
...
...
@@ -1068,7 +1071,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* do we need to setup our suspend state */
if
(
rdev
->
constraints
->
initial_state
)
{
ret
=
suspend_
prepar
e
(
rdev
,
rdev
->
constraints
->
initial_state
);
ret
=
suspend_
set_stat
e
(
rdev
,
rdev
->
constraints
->
initial_state
);
if
(
ret
<
0
)
{
rdev_err
(
rdev
,
"failed to set suspend state
\n
"
);
return
ret
;
...
...
@@ -1356,9 +1359,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
debugfs_create_u32
(
"uA_load"
,
0444
,
regulator
->
debugfs
,
&
regulator
->
uA_load
);
debugfs_create_u32
(
"min_uV"
,
0444
,
regulator
->
debugfs
,
&
regulator
->
min_uV
);
&
regulator
->
voltage
[
PM_SUSPEND_ON
].
min_uV
);
debugfs_create_u32
(
"max_uV"
,
0444
,
regulator
->
debugfs
,
&
regulator
->
max_uV
);
&
regulator
->
voltage
[
PM_SUSPEND_ON
].
max_uV
);
debugfs_create_file
(
"constraint_flags"
,
0444
,
regulator
->
debugfs
,
regulator
,
&
constraint_flags_fops
);
...
...
@@ -1417,20 +1420,6 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
}
}
static
int
of_node_match
(
struct
device
*
dev
,
const
void
*
data
)
{
return
dev
->
of_node
==
data
;
}
static
struct
regulator_dev
*
of_find_regulator_by_node
(
struct
device_node
*
np
)
{
struct
device
*
dev
;
dev
=
class_find_device
(
&
regulator_class
,
NULL
,
np
,
of_node_match
);
return
dev
?
dev_to_rdev
(
dev
)
:
NULL
;
}
static
int
regulator_match
(
struct
device
*
dev
,
const
void
*
data
)
{
struct
regulator_dev
*
r
=
dev_to_rdev
(
dev
);
...
...
@@ -2468,10 +2457,9 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
return
rdev
->
desc
->
ops
->
is_enabled
(
rdev
);
}
static
int
_regulator_list_voltage
(
struct
regulator
*
regulator
,
unsigned
selector
,
int
lock
)
static
int
_regulator_list_voltage
(
struct
regulator
_dev
*
rdev
,
unsigned
selector
,
int
lock
)
{
struct
regulator_dev
*
rdev
=
regulator
->
rdev
;
const
struct
regulator_ops
*
ops
=
rdev
->
desc
->
ops
;
int
ret
;
...
...
@@ -2487,7 +2475,8 @@ static int _regulator_list_voltage(struct regulator *regulator,
if
(
lock
)
mutex_unlock
(
&
rdev
->
mutex
);
}
else
if
(
rdev
->
is_switch
&&
rdev
->
supply
)
{
ret
=
_regulator_list_voltage
(
rdev
->
supply
,
selector
,
lock
);
ret
=
_regulator_list_voltage
(
rdev
->
supply
->
rdev
,
selector
,
lock
);
}
else
{
return
-
EINVAL
;
}
...
...
@@ -2563,7 +2552,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
*/
int
regulator_list_voltage
(
struct
regulator
*
regulator
,
unsigned
selector
)
{
return
_regulator_list_voltage
(
regulator
,
selector
,
1
);
return
_regulator_list_voltage
(
regulator
->
rdev
,
selector
,
1
);
}
EXPORT_SYMBOL_GPL
(
regulator_list_voltage
);
...
...
@@ -2605,8 +2594,8 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator,
if
(
ops
->
set_voltage_sel
!=
regulator_set_voltage_sel_regmap
)
return
-
EOPNOTSUPP
;
*
vsel_reg
=
rdev
->
desc
->
vsel_reg
;
*
vsel_mask
=
rdev
->
desc
->
vsel_mask
;
*
vsel_reg
=
rdev
->
desc
->
vsel_reg
;
*
vsel_mask
=
rdev
->
desc
->
vsel_mask
;
return
0
;
}
...
...
@@ -2897,10 +2886,38 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
return
ret
;
}
static
int
_regulator_do_set_suspend_voltage
(
struct
regulator_dev
*
rdev
,
int
min_uV
,
int
max_uV
,
suspend_state_t
state
)
{
struct
regulator_state
*
rstate
;
int
uV
,
sel
;
rstate
=
regulator_get_suspend_state
(
rdev
,
state
);
if
(
rstate
==
NULL
)
return
-
EINVAL
;
if
(
min_uV
<
rstate
->
min_uV
)
min_uV
=
rstate
->
min_uV
;
if
(
max_uV
>
rstate
->
max_uV
)
max_uV
=
rstate
->
max_uV
;
sel
=
regulator_map_voltage
(
rdev
,
min_uV
,
max_uV
);
if
(
sel
<
0
)
return
sel
;
uV
=
rdev
->
desc
->
ops
->
list_voltage
(
rdev
,
sel
);
if
(
uV
>=
min_uV
&&
uV
<=
max_uV
)
rstate
->
uV
=
uV
;
return
0
;
}
static
int
regulator_set_voltage_unlocked
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
)
int
min_uV
,
int
max_uV
,
suspend_state_t
state
)
{
struct
regulator_dev
*
rdev
=
regulator
->
rdev
;
struct
regulator_voltage
*
voltage
=
&
regulator
->
voltage
[
state
];
int
ret
=
0
;
int
old_min_uV
,
old_max_uV
;
int
current_uV
;
...
...
@@ -2911,7 +2928,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
* should be a noop (some cpufreq implementations use the same
* voltage for multiple frequencies, for example).
*/
if
(
regulator
->
min_uV
==
min_uV
&&
regulator
->
max_uV
==
max_uV
)
if
(
voltage
->
min_uV
==
min_uV
&&
voltage
->
max_uV
==
max_uV
)
goto
out
;
/* If we're trying to set a range that overlaps the current voltage,
...
...
@@ -2921,8 +2938,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
if
(
!
regulator_ops_is_valid
(
rdev
,
REGULATOR_CHANGE_VOLTAGE
))
{
current_uV
=
_regulator_get_voltage
(
rdev
);
if
(
min_uV
<=
current_uV
&&
current_uV
<=
max_uV
)
{
regulator
->
min_uV
=
min_uV
;
regulator
->
max_uV
=
max_uV
;
voltage
->
min_uV
=
min_uV
;
voltage
->
max_uV
=
max_uV
;
goto
out
;
}
}
...
...
@@ -2940,12 +2957,12 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
goto
out
;
/* restore original values in case of error */
old_min_uV
=
regulator
->
min_uV
;
old_max_uV
=
regulator
->
max_uV
;
regulator
->
min_uV
=
min_uV
;
regulator
->
max_uV
=
max_uV
;
old_min_uV
=
voltage
->
min_uV
;
old_max_uV
=
voltage
->
max_uV
;
voltage
->
min_uV
=
min_uV
;
voltage
->
max_uV
=
max_uV
;
ret
=
regulator_check_consumers
(
rdev
,
&
min_uV
,
&
max_uV
);
ret
=
regulator_check_consumers
(
rdev
,
&
min_uV
,
&
max_uV
,
state
);
if
(
ret
<
0
)
goto
out2
;
...
...
@@ -2963,7 +2980,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
goto
out2
;
}
best_supply_uV
=
_regulator_list_voltage
(
r
egulator
,
selector
,
0
);
best_supply_uV
=
_regulator_list_voltage
(
r
dev
,
selector
,
0
);
if
(
best_supply_uV
<
0
)
{
ret
=
best_supply_uV
;
goto
out2
;
...
...
@@ -2982,7 +2999,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
if
(
supply_change_uV
>
0
)
{
ret
=
regulator_set_voltage_unlocked
(
rdev
->
supply
,
best_supply_uV
,
INT_MAX
);
best_supply_uV
,
INT_MAX
,
state
);
if
(
ret
)
{
dev_err
(
&
rdev
->
dev
,
"Failed to increase supply voltage: %d
\n
"
,
ret
);
...
...
@@ -2990,13 +3007,17 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
}
}
ret
=
_regulator_do_set_voltage
(
rdev
,
min_uV
,
max_uV
);
if
(
state
==
PM_SUSPEND_ON
)
ret
=
_regulator_do_set_voltage
(
rdev
,
min_uV
,
max_uV
);
else
ret
=
_regulator_do_set_suspend_voltage
(
rdev
,
min_uV
,
max_uV
,
state
);
if
(
ret
<
0
)
goto
out2
;
if
(
supply_change_uV
<
0
)
{
ret
=
regulator_set_voltage_unlocked
(
rdev
->
supply
,
best_supply_uV
,
INT_MAX
);
best_supply_uV
,
INT_MAX
,
state
);
if
(
ret
)
dev_warn
(
&
rdev
->
dev
,
"Failed to decrease supply voltage: %d
\n
"
,
ret
);
...
...
@@ -3007,8 +3028,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
out:
return
ret
;
out2:
regulator
->
min_uV
=
old_min_uV
;
regulator
->
max_uV
=
old_max_uV
;
voltage
->
min_uV
=
old_min_uV
;
voltage
->
max_uV
=
old_max_uV
;
return
ret
;
}
...
...
@@ -3037,7 +3058,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
regulator_lock_supply
(
regulator
->
rdev
);
ret
=
regulator_set_voltage_unlocked
(
regulator
,
min_uV
,
max_uV
);
ret
=
regulator_set_voltage_unlocked
(
regulator
,
min_uV
,
max_uV
,
PM_SUSPEND_ON
);
regulator_unlock_supply
(
regulator
->
rdev
);
...
...
@@ -3045,6 +3067,89 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
}
EXPORT_SYMBOL_GPL
(
regulator_set_voltage
);
static
inline
int
regulator_suspend_toggle
(
struct
regulator_dev
*
rdev
,
suspend_state_t
state
,
bool
en
)
{
struct
regulator_state
*
rstate
;
rstate
=
regulator_get_suspend_state
(
rdev
,
state
);
if
(
rstate
==
NULL
)
return
-
EINVAL
;
if
(
!
rstate
->
changeable
)
return
-
EPERM
;
rstate
->
enabled
=
en
;
return
0
;
}
int
regulator_suspend_enable
(
struct
regulator_dev
*
rdev
,
suspend_state_t
state
)
{
return
regulator_suspend_toggle
(
rdev
,
state
,
true
);
}
EXPORT_SYMBOL_GPL
(
regulator_suspend_enable
);
int
regulator_suspend_disable
(
struct
regulator_dev
*
rdev
,
suspend_state_t
state
)
{
struct
regulator
*
regulator
;
struct
regulator_voltage
*
voltage
;
/*
* if any consumer wants this regulator device keeping on in
* suspend states, don't set it as disabled.
*/
list_for_each_entry
(
regulator
,
&
rdev
->
consumer_list
,
list
)
{
voltage
=
&
regulator
->
voltage
[
state
];
if
(
voltage
->
min_uV
||
voltage
->
max_uV
)
return
0
;
}
return
regulator_suspend_toggle
(
rdev
,
state
,
false
);
}
EXPORT_SYMBOL_GPL
(
regulator_suspend_disable
);
static
int
_regulator_set_suspend_voltage
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
,
suspend_state_t
state
)
{
struct
regulator_dev
*
rdev
=
regulator
->
rdev
;
struct
regulator_state
*
rstate
;
rstate
=
regulator_get_suspend_state
(
rdev
,
state
);
if
(
rstate
==
NULL
)
return
-
EINVAL
;
if
(
rstate
->
min_uV
==
rstate
->
max_uV
)
{
rdev_err
(
rdev
,
"The suspend voltage can't be changed!
\n
"
);
return
-
EPERM
;
}
return
regulator_set_voltage_unlocked
(
regulator
,
min_uV
,
max_uV
,
state
);
}
int
regulator_set_suspend_voltage
(
struct
regulator
*
regulator
,
int
min_uV
,
int
max_uV
,
suspend_state_t
state
)
{
int
ret
=
0
;
/* PM_SUSPEND_ON is handled by regulator_set_voltage() */
if
(
regulator_check_states
(
state
)
||
state
==
PM_SUSPEND_ON
)
return
-
EINVAL
;
regulator_lock_supply
(
regulator
->
rdev
);
ret
=
_regulator_set_suspend_voltage
(
regulator
,
min_uV
,
max_uV
,
state
);
regulator_unlock_supply
(
regulator
->
rdev
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regulator_set_suspend_voltage
);
/**
* regulator_set_voltage_time - get raise/fall time
* @regulator: regulator source
...
...
@@ -3138,6 +3243,7 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
int
regulator_sync_voltage
(
struct
regulator
*
regulator
)
{
struct
regulator_dev
*
rdev
=
regulator
->
rdev
;
struct
regulator_voltage
*
voltage
=
&
regulator
->
voltage
[
PM_SUSPEND_ON
];
int
ret
,
min_uV
,
max_uV
;
mutex_lock
(
&
rdev
->
mutex
);
...
...
@@ -3149,20 +3255,20 @@ int regulator_sync_voltage(struct regulator *regulator)
}
/* This is only going to work if we've had a voltage configured. */
if
(
!
regulator
->
min_uV
&&
!
regulator
->
max_uV
)
{
if
(
!
voltage
->
min_uV
&&
!
voltage
->
max_uV
)
{
ret
=
-
EINVAL
;
goto
out
;
}
min_uV
=
regulator
->
min_uV
;
max_uV
=
regulator
->
max_uV
;
min_uV
=
voltage
->
min_uV
;
max_uV
=
voltage
->
max_uV
;
/* This should be a paranoia check... */
ret
=
regulator_check_voltage
(
rdev
,
&
min_uV
,
&
max_uV
);
if
(
ret
<
0
)
goto
out
;
ret
=
regulator_check_consumers
(
rdev
,
&
min_uV
,
&
max_uV
);
ret
=
regulator_check_consumers
(
rdev
,
&
min_uV
,
&
max_uV
,
0
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -3918,12 +4024,6 @@ static void regulator_dev_release(struct device *dev)
kfree
(
rdev
);
}
static
struct
class
regulator_class
=
{
.
name
=
"regulator"
,
.
dev_release
=
regulator_dev_release
,
.
dev_groups
=
regulator_dev_groups
,
};
static
void
rdev_init_debugfs
(
struct
regulator_dev
*
rdev
)
{
struct
device
*
parent
=
rdev
->
dev
.
parent
;
...
...
@@ -4174,81 +4274,86 @@ void regulator_unregister(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL
(
regulator_unregister
);
static
int
_regulator_suspend_prepare
(
struct
device
*
dev
,
void
*
data
)
#ifdef CONFIG_SUSPEND
static
int
_regulator_suspend_late
(
struct
device
*
dev
,
void
*
data
)
{
struct
regulator_dev
*
rdev
=
dev_to_rdev
(
dev
);
const
suspend_state_t
*
state
=
data
;
suspend_state_t
*
state
=
data
;
int
ret
;
mutex_lock
(
&
rdev
->
mutex
);
ret
=
suspend_
prepar
e
(
rdev
,
*
state
);
ret
=
suspend_
set_stat
e
(
rdev
,
*
state
);
mutex_unlock
(
&
rdev
->
mutex
);
return
ret
;
}
/**
* regulator_suspend_
prepar
e - prepare regulators for system wide suspend
* regulator_suspend_
lat
e - prepare regulators for system wide suspend
* @state: system suspend state
*
* Configure each regulator with it's suspend operating parameters for state.
* This will usually be called by machine suspend code prior to supending.
*/
int
regulator_suspend_prepare
(
suspend_state_t
state
)
static
int
regulator_suspend_late
(
struct
device
*
dev
)
{
/* ON is handled by regulator active state */
if
(
state
==
PM_SUSPEND_ON
)
return
-
EINVAL
;
suspend_state_t
state
=
pm_suspend_target_state
;
return
class_for_each_device
(
&
regulator_class
,
NULL
,
&
state
,
_regulator_suspend_
prepar
e
);
_regulator_suspend_
lat
e
);
}
EXPORT_SYMBOL_GPL
(
regulator_suspend_prepare
);
static
int
_regulator_suspend_finish
(
struct
device
*
dev
,
void
*
data
)
static
int
_regulator_resume_early
(
struct
device
*
dev
,
void
*
data
)
{
int
ret
=
0
;
struct
regulator_dev
*
rdev
=
dev_to_rdev
(
dev
);
int
ret
;
suspend_state_t
*
state
=
data
;
struct
regulator_state
*
rstate
;
rstate
=
regulator_get_suspend_state
(
rdev
,
*
state
);
if
(
rstate
==
NULL
)
return
-
EINVAL
;
mutex_lock
(
&
rdev
->
mutex
);
if
(
rdev
->
use_count
>
0
||
rdev
->
constraints
->
always_on
)
{
if
(
!
_regulator_is_enabled
(
rdev
))
{
ret
=
_regulator_do_enable
(
rdev
);
if
(
ret
)
dev_err
(
dev
,
"Failed to resume regulator %d
\n
"
,
ret
);
}
}
else
{
if
(
!
have_full_constraints
())
goto
unlock
;
if
(
!
_regulator_is_enabled
(
rdev
))
goto
unlock
;
ret
=
_regulator_do_disable
(
rdev
);
if
(
ret
)
dev_err
(
dev
,
"Failed to suspend regulator %d
\n
"
,
ret
);
}
unlock:
if
(
rdev
->
desc
->
ops
->
resume_early
&&
(
rstate
->
enabled
==
ENABLE_IN_SUSPEND
||
rstate
->
enabled
==
DISABLE_IN_SUSPEND
))
ret
=
rdev
->
desc
->
ops
->
resume_early
(
rdev
);
mutex_unlock
(
&
rdev
->
mutex
);
/* Keep processing regulators in spite of any errors */
return
0
;
return
ret
;
}
/**
* regulator_suspend_finish - resume regulators from system wide suspend
*
* Turn on regulators that might be turned off by regulator_suspend_prepare
* and that should be turned on according to the regulators properties.
*/
int
regulator_suspend_finish
(
void
)
static
int
regulator_resume_early
(
struct
device
*
dev
)
{
return
class_for_each_device
(
&
regulator_class
,
NULL
,
NULL
,
_regulator_suspend_finish
);
suspend_state_t
state
=
pm_suspend_target_state
;
return
class_for_each_device
(
&
regulator_class
,
NULL
,
&
state
,
_regulator_resume_early
);
}
EXPORT_SYMBOL_GPL
(
regulator_suspend_finish
);
#else
/* !CONFIG_SUSPEND */
#define regulator_suspend_late NULL
#define regulator_resume_early NULL
#endif
/* !CONFIG_SUSPEND */
#ifdef CONFIG_PM
static
const
struct
dev_pm_ops
__maybe_unused
regulator_pm_ops
=
{
.
suspend_late
=
regulator_suspend_late
,
.
resume_early
=
regulator_resume_early
,
};
#endif
struct
class
regulator_class
=
{
.
name
=
"regulator"
,
.
dev_release
=
regulator_dev_release
,
.
dev_groups
=
regulator_dev_groups
,
#ifdef CONFIG_PM
.
pm
=
&
regulator_pm_ops
,
#endif
};
/**
* regulator_has_full_constraints - the system has fully specified constraints
*
...
...
@@ -4424,8 +4529,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
switch
(
rdev
->
desc
->
type
)
{
case
REGULATOR_VOLTAGE
:
seq_printf
(
s
,
"%37dmV %5dmV"
,
consumer
->
min_uV
/
1000
,
consumer
->
max_uV
/
1000
);
consumer
->
voltage
[
PM_SUSPEND_ON
].
min_uV
/
1000
,
consumer
->
voltage
[
PM_SUSPEND_ON
].
max_uV
/
1000
);
break
;
case
REGULATOR_CURRENT
:
break
;
...
...
drivers/regulator/internal.h
View file @
73d80037
...
...
@@ -16,10 +16,25 @@
#ifndef __REGULATOR_INTERNAL_H
#define __REGULATOR_INTERNAL_H
#include <linux/suspend.h>
#define REGULATOR_STATES_NUM (PM_SUSPEND_MAX + 1)
struct
regulator_voltage
{
int
min_uV
;
int
max_uV
;
};
/*
* struct regulator
*
* One for each consumer device.
* @voltage - a voltage array for each state of runtime, i.e.:
* PM_SUSPEND_ON
* PM_SUSPEND_TO_IDLE
* PM_SUSPEND_STANDBY
* PM_SUSPEND_MEM
* PM_SUSPEND_MAX
*/
struct
regulator
{
struct
device
*
dev
;
...
...
@@ -27,14 +42,22 @@ struct regulator {
unsigned
int
always_on
:
1
;
unsigned
int
bypass
:
1
;
int
uA_load
;
int
min_uV
;
int
max_uV
;
struct
regulator_voltage
voltage
[
REGULATOR_STATES_NUM
];
const
char
*
supply_name
;
struct
device_attribute
dev_attr
;
struct
regulator_dev
*
rdev
;
struct
dentry
*
debugfs
;
};
extern
struct
class
regulator_class
;
static
inline
struct
regulator_dev
*
dev_to_rdev
(
struct
device
*
dev
)
{
return
container_of
(
dev
,
struct
regulator_dev
,
dev
);
}
struct
regulator_dev
*
of_find_regulator_by_node
(
struct
device_node
*
np
);
#ifdef CONFIG_OF
struct
regulator_init_data
*
regulator_of_get_init_data
(
struct
device
*
dev
,
const
struct
regulator_desc
*
desc
,
...
...
drivers/regulator/of_regulator.c
View file @
73d80037
...
...
@@ -177,14 +177,30 @@ static void of_get_regulation_constraints(struct device_node *np,
if
(
of_property_read_bool
(
suspend_np
,
"regulator-on-in-suspend"
))
suspend_state
->
enabled
=
true
;
suspend_state
->
enabled
=
ENABLE_IN_SUSPEND
;
else
if
(
of_property_read_bool
(
suspend_np
,
"regulator-off-in-suspend"
))
suspend_state
->
disabled
=
true
;
suspend_state
->
enabled
=
DISABLE_IN_SUSPEND
;
else
suspend_state
->
enabled
=
DO_NOTHING_IN_SUSPEND
;
if
(
!
of_property_read_u32
(
np
,
"regulator-suspend-min-microvolt"
,
&
pval
))
suspend_state
->
min_uV
=
pval
;
if
(
!
of_property_read_u32
(
np
,
"regulator-suspend-max-microvolt"
,
&
pval
))
suspend_state
->
max_uV
=
pval
;
if
(
!
of_property_read_u32
(
suspend_np
,
"regulator-suspend-microvolt"
,
&
pval
))
suspend_state
->
uV
=
pval
;
else
/* otherwise use min_uV as default suspend voltage */
suspend_state
->
uV
=
suspend_state
->
min_uV
;
if
(
of_property_read_bool
(
suspend_np
,
"regulator-changeable-in-suspend"
))
suspend_state
->
changeable
=
true
;
if
(
i
==
PM_SUSPEND_MEM
)
constraints
->
initial_state
=
PM_SUSPEND_MEM
;
...
...
@@ -376,3 +392,17 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
return
init_data
;
}
static
int
of_node_match
(
struct
device
*
dev
,
const
void
*
data
)
{
return
dev
->
of_node
==
data
;
}
struct
regulator_dev
*
of_find_regulator_by_node
(
struct
device_node
*
np
)
{
struct
device
*
dev
;
dev
=
class_find_device
(
&
regulator_class
,
NULL
,
np
,
of_node_match
);
return
dev
?
dev_to_rdev
(
dev
)
:
NULL
;
}
include/linux/regulator/driver.h
View file @
73d80037
...
...
@@ -214,6 +214,8 @@ struct regulator_ops {
/* set regulator suspend operating mode (defined in consumer.h) */
int
(
*
set_suspend_mode
)
(
struct
regulator_dev
*
,
unsigned
int
mode
);
int
(
*
resume_early
)(
struct
regulator_dev
*
rdev
);
int
(
*
set_pull_down
)
(
struct
regulator_dev
*
);
};
...
...
include/linux/regulator/machine.h
View file @
73d80037
...
...
@@ -42,6 +42,16 @@ struct regulator;
#define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/*
* operations in suspend mode
* DO_NOTHING_IN_SUSPEND - the default value
* DISABLE_IN_SUSPEND - turn off regulator in suspend states
* ENABLE_IN_SUSPEND - keep regulator on in suspend states
*/
#define DO_NOTHING_IN_SUSPEND (-1)
#define DISABLE_IN_SUSPEND 0
#define ENABLE_IN_SUSPEND 1
/* Regulator active discharge flags */
enum
regulator_active_discharge
{
REGULATOR_ACTIVE_DISCHARGE_DEFAULT
,
...
...
@@ -56,16 +66,24 @@ enum regulator_active_discharge {
* state. One of enabled or disabled must be set for the
* configuration to be applied.
*
* @uV: Operating voltage during suspend.
* @uV: Default operating voltage during suspend, it can be adjusted
* among <min_uV, max_uV>.
* @min_uV: Minimum suspend voltage may be set.
* @max_uV: Maximum suspend voltage may be set.
* @mode: Operating mode during suspend.
* @enabled: Enabled during suspend.
* @disabled: Disabled during suspend.
* @enabled: operations during suspend.
* - DO_NOTHING_IN_SUSPEND
* - DISABLE_IN_SUSPEND
* - ENABLE_IN_SUSPEND
* @changeable: Is this state can be switched between enabled/disabled,
*/
struct
regulator_state
{
int
uV
;
/* suspend voltage */
unsigned
int
mode
;
/* suspend regulator operating mode */
int
enabled
;
/* is regulator enabled in this suspend state */
int
disabled
;
/* is the regulator disabled in this suspend state */
int
uV
;
int
min_uV
;
int
max_uV
;
unsigned
int
mode
;
int
enabled
;
bool
changeable
;
};
/**
...
...
@@ -225,12 +243,12 @@ struct regulator_init_data {
#ifdef CONFIG_REGULATOR
void
regulator_has_full_constraints
(
void
);
int
regulator_suspend_prepare
(
suspend_state_t
state
);
int
regulator_suspend_finish
(
void
);
#else
static
inline
void
regulator_has_full_constraints
(
void
)
{
}
#endif
static
inline
int
regulator_suspend_prepare
(
suspend_state_t
state
)
{
return
0
;
...
...
@@ -239,6 +257,5 @@ static inline int regulator_suspend_finish(void)
{
return
0
;
}
#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