Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
ae53b5db
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
ae53b5db
编写于
4月 30, 2017
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'regulator/topic/vctrl' into regulator-next
上级
81bc8e38
a9bbb453
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
603 addition
and
0 deletion
+603
-0
Documentation/devicetree/bindings/regulator/vctrl.txt
Documentation/devicetree/bindings/regulator/vctrl.txt
+49
-0
drivers/regulator/Kconfig
drivers/regulator/Kconfig
+7
-0
drivers/regulator/Makefile
drivers/regulator/Makefile
+1
-0
drivers/regulator/vctrl-regulator.c
drivers/regulator/vctrl-regulator.c
+546
-0
未找到文件。
Documentation/devicetree/bindings/regulator/vctrl.txt
0 → 100644
浏览文件 @
ae53b5db
Bindings for Voltage controlled regulators
==========================================
Required properties:
--------------------
- compatible : must be "vctrl-regulator".
- regulator-min-microvolt : smallest voltage consumers may set
- regulator-max-microvolt : largest voltage consumers may set
- ctrl-supply : The regulator supplying the control voltage.
- ctrl-voltage-range : an array of two integer values describing the range
(min/max) of the control voltage. The values specify
the control voltage needed to generate the corresponding
regulator-min/max-microvolt output voltage.
Optional properties:
--------------------
- ovp-threshold-percent : overvoltage protection (OVP) threshold of the
regulator in percent. Some regulators have an OVP
circuitry which shuts down the regulator when the
actual output voltage deviates beyond a certain
margin from the expected value for a given control
voltage. On larger voltage decreases this can occur
undesiredly since the output voltage does not adjust
inmediately to changes in the control voltage. To
avoid this situation the vctrl driver breaks down
larger voltage decreases into multiple steps, where
each step is within the OVP threshold.
- min-slew-down-rate : Describes how slowly the regulator voltage will decay
down in the worst case (lightest expected load).
Specified in uV / us (like main regulator ramp rate).
This value is required when ovp-threshold-percent is
specified.
Example:
vctrl-reg {
compatible = "vctrl-regulator";
regulator-name = "vctrl_reg";
ctrl-supply = <&ctrl_reg>;
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <1500000>;
ctrl-voltage-range = <200000 500000>;
min-slew-down-rate = <225>;
ovp-threshold-percent = <16>;
};
drivers/regulator/Kconfig
浏览文件 @
ae53b5db
...
...
@@ -877,6 +877,13 @@ config REGULATOR_TWL4030
This driver supports the voltage regulators provided by
this family of companion chips.
config REGULATOR_VCTRL
tristate "Voltage controlled regulators"
depends on OF
help
This driver provides support for voltage regulators whose output
voltage is controlled by the voltage of another regulator.
config REGULATOR_VEXPRESS
tristate "Versatile Express regulators"
depends on VEXPRESS_CONFIG
...
...
drivers/regulator/Makefile
浏览文件 @
ae53b5db
...
...
@@ -109,6 +109,7 @@ obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031)
+=
tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TPS65132)
+=
tps65132-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030)
+=
twl-regulator.o twl6030-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL)
+=
vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS)
+=
vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X)
+=
wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X)
+=
wm831x-isink.o
...
...
drivers/regulator/vctrl-regulator.c
0 → 100644
浏览文件 @
ae53b5db
/*
* Driver for voltage controller regulators
*
* Copyright (C) 2017 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/sort.h>
struct
vctrl_voltage_range
{
int
min_uV
;
int
max_uV
;
};
struct
vctrl_voltage_ranges
{
struct
vctrl_voltage_range
ctrl
;
struct
vctrl_voltage_range
out
;
};
struct
vctrl_voltage_table
{
int
ctrl
;
int
out
;
int
ovp_min_sel
;
};
struct
vctrl_data
{
struct
regulator_dev
*
rdev
;
struct
regulator_desc
desc
;
struct
regulator
*
ctrl_reg
;
bool
enabled
;
unsigned
int
min_slew_down_rate
;
unsigned
int
ovp_threshold
;
struct
vctrl_voltage_ranges
vrange
;
struct
vctrl_voltage_table
*
vtable
;
unsigned
int
sel
;
};
static
int
vctrl_calc_ctrl_voltage
(
struct
vctrl_data
*
vctrl
,
int
out_uV
)
{
struct
vctrl_voltage_range
*
ctrl
=
&
vctrl
->
vrange
.
ctrl
;
struct
vctrl_voltage_range
*
out
=
&
vctrl
->
vrange
.
out
;
return
ctrl
->
min_uV
+
DIV_ROUND_CLOSEST_ULL
((
s64
)(
out_uV
-
out
->
min_uV
)
*
(
ctrl
->
max_uV
-
ctrl
->
min_uV
),
out
->
max_uV
-
out
->
min_uV
);
}
static
int
vctrl_calc_output_voltage
(
struct
vctrl_data
*
vctrl
,
int
ctrl_uV
)
{
struct
vctrl_voltage_range
*
ctrl
=
&
vctrl
->
vrange
.
ctrl
;
struct
vctrl_voltage_range
*
out
=
&
vctrl
->
vrange
.
out
;
if
(
ctrl_uV
<
0
)
{
pr_err
(
"vctrl: failed to get control voltage
\n
"
);
return
ctrl_uV
;
}
if
(
ctrl_uV
<
ctrl
->
min_uV
)
return
out
->
min_uV
;
if
(
ctrl_uV
>
ctrl
->
max_uV
)
return
out
->
max_uV
;
return
out
->
min_uV
+
DIV_ROUND_CLOSEST_ULL
((
s64
)(
ctrl_uV
-
ctrl
->
min_uV
)
*
(
out
->
max_uV
-
out
->
min_uV
),
ctrl
->
max_uV
-
ctrl
->
min_uV
);
}
static
int
vctrl_get_voltage
(
struct
regulator_dev
*
rdev
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
int
ctrl_uV
=
regulator_get_voltage
(
vctrl
->
ctrl_reg
);
return
vctrl_calc_output_voltage
(
vctrl
,
ctrl_uV
);
}
static
int
vctrl_set_voltage
(
struct
regulator_dev
*
rdev
,
int
req_min_uV
,
int
req_max_uV
,
unsigned
int
*
selector
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
struct
regulator
*
ctrl_reg
=
vctrl
->
ctrl_reg
;
int
orig_ctrl_uV
=
regulator_get_voltage
(
ctrl_reg
);
int
uV
=
vctrl_calc_output_voltage
(
vctrl
,
orig_ctrl_uV
);
int
ret
;
if
(
req_min_uV
>=
uV
||
!
vctrl
->
ovp_threshold
)
/* voltage rising or no OVP */
return
regulator_set_voltage
(
ctrl_reg
,
vctrl_calc_ctrl_voltage
(
vctrl
,
req_min_uV
),
vctrl_calc_ctrl_voltage
(
vctrl
,
req_max_uV
));
while
(
uV
>
req_min_uV
)
{
int
max_drop_uV
=
(
uV
*
vctrl
->
ovp_threshold
)
/
100
;
int
next_uV
;
int
next_ctrl_uV
;
int
delay
;
/* Make sure no infinite loop even in crazy cases */
if
(
max_drop_uV
==
0
)
max_drop_uV
=
1
;
next_uV
=
max_t
(
int
,
req_min_uV
,
uV
-
max_drop_uV
);
next_ctrl_uV
=
vctrl_calc_ctrl_voltage
(
vctrl
,
next_uV
);
ret
=
regulator_set_voltage
(
ctrl_reg
,
next_ctrl_uV
,
next_ctrl_uV
);
if
(
ret
)
goto
err
;
delay
=
DIV_ROUND_UP
(
uV
-
next_uV
,
vctrl
->
min_slew_down_rate
);
usleep_range
(
delay
,
delay
+
DIV_ROUND_UP
(
delay
,
10
));
uV
=
next_uV
;
}
return
0
;
err:
/* Try to go back to original voltage */
regulator_set_voltage
(
ctrl_reg
,
orig_ctrl_uV
,
orig_ctrl_uV
);
return
ret
;
}
static
int
vctrl_get_voltage_sel
(
struct
regulator_dev
*
rdev
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
return
vctrl
->
sel
;
}
static
int
vctrl_set_voltage_sel
(
struct
regulator_dev
*
rdev
,
unsigned
int
selector
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
struct
regulator
*
ctrl_reg
=
vctrl
->
ctrl_reg
;
unsigned
int
orig_sel
=
vctrl
->
sel
;
int
ret
;
if
(
selector
>=
rdev
->
desc
->
n_voltages
)
return
-
EINVAL
;
if
(
selector
>=
vctrl
->
sel
||
!
vctrl
->
ovp_threshold
)
{
/* voltage rising or no OVP */
ret
=
regulator_set_voltage
(
ctrl_reg
,
vctrl
->
vtable
[
selector
].
ctrl
,
vctrl
->
vtable
[
selector
].
ctrl
);
if
(
!
ret
)
vctrl
->
sel
=
selector
;
return
ret
;
}
while
(
vctrl
->
sel
!=
selector
)
{
unsigned
int
next_sel
;
int
delay
;
if
(
selector
>=
vctrl
->
vtable
[
vctrl
->
sel
].
ovp_min_sel
)
next_sel
=
selector
;
else
next_sel
=
vctrl
->
vtable
[
vctrl
->
sel
].
ovp_min_sel
;
ret
=
regulator_set_voltage
(
ctrl_reg
,
vctrl
->
vtable
[
next_sel
].
ctrl
,
vctrl
->
vtable
[
next_sel
].
ctrl
);
if
(
ret
)
{
dev_err
(
&
rdev
->
dev
,
"failed to set control voltage to %duV
\n
"
,
vctrl
->
vtable
[
next_sel
].
ctrl
);
goto
err
;
}
vctrl
->
sel
=
next_sel
;
delay
=
DIV_ROUND_UP
(
vctrl
->
vtable
[
vctrl
->
sel
].
out
-
vctrl
->
vtable
[
next_sel
].
out
,
vctrl
->
min_slew_down_rate
);
usleep_range
(
delay
,
delay
+
DIV_ROUND_UP
(
delay
,
10
));
}
return
0
;
err:
if
(
vctrl
->
sel
!=
orig_sel
)
{
/* Try to go back to original voltage */
if
(
!
regulator_set_voltage
(
ctrl_reg
,
vctrl
->
vtable
[
orig_sel
].
ctrl
,
vctrl
->
vtable
[
orig_sel
].
ctrl
))
vctrl
->
sel
=
orig_sel
;
else
dev_warn
(
&
rdev
->
dev
,
"failed to restore original voltage
\n
"
);
}
return
ret
;
}
static
int
vctrl_list_voltage
(
struct
regulator_dev
*
rdev
,
unsigned
int
selector
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
if
(
selector
>=
rdev
->
desc
->
n_voltages
)
return
-
EINVAL
;
return
vctrl
->
vtable
[
selector
].
out
;
}
static
int
vctrl_parse_dt
(
struct
platform_device
*
pdev
,
struct
vctrl_data
*
vctrl
)
{
int
ret
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
u32
pval
;
u32
vrange_ctrl
[
2
];
vctrl
->
ctrl_reg
=
devm_regulator_get
(
&
pdev
->
dev
,
"ctrl"
);
if
(
IS_ERR
(
vctrl
->
ctrl_reg
))
return
PTR_ERR
(
vctrl
->
ctrl_reg
);
ret
=
of_property_read_u32
(
np
,
"ovp-threshold-percent"
,
&
pval
);
if
(
!
ret
)
{
vctrl
->
ovp_threshold
=
pval
;
if
(
vctrl
->
ovp_threshold
>
100
)
{
dev_err
(
&
pdev
->
dev
,
"ovp-threshold-percent (%u) > 100
\n
"
,
vctrl
->
ovp_threshold
);
return
-
EINVAL
;
}
}
ret
=
of_property_read_u32
(
np
,
"min-slew-down-rate"
,
&
pval
);
if
(
!
ret
)
{
vctrl
->
min_slew_down_rate
=
pval
;
/* We use the value as int and as divider; sanity check */
if
(
vctrl
->
min_slew_down_rate
==
0
)
{
dev_err
(
&
pdev
->
dev
,
"min-slew-down-rate must not be 0
\n
"
);
return
-
EINVAL
;
}
else
if
(
vctrl
->
min_slew_down_rate
>
INT_MAX
)
{
dev_err
(
&
pdev
->
dev
,
"min-slew-down-rate (%u) too big
\n
"
,
vctrl
->
min_slew_down_rate
);
return
-
EINVAL
;
}
}
if
(
vctrl
->
ovp_threshold
&&
!
vctrl
->
min_slew_down_rate
)
{
dev_err
(
&
pdev
->
dev
,
"ovp-threshold-percent requires min-slew-down-rate
\n
"
);
return
-
EINVAL
;
}
ret
=
of_property_read_u32
(
np
,
"regulator-min-microvolt"
,
&
pval
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to read regulator-min-microvolt: %d
\n
"
,
ret
);
return
ret
;
}
vctrl
->
vrange
.
out
.
min_uV
=
pval
;
ret
=
of_property_read_u32
(
np
,
"regulator-max-microvolt"
,
&
pval
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to read regulator-max-microvolt: %d
\n
"
,
ret
);
return
ret
;
}
vctrl
->
vrange
.
out
.
max_uV
=
pval
;
ret
=
of_property_read_u32_array
(
np
,
"ctrl-voltage-range"
,
vrange_ctrl
,
2
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to read ctrl-voltage-range: %d
\n
"
,
ret
);
return
ret
;
}
if
(
vrange_ctrl
[
0
]
>=
vrange_ctrl
[
1
])
{
dev_err
(
&
pdev
->
dev
,
"ctrl-voltage-range is invalid: %d-%d
\n
"
,
vrange_ctrl
[
0
],
vrange_ctrl
[
1
]);
return
-
EINVAL
;
}
vctrl
->
vrange
.
ctrl
.
min_uV
=
vrange_ctrl
[
0
];
vctrl
->
vrange
.
ctrl
.
max_uV
=
vrange_ctrl
[
1
];
return
0
;
}
static
int
vctrl_cmp_ctrl_uV
(
const
void
*
a
,
const
void
*
b
)
{
const
struct
vctrl_voltage_table
*
at
=
a
;
const
struct
vctrl_voltage_table
*
bt
=
b
;
return
at
->
ctrl
-
bt
->
ctrl
;
}
static
int
vctrl_init_vtable
(
struct
platform_device
*
pdev
)
{
struct
vctrl_data
*
vctrl
=
platform_get_drvdata
(
pdev
);
struct
regulator_desc
*
rdesc
=
&
vctrl
->
desc
;
struct
regulator
*
ctrl_reg
=
vctrl
->
ctrl_reg
;
struct
vctrl_voltage_range
*
vrange_ctrl
=
&
vctrl
->
vrange
.
ctrl
;
int
n_voltages
;
int
ctrl_uV
;
int
i
,
idx_vt
;
n_voltages
=
regulator_count_voltages
(
ctrl_reg
);
rdesc
->
n_voltages
=
n_voltages
;
/* determine number of steps within the range of the vctrl regulator */
for
(
i
=
0
;
i
<
n_voltages
;
i
++
)
{
ctrl_uV
=
regulator_list_voltage
(
ctrl_reg
,
i
);
if
(
ctrl_uV
<
vrange_ctrl
->
min_uV
||
ctrl_uV
>
vrange_ctrl
->
max_uV
)
{
rdesc
->
n_voltages
--
;
continue
;
}
}
if
(
rdesc
->
n_voltages
==
0
)
{
dev_err
(
&
pdev
->
dev
,
"invalid configuration
\n
"
);
return
-
EINVAL
;
}
vctrl
->
vtable
=
devm_kcalloc
(
&
pdev
->
dev
,
rdesc
->
n_voltages
,
sizeof
(
struct
vctrl_voltage_table
),
GFP_KERNEL
);
if
(
!
vctrl
->
vtable
)
return
-
ENOMEM
;
/* create mapping control <=> output voltage */
for
(
i
=
0
,
idx_vt
=
0
;
i
<
n_voltages
;
i
++
)
{
ctrl_uV
=
regulator_list_voltage
(
ctrl_reg
,
i
);
if
(
ctrl_uV
<
vrange_ctrl
->
min_uV
||
ctrl_uV
>
vrange_ctrl
->
max_uV
)
continue
;
vctrl
->
vtable
[
idx_vt
].
ctrl
=
ctrl_uV
;
vctrl
->
vtable
[
idx_vt
].
out
=
vctrl_calc_output_voltage
(
vctrl
,
ctrl_uV
);
idx_vt
++
;
}
/* we rely on the table to be ordered by ascending voltage */
sort
(
vctrl
->
vtable
,
rdesc
->
n_voltages
,
sizeof
(
struct
vctrl_voltage_table
),
vctrl_cmp_ctrl_uV
,
NULL
);
/* pre-calculate OVP-safe downward transitions */
for
(
i
=
rdesc
->
n_voltages
-
1
;
i
>
0
;
i
--
)
{
int
j
;
int
ovp_min_uV
=
(
vctrl
->
vtable
[
i
].
out
*
(
100
-
vctrl
->
ovp_threshold
))
/
100
;
for
(
j
=
0
;
j
<
i
;
j
++
)
{
if
(
vctrl
->
vtable
[
j
].
out
>=
ovp_min_uV
)
{
vctrl
->
vtable
[
i
].
ovp_min_sel
=
j
;
break
;
}
}
if
(
j
==
i
)
{
dev_warn
(
&
pdev
->
dev
,
"switching down from %duV may cause OVP shutdown
\n
"
,
vctrl
->
vtable
[
i
].
out
);
/* use next lowest voltage */
vctrl
->
vtable
[
i
].
ovp_min_sel
=
i
-
1
;
}
}
return
0
;
}
static
int
vctrl_enable
(
struct
regulator_dev
*
rdev
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
int
ret
=
regulator_enable
(
vctrl
->
ctrl_reg
);
if
(
!
ret
)
vctrl
->
enabled
=
true
;
return
ret
;
}
static
int
vctrl_disable
(
struct
regulator_dev
*
rdev
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
int
ret
=
regulator_disable
(
vctrl
->
ctrl_reg
);
if
(
!
ret
)
vctrl
->
enabled
=
false
;
return
ret
;
}
static
int
vctrl_is_enabled
(
struct
regulator_dev
*
rdev
)
{
struct
vctrl_data
*
vctrl
=
rdev_get_drvdata
(
rdev
);
return
vctrl
->
enabled
;
}
static
const
struct
regulator_ops
vctrl_ops_cont
=
{
.
enable
=
vctrl_enable
,
.
disable
=
vctrl_disable
,
.
is_enabled
=
vctrl_is_enabled
,
.
get_voltage
=
vctrl_get_voltage
,
.
set_voltage
=
vctrl_set_voltage
,
};
static
const
struct
regulator_ops
vctrl_ops_non_cont
=
{
.
enable
=
vctrl_enable
,
.
disable
=
vctrl_disable
,
.
is_enabled
=
vctrl_is_enabled
,
.
set_voltage_sel
=
vctrl_set_voltage_sel
,
.
get_voltage_sel
=
vctrl_get_voltage_sel
,
.
list_voltage
=
vctrl_list_voltage
,
.
map_voltage
=
regulator_map_voltage_iterate
,
};
static
int
vctrl_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
vctrl_data
*
vctrl
;
const
struct
regulator_init_data
*
init_data
;
struct
regulator_desc
*
rdesc
;
struct
regulator_config
cfg
=
{
};
struct
vctrl_voltage_range
*
vrange_ctrl
;
int
ctrl_uV
;
int
ret
;
vctrl
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
vctrl_data
),
GFP_KERNEL
);
if
(
!
vctrl
)
return
-
ENOMEM
;
platform_set_drvdata
(
pdev
,
vctrl
);
ret
=
vctrl_parse_dt
(
pdev
,
vctrl
);
if
(
ret
)
return
ret
;
vrange_ctrl
=
&
vctrl
->
vrange
.
ctrl
;
rdesc
=
&
vctrl
->
desc
;
rdesc
->
name
=
"vctrl"
;
rdesc
->
type
=
REGULATOR_VOLTAGE
;
rdesc
->
owner
=
THIS_MODULE
;
if
((
regulator_get_linear_step
(
vctrl
->
ctrl_reg
)
==
1
)
||
(
regulator_count_voltages
(
vctrl
->
ctrl_reg
)
==
-
EINVAL
))
{
rdesc
->
continuous_voltage_range
=
true
;
rdesc
->
ops
=
&
vctrl_ops_cont
;
}
else
{
rdesc
->
ops
=
&
vctrl_ops_non_cont
;
}
init_data
=
of_get_regulator_init_data
(
&
pdev
->
dev
,
np
,
rdesc
);
if
(
!
init_data
)
return
-
ENOMEM
;
cfg
.
of_node
=
np
;
cfg
.
dev
=
&
pdev
->
dev
;
cfg
.
driver_data
=
vctrl
;
cfg
.
init_data
=
init_data
;
if
(
!
rdesc
->
continuous_voltage_range
)
{
ret
=
vctrl_init_vtable
(
pdev
);
if
(
ret
)
return
ret
;
ctrl_uV
=
regulator_get_voltage
(
vctrl
->
ctrl_reg
);
if
(
ctrl_uV
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"failed to get control voltage
\n
"
);
return
ctrl_uV
;
}
/* determine current voltage selector from control voltage */
if
(
ctrl_uV
<
vrange_ctrl
->
min_uV
)
{
vctrl
->
sel
=
0
;
}
else
if
(
ctrl_uV
>
vrange_ctrl
->
max_uV
)
{
vctrl
->
sel
=
rdesc
->
n_voltages
-
1
;
}
else
{
int
i
;
for
(
i
=
0
;
i
<
rdesc
->
n_voltages
;
i
++
)
{
if
(
ctrl_uV
==
vctrl
->
vtable
[
i
].
ctrl
)
{
vctrl
->
sel
=
i
;
break
;
}
}
}
}
vctrl
->
rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
rdesc
,
&
cfg
);
if
(
IS_ERR
(
vctrl
->
rdev
))
{
ret
=
PTR_ERR
(
vctrl
->
rdev
);
dev_err
(
&
pdev
->
dev
,
"failed to register regulator: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
const
struct
of_device_id
vctrl_of_match
[]
=
{
{
.
compatible
=
"vctrl-regulator"
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
vctrl_of_match
);
static
struct
platform_driver
vctrl_driver
=
{
.
probe
=
vctrl_probe
,
.
driver
=
{
.
name
=
"vctrl-regulator"
,
.
of_match_table
=
of_match_ptr
(
vctrl_of_match
),
},
};
module_platform_driver
(
vctrl_driver
);
MODULE_DESCRIPTION
(
"Voltage Controlled Regulator Driver"
);
MODULE_AUTHOR
(
"Matthias Kaehlcke <mka@chromium.org>"
);
MODULE_LICENSE
(
"GPL v2"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录