Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
5ec8c48a
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看板
提交
5ec8c48a
编写于
7月 06, 2017
作者:
T
Thierry Reding
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-4.13/drivers' into for-next
上级
72f2ebbd
e47866a1
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
208 addition
and
131 deletion
+208
-131
drivers/pwm/pwm-bfin.c
drivers/pwm/pwm-bfin.c
+1
-3
drivers/pwm/pwm-cros-ec.c
drivers/pwm/pwm-cros-ec.c
+2
-2
drivers/pwm/pwm-hibvt.c
drivers/pwm/pwm-hibvt.c
+1
-1
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-meson.c
+39
-9
drivers/pwm/pwm-sun4i.c
drivers/pwm/pwm-sun4i.c
+148
-115
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tegra.c
+17
-1
未找到文件。
drivers/pwm/pwm-bfin.c
浏览文件 @
5ec8c48a
...
...
@@ -118,10 +118,8 @@ static int bfin_pwm_probe(struct platform_device *pdev)
int
ret
;
pwm
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pwm
),
GFP_KERNEL
);
if
(
!
pwm
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate memory
\n
"
);
if
(
!
pwm
)
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
pwm
);
...
...
drivers/pwm/pwm-cros-ec.c
浏览文件 @
5ec8c48a
...
...
@@ -75,8 +75,8 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index,
msg
->
version
=
0
;
msg
->
command
=
EC_CMD_PWM_GET_DUTY
;
msg
->
insize
=
sizeof
(
*
params
);
msg
->
outsize
=
sizeof
(
*
resp
);
msg
->
insize
=
sizeof
(
*
resp
);
msg
->
outsize
=
sizeof
(
*
params
);
params
->
pwm_type
=
EC_PWM_TYPE_GENERIC
;
params
->
index
=
index
;
...
...
drivers/pwm/pwm-hibvt.c
浏览文件 @
5ec8c48a
...
...
@@ -165,7 +165,7 @@ static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return
0
;
}
static
struct
pwm_ops
hibvt_pwm_ops
=
{
static
const
struct
pwm_ops
hibvt_pwm_ops
=
{
.
get_state
=
hibvt_pwm_get_state
,
.
apply
=
hibvt_pwm_apply
,
...
...
drivers/pwm/pwm-meson.c
浏览文件 @
5ec8c48a
...
...
@@ -103,6 +103,7 @@ struct meson_pwm_channel {
struct
meson_pwm_data
{
const
char
*
const
*
parent_names
;
unsigned
int
num_parents
;
};
struct
meson_pwm
{
...
...
@@ -162,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
unsigned
int
duty
,
unsigned
int
period
)
{
unsigned
int
pre_div
,
cnt
,
duty_cnt
;
unsigned
long
fin_freq
=
-
1
,
fin_ns
;
unsigned
long
fin_freq
=
-
1
;
u64
fin_ps
;
if
(
~
(
meson
->
inverter_mask
>>
id
)
&
0x1
)
duty
=
period
-
duty
;
...
...
@@ -178,13 +180,15 @@ static int meson_pwm_calc(struct meson_pwm *meson,
}
dev_dbg
(
meson
->
chip
.
dev
,
"fin_freq: %lu Hz
\n
"
,
fin_freq
);
fin_ns
=
NSEC_PER_SEC
/
fin_freq
;
fin_ps
=
(
u64
)
NSEC_PER_SEC
*
1000
;
do_div
(
fin_ps
,
fin_freq
);
/* Calc pre_div with the period */
for
(
pre_div
=
0
;
pre_div
<
MISC_CLK_DIV_MASK
;
pre_div
++
)
{
cnt
=
DIV_ROUND_CLOSEST
(
period
,
fin_ns
*
(
pre_div
+
1
));
dev_dbg
(
meson
->
chip
.
dev
,
"fin_ns=%lu pre_div=%u cnt=%u
\n
"
,
fin_ns
,
pre_div
,
cnt
);
cnt
=
DIV_ROUND_CLOSEST_ULL
((
u64
)
period
*
1000
,
fin_ps
*
(
pre_div
+
1
));
dev_dbg
(
meson
->
chip
.
dev
,
"fin_ps=%llu pre_div=%u cnt=%u
\n
"
,
fin_ps
,
pre_div
,
cnt
);
if
(
cnt
<=
0xffff
)
break
;
}
...
...
@@ -207,7 +211,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
channel
->
lo
=
cnt
;
}
else
{
/* Then check is we can have the duty with the same pre_div */
duty_cnt
=
DIV_ROUND_CLOSEST
(
duty
,
fin_ns
*
(
pre_div
+
1
));
duty_cnt
=
DIV_ROUND_CLOSEST_ULL
((
u64
)
duty
*
1000
,
fin_ps
*
(
pre_div
+
1
));
if
(
duty_cnt
>
0xffff
)
{
dev_err
(
meson
->
chip
.
dev
,
"unable to get duty cycle
\n
"
);
return
-
EINVAL
;
...
...
@@ -381,6 +386,7 @@ static const char * const pwm_meson8b_parent_names[] = {
static
const
struct
meson_pwm_data
pwm_meson8b_data
=
{
.
parent_names
=
pwm_meson8b_parent_names
,
.
num_parents
=
ARRAY_SIZE
(
pwm_meson8b_parent_names
),
};
static
const
char
*
const
pwm_gxbb_parent_names
[]
=
{
...
...
@@ -389,11 +395,35 @@ static const char * const pwm_gxbb_parent_names[] = {
static
const
struct
meson_pwm_data
pwm_gxbb_data
=
{
.
parent_names
=
pwm_gxbb_parent_names
,
.
num_parents
=
ARRAY_SIZE
(
pwm_gxbb_parent_names
),
};
/*
* Only the 2 first inputs of the GXBB AO PWMs are valid
* The last 2 are grounded
*/
static
const
char
*
const
pwm_gxbb_ao_parent_names
[]
=
{
"xtal"
,
"clk81"
};
static
const
struct
meson_pwm_data
pwm_gxbb_ao_data
=
{
.
parent_names
=
pwm_gxbb_ao_parent_names
,
.
num_parents
=
ARRAY_SIZE
(
pwm_gxbb_ao_parent_names
),
};
static
const
struct
of_device_id
meson_pwm_matches
[]
=
{
{
.
compatible
=
"amlogic,meson8b-pwm"
,
.
data
=
&
pwm_meson8b_data
},
{
.
compatible
=
"amlogic,meson-gxbb-pwm"
,
.
data
=
&
pwm_gxbb_data
},
{
.
compatible
=
"amlogic,meson8b-pwm"
,
.
data
=
&
pwm_meson8b_data
},
{
.
compatible
=
"amlogic,meson-gxbb-pwm"
,
.
data
=
&
pwm_gxbb_data
},
{
.
compatible
=
"amlogic,meson-gxbb-ao-pwm"
,
.
data
=
&
pwm_gxbb_ao_data
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
meson_pwm_matches
);
...
...
@@ -417,7 +447,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
init
.
ops
=
&
clk_mux_ops
;
init
.
flags
=
CLK_IS_BASIC
;
init
.
parent_names
=
meson
->
data
->
parent_names
;
init
.
num_parents
=
1
<<
MISC_CLK_SEL_WIDTH
;
init
.
num_parents
=
meson
->
data
->
num_parents
;
channel
->
mux
.
reg
=
meson
->
base
+
REG_MISC_AB
;
channel
->
mux
.
shift
=
mux_reg_shifts
[
i
];
...
...
drivers/pwm/pwm-sun4i.c
浏览文件 @
5ec8c48a
...
...
@@ -8,8 +8,10 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
...
...
@@ -44,6 +46,10 @@
#define PWM_DTY_MASK GENMASK(15, 0)
#define PWM_REG_PRD(reg) ((((reg) >> 16) & PWM_PRD_MASK) + 1)
#define PWM_REG_DTY(reg) ((reg) & PWM_DTY_MASK)
#define PWM_REG_PRESCAL(reg, chan) (((reg) >> ((chan) * PWMCH_OFFSET)) & PWM_PRESCAL_MASK)
#define BIT_CH(bit, chan) ((bit) << ((chan) * PWMCH_OFFSET))
static
const
u32
prescaler_table
[]
=
{
...
...
@@ -77,6 +83,8 @@ struct sun4i_pwm_chip {
void
__iomem
*
base
;
spinlock_t
ctrl_lock
;
const
struct
sun4i_pwm_data
*
data
;
unsigned
long
next_period
[
2
];
bool
needs_delay
[
2
];
};
static
inline
struct
sun4i_pwm_chip
*
to_sun4i_pwm_chip
(
struct
pwm_chip
*
chip
)
...
...
@@ -96,26 +104,65 @@ static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
writel
(
val
,
chip
->
base
+
offset
);
}
static
int
sun4i_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
static
void
sun4i_pwm_get_state
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
sun4i_pwm_chip
*
sun4i_pwm
=
to_sun4i_pwm_chip
(
chip
);
u32
prd
,
dty
,
val
,
clk_gate
;
u64
clk_rate
,
tmp
;
u32
val
;
unsigned
int
prescaler
;
clk_rate
=
clk_get_rate
(
sun4i_pwm
->
clk
);
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
if
((
val
==
PWM_PRESCAL_MASK
)
&&
sun4i_pwm
->
data
->
has_prescaler_bypass
)
prescaler
=
1
;
else
prescaler
=
prescaler_table
[
PWM_REG_PRESCAL
(
val
,
pwm
->
hwpwm
)];
if
(
prescaler
==
0
)
return
;
if
(
val
&
BIT_CH
(
PWM_ACT_STATE
,
pwm
->
hwpwm
))
state
->
polarity
=
PWM_POLARITY_NORMAL
;
else
state
->
polarity
=
PWM_POLARITY_INVERSED
;
if
(
val
&
BIT_CH
(
PWM_CLK_GATING
|
PWM_EN
,
pwm
->
hwpwm
))
state
->
enabled
=
true
;
else
state
->
enabled
=
false
;
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CH_PRD
(
pwm
->
hwpwm
));
tmp
=
prescaler
*
NSEC_PER_SEC
*
PWM_REG_DTY
(
val
);
state
->
duty_cycle
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
clk_rate
);
tmp
=
prescaler
*
NSEC_PER_SEC
*
PWM_REG_PRD
(
val
);
state
->
period
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
clk_rate
);
}
static
int
sun4i_pwm_calculate
(
struct
sun4i_pwm_chip
*
sun4i_pwm
,
struct
pwm_state
*
state
,
u32
*
dty
,
u32
*
prd
,
unsigned
int
*
prsclr
)
{
u64
clk_rate
,
div
=
0
;
unsigned
int
prescaler
=
0
;
int
err
;
unsigned
int
pval
,
prescaler
=
0
;
clk_rate
=
clk_get_rate
(
sun4i_pwm
->
clk
);
if
(
sun4i_pwm
->
data
->
has_prescaler_bypass
)
{
/* First, test without any prescaler when available */
prescaler
=
PWM_PRESCAL_MASK
;
pval
=
1
;
/*
* When not using any prescaler, the clock period in nanoseconds
* is not an integer so round it half up instead of
* truncating to get less surprising values.
*/
div
=
clk_rate
*
period_ns
+
NSEC_PER_SEC
/
2
;
div
=
clk_rate
*
state
->
period
+
NSEC_PER_SEC
/
2
;
do_div
(
div
,
NSEC_PER_SEC
);
if
(
div
-
1
>
PWM_PRD_MASK
)
prescaler
=
0
;
...
...
@@ -126,137 +173,141 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
for
(
prescaler
=
0
;
prescaler
<
PWM_PRESCAL_MASK
;
prescaler
++
)
{
if
(
!
prescaler_table
[
prescaler
])
continue
;
pval
=
prescaler_table
[
prescaler
];
div
=
clk_rate
;
do_div
(
div
,
p
rescaler_table
[
prescaler
]
);
div
=
div
*
period_ns
;
do_div
(
div
,
p
val
);
div
=
div
*
state
->
period
;
do_div
(
div
,
NSEC_PER_SEC
);
if
(
div
-
1
<=
PWM_PRD_MASK
)
break
;
}
if
(
div
-
1
>
PWM_PRD_MASK
)
{
dev_err
(
chip
->
dev
,
"period exceeds the maximum value
\n
"
);
if
(
div
-
1
>
PWM_PRD_MASK
)
return
-
EINVAL
;
}
}
prd
=
div
;
div
*=
duty_ns
;
do_div
(
div
,
period_ns
);
dty
=
div
;
err
=
clk_prepare_enable
(
sun4i_pwm
->
clk
);
if
(
err
)
{
dev_err
(
chip
->
dev
,
"failed to enable PWM clock
\n
"
);
return
err
;
}
spin_lock
(
&
sun4i_pwm
->
ctrl_lock
);
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
if
(
sun4i_pwm
->
data
->
has_rdy
&&
(
val
&
PWM_RDY
(
pwm
->
hwpwm
)))
{
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
);
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
return
-
EBUSY
;
}
clk_gate
=
val
&
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
if
(
clk_gate
)
{
val
&=
~
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CTRL_REG
);
}
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
val
&=
~
BIT_CH
(
PWM_PRESCAL_MASK
,
pwm
->
hwpwm
);
val
|=
BIT_CH
(
prescaler
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CTRL_REG
);
val
=
(
dty
&
PWM_DTY_MASK
)
|
PWM_PRD
(
prd
);
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CH_PRD
(
pwm
->
hwpwm
));
*
prd
=
div
;
div
*=
state
->
duty_cycle
;
do_div
(
div
,
state
->
period
);
*
dty
=
div
;
*
prsclr
=
prescaler
;
if
(
clk_gate
)
{
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
val
|=
clk_gate
;
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CTRL_REG
);
}
div
=
(
u64
)
pval
*
NSEC_PER_SEC
*
*
prd
;
state
->
period
=
DIV_ROUND_CLOSEST_ULL
(
div
,
clk_rate
);
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
)
;
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
div
=
(
u64
)
pval
*
NSEC_PER_SEC
*
*
dty
;
state
->
duty_cycle
=
DIV_ROUND_CLOSEST_ULL
(
div
,
clk_rate
);
return
0
;
}
static
int
sun4i_pwm_
set_polarit
y
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
enum
pwm_polarity
polarity
)
static
int
sun4i_pwm_
appl
y
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
sun4i_pwm_chip
*
sun4i_pwm
=
to_sun4i_pwm_chip
(
chip
);
u32
val
;
struct
pwm_state
cstate
;
u32
ctrl
;
int
ret
;
unsigned
int
delay_us
;
unsigned
long
now
;
ret
=
clk_prepare_enable
(
sun4i_pwm
->
clk
);
if
(
ret
)
{
dev_err
(
chip
->
dev
,
"failed to enable PWM clock
\n
"
);
return
ret
;
pwm_get_state
(
pwm
,
&
cstate
);
if
(
!
cstate
.
enabled
)
{
ret
=
clk_prepare_enable
(
sun4i_pwm
->
clk
);
if
(
ret
)
{
dev_err
(
chip
->
dev
,
"failed to enable PWM clock
\n
"
);
return
ret
;
}
}
spin_lock
(
&
sun4i_pwm
->
ctrl_lock
);
va
l
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
ctr
l
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
if
(
polarity
!=
PWM_POLARITY_NORMAL
)
val
&=
~
BIT_CH
(
PWM_ACT_STATE
,
pwm
->
hwpwm
);
else
val
|=
BIT_CH
(
PWM_ACT_STATE
,
pwm
->
hwpwm
)
;
if
(
(
cstate
.
period
!=
state
->
period
)
||
(
cstate
.
duty_cycle
!=
state
->
duty_cycle
))
{
u32
period
,
duty
,
val
;
unsigned
int
prescaler
;
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CTRL_REG
);
ret
=
sun4i_pwm_calculate
(
sun4i_pwm
,
state
,
&
duty
,
&
period
,
&
prescaler
);
if
(
ret
)
{
dev_err
(
chip
->
dev
,
"period exceeds the maximum value
\n
"
);
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
);
if
(
!
cstate
.
enabled
)
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
return
ret
;
}
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
);
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
if
(
PWM_REG_PRESCAL
(
ctrl
,
pwm
->
hwpwm
)
!=
prescaler
)
{
/* Prescaler changed, the clock has to be gated */
ctrl
&=
~
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
ctrl
,
PWM_CTRL_REG
);
return
0
;
}
ctrl
&=
~
BIT_CH
(
PWM_PRESCAL_MASK
,
pwm
->
hwpwm
);
ctrl
|=
BIT_CH
(
prescaler
,
pwm
->
hwpwm
);
}
static
int
sun4i_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
sun4i_pwm_chip
*
sun4i_pwm
=
to_sun4i_pwm_chip
(
chip
);
u32
val
;
int
ret
;
val
=
(
duty
&
PWM_DTY_MASK
)
|
PWM_PRD
(
period
);
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CH_PRD
(
pwm
->
hwpwm
));
sun4i_pwm
->
next_period
[
pwm
->
hwpwm
]
=
jiffies
+
usecs_to_jiffies
(
cstate
.
period
/
1000
+
1
);
sun4i_pwm
->
needs_delay
[
pwm
->
hwpwm
]
=
true
;
}
ret
=
clk_prepare_enable
(
sun4i_pwm
->
clk
);
if
(
ret
)
{
dev_err
(
chip
->
dev
,
"failed to enable PWM clock
\n
"
);
return
ret
;
if
(
state
->
polarity
!=
PWM_POLARITY_NORMAL
)
ctrl
&=
~
BIT_CH
(
PWM_ACT_STATE
,
pwm
->
hwpwm
);
else
ctrl
|=
BIT_CH
(
PWM_ACT_STATE
,
pwm
->
hwpwm
);
ctrl
|=
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
if
(
state
->
enabled
)
{
ctrl
|=
BIT_CH
(
PWM_EN
,
pwm
->
hwpwm
);
}
else
if
(
!
sun4i_pwm
->
needs_delay
[
pwm
->
hwpwm
])
{
ctrl
&=
~
BIT_CH
(
PWM_EN
,
pwm
->
hwpwm
);
ctrl
&=
~
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
}
spin_lock
(
&
sun4i_pwm
->
ctrl_lock
);
val
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
val
|=
BIT_CH
(
PWM_EN
,
pwm
->
hwpwm
);
val
|=
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
val
,
PWM_CTRL_REG
);
sun4i_pwm_writel
(
sun4i_pwm
,
ctrl
,
PWM_CTRL_REG
);
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
);
return
0
;
}
if
(
state
->
enabled
)
return
0
;
static
void
sun4i_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
sun4i_pwm_chip
*
sun4i_pwm
=
to_sun4i_pwm_chip
(
chip
);
u32
val
;
if
(
!
sun4i_pwm
->
needs_delay
[
pwm
->
hwpwm
])
{
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
return
0
;
}
/* We need a full period to elapse before disabling the channel. */
now
=
jiffies
;
if
(
sun4i_pwm
->
needs_delay
[
pwm
->
hwpwm
]
&&
time_before
(
now
,
sun4i_pwm
->
next_period
[
pwm
->
hwpwm
]))
{
delay_us
=
jiffies_to_usecs
(
sun4i_pwm
->
next_period
[
pwm
->
hwpwm
]
-
now
);
if
((
delay_us
/
500
)
>
MAX_UDELAY_MS
)
msleep
(
delay_us
/
1000
+
1
);
else
usleep_range
(
delay_us
,
delay_us
*
2
);
}
sun4i_pwm
->
needs_delay
[
pwm
->
hwpwm
]
=
false
;
spin_lock
(
&
sun4i_pwm
->
ctrl_lock
);
va
l
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
val
&=
~
BIT_CH
(
PWM_EN
,
pwm
->
hwpwm
);
val
&=
~
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
va
l
,
PWM_CTRL_REG
);
ctr
l
=
sun4i_pwm_readl
(
sun4i_pwm
,
PWM_CTRL_REG
);
ctrl
&=
~
BIT_CH
(
PWM_CLK_GATING
,
pwm
->
hwpwm
);
ctrl
&=
~
BIT_CH
(
PWM_EN
,
pwm
->
hwpwm
);
sun4i_pwm_writel
(
sun4i_pwm
,
ctr
l
,
PWM_CTRL_REG
);
spin_unlock
(
&
sun4i_pwm
->
ctrl_lock
);
clk_disable_unprepare
(
sun4i_pwm
->
clk
);
return
0
;
}
static
const
struct
pwm_ops
sun4i_pwm_ops
=
{
.
config
=
sun4i_pwm_config
,
.
set_polarity
=
sun4i_pwm_set_polarity
,
.
enable
=
sun4i_pwm_enable
,
.
disable
=
sun4i_pwm_disable
,
.
apply
=
sun4i_pwm_apply
,
.
get_state
=
sun4i_pwm_get_state
,
.
owner
=
THIS_MODULE
,
};
...
...
@@ -316,8 +367,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
{
struct
sun4i_pwm_chip
*
pwm
;
struct
resource
*
res
;
u32
val
;
int
i
,
ret
;
int
ret
;
const
struct
of_device_id
*
match
;
match
=
of_match_device
(
sun4i_pwm_dt_ids
,
&
pdev
->
dev
);
...
...
@@ -353,24 +403,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
platform_set_drvdata
(
pdev
,
pwm
);
ret
=
clk_prepare_enable
(
pwm
->
clk
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to enable PWM clock
\n
"
);
goto
clk_error
;
}
val
=
sun4i_pwm_readl
(
pwm
,
PWM_CTRL_REG
);
for
(
i
=
0
;
i
<
pwm
->
chip
.
npwm
;
i
++
)
if
(
!
(
val
&
BIT_CH
(
PWM_ACT_STATE
,
i
)))
pwm_set_polarity
(
&
pwm
->
chip
.
pwms
[
i
],
PWM_POLARITY_INVERSED
);
clk_disable_unprepare
(
pwm
->
clk
);
return
0
;
clk_error:
pwmchip_remove
(
&
pwm
->
chip
);
return
ret
;
}
static
int
sun4i_pwm_remove
(
struct
platform_device
*
pdev
)
...
...
drivers/pwm/pwm-tegra.c
浏览文件 @
5ec8c48a
...
...
@@ -41,6 +41,9 @@
struct
tegra_pwm_soc
{
unsigned
int
num_channels
;
/* Maximum IP frequency for given SoCs */
unsigned
long
max_frequency
;
};
struct
tegra_pwm_chip
{
...
...
@@ -201,7 +204,18 @@ static int tegra_pwm_probe(struct platform_device *pdev)
if
(
IS_ERR
(
pwm
->
clk
))
return
PTR_ERR
(
pwm
->
clk
);
/* Read PWM clock rate from source */
/* Set maximum frequency of the IP */
ret
=
clk_set_rate
(
pwm
->
clk
,
pwm
->
soc
->
max_frequency
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to set max frequency: %d
\n
"
,
ret
);
return
ret
;
}
/*
* The requested and configured frequency may differ due to
* clock register resolutions. Get the configured frequency
* so that PWM period can be calculated more accurately.
*/
pwm
->
clk_rate
=
clk_get_rate
(
pwm
->
clk
);
pwm
->
rst
=
devm_reset_control_get
(
&
pdev
->
dev
,
"pwm"
);
...
...
@@ -273,10 +287,12 @@ static int tegra_pwm_resume(struct device *dev)
static
const
struct
tegra_pwm_soc
tegra20_pwm_soc
=
{
.
num_channels
=
4
,
.
max_frequency
=
48000000UL
,
};
static
const
struct
tegra_pwm_soc
tegra186_pwm_soc
=
{
.
num_channels
=
1
,
.
max_frequency
=
102000000UL
,
};
static
const
struct
of_device_id
tegra_pwm_of_match
[]
=
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录