Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
82d0f8bc
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
82d0f8bc
编写于
12月 24, 2015
作者:
M
Michael Turquette
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'clk-bcm2835' into clk-next
上级
5b50c522
cfbab8fb
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
103 addition
and
55 deletion
+103
-55
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/bcm/clk-bcm2835.c
+101
-54
include/dt-bindings/clock/bcm2835.h
include/dt-bindings/clock/bcm2835.h
+2
-1
未找到文件。
drivers/clk/bcm/clk-bcm2835.c
浏览文件 @
82d0f8bc
...
...
@@ -807,6 +807,16 @@ static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
.
frac_bits
=
8
,
};
static
const
struct
bcm2835_clock_data
bcm2835_clock_pwm_data
=
{
.
name
=
"pwm"
,
.
num_mux_parents
=
ARRAY_SIZE
(
bcm2835_clock_per_parents
),
.
parents
=
bcm2835_clock_per_parents
,
.
ctl_reg
=
CM_PWMCTL
,
.
div_reg
=
CM_PWMDIV
,
.
int_bits
=
12
,
.
frac_bits
=
12
,
};
struct
bcm2835_pll
{
struct
clk_hw
hw
;
struct
bcm2835_cprman
*
cprman
;
...
...
@@ -1148,22 +1158,24 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
static
u32
bcm2835_clock_choose_div
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
unsigned
long
parent_rate
,
bool
round_up
)
{
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
const
struct
bcm2835_clock_data
*
data
=
clock
->
data
;
u32
unused_frac_mask
=
GENMASK
(
CM_DIV_FRAC_BITS
-
data
->
frac_bits
,
0
);
u32
unused_frac_mask
=
GENMASK
(
CM_DIV_FRAC_BITS
-
data
->
frac_bits
,
0
)
>>
1
;
u64
temp
=
(
u64
)
parent_rate
<<
CM_DIV_FRAC_BITS
;
u64
rem
;
u32
div
;
do_div
(
temp
,
rate
);
rem
=
do_div
(
temp
,
rate
);
div
=
temp
;
/* Round and mask off the unused bits */
if
(
unused_frac_mask
!=
0
)
{
div
+=
unused_frac_mask
>>
1
;
/* Round
up
and mask off the unused bits */
if
(
round_up
&&
((
div
&
unused_frac_mask
)
!=
0
||
rem
!=
0
))
div
+=
unused_frac_mask
+
1
;
div
&=
~
unused_frac_mask
;
}
/* Clamp to the limits. */
div
=
max
(
div
,
unused_frac_mask
+
1
);
...
...
@@ -1197,16 +1209,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
return
temp
;
}
static
long
bcm2835_clock_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
u32
div
=
bcm2835_clock_choose_div
(
hw
,
rate
,
*
parent_rate
);
return
bcm2835_clock_rate_from_divisor
(
clock
,
*
parent_rate
,
div
);
}
static
unsigned
long
bcm2835_clock_get_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
...
...
@@ -1271,20 +1273,82 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
struct
bcm2835_cprman
*
cprman
=
clock
->
cprman
;
const
struct
bcm2835_clock_data
*
data
=
clock
->
data
;
u32
div
=
bcm2835_clock_choose_div
(
hw
,
rate
,
parent_rate
);
u32
div
=
bcm2835_clock_choose_div
(
hw
,
rate
,
parent_rate
,
false
);
cprman_write
(
cprman
,
data
->
div_reg
,
div
);
return
0
;
}
static
int
bcm2835_clock_determine_rate
(
struct
clk_hw
*
hw
,
struct
clk_rate_request
*
req
)
{
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
struct
clk_hw
*
parent
,
*
best_parent
=
NULL
;
unsigned
long
rate
,
best_rate
=
0
;
unsigned
long
prate
,
best_prate
=
0
;
size_t
i
;
u32
div
;
/*
* Select parent clock that results in the closest but lower rate
*/
for
(
i
=
0
;
i
<
clk_hw_get_num_parents
(
hw
);
++
i
)
{
parent
=
clk_hw_get_parent_by_index
(
hw
,
i
);
if
(
!
parent
)
continue
;
prate
=
clk_hw_get_rate
(
parent
);
div
=
bcm2835_clock_choose_div
(
hw
,
req
->
rate
,
prate
,
true
);
rate
=
bcm2835_clock_rate_from_divisor
(
clock
,
prate
,
div
);
if
(
rate
>
best_rate
&&
rate
<=
req
->
rate
)
{
best_parent
=
parent
;
best_prate
=
prate
;
best_rate
=
rate
;
}
}
if
(
!
best_parent
)
return
-
EINVAL
;
req
->
best_parent_hw
=
best_parent
;
req
->
best_parent_rate
=
best_prate
;
req
->
rate
=
best_rate
;
return
0
;
}
static
int
bcm2835_clock_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
struct
bcm2835_cprman
*
cprman
=
clock
->
cprman
;
const
struct
bcm2835_clock_data
*
data
=
clock
->
data
;
u8
src
=
(
index
<<
CM_SRC_SHIFT
)
&
CM_SRC_MASK
;
cprman_write
(
cprman
,
data
->
ctl_reg
,
src
);
return
0
;
}
static
u8
bcm2835_clock_get_parent
(
struct
clk_hw
*
hw
)
{
struct
bcm2835_clock
*
clock
=
bcm2835_clock_from_hw
(
hw
);
struct
bcm2835_cprman
*
cprman
=
clock
->
cprman
;
const
struct
bcm2835_clock_data
*
data
=
clock
->
data
;
u32
src
=
cprman_read
(
cprman
,
data
->
ctl_reg
);
return
(
src
&
CM_SRC_MASK
)
>>
CM_SRC_SHIFT
;
}
static
const
struct
clk_ops
bcm2835_clock_clk_ops
=
{
.
is_prepared
=
bcm2835_clock_is_on
,
.
prepare
=
bcm2835_clock_on
,
.
unprepare
=
bcm2835_clock_off
,
.
recalc_rate
=
bcm2835_clock_get_rate
,
.
set_rate
=
bcm2835_clock_set_rate
,
.
round_rate
=
bcm2835_clock_round_rate
,
.
determine_rate
=
bcm2835_clock_determine_rate
,
.
set_parent
=
bcm2835_clock_set_parent
,
.
get_parent
=
bcm2835_clock_get_parent
,
};
static
int
bcm2835_vpu_clock_is_on
(
struct
clk_hw
*
hw
)
...
...
@@ -1300,7 +1364,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.
is_prepared
=
bcm2835_vpu_clock_is_on
,
.
recalc_rate
=
bcm2835_clock_get_rate
,
.
set_rate
=
bcm2835_clock_set_rate
,
.
round_rate
=
bcm2835_clock_round_rate
,
.
determine_rate
=
bcm2835_clock_determine_rate
,
.
set_parent
=
bcm2835_clock_set_parent
,
.
get_parent
=
bcm2835_clock_get_parent
,
};
static
struct
clk
*
bcm2835_register_pll
(
struct
bcm2835_cprman
*
cprman
,
...
...
@@ -1394,20 +1460,8 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
{
struct
bcm2835_clock
*
clock
;
struct
clk_init_data
init
;
const
char
*
parent
;
/*
* Most of the clock generators have a mux field, so we
* instantiate a generic mux as our parent to handle it.
*/
if
(
data
->
num_mux_parents
)
{
const
char
*
parents
[
1
<<
CM_SRC_BITS
];
int
i
;
parent
=
devm_kasprintf
(
cprman
->
dev
,
GFP_KERNEL
,
"mux_%s"
,
data
->
name
);
if
(
!
parent
)
return
NULL
;
size_t
i
;
/*
* Replace our "xosc" references with the oscillator's
...
...
@@ -1420,19 +1474,9 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
parents
[
i
]
=
data
->
parents
[
i
];
}
clk_register_mux
(
cprman
->
dev
,
parent
,
parents
,
data
->
num_mux_parents
,
CLK_SET_RATE_PARENT
,
cprman
->
regs
+
data
->
ctl_reg
,
CM_SRC_SHIFT
,
CM_SRC_BITS
,
0
,
&
cprman
->
regs_lock
);
}
else
{
parent
=
data
->
parents
[
0
];
}
memset
(
&
init
,
0
,
sizeof
(
init
));
init
.
parent_names
=
&
parent
;
init
.
num_parents
=
1
;
init
.
parent_names
=
parents
;
init
.
num_parents
=
data
->
num_mux_parents
;
init
.
name
=
data
->
name
;
init
.
flags
=
CLK_IGNORE_UNUSED
;
...
...
@@ -1550,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
cprman
->
regs
+
CM_PERIICTL
,
CM_GATE_BIT
,
0
,
&
cprman
->
regs_lock
);
clks
[
BCM2835_CLOCK_PWM
]
=
bcm2835_register_clock
(
cprman
,
&
bcm2835_clock_pwm_data
);
return
of_clk_add_provider
(
dev
->
of_node
,
of_clk_src_onecell_get
,
&
cprman
->
onecell
);
}
...
...
include/dt-bindings/clock/bcm2835.h
浏览文件 @
82d0f8bc
...
...
@@ -43,5 +43,6 @@
#define BCM2835_CLOCK_TSENS 27
#define BCM2835_CLOCK_EMMC 28
#define BCM2835_CLOCK_PERI_IMAGE 29
#define BCM2835_CLOCK_PWM 30
#define BCM2835_CLOCK_COUNT 3
0
#define BCM2835_CLOCK_COUNT 3
1
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录