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
nexedi
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