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
3dc06c1b
Commit
3dc06c1b
authored
Apr 28, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regulator/topic/gpio' into v3.9-rc8
parents
5f19a85b
407945fd
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
142 additions
and
102 deletions
+142
-102
drivers/regulator/core.c
drivers/regulator/core.c
+123
-19
drivers/regulator/lp8788-ldo.c
drivers/regulator/lp8788-ldo.c
+17
-81
include/linux/regulator/driver.h
include/linux/regulator/driver.h
+2
-2
No files found.
drivers/regulator/core.c
View file @
3dc06c1b
...
...
@@ -51,6 +51,7 @@
static
DEFINE_MUTEX
(
regulator_list_mutex
);
static
LIST_HEAD
(
regulator_list
);
static
LIST_HEAD
(
regulator_map_list
);
static
LIST_HEAD
(
regulator_ena_gpio_list
);
static
bool
has_full_constraints
;
static
bool
board_wants_dummy_regulator
;
...
...
@@ -68,6 +69,19 @@ struct regulator_map {
struct
regulator_dev
*
regulator
;
};
/*
* struct regulator_enable_gpio
*
* Management for shared enable GPIO pin
*/
struct
regulator_enable_gpio
{
struct
list_head
list
;
int
gpio
;
u32
enable_count
;
/* a number of enabled shared GPIO */
u32
request_count
;
/* a number of requested shared GPIO */
unsigned
int
ena_gpio_invert
:
1
;
};
/*
* struct regulator
*
...
...
@@ -1465,6 +1479,101 @@ void devm_regulator_put(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL
(
devm_regulator_put
);
/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
static
int
regulator_ena_gpio_request
(
struct
regulator_dev
*
rdev
,
const
struct
regulator_config
*
config
)
{
struct
regulator_enable_gpio
*
pin
;
int
ret
;
list_for_each_entry
(
pin
,
&
regulator_ena_gpio_list
,
list
)
{
if
(
pin
->
gpio
==
config
->
ena_gpio
)
{
rdev_dbg
(
rdev
,
"GPIO %d is already used
\n
"
,
config
->
ena_gpio
);
goto
update_ena_gpio_to_rdev
;
}
}
ret
=
gpio_request_one
(
config
->
ena_gpio
,
GPIOF_DIR_OUT
|
config
->
ena_gpio_flags
,
rdev_get_name
(
rdev
));
if
(
ret
)
return
ret
;
pin
=
kzalloc
(
sizeof
(
struct
regulator_enable_gpio
),
GFP_KERNEL
);
if
(
pin
==
NULL
)
{
gpio_free
(
config
->
ena_gpio
);
return
-
ENOMEM
;
}
pin
->
gpio
=
config
->
ena_gpio
;
pin
->
ena_gpio_invert
=
config
->
ena_gpio_invert
;
list_add
(
&
pin
->
list
,
&
regulator_ena_gpio_list
);
update_ena_gpio_to_rdev:
pin
->
request_count
++
;
rdev
->
ena_pin
=
pin
;
return
0
;
}
static
void
regulator_ena_gpio_free
(
struct
regulator_dev
*
rdev
)
{
struct
regulator_enable_gpio
*
pin
,
*
n
;
if
(
!
rdev
->
ena_pin
)
return
;
/* Free the GPIO only in case of no use */
list_for_each_entry_safe
(
pin
,
n
,
&
regulator_ena_gpio_list
,
list
)
{
if
(
pin
->
gpio
==
rdev
->
ena_pin
->
gpio
)
{
if
(
pin
->
request_count
<=
1
)
{
pin
->
request_count
=
0
;
gpio_free
(
pin
->
gpio
);
list_del
(
&
pin
->
list
);
kfree
(
pin
);
}
else
{
pin
->
request_count
--
;
}
}
}
}
/**
* Balance enable_count of each GPIO and actual GPIO pin control.
* GPIO is enabled in case of initial use. (enable_count is 0)
* GPIO is disabled when it is not shared any more. (enable_count <= 1)
*/
static
int
regulator_ena_gpio_ctrl
(
struct
regulator_dev
*
rdev
,
bool
enable
)
{
struct
regulator_enable_gpio
*
pin
=
rdev
->
ena_pin
;
if
(
!
pin
)
return
-
EINVAL
;
if
(
enable
)
{
/* Enable GPIO at initial use */
if
(
pin
->
enable_count
==
0
)
gpio_set_value_cansleep
(
pin
->
gpio
,
!
pin
->
ena_gpio_invert
);
pin
->
enable_count
++
;
}
else
{
if
(
pin
->
enable_count
>
1
)
{
pin
->
enable_count
--
;
return
0
;
}
/* Disable GPIO if not used */
if
(
pin
->
enable_count
<=
1
)
{
gpio_set_value_cansleep
(
pin
->
gpio
,
pin
->
ena_gpio_invert
);
pin
->
enable_count
=
0
;
}
}
return
0
;
}
static
int
_regulator_do_enable
(
struct
regulator_dev
*
rdev
)
{
int
ret
,
delay
;
...
...
@@ -1480,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable
(
rdev_get_name
(
rdev
));
if
(
rdev
->
ena_gpio
)
{
gpio_set_value_cansleep
(
rdev
->
ena_gpio
,
!
rdev
->
ena_gpio_invert
);
if
(
rdev
->
ena_pin
)
{
ret
=
regulator_ena_gpio_ctrl
(
rdev
,
true
);
if
(
ret
<
0
)
return
ret
;
rdev
->
ena_gpio_state
=
1
;
}
else
if
(
rdev
->
desc
->
ops
->
enable
)
{
ret
=
rdev
->
desc
->
ops
->
enable
(
rdev
);
...
...
@@ -1584,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable
(
rdev_get_name
(
rdev
));
if
(
rdev
->
ena_gpio
)
{
gpio_set_value_cansleep
(
rdev
->
ena_gpio
,
rdev
->
ena_gpio_invert
);
if
(
rdev
->
ena_pin
)
{
ret
=
regulator_ena_gpio_ctrl
(
rdev
,
false
);
if
(
ret
<
0
)
return
ret
;
rdev
->
ena_gpio_state
=
0
;
}
else
if
(
rdev
->
desc
->
ops
->
disable
)
{
...
...
@@ -1859,7 +1970,7 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
static
int
_regulator_is_enabled
(
struct
regulator_dev
*
rdev
)
{
/* A GPIO control always takes precedence */
if
(
rdev
->
ena_
gpio
)
if
(
rdev
->
ena_
pin
)
return
rdev
->
ena_gpio_state
;
/* If we don't know then assume that the regulator is always on */
...
...
@@ -3293,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if
(
status
<
0
)
return
status
;
}
if
(
rdev
->
ena_
gpio
||
ops
->
is_enabled
)
{
if
(
rdev
->
ena_
pin
||
ops
->
is_enabled
)
{
status
=
device_create_file
(
dev
,
&
dev_attr_state
);
if
(
status
<
0
)
return
status
;
...
...
@@ -3495,22 +3606,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
dev_set_drvdata
(
&
rdev
->
dev
,
rdev
);
if
(
config
->
ena_gpio
&&
gpio_is_valid
(
config
->
ena_gpio
))
{
ret
=
gpio_request_one
(
config
->
ena_gpio
,
GPIOF_DIR_OUT
|
config
->
ena_gpio_flags
,
rdev_get_name
(
rdev
));
ret
=
regulator_ena_gpio_request
(
rdev
,
config
);
if
(
ret
!=
0
)
{
rdev_err
(
rdev
,
"Failed to request enable GPIO%d: %d
\n
"
,
config
->
ena_gpio
,
ret
);
goto
wash
;
}
rdev
->
ena_gpio
=
config
->
ena_gpio
;
rdev
->
ena_gpio_invert
=
config
->
ena_gpio_invert
;
if
(
config
->
ena_gpio_flags
&
GPIOF_OUT_INIT_HIGH
)
rdev
->
ena_gpio_state
=
1
;
if
(
rdev
->
ena_gpio_invert
)
if
(
config
->
ena_gpio_invert
)
rdev
->
ena_gpio_state
=
!
rdev
->
ena_gpio_state
;
}
...
...
@@ -3590,8 +3696,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
scrub:
if
(
rdev
->
supply
)
_regulator_put
(
rdev
->
supply
);
if
(
rdev
->
ena_gpio
)
gpio_free
(
rdev
->
ena_gpio
);
regulator_ena_gpio_free
(
rdev
);
kfree
(
rdev
->
constraints
);
wash:
device_unregister
(
&
rdev
->
dev
);
...
...
@@ -3626,8 +3731,7 @@ void regulator_unregister(struct regulator_dev *rdev)
unset_regulator_supplies
(
rdev
);
list_del
(
&
rdev
->
list
);
kfree
(
rdev
->
constraints
);
if
(
rdev
->
ena_gpio
)
gpio_free
(
rdev
->
ena_gpio
);
regulator_ena_gpio_free
(
rdev
);
device_unregister
(
&
rdev
->
dev
);
mutex_unlock
(
&
regulator_list_mutex
);
}
...
...
drivers/regulator/lp8788-ldo.c
View file @
3dc06c1b
...
...
@@ -184,40 +184,6 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
ALDO10
,
};
static
int
lp8788_ldo_enable
(
struct
regulator_dev
*
rdev
)
{
struct
lp8788_ldo
*
ldo
=
rdev_get_drvdata
(
rdev
);
if
(
ldo
->
en_pin
)
{
gpio_set_value
(
ldo
->
en_pin
->
gpio
,
ENABLE
);
return
0
;
}
else
{
return
regulator_enable_regmap
(
rdev
);
}
}
static
int
lp8788_ldo_disable
(
struct
regulator_dev
*
rdev
)
{
struct
lp8788_ldo
*
ldo
=
rdev_get_drvdata
(
rdev
);
if
(
ldo
->
en_pin
)
{
gpio_set_value
(
ldo
->
en_pin
->
gpio
,
DISABLE
);
return
0
;
}
else
{
return
regulator_disable_regmap
(
rdev
);
}
}
static
int
lp8788_ldo_is_enabled
(
struct
regulator_dev
*
rdev
)
{
struct
lp8788_ldo
*
ldo
=
rdev_get_drvdata
(
rdev
);
if
(
ldo
->
en_pin
)
return
gpio_get_value
(
ldo
->
en_pin
->
gpio
)
?
1
:
0
;
else
return
regulator_is_enabled_regmap
(
rdev
);
}
static
int
lp8788_ldo_enable_time
(
struct
regulator_dev
*
rdev
)
{
struct
lp8788_ldo
*
ldo
=
rdev_get_drvdata
(
rdev
);
...
...
@@ -253,17 +219,17 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = {
.
list_voltage
=
regulator_list_voltage_table
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
enable
=
lp8788_ldo_enable
,
.
disable
=
lp8788_ldo_disable
,
.
is_enabled
=
lp8788_ldo_is_enabled
,
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
enable_time
=
lp8788_ldo_enable_time
,
};
static
struct
regulator_ops
lp8788_ldo_voltage_fixed_ops
=
{
.
get_voltage
=
lp8788_ldo_fixed_get_voltage
,
.
enable
=
lp8788_ldo_enable
,
.
disable
=
lp8788_ldo_disable
,
.
is_enabled
=
lp8788_ldo_is_enabled
,
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
enable_time
=
lp8788_ldo_enable_time
,
};
...
...
@@ -535,43 +501,10 @@ static struct regulator_desc lp8788_aldo_desc[] = {
},
};
static
int
lp8788_gpio_request_ldo_en
(
struct
platform_device
*
pdev
,
struct
lp8788_ldo
*
ldo
,
enum
lp8788_ext_ldo_en_id
id
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
lp8788_ldo_enable_pin
*
pin
=
ldo
->
en_pin
;
int
ret
,
gpio
,
pinstate
;
char
*
name
[]
=
{
[
EN_ALDO1
]
=
"LP8788_EN_ALDO1"
,
[
EN_ALDO234
]
=
"LP8788_EN_ALDO234"
,
[
EN_ALDO5
]
=
"LP8788_EN_ALDO5"
,
[
EN_ALDO7
]
=
"LP8788_EN_ALDO7"
,
[
EN_DLDO7
]
=
"LP8788_EN_DLDO7"
,
[
EN_DLDO911
]
=
"LP8788_EN_DLDO911"
,
};
gpio
=
pin
->
gpio
;
if
(
!
gpio_is_valid
(
gpio
))
{
dev_err
(
dev
,
"invalid gpio: %d
\n
"
,
gpio
);
return
-
EINVAL
;
}
pinstate
=
pin
->
init_state
;
ret
=
devm_gpio_request_one
(
dev
,
gpio
,
pinstate
,
name
[
id
]);
if
(
ret
==
-
EBUSY
)
{
dev_warn
(
dev
,
"gpio%d already used
\n
"
,
gpio
);
return
0
;
}
return
ret
;
}
static
int
lp8788_config_ldo_enable_mode
(
struct
platform_device
*
pdev
,
struct
lp8788_ldo
*
ldo
,
enum
lp8788_ldo_id
id
)
{
int
ret
;
struct
lp8788
*
lp
=
ldo
->
lp
;
struct
lp8788_platform_data
*
pdata
=
lp
->
pdata
;
enum
lp8788_ext_ldo_en_id
enable_id
;
...
...
@@ -613,14 +546,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
goto
set_default_ldo_enable_mode
;
ldo
->
en_pin
=
pdata
->
ldo_pin
[
enable_id
];
ret
=
lp8788_gpio_request_ldo_en
(
pdev
,
ldo
,
enable_id
);
if
(
ret
)
{
ldo
->
en_pin
=
NULL
;
goto
set_default_ldo_enable_mode
;
}
return
ret
;
return
0
;
set_default_ldo_enable_mode:
return
lp8788_update_bits
(
lp
,
LP8788_EN_SEL
,
en_mask
[
enable_id
],
0
);
...
...
@@ -644,6 +570,11 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
if
(
ret
)
return
ret
;
if
(
ldo
->
en_pin
)
{
cfg
.
ena_gpio
=
ldo
->
en_pin
->
gpio
;
cfg
.
ena_gpio_flags
=
ldo
->
en_pin
->
init_state
;
}
cfg
.
dev
=
pdev
->
dev
.
parent
;
cfg
.
init_data
=
lp
->
pdata
?
lp
->
pdata
->
dldo_data
[
id
]
:
NULL
;
cfg
.
driver_data
=
ldo
;
...
...
@@ -700,6 +631,11 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
if
(
ret
)
return
ret
;
if
(
ldo
->
en_pin
)
{
cfg
.
ena_gpio
=
ldo
->
en_pin
->
gpio
;
cfg
.
ena_gpio_flags
=
ldo
->
en_pin
->
init_state
;
}
cfg
.
dev
=
pdev
->
dev
.
parent
;
cfg
.
init_data
=
lp
->
pdata
?
lp
->
pdata
->
aldo_data
[
id
]
:
NULL
;
cfg
.
driver_data
=
ldo
;
...
...
include/linux/regulator/driver.h
View file @
3dc06c1b
...
...
@@ -22,6 +22,7 @@
struct
regmap
;
struct
regulator_dev
;
struct
regulator_init_data
;
struct
regulator_enable_gpio
;
enum
regulator_status
{
REGULATOR_STATUS_OFF
,
...
...
@@ -305,8 +306,7 @@ struct regulator_dev {
struct
dentry
*
debugfs
;
int
ena_gpio
;
unsigned
int
ena_gpio_invert
:
1
;
struct
regulator_enable_gpio
*
ena_pin
;
unsigned
int
ena_gpio_state
:
1
;
};
...
...
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