Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
7755daf5
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
7755daf5
编写于
8月 21, 2017
作者:
T
Thierry Reding
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-4.14/drivers' into for-next
上级
5771a8c0
08a4d8ec
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
699 addition
and
307 deletion
+699
-307
Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt
Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt
+2
-2
Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
+5
-1
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
+9
-2
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
+1
-0
Documentation/devicetree/bindings/pwm/pwm-zx.txt
Documentation/devicetree/bindings/pwm/pwm-zx.txt
+22
-0
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
+0
-1
drivers/pwm/Kconfig
drivers/pwm/Kconfig
+11
-2
drivers/pwm/Makefile
drivers/pwm/Makefile
+1
-0
drivers/pwm/pwm-bcm2835.c
drivers/pwm/pwm-bcm2835.c
+2
-0
drivers/pwm/pwm-hibvt.c
drivers/pwm/pwm-hibvt.c
+1
-1
drivers/pwm/pwm-mediatek.c
drivers/pwm/pwm-mediatek.c
+54
-24
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-meson.c
+1
-1
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-pca9685.c
+7
-7
drivers/pwm/pwm-renesas-tpu.c
drivers/pwm/pwm-renesas-tpu.c
+0
-1
drivers/pwm/pwm-rockchip.c
drivers/pwm/pwm-rockchip.c
+147
-134
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-samsung.c
+35
-35
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tegra.c
+1
-1
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiecap.c
+48
-42
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tiehrpwm.c
+69
-53
drivers/pwm/pwm-vt8500.c
drivers/pwm/pwm-vt8500.c
+1
-0
drivers/pwm/pwm-zx.c
drivers/pwm/pwm-zx.c
+282
-0
未找到文件。
Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt
浏览文件 @
7755daf5
...
@@ -6,7 +6,7 @@ Required properties:
...
@@ -6,7 +6,7 @@ Required properties:
- clocks: This clock defines the base clock frequency of the PWM hardware
- clocks: This clock defines the base clock frequency of the PWM hardware
system, the period and the duty_cycle of the PWM signal is a multiple of
system, the period and the duty_cycle of the PWM signal is a multiple of
the base period.
the base period.
- #pwm-cells: Should be
2
. See pwm.txt in this directory for a description of
- #pwm-cells: Should be
3
. See pwm.txt in this directory for a description of
the cells format.
the cells format.
Examples:
Examples:
...
@@ -15,7 +15,7 @@ pwm@2020c000 {
...
@@ -15,7 +15,7 @@ pwm@2020c000 {
compatible = "brcm,bcm2835-pwm";
compatible = "brcm,bcm2835-pwm";
reg = <0x2020c000 0x28>;
reg = <0x2020c000 0x28>;
clocks = <&clk_pwm>;
clocks = <&clk_pwm>;
#pwm-cells = <
2
>;
#pwm-cells = <
3
>;
};
};
clocks {
clocks {
...
...
Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
浏览文件 @
7755daf5
...
@@ -2,6 +2,8 @@ MediaTek PWM controller
...
@@ -2,6 +2,8 @@ MediaTek PWM controller
Required properties:
Required properties:
- compatible: should be "mediatek,<name>-pwm":
- compatible: should be "mediatek,<name>-pwm":
- "mediatek,mt2712-pwm": found on mt2712 SoC.
- "mediatek,mt7622-pwm": found on mt7622 SoC.
- "mediatek,mt7623-pwm": found on mt7623 SoC.
- "mediatek,mt7623-pwm": found on mt7623 SoC.
- reg: physical base address and length of the controller's registers.
- reg: physical base address and length of the controller's registers.
- #pwm-cells: must be 2. See pwm.txt in this directory for a description of
- #pwm-cells: must be 2. See pwm.txt in this directory for a description of
...
@@ -10,7 +12,9 @@ Required properties:
...
@@ -10,7 +12,9 @@ Required properties:
- clock-names: must contain the following:
- clock-names: must contain the following:
- "top": the top clock generator
- "top": the top clock generator
- "main": clock used by the PWM core
- "main": clock used by the PWM core
- "pwm1-5": the five per PWM clocks
- "pwm1-8": the eight per PWM clocks for mt2712
- "pwm1-6": the six per PWM clocks for mt7622
- "pwm1-5": the five per PWM clocks for mt7623
- pinctrl-names: Must contain a "default" entry.
- pinctrl-names: Must contain a "default" entry.
- pinctrl-0: One property must exist for each entry in pinctrl-names.
- pinctrl-0: One property must exist for each entry in pinctrl-names.
See pinctrl/pinctrl-bindings.txt for details of the property values.
See pinctrl/pinctrl-bindings.txt for details of the property values.
...
...
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
浏览文件 @
7755daf5
...
@@ -3,10 +3,17 @@ Rockchip PWM controller
...
@@ -3,10 +3,17 @@ Rockchip PWM controller
Required properties:
Required properties:
- compatible: should be "rockchip,<name>-pwm"
- compatible: should be "rockchip,<name>-pwm"
"rockchip,rk2928-pwm": found on RK29XX,RK3066 and RK3188 SoCs
"rockchip,rk2928-pwm": found on RK29XX,RK3066 and RK3188 SoCs
"rockchip,rk3288-pwm": found on RK3288 SoC
"rockchip,rk3288-pwm": found on RK3288 SOC
"rockchip,rv1108-pwm", "rockchip,rk3288-pwm": found on RV1108 SoC
"rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
"rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
- reg: physical base address and length of the controller's registers
- reg: physical base address and length of the controller's registers
- clocks: phandle and clock specifier of the PWM reference clock
- clocks: See ../clock/clock-bindings.txt
- For older hardware (rk2928, rk3066, rk3188, rk3228, rk3288, rk3399):
- There is one clock that's used both to derive the functional clock
for the device and as the bus clock.
- For newer hardware (rk3328 and future socs): specified by name
- "pwm": This is used to derive the functional clock.
- "pclk": This is the APB bus clock.
- #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory
- #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory
for a description of the cell format.
for a description of the cell format.
...
...
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
浏览文件 @
7755daf5
...
@@ -6,6 +6,7 @@ Required properties:
...
@@ -6,6 +6,7 @@ Required properties:
for am4372 - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
for am4372 - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
the cells format. The PWM channel index ranges from 0 to 4. The only third
the cells format. The PWM channel index ranges from 0 to 4. The only third
cell flag supported by this binding is PWM_POLARITY_INVERTED.
cell flag supported by this binding is PWM_POLARITY_INVERTED.
...
...
Documentation/devicetree/bindings/pwm/pwm-zx.txt
0 → 100644
浏览文件 @
7755daf5
ZTE ZX PWM controller
Required properties:
- compatible: Should be "zte,zx296718-pwm".
- reg: Physical base address and length of the controller's registers.
- clocks : The phandle and specifier referencing the controller's clocks.
- clock-names: "pclk" for PCLK, "wclk" for WCLK to the PWM controller. The
PCLK is for register access, while WCLK is the reference clock for
calculating period and duty cycles.
- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
the cells format.
Example:
pwm: pwm@1439000 {
compatible = "zte,zx296718-pwm";
reg = <0x1439000 0x1000>;
clocks = <&lsp1crm LSP1_PWM_PCLK>,
<&lsp1crm LSP1_PWM_WCLK>;
clock-names = "pclk", "wclk";
#pwm-cells = <3>;
};
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
浏览文件 @
7755daf5
...
@@ -6,7 +6,6 @@ Required Properties:
...
@@ -6,7 +6,6 @@ Required Properties:
- "renesas,tpu-r8a73a4": for R8A77A4 (R-Mobile APE6) compatible PWM controller.
- "renesas,tpu-r8a73a4": for R8A77A4 (R-Mobile APE6) compatible PWM controller.
- "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller.
- "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller.
- "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller.
- "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller.
- "renesas,tpu-sh7372": for SH7372 (SH-Mobile AP4) compatible PWM controller.
- "renesas,tpu": for generic R-Car TPU PWM controller.
- "renesas,tpu": for generic R-Car TPU PWM controller.
- reg: Base address and length of each memory resource used by the PWM
- reg: Base address and length of each memory resource used by the PWM
...
...
drivers/pwm/Kconfig
浏览文件 @
7755daf5
...
@@ -300,7 +300,7 @@ config PWM_MEDIATEK
...
@@ -300,7 +300,7 @@ config PWM_MEDIATEK
Generic PWM framework driver for Mediatek ARM SoC.
Generic PWM framework driver for Mediatek ARM SoC.
To compile this driver as a module, choose M here: the module
To compile this driver as a module, choose M here: the module
will be called pwm-m
xs
.
will be called pwm-m
ediatek
.
config PWM_MXS
config PWM_MXS
tristate "Freescale MXS PWM support"
tristate "Freescale MXS PWM support"
...
@@ -446,7 +446,7 @@ config PWM_TEGRA
...
@@ -446,7 +446,7 @@ config PWM_TEGRA
config PWM_TIECAP
config PWM_TIECAP
tristate "ECAP PWM support"
tristate "ECAP PWM support"
depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
|| ARCH_KEYSTONE
help
help
PWM driver support for the ECAP APWM controller found on AM33XX
PWM driver support for the ECAP APWM controller found on AM33XX
TI SOC
TI SOC
...
@@ -500,4 +500,13 @@ config PWM_VT8500
...
@@ -500,4 +500,13 @@ config PWM_VT8500
To compile this driver as a module, choose M here: the module
To compile this driver as a module, choose M here: the module
will be called pwm-vt8500.
will be called pwm-vt8500.
config PWM_ZX
tristate "ZTE ZX PWM support"
depends on ARCH_ZX
help
Generic PWM framework driver for ZTE ZX family SoCs.
To compile this driver as a module, choose M here: the module
will be called pwm-zx.
endif
endif
drivers/pwm/Makefile
浏览文件 @
7755daf5
...
@@ -49,3 +49,4 @@ obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
...
@@ -49,3 +49,4 @@ obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
obj-$(CONFIG_PWM_TWL)
+=
pwm-twl.o
obj-$(CONFIG_PWM_TWL)
+=
pwm-twl.o
obj-$(CONFIG_PWM_TWL_LED)
+=
pwm-twl-led.o
obj-$(CONFIG_PWM_TWL_LED)
+=
pwm-twl-led.o
obj-$(CONFIG_PWM_VT8500)
+=
pwm-vt8500.o
obj-$(CONFIG_PWM_VT8500)
+=
pwm-vt8500.o
obj-$(CONFIG_PWM_ZX)
+=
pwm-zx.o
drivers/pwm/pwm-bcm2835.c
浏览文件 @
7755daf5
...
@@ -167,6 +167,8 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
...
@@ -167,6 +167,8 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
pc
->
chip
.
dev
=
&
pdev
->
dev
;
pc
->
chip
.
dev
=
&
pdev
->
dev
;
pc
->
chip
.
ops
=
&
bcm2835_pwm_ops
;
pc
->
chip
.
ops
=
&
bcm2835_pwm_ops
;
pc
->
chip
.
npwm
=
2
;
pc
->
chip
.
npwm
=
2
;
pc
->
chip
.
of_xlate
=
of_pwm_xlate_with_flags
;
pc
->
chip
.
of_pwm_n_cells
=
3
;
platform_set_drvdata
(
pdev
,
pc
);
platform_set_drvdata
(
pdev
,
pc
);
...
...
drivers/pwm/pwm-hibvt.c
浏览文件 @
7755daf5
...
@@ -208,7 +208,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
...
@@ -208,7 +208,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
if
(
ret
<
0
)
if
(
ret
<
0
)
return
ret
;
return
ret
;
pwm_chip
->
rstc
=
devm_reset_control_get
(
&
pdev
->
dev
,
NULL
);
pwm_chip
->
rstc
=
devm_reset_control_get
_exclusive
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
pwm_chip
->
rstc
))
{
if
(
IS_ERR
(
pwm_chip
->
rstc
))
{
clk_disable_unprepare
(
pwm_chip
->
clk
);
clk_disable_unprepare
(
pwm_chip
->
clk
);
return
PTR_ERR
(
pwm_chip
->
rstc
);
return
PTR_ERR
(
pwm_chip
->
rstc
);
...
...
drivers/pwm/pwm-mediatek.c
浏览文件 @
7755daf5
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
* Mediatek Pulse Width Modulator driver
* Mediatek Pulse Width Modulator driver
*
*
* Copyright (C) 2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com>
*
*
* This file is licensed under the terms of the GNU General Public
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* License version 2. This program is licensed "as is" without any
...
@@ -29,6 +30,8 @@
...
@@ -29,6 +30,8 @@
#define PWMDWIDTH 0x2c
#define PWMDWIDTH 0x2c
#define PWMTHRES 0x30
#define PWMTHRES 0x30
#define PWM_CLK_DIV_MAX 7
enum
{
enum
{
MTK_CLK_MAIN
=
0
,
MTK_CLK_MAIN
=
0
,
MTK_CLK_TOP
,
MTK_CLK_TOP
,
...
@@ -61,6 +64,42 @@ static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
...
@@ -61,6 +64,42 @@ static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
return
container_of
(
chip
,
struct
mtk_pwm_chip
,
chip
);
return
container_of
(
chip
,
struct
mtk_pwm_chip
,
chip
);
}
}
static
int
mtk_pwm_clk_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
mtk_pwm_chip
*
pc
=
to_mtk_pwm_chip
(
chip
);
int
ret
;
ret
=
clk_prepare_enable
(
pc
->
clks
[
MTK_CLK_TOP
]);
if
(
ret
<
0
)
return
ret
;
ret
=
clk_prepare_enable
(
pc
->
clks
[
MTK_CLK_MAIN
]);
if
(
ret
<
0
)
goto
disable_clk_top
;
ret
=
clk_prepare_enable
(
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
]);
if
(
ret
<
0
)
goto
disable_clk_main
;
return
0
;
disable_clk_main:
clk_disable_unprepare
(
pc
->
clks
[
MTK_CLK_MAIN
]);
disable_clk_top:
clk_disable_unprepare
(
pc
->
clks
[
MTK_CLK_TOP
]);
return
ret
;
}
static
void
mtk_pwm_clk_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
mtk_pwm_chip
*
pc
=
to_mtk_pwm_chip
(
chip
);
clk_disable_unprepare
(
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
]);
clk_disable_unprepare
(
pc
->
clks
[
MTK_CLK_MAIN
]);
clk_disable_unprepare
(
pc
->
clks
[
MTK_CLK_TOP
]);
}
static
inline
u32
mtk_pwm_readl
(
struct
mtk_pwm_chip
*
chip
,
unsigned
int
num
,
static
inline
u32
mtk_pwm_readl
(
struct
mtk_pwm_chip
*
chip
,
unsigned
int
num
,
unsigned
int
offset
)
unsigned
int
offset
)
{
{
...
@@ -80,6 +119,11 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -80,6 +119,11 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
struct
mtk_pwm_chip
*
pc
=
to_mtk_pwm_chip
(
chip
);
struct
mtk_pwm_chip
*
pc
=
to_mtk_pwm_chip
(
chip
);
struct
clk
*
clk
=
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
];
struct
clk
*
clk
=
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
];
u32
resolution
,
clkdiv
=
0
;
u32
resolution
,
clkdiv
=
0
;
int
ret
;
ret
=
mtk_pwm_clk_enable
(
chip
,
pwm
);
if
(
ret
<
0
)
return
ret
;
resolution
=
NSEC_PER_SEC
/
clk_get_rate
(
clk
);
resolution
=
NSEC_PER_SEC
/
clk_get_rate
(
clk
);
...
@@ -88,13 +132,18 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -88,13 +132,18 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
clkdiv
++
;
clkdiv
++
;
}
}
if
(
clkdiv
>
7
)
if
(
clkdiv
>
PWM_CLK_DIV_MAX
)
{
mtk_pwm_clk_disable
(
chip
,
pwm
);
dev_err
(
chip
->
dev
,
"period %d not supported
\n
"
,
period_ns
);
return
-
EINVAL
;
return
-
EINVAL
;
}
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMCON
,
BIT
(
15
)
|
BIT
(
3
)
|
clkdiv
);
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMCON
,
BIT
(
15
)
|
clkdiv
);
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMDWIDTH
,
period_ns
/
resolution
);
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMDWIDTH
,
period_ns
/
resolution
);
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMTHRES
,
duty_ns
/
resolution
);
mtk_pwm_writel
(
pc
,
pwm
->
hwpwm
,
PWMTHRES
,
duty_ns
/
resolution
);
mtk_pwm_clk_disable
(
chip
,
pwm
);
return
0
;
return
0
;
}
}
...
@@ -104,7 +153,7 @@ static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -104,7 +153,7 @@ static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
u32
value
;
u32
value
;
int
ret
;
int
ret
;
ret
=
clk_prepare
(
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
]
);
ret
=
mtk_pwm_clk_enable
(
chip
,
pwm
);
if
(
ret
<
0
)
if
(
ret
<
0
)
return
ret
;
return
ret
;
...
@@ -124,7 +173,7 @@ static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -124,7 +173,7 @@ static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
value
&=
~
BIT
(
pwm
->
hwpwm
);
value
&=
~
BIT
(
pwm
->
hwpwm
);
writel
(
value
,
pc
->
regs
);
writel
(
value
,
pc
->
regs
);
clk_unprepare
(
pc
->
clks
[
MTK_CLK_PWM1
+
pwm
->
hwpwm
]
);
mtk_pwm_clk_disable
(
chip
,
pwm
);
}
}
static
const
struct
pwm_ops
mtk_pwm_ops
=
{
static
const
struct
pwm_ops
mtk_pwm_ops
=
{
...
@@ -156,14 +205,6 @@ static int mtk_pwm_probe(struct platform_device *pdev)
...
@@ -156,14 +205,6 @@ static int mtk_pwm_probe(struct platform_device *pdev)
return
PTR_ERR
(
pc
->
clks
[
i
]);
return
PTR_ERR
(
pc
->
clks
[
i
]);
}
}
ret
=
clk_prepare
(
pc
->
clks
[
MTK_CLK_TOP
]);
if
(
ret
<
0
)
return
ret
;
ret
=
clk_prepare
(
pc
->
clks
[
MTK_CLK_MAIN
]);
if
(
ret
<
0
)
goto
disable_clk_top
;
platform_set_drvdata
(
pdev
,
pc
);
platform_set_drvdata
(
pdev
,
pc
);
pc
->
chip
.
dev
=
&
pdev
->
dev
;
pc
->
chip
.
dev
=
&
pdev
->
dev
;
...
@@ -174,26 +215,15 @@ static int mtk_pwm_probe(struct platform_device *pdev)
...
@@ -174,26 +215,15 @@ static int mtk_pwm_probe(struct platform_device *pdev)
ret
=
pwmchip_add
(
&
pc
->
chip
);
ret
=
pwmchip_add
(
&
pc
->
chip
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
goto
disable_clk_main
;
return
ret
;
}
}
return
0
;
return
0
;
disable_clk_main:
clk_unprepare
(
pc
->
clks
[
MTK_CLK_MAIN
]);
disable_clk_top:
clk_unprepare
(
pc
->
clks
[
MTK_CLK_TOP
]);
return
ret
;
}
}
static
int
mtk_pwm_remove
(
struct
platform_device
*
pdev
)
static
int
mtk_pwm_remove
(
struct
platform_device
*
pdev
)
{
{
struct
mtk_pwm_chip
*
pc
=
platform_get_drvdata
(
pdev
);
struct
mtk_pwm_chip
*
pc
=
platform_get_drvdata
(
pdev
);
unsigned
int
i
;
for
(
i
=
0
;
i
<
pc
->
chip
.
npwm
;
i
++
)
pwm_disable
(
&
pc
->
chip
.
pwms
[
i
]);
return
pwmchip_remove
(
&
pc
->
chip
);
return
pwmchip_remove
(
&
pc
->
chip
);
}
}
...
...
drivers/pwm/pwm-meson.c
浏览文件 @
7755daf5
...
@@ -441,7 +441,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
...
@@ -441,7 +441,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
for
(
i
=
0
;
i
<
meson
->
chip
.
npwm
;
i
++
)
{
for
(
i
=
0
;
i
<
meson
->
chip
.
npwm
;
i
++
)
{
struct
meson_pwm_channel
*
channel
=
&
channels
[
i
];
struct
meson_pwm_channel
*
channel
=
&
channels
[
i
];
snprintf
(
name
,
sizeof
(
name
),
"%
s#mux%u"
,
np
->
full_name
,
i
);
snprintf
(
name
,
sizeof
(
name
),
"%
pOF#mux%u"
,
np
,
i
);
init
.
name
=
name
;
init
.
name
=
name
;
init
.
ops
=
&
clk_mux_ops
;
init
.
ops
=
&
clk_mux_ops
;
...
...
drivers/pwm/pwm-pca9685.c
浏览文件 @
7755daf5
...
@@ -241,11 +241,11 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
...
@@ -241,11 +241,11 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
}
}
#endif
#endif
static
void
pca9685_set_sleep_mode
(
struct
pca9685
*
pca
,
int
sleep
)
static
void
pca9685_set_sleep_mode
(
struct
pca9685
*
pca
,
bool
enable
)
{
{
regmap_update_bits
(
pca
->
regmap
,
PCA9685_MODE1
,
regmap_update_bits
(
pca
->
regmap
,
PCA9685_MODE1
,
MODE1_SLEEP
,
sleep
?
MODE1_SLEEP
:
0
);
MODE1_SLEEP
,
enable
?
MODE1_SLEEP
:
0
);
if
(
!
sleep
)
{
if
(
!
enable
)
{
/* Wait 500us for the oscillator to be back up */
/* Wait 500us for the oscillator to be back up */
udelay
(
500
);
udelay
(
500
);
}
}
...
@@ -272,13 +272,13 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -272,13 +272,13 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* state is guaranteed active here.
* state is guaranteed active here.
*/
*/
/* Put chip into sleep mode */
/* Put chip into sleep mode */
pca9685_set_sleep_mode
(
pca
,
1
);
pca9685_set_sleep_mode
(
pca
,
true
);
/* Change the chip-wide output frequency */
/* Change the chip-wide output frequency */
regmap_write
(
pca
->
regmap
,
PCA9685_PRESCALE
,
prescale
);
regmap_write
(
pca
->
regmap
,
PCA9685_PRESCALE
,
prescale
);
/* Wake the chip up */
/* Wake the chip up */
pca9685_set_sleep_mode
(
pca
,
0
);
pca9685_set_sleep_mode
(
pca
,
false
);
pca
->
period_ns
=
period_ns
;
pca
->
period_ns
=
period_ns
;
}
else
{
}
else
{
...
@@ -534,7 +534,7 @@ static int pca9685_pwm_runtime_suspend(struct device *dev)
...
@@ -534,7 +534,7 @@ static int pca9685_pwm_runtime_suspend(struct device *dev)
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
pca9685
*
pca
=
i2c_get_clientdata
(
client
);
struct
pca9685
*
pca
=
i2c_get_clientdata
(
client
);
pca9685_set_sleep_mode
(
pca
,
1
);
pca9685_set_sleep_mode
(
pca
,
true
);
return
0
;
return
0
;
}
}
...
@@ -543,7 +543,7 @@ static int pca9685_pwm_runtime_resume(struct device *dev)
...
@@ -543,7 +543,7 @@ static int pca9685_pwm_runtime_resume(struct device *dev)
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
pca9685
*
pca
=
i2c_get_clientdata
(
client
);
struct
pca9685
*
pca
=
i2c_get_clientdata
(
client
);
pca9685_set_sleep_mode
(
pca
,
0
);
pca9685_set_sleep_mode
(
pca
,
false
);
return
0
;
return
0
;
}
}
#endif
#endif
...
...
drivers/pwm/pwm-renesas-tpu.c
浏览文件 @
7755daf5
...
@@ -455,7 +455,6 @@ static const struct of_device_id tpu_of_table[] = {
...
@@ -455,7 +455,6 @@ static const struct of_device_id tpu_of_table[] = {
{
.
compatible
=
"renesas,tpu-r8a73a4"
,
},
{
.
compatible
=
"renesas,tpu-r8a73a4"
,
},
{
.
compatible
=
"renesas,tpu-r8a7740"
,
},
{
.
compatible
=
"renesas,tpu-r8a7740"
,
},
{
.
compatible
=
"renesas,tpu-r8a7790"
,
},
{
.
compatible
=
"renesas,tpu-r8a7790"
,
},
{
.
compatible
=
"renesas,tpu-sh7372"
,
},
{
.
compatible
=
"renesas,tpu"
,
},
{
.
compatible
=
"renesas,tpu"
,
},
{
},
{
},
};
};
...
...
drivers/pwm/pwm-rockchip.c
浏览文件 @
7755daf5
...
@@ -27,12 +27,15 @@
...
@@ -27,12 +27,15 @@
#define PWM_DUTY_NEGATIVE (0 << 3)
#define PWM_DUTY_NEGATIVE (0 << 3)
#define PWM_INACTIVE_NEGATIVE (0 << 4)
#define PWM_INACTIVE_NEGATIVE (0 << 4)
#define PWM_INACTIVE_POSITIVE (1 << 4)
#define PWM_INACTIVE_POSITIVE (1 << 4)
#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
#define PWM_OUTPUT_LEFT (0 << 5)
#define PWM_OUTPUT_LEFT (0 << 5)
#define PWM_LOCK_EN (1 << 6)
#define PWM_LP_DISABLE (0 << 8)
#define PWM_LP_DISABLE (0 << 8)
struct
rockchip_pwm_chip
{
struct
rockchip_pwm_chip
{
struct
pwm_chip
chip
;
struct
pwm_chip
chip
;
struct
clk
*
clk
;
struct
clk
*
clk
;
struct
clk
*
pclk
;
const
struct
rockchip_pwm_data
*
data
;
const
struct
rockchip_pwm_data
*
data
;
void
__iomem
*
base
;
void
__iomem
*
base
;
};
};
...
@@ -48,13 +51,8 @@ struct rockchip_pwm_data {
...
@@ -48,13 +51,8 @@ struct rockchip_pwm_data {
struct
rockchip_pwm_regs
regs
;
struct
rockchip_pwm_regs
regs
;
unsigned
int
prescaler
;
unsigned
int
prescaler
;
bool
supports_polarity
;
bool
supports_polarity
;
const
struct
pwm_ops
*
ops
;
bool
supports_lock
;
u32
enable_conf
;
void
(
*
set_enable
)(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
bool
enable
,
enum
pwm_polarity
polarity
);
void
(
*
get_state
)(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
);
};
};
static
inline
struct
rockchip_pwm_chip
*
to_rockchip_pwm_chip
(
struct
pwm_chip
*
c
)
static
inline
struct
rockchip_pwm_chip
*
to_rockchip_pwm_chip
(
struct
pwm_chip
*
c
)
...
@@ -62,90 +60,18 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
...
@@ -62,90 +60,18 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
return
container_of
(
c
,
struct
rockchip_pwm_chip
,
chip
);
return
container_of
(
c
,
struct
rockchip_pwm_chip
,
chip
);
}
}
static
void
rockchip_pwm_set_enable_v1
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
bool
enable
,
enum
pwm_polarity
polarity
)
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
PWM_CTRL_OUTPUT_EN
|
PWM_CTRL_TIMER_EN
;
u32
val
;
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
enable
)
val
|=
enable_conf
;
else
val
&=
~
enable_conf
;
writel_relaxed
(
val
,
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
}
static
void
rockchip_pwm_get_state_v1
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
PWM_CTRL_OUTPUT_EN
|
PWM_CTRL_TIMER_EN
;
u32
val
;
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
((
val
&
enable_conf
)
==
enable_conf
)
state
->
enabled
=
true
;
}
static
void
rockchip_pwm_set_enable_v2
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
bool
enable
,
enum
pwm_polarity
polarity
)
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
PWM_OUTPUT_LEFT
|
PWM_LP_DISABLE
|
PWM_ENABLE
|
PWM_CONTINUOUS
;
u32
val
;
if
(
polarity
==
PWM_POLARITY_INVERSED
)
enable_conf
|=
PWM_DUTY_NEGATIVE
|
PWM_INACTIVE_POSITIVE
;
else
enable_conf
|=
PWM_DUTY_POSITIVE
|
PWM_INACTIVE_NEGATIVE
;
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
enable
)
val
|=
enable_conf
;
else
val
&=
~
enable_conf
;
writel_relaxed
(
val
,
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
}
static
void
rockchip_pwm_get_state_v2
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
PWM_OUTPUT_LEFT
|
PWM_LP_DISABLE
|
PWM_ENABLE
|
PWM_CONTINUOUS
;
u32
val
;
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
((
val
&
enable_conf
)
!=
enable_conf
)
return
;
state
->
enabled
=
true
;
if
(
!
(
val
&
PWM_DUTY_POSITIVE
))
state
->
polarity
=
PWM_POLARITY_INVERSED
;
}
static
void
rockchip_pwm_get_state
(
struct
pwm_chip
*
chip
,
static
void
rockchip_pwm_get_state
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
struct
pwm_state
*
state
)
{
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
pc
->
data
->
enable_conf
;
unsigned
long
clk_rate
;
unsigned
long
clk_rate
;
u64
tmp
;
u64
tmp
;
u32
val
;
int
ret
;
int
ret
;
ret
=
clk_enable
(
pc
->
clk
);
ret
=
clk_enable
(
pc
->
p
clk
);
if
(
ret
)
if
(
ret
)
return
;
return
;
...
@@ -157,19 +83,31 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
...
@@ -157,19 +83,31 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
tmp
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
duty
);
tmp
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
duty
);
tmp
*=
pc
->
data
->
prescaler
*
NSEC_PER_SEC
;
tmp
*=
pc
->
data
->
prescaler
*
NSEC_PER_SEC
;
state
->
duty_cycle
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
clk_rate
);
state
->
duty_cycle
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
clk_rate
);
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
pc
->
data
->
supports_polarity
)
state
->
enabled
=
((
val
&
enable_conf
)
!=
enable_conf
)
?
false
:
true
;
else
state
->
enabled
=
((
val
&
enable_conf
)
==
enable_conf
)
?
true
:
false
;
pc
->
data
->
get_state
(
chip
,
pwm
,
state
);
if
(
pc
->
data
->
supports_polarity
)
{
if
(
!
(
val
&
PWM_DUTY_POSITIVE
))
state
->
polarity
=
PWM_POLARITY_INVERSED
;
}
clk_disable
(
pc
->
clk
);
clk_disable
(
pc
->
p
clk
);
}
}
static
int
rockchip_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
static
void
rockchip_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
struct
pwm_state
*
state
)
{
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
unsigned
long
period
,
duty
;
unsigned
long
period
,
duty
;
u64
clk_rate
,
div
;
u64
clk_rate
,
div
;
u32
ctrl
;
clk_rate
=
clk_get_rate
(
pc
->
clk
);
clk_rate
=
clk_get_rate
(
pc
->
clk
);
...
@@ -178,26 +116,53 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -178,26 +116,53 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* bits, every possible input period can be obtained using the
* bits, every possible input period can be obtained using the
* default prescaler value for all practical clock rate values.
* default prescaler value for all practical clock rate values.
*/
*/
div
=
clk_rate
*
period_ns
;
div
=
clk_rate
*
state
->
period
;
period
=
DIV_ROUND_CLOSEST_ULL
(
div
,
period
=
DIV_ROUND_CLOSEST_ULL
(
div
,
pc
->
data
->
prescaler
*
NSEC_PER_SEC
);
pc
->
data
->
prescaler
*
NSEC_PER_SEC
);
div
=
clk_rate
*
duty_ns
;
div
=
clk_rate
*
state
->
duty_cycle
;
duty
=
DIV_ROUND_CLOSEST_ULL
(
div
,
pc
->
data
->
prescaler
*
NSEC_PER_SEC
);
duty
=
DIV_ROUND_CLOSEST_ULL
(
div
,
pc
->
data
->
prescaler
*
NSEC_PER_SEC
);
/*
* Lock the period and duty of previous configuration, then
* change the duty and period, that would not be effective.
*/
ctrl
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
pc
->
data
->
supports_lock
)
{
ctrl
|=
PWM_LOCK_EN
;
writel_relaxed
(
ctrl
,
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
}
writel
(
period
,
pc
->
base
+
pc
->
data
->
regs
.
period
);
writel
(
period
,
pc
->
base
+
pc
->
data
->
regs
.
period
);
writel
(
duty
,
pc
->
base
+
pc
->
data
->
regs
.
duty
);
writel
(
duty
,
pc
->
base
+
pc
->
data
->
regs
.
duty
);
return
0
;
if
(
pc
->
data
->
supports_polarity
)
{
ctrl
&=
~
PWM_POLARITY_MASK
;
if
(
state
->
polarity
==
PWM_POLARITY_INVERSED
)
ctrl
|=
PWM_DUTY_NEGATIVE
|
PWM_INACTIVE_POSITIVE
;
else
ctrl
|=
PWM_DUTY_POSITIVE
|
PWM_INACTIVE_NEGATIVE
;
}
/*
* Unlock and set polarity at the same time,
* the configuration of duty, period and polarity
* would be effective together at next period.
*/
if
(
pc
->
data
->
supports_lock
)
ctrl
&=
~
PWM_LOCK_EN
;
writel
(
ctrl
,
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
}
}
static
int
rockchip_pwm_enable
(
struct
pwm_chip
*
chip
,
static
int
rockchip_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_device
*
pwm
,
bool
enable
,
bool
enable
)
enum
pwm_polarity
polarity
)
{
{
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
u32
enable_conf
=
pc
->
data
->
enable_conf
;
int
ret
;
int
ret
;
u32
val
;
if
(
enable
)
{
if
(
enable
)
{
ret
=
clk_enable
(
pc
->
clk
);
ret
=
clk_enable
(
pc
->
clk
);
...
@@ -205,7 +170,14 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
...
@@ -205,7 +170,14 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
return
ret
;
return
ret
;
}
}
pc
->
data
->
set_enable
(
chip
,
pwm
,
enable
,
polarity
);
val
=
readl_relaxed
(
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
enable
)
val
|=
enable_conf
;
else
val
&=
~
enable_conf
;
writel_relaxed
(
val
,
pc
->
base
+
pc
->
data
->
regs
.
ctrl
);
if
(
!
enable
)
if
(
!
enable
)
clk_disable
(
pc
->
clk
);
clk_disable
(
pc
->
clk
);
...
@@ -219,33 +191,26 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -219,33 +191,26 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
struct
rockchip_pwm_chip
*
pc
=
to_rockchip_pwm_chip
(
chip
);
struct
pwm_state
curstate
;
struct
pwm_state
curstate
;
bool
enabled
;
bool
enabled
;
int
ret
;
int
ret
=
0
;
pwm_get_state
(
pwm
,
&
curstate
);
ret
=
clk_enable
(
pc
->
pclk
);
enabled
=
curstate
.
enabled
;
ret
=
clk_enable
(
pc
->
clk
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
if
(
state
->
polarity
!=
curstate
.
polarity
&&
enabled
)
{
pwm_get_state
(
pwm
,
&
curstate
);
ret
=
rockchip_pwm_enable
(
chip
,
pwm
,
false
,
state
->
polarity
);
enabled
=
curstate
.
enabled
;
if
(
state
->
polarity
!=
curstate
.
polarity
&&
enabled
&&
!
pc
->
data
->
supports_lock
)
{
ret
=
rockchip_pwm_enable
(
chip
,
pwm
,
false
);
if
(
ret
)
if
(
ret
)
goto
out
;
goto
out
;
enabled
=
false
;
enabled
=
false
;
}
}
ret
=
rockchip_pwm_config
(
chip
,
pwm
,
state
->
duty_cycle
,
state
->
period
);
rockchip_pwm_config
(
chip
,
pwm
,
state
);
if
(
ret
)
{
if
(
enabled
!=
curstate
.
enabled
)
rockchip_pwm_enable
(
chip
,
pwm
,
!
enabled
,
state
->
polarity
);
goto
out
;
}
if
(
state
->
enabled
!=
enabled
)
{
if
(
state
->
enabled
!=
enabled
)
{
ret
=
rockchip_pwm_enable
(
chip
,
pwm
,
state
->
enabled
,
ret
=
rockchip_pwm_enable
(
chip
,
pwm
,
state
->
enabled
);
state
->
polarity
);
if
(
ret
)
if
(
ret
)
goto
out
;
goto
out
;
}
}
...
@@ -257,18 +222,12 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -257,18 +222,12 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
rockchip_pwm_get_state
(
chip
,
pwm
,
state
);
rockchip_pwm_get_state
(
chip
,
pwm
,
state
);
out:
out:
clk_disable
(
pc
->
clk
);
clk_disable
(
pc
->
p
clk
);
return
ret
;
return
ret
;
}
}
static
const
struct
pwm_ops
rockchip_pwm_ops_v1
=
{
static
const
struct
pwm_ops
rockchip_pwm_ops
=
{
.
get_state
=
rockchip_pwm_get_state
,
.
apply
=
rockchip_pwm_apply
,
.
owner
=
THIS_MODULE
,
};
static
const
struct
pwm_ops
rockchip_pwm_ops_v2
=
{
.
get_state
=
rockchip_pwm_get_state
,
.
get_state
=
rockchip_pwm_get_state
,
.
apply
=
rockchip_pwm_apply
,
.
apply
=
rockchip_pwm_apply
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
...
@@ -282,9 +241,9 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
...
@@ -282,9 +241,9 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
.
ctrl
=
0x0c
,
.
ctrl
=
0x0c
,
},
},
.
prescaler
=
2
,
.
prescaler
=
2
,
.
ops
=
&
rockchip_pwm_ops_v1
,
.
supports_polarity
=
false
,
.
s
et_enable
=
rockchip_pwm_set_enable_v1
,
.
s
upports_lock
=
false
,
.
get_state
=
rockchip_pwm_get_state_v1
,
.
enable_conf
=
PWM_CTRL_OUTPUT_EN
|
PWM_CTRL_TIMER_EN
,
};
};
static
const
struct
rockchip_pwm_data
pwm_data_v2
=
{
static
const
struct
rockchip_pwm_data
pwm_data_v2
=
{
...
@@ -296,9 +255,9 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
...
@@ -296,9 +255,9 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
},
},
.
prescaler
=
1
,
.
prescaler
=
1
,
.
supports_polarity
=
true
,
.
supports_polarity
=
true
,
.
ops
=
&
rockchip_pwm_ops_v2
,
.
supports_lock
=
false
,
.
set_enable
=
rockchip_pwm_set_enable_v2
,
.
enable_conf
=
PWM_OUTPUT_LEFT
|
PWM_LP_DISABLE
|
PWM_ENABLE
|
.
get_state
=
rockchip_pwm_get_state_v2
,
PWM_CONTINUOUS
,
};
};
static
const
struct
rockchip_pwm_data
pwm_data_vop
=
{
static
const
struct
rockchip_pwm_data
pwm_data_vop
=
{
...
@@ -310,15 +269,30 @@ static const struct rockchip_pwm_data pwm_data_vop = {
...
@@ -310,15 +269,30 @@ static const struct rockchip_pwm_data pwm_data_vop = {
},
},
.
prescaler
=
1
,
.
prescaler
=
1
,
.
supports_polarity
=
true
,
.
supports_polarity
=
true
,
.
ops
=
&
rockchip_pwm_ops_v2
,
.
supports_lock
=
false
,
.
set_enable
=
rockchip_pwm_set_enable_v2
,
.
enable_conf
=
PWM_OUTPUT_LEFT
|
PWM_LP_DISABLE
|
PWM_ENABLE
|
.
get_state
=
rockchip_pwm_get_state_v2
,
PWM_CONTINUOUS
,
};
static
const
struct
rockchip_pwm_data
pwm_data_v3
=
{
.
regs
=
{
.
duty
=
0x08
,
.
period
=
0x04
,
.
cntr
=
0x00
,
.
ctrl
=
0x0c
,
},
.
prescaler
=
1
,
.
supports_polarity
=
true
,
.
supports_lock
=
true
,
.
enable_conf
=
PWM_OUTPUT_LEFT
|
PWM_LP_DISABLE
|
PWM_ENABLE
|
PWM_CONTINUOUS
,
};
};
static
const
struct
of_device_id
rockchip_pwm_dt_ids
[]
=
{
static
const
struct
of_device_id
rockchip_pwm_dt_ids
[]
=
{
{
.
compatible
=
"rockchip,rk2928-pwm"
,
.
data
=
&
pwm_data_v1
},
{
.
compatible
=
"rockchip,rk2928-pwm"
,
.
data
=
&
pwm_data_v1
},
{
.
compatible
=
"rockchip,rk3288-pwm"
,
.
data
=
&
pwm_data_v2
},
{
.
compatible
=
"rockchip,rk3288-pwm"
,
.
data
=
&
pwm_data_v2
},
{
.
compatible
=
"rockchip,vop-pwm"
,
.
data
=
&
pwm_data_vop
},
{
.
compatible
=
"rockchip,vop-pwm"
,
.
data
=
&
pwm_data_vop
},
{
.
compatible
=
"rockchip,rk3328-pwm"
,
.
data
=
&
pwm_data_v3
},
{
/* sentinel */
}
{
/* sentinel */
}
};
};
MODULE_DEVICE_TABLE
(
of
,
rockchip_pwm_dt_ids
);
MODULE_DEVICE_TABLE
(
of
,
rockchip_pwm_dt_ids
);
...
@@ -328,7 +302,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
...
@@ -328,7 +302,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
const
struct
of_device_id
*
id
;
const
struct
of_device_id
*
id
;
struct
rockchip_pwm_chip
*
pc
;
struct
rockchip_pwm_chip
*
pc
;
struct
resource
*
r
;
struct
resource
*
r
;
int
ret
;
int
ret
,
count
;
id
=
of_match_device
(
rockchip_pwm_dt_ids
,
&
pdev
->
dev
);
id
=
of_match_device
(
rockchip_pwm_dt_ids
,
&
pdev
->
dev
);
if
(
!
id
)
if
(
!
id
)
...
@@ -343,19 +317,49 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
...
@@ -343,19 +317,49 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
if
(
IS_ERR
(
pc
->
base
))
if
(
IS_ERR
(
pc
->
base
))
return
PTR_ERR
(
pc
->
base
);
return
PTR_ERR
(
pc
->
base
);
pc
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
NULL
);
pc
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
"pwm"
);
if
(
IS_ERR
(
pc
->
clk
))
if
(
IS_ERR
(
pc
->
clk
))
{
return
PTR_ERR
(
pc
->
clk
);
pc
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
pc
->
clk
))
{
ret
=
PTR_ERR
(
pc
->
clk
);
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
&
pdev
->
dev
,
"Can't get bus clk: %d
\n
"
,
ret
);
return
ret
;
}
}
count
=
of_count_phandle_with_args
(
pdev
->
dev
.
of_node
,
"clocks"
,
"#clock-cells"
);
if
(
count
==
2
)
pc
->
pclk
=
devm_clk_get
(
&
pdev
->
dev
,
"pclk"
);
else
pc
->
pclk
=
pc
->
clk
;
if
(
IS_ERR
(
pc
->
pclk
))
{
ret
=
PTR_ERR
(
pc
->
pclk
);
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
&
pdev
->
dev
,
"Can't get APB clk: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
clk_prepare_enable
(
pc
->
clk
);
ret
=
clk_prepare_enable
(
pc
->
clk
);
if
(
ret
)
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Can't prepare enable bus clk: %d
\n
"
,
ret
);
return
ret
;
return
ret
;
}
ret
=
clk_prepare
(
pc
->
pclk
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Can't prepare APB clk: %d
\n
"
,
ret
);
goto
err_clk
;
}
platform_set_drvdata
(
pdev
,
pc
);
platform_set_drvdata
(
pdev
,
pc
);
pc
->
data
=
id
->
data
;
pc
->
data
=
id
->
data
;
pc
->
chip
.
dev
=
&
pdev
->
dev
;
pc
->
chip
.
dev
=
&
pdev
->
dev
;
pc
->
chip
.
ops
=
pc
->
data
->
ops
;
pc
->
chip
.
ops
=
&
rockchip_pwm_
ops
;
pc
->
chip
.
base
=
-
1
;
pc
->
chip
.
base
=
-
1
;
pc
->
chip
.
npwm
=
1
;
pc
->
chip
.
npwm
=
1
;
...
@@ -368,12 +372,20 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
...
@@ -368,12 +372,20 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
clk_unprepare
(
pc
->
clk
);
clk_unprepare
(
pc
->
clk
);
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
goto
err_pclk
;
}
}
/* Keep the PWM clk enabled if the PWM appears to be up and running. */
/* Keep the PWM clk enabled if the PWM appears to be up and running. */
if
(
!
pwm_is_enabled
(
pc
->
chip
.
pwms
))
if
(
!
pwm_is_enabled
(
pc
->
chip
.
pwms
))
clk_disable
(
pc
->
clk
);
clk_disable
(
pc
->
clk
);
return
0
;
err_pclk:
clk_unprepare
(
pc
->
pclk
);
err_clk:
clk_disable_unprepare
(
pc
->
clk
);
return
ret
;
return
ret
;
}
}
...
@@ -395,6 +407,7 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
...
@@ -395,6 +407,7 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
if
(
pwm_is_enabled
(
pc
->
chip
.
pwms
))
if
(
pwm_is_enabled
(
pc
->
chip
.
pwms
))
clk_disable
(
pc
->
clk
);
clk_disable
(
pc
->
clk
);
clk_unprepare
(
pc
->
pclk
);
clk_unprepare
(
pc
->
clk
);
clk_unprepare
(
pc
->
clk
);
return
pwmchip_remove
(
&
pc
->
chip
);
return
pwmchip_remove
(
&
pc
->
chip
);
...
...
drivers/pwm/pwm-samsung.c
浏览文件 @
7755daf5
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
* Copyright (c) 2008 Simtec Electronics
* Copyright (c) 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
* Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
* Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
* Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
*
*
* PWM driver for Samsung SoCs
* PWM driver for Samsung SoCs
*
*
...
@@ -74,6 +75,7 @@ struct samsung_pwm_channel {
...
@@ -74,6 +75,7 @@ struct samsung_pwm_channel {
* @chip: generic PWM chip
* @chip: generic PWM chip
* @variant: local copy of hardware variant data
* @variant: local copy of hardware variant data
* @inverter_mask: inverter status for all channels - one bit per channel
* @inverter_mask: inverter status for all channels - one bit per channel
* @disabled_mask: disabled status for all channels - one bit per channel
* @base: base address of mapped PWM registers
* @base: base address of mapped PWM registers
* @base_clk: base clock used to drive the timers
* @base_clk: base clock used to drive the timers
* @tclk0: external clock 0 (can be ERR_PTR if not present)
* @tclk0: external clock 0 (can be ERR_PTR if not present)
...
@@ -83,6 +85,7 @@ struct samsung_pwm_chip {
...
@@ -83,6 +85,7 @@ struct samsung_pwm_chip {
struct
pwm_chip
chip
;
struct
pwm_chip
chip
;
struct
samsung_pwm_variant
variant
;
struct
samsung_pwm_variant
variant
;
u8
inverter_mask
;
u8
inverter_mask
;
u8
disabled_mask
;
void
__iomem
*
base
;
void
__iomem
*
base
;
struct
clk
*
base_clk
;
struct
clk
*
base_clk
;
...
@@ -257,6 +260,8 @@ static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -257,6 +260,8 @@ static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
tcon
|=
TCON_START
(
tcon_chan
)
|
TCON_AUTORELOAD
(
tcon_chan
);
tcon
|=
TCON_START
(
tcon_chan
)
|
TCON_AUTORELOAD
(
tcon_chan
);
writel
(
tcon
,
our_chip
->
base
+
REG_TCON
);
writel
(
tcon
,
our_chip
->
base
+
REG_TCON
);
our_chip
->
disabled_mask
&=
~
BIT
(
pwm
->
hwpwm
);
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
return
0
;
return
0
;
...
@@ -275,6 +280,8 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -275,6 +280,8 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
tcon
&=
~
TCON_AUTORELOAD
(
tcon_chan
);
tcon
&=
~
TCON_AUTORELOAD
(
tcon_chan
);
writel
(
tcon
,
our_chip
->
base
+
REG_TCON
);
writel
(
tcon
,
our_chip
->
base
+
REG_TCON
);
our_chip
->
disabled_mask
|=
BIT
(
pwm
->
hwpwm
);
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
}
}
...
@@ -297,8 +304,8 @@ static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
...
@@ -297,8 +304,8 @@ static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
spin_unlock_irqrestore
(
&
samsung_pwm_lock
,
flags
);
}
}
static
int
pwm_samsung_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
static
int
__
pwm_samsung_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
int
duty_ns
,
int
period_ns
,
bool
force_period
)
{
{
struct
samsung_pwm_chip
*
our_chip
=
to_samsung_pwm_chip
(
chip
);
struct
samsung_pwm_chip
*
our_chip
=
to_samsung_pwm_chip
(
chip
);
struct
samsung_pwm_channel
*
chan
=
pwm_get_chip_data
(
pwm
);
struct
samsung_pwm_channel
*
chan
=
pwm_get_chip_data
(
pwm
);
...
@@ -312,9 +319,6 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -312,9 +319,6 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
if
(
period_ns
>
NSEC_PER_SEC
)
if
(
period_ns
>
NSEC_PER_SEC
)
return
-
ERANGE
;
return
-
ERANGE
;
if
(
period_ns
==
chan
->
period_ns
&&
duty_ns
==
chan
->
duty_ns
)
return
0
;
tcnt
=
readl
(
our_chip
->
base
+
REG_TCNTB
(
pwm
->
hwpwm
));
tcnt
=
readl
(
our_chip
->
base
+
REG_TCNTB
(
pwm
->
hwpwm
));
oldtcmp
=
readl
(
our_chip
->
base
+
REG_TCMPB
(
pwm
->
hwpwm
));
oldtcmp
=
readl
(
our_chip
->
base
+
REG_TCMPB
(
pwm
->
hwpwm
));
...
@@ -322,7 +326,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -322,7 +326,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
++
tcnt
;
++
tcnt
;
/* Check to see if we are changing the clock rate of the PWM. */
/* Check to see if we are changing the clock rate of the PWM. */
if
(
chan
->
period_ns
!=
period_ns
)
{
if
(
chan
->
period_ns
!=
period_ns
||
force_period
)
{
unsigned
long
tin_rate
;
unsigned
long
tin_rate
;
u32
period
;
u32
period
;
...
@@ -381,6 +385,12 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -381,6 +385,12 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
return
0
;
return
0
;
}
}
static
int
pwm_samsung_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
{
return
__pwm_samsung_config
(
chip
,
pwm
,
duty_ns
,
period_ns
,
false
);
}
static
void
pwm_samsung_set_invert
(
struct
samsung_pwm_chip
*
chip
,
static
void
pwm_samsung_set_invert
(
struct
samsung_pwm_chip
*
chip
,
unsigned
int
channel
,
bool
invert
)
unsigned
int
channel
,
bool
invert
)
{
{
...
@@ -592,51 +602,41 @@ static int pwm_samsung_remove(struct platform_device *pdev)
...
@@ -592,51 +602,41 @@ static int pwm_samsung_remove(struct platform_device *pdev)
}
}
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
static
int
pwm_samsung_
suspend
(
struct
device
*
dev
)
static
int
pwm_samsung_
resume
(
struct
device
*
dev
)
{
{
struct
samsung_pwm_chip
*
chip
=
dev_get_drvdata
(
dev
);
struct
samsung_pwm_chip
*
our_chip
=
dev_get_drvdata
(
dev
);
struct
pwm_chip
*
chip
=
&
our_chip
->
chip
;
unsigned
int
i
;
unsigned
int
i
;
/*
for
(
i
=
0
;
i
<
SAMSUNG_PWM_NUM
;
i
++
)
{
* No one preserves these values during suspend so reset them.
struct
pwm_device
*
pwm
=
&
chip
->
pwms
[
i
];
* Otherwise driver leaves PWM unconfigured if same values are
* passed to pwm_config() next time.
*/
for
(
i
=
0
;
i
<
SAMSUNG_PWM_NUM
;
++
i
)
{
struct
pwm_device
*
pwm
=
&
chip
->
chip
.
pwms
[
i
];
struct
samsung_pwm_channel
*
chan
=
pwm_get_chip_data
(
pwm
);
struct
samsung_pwm_channel
*
chan
=
pwm_get_chip_data
(
pwm
);
if
(
!
chan
)
if
(
!
chan
)
continue
;
continue
;
chan
->
period_ns
=
0
;
if
(
our_chip
->
variant
.
output_mask
&
BIT
(
i
))
chan
->
duty_ns
=
0
;
pwm_samsung_set_invert
(
our_chip
,
i
,
}
our_chip
->
inverter_mask
&
BIT
(
i
));
return
0
;
}
static
int
pwm_samsung_resume
(
struct
device
*
dev
)
if
(
chan
->
period_ns
)
{
{
__pwm_samsung_config
(
chip
,
pwm
,
chan
->
duty_ns
,
struct
samsung_pwm_chip
*
chip
=
dev_get_drvdata
(
dev
);
chan
->
period_ns
,
true
);
unsigned
int
chan
;
/* needed to make PWM disable work on Odroid-XU3 */
pwm_samsung_manual_update
(
our_chip
,
pwm
);
}
/*
if
(
our_chip
->
disabled_mask
&
BIT
(
i
))
* Inverter setting must be preserved across suspend/resume
pwm_samsung_disable
(
chip
,
pwm
);
* as nobody really seems to configure it more than once.
else
*/
pwm_samsung_enable
(
chip
,
pwm
);
for
(
chan
=
0
;
chan
<
SAMSUNG_PWM_NUM
;
++
chan
)
{
if
(
chip
->
variant
.
output_mask
&
BIT
(
chan
))
pwm_samsung_set_invert
(
chip
,
chan
,
chip
->
inverter_mask
&
BIT
(
chan
));
}
}
return
0
;
return
0
;
}
}
#endif
#endif
static
SIMPLE_DEV_PM_OPS
(
pwm_samsung_pm_ops
,
pwm_samsung_suspend
,
static
SIMPLE_DEV_PM_OPS
(
pwm_samsung_pm_ops
,
NULL
,
pwm_samsung_resume
);
pwm_samsung_resume
);
static
struct
platform_driver
pwm_samsung_driver
=
{
static
struct
platform_driver
pwm_samsung_driver
=
{
.
driver
=
{
.
driver
=
{
...
...
drivers/pwm/pwm-tegra.c
浏览文件 @
7755daf5
...
@@ -218,7 +218,7 @@ static int tegra_pwm_probe(struct platform_device *pdev)
...
@@ -218,7 +218,7 @@ static int tegra_pwm_probe(struct platform_device *pdev)
*/
*/
pwm
->
clk_rate
=
clk_get_rate
(
pwm
->
clk
);
pwm
->
clk_rate
=
clk_get_rate
(
pwm
->
clk
);
pwm
->
rst
=
devm_reset_control_get
(
&
pdev
->
dev
,
"pwm"
);
pwm
->
rst
=
devm_reset_control_get
_exclusive
(
&
pdev
->
dev
,
"pwm"
);
if
(
IS_ERR
(
pwm
->
rst
))
{
if
(
IS_ERR
(
pwm
->
rst
))
{
ret
=
PTR_ERR
(
pwm
->
rst
);
ret
=
PTR_ERR
(
pwm
->
rst
);
dev_err
(
&
pdev
->
dev
,
"Reset control is not found: %d
\n
"
,
ret
);
dev_err
(
&
pdev
->
dev
,
"Reset control is not found: %d
\n
"
,
ret
);
...
...
drivers/pwm/pwm-tiecap.c
浏览文件 @
7755daf5
...
@@ -39,15 +39,15 @@
...
@@ -39,15 +39,15 @@
#define ECCTL2_TSCTR_FREERUN BIT(4)
#define ECCTL2_TSCTR_FREERUN BIT(4)
struct
ecap_context
{
struct
ecap_context
{
u32
cap3
;
u32
cap3
;
u32
cap4
;
u32
cap4
;
u16
ecctl2
;
u16
ecctl2
;
};
};
struct
ecap_pwm_chip
{
struct
ecap_pwm_chip
{
struct
pwm_chip
chip
;
struct
pwm_chip
chip
;
unsigned
int
clk_rate
;
unsigned
int
clk_rate
;
void
__iomem
*
mmio_base
;
void
__iomem
*
mmio_base
;
struct
ecap_context
ctx
;
struct
ecap_context
ctx
;
};
};
...
@@ -64,9 +64,9 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -64,9 +64,9 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int
duty_ns
,
int
period_ns
)
int
duty_ns
,
int
period_ns
)
{
{
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
u32
period_cycles
,
duty_cycles
;
unsigned
long
long
c
;
unsigned
long
long
c
;
unsigned
long
period_cycles
,
duty_cycles
;
u16
value
;
unsigned
int
reg_val
;
if
(
period_ns
>
NSEC_PER_SEC
)
if
(
period_ns
>
NSEC_PER_SEC
)
return
-
ERANGE
;
return
-
ERANGE
;
...
@@ -74,7 +74,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -74,7 +74,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
c
=
pc
->
clk_rate
;
c
=
pc
->
clk_rate
;
c
=
c
*
period_ns
;
c
=
c
*
period_ns
;
do_div
(
c
,
NSEC_PER_SEC
);
do_div
(
c
,
NSEC_PER_SEC
);
period_cycles
=
(
u
nsigned
long
)
c
;
period_cycles
=
(
u
32
)
c
;
if
(
period_cycles
<
1
)
{
if
(
period_cycles
<
1
)
{
period_cycles
=
1
;
period_cycles
=
1
;
...
@@ -83,17 +83,17 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -83,17 +83,17 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
c
=
pc
->
clk_rate
;
c
=
pc
->
clk_rate
;
c
=
c
*
duty_ns
;
c
=
c
*
duty_ns
;
do_div
(
c
,
NSEC_PER_SEC
);
do_div
(
c
,
NSEC_PER_SEC
);
duty_cycles
=
(
u
nsigned
long
)
c
;
duty_cycles
=
(
u
32
)
c
;
}
}
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
reg_val
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
value
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
/* Configure APWM mode & disable sync option */
/* Configure APWM mode & disable sync option */
reg_val
|=
ECCTL2_APWM_MODE
|
ECCTL2_SYNC_SEL_DISA
;
value
|=
ECCTL2_APWM_MODE
|
ECCTL2_SYNC_SEL_DISA
;
writew
(
reg_val
,
pc
->
mmio_base
+
ECCTL2
);
writew
(
value
,
pc
->
mmio_base
+
ECCTL2
);
if
(
!
pwm_is_enabled
(
pwm
))
{
if
(
!
pwm_is_enabled
(
pwm
))
{
/* Update active registers if not running */
/* Update active registers if not running */
...
@@ -110,40 +110,45 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -110,40 +110,45 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
}
}
if
(
!
pwm_is_enabled
(
pwm
))
{
if
(
!
pwm_is_enabled
(
pwm
))
{
reg_val
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
value
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
/* Disable APWM mode to put APWM output Low */
/* Disable APWM mode to put APWM output Low */
reg_val
&=
~
ECCTL2_APWM_MODE
;
value
&=
~
ECCTL2_APWM_MODE
;
writew
(
reg_val
,
pc
->
mmio_base
+
ECCTL2
);
writew
(
value
,
pc
->
mmio_base
+
ECCTL2
);
}
}
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
return
0
;
return
0
;
}
}
static
int
ecap_pwm_set_polarity
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
static
int
ecap_pwm_set_polarity
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
enum
pwm_polarity
polarity
)
enum
pwm_polarity
polarity
)
{
{
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
u
nsigned
short
reg_val
;
u
16
value
;
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
reg_val
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
value
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
if
(
polarity
==
PWM_POLARITY_INVERSED
)
if
(
polarity
==
PWM_POLARITY_INVERSED
)
/* Duty cycle defines LOW period of PWM */
/* Duty cycle defines LOW period of PWM */
reg_val
|=
ECCTL2_APWM_POL_LOW
;
value
|=
ECCTL2_APWM_POL_LOW
;
else
else
/* Duty cycle defines HIGH period of PWM */
/* Duty cycle defines HIGH period of PWM */
reg_val
&=
~
ECCTL2_APWM_POL_LOW
;
value
&=
~
ECCTL2_APWM_POL_LOW
;
writew
(
value
,
pc
->
mmio_base
+
ECCTL2
);
writew
(
reg_val
,
pc
->
mmio_base
+
ECCTL2
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
return
0
;
return
0
;
}
}
static
int
ecap_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
int
ecap_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
{
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
u
nsigned
int
reg_val
;
u
16
value
;
/* Leave clock enabled on enabling PWM */
/* Leave clock enabled on enabling PWM */
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
...
@@ -152,24 +157,25 @@ static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -152,24 +157,25 @@ static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
* Enable 'Free run Time stamp counter mode' to start counter
* Enable 'Free run Time stamp counter mode' to start counter
* and 'APWM mode' to enable APWM output
* and 'APWM mode' to enable APWM output
*/
*/
reg_val
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
value
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
reg_val
|=
ECCTL2_TSCTR_FREERUN
|
ECCTL2_APWM_MODE
;
value
|=
ECCTL2_TSCTR_FREERUN
|
ECCTL2_APWM_MODE
;
writew
(
reg_val
,
pc
->
mmio_base
+
ECCTL2
);
writew
(
value
,
pc
->
mmio_base
+
ECCTL2
);
return
0
;
return
0
;
}
}
static
void
ecap_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
void
ecap_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
{
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
struct
ecap_pwm_chip
*
pc
=
to_ecap_pwm_chip
(
chip
);
u
nsigned
int
reg_val
;
u
16
value
;
/*
/*
* Disable 'Free run Time stamp counter mode' to stop counter
* Disable 'Free run Time stamp counter mode' to stop counter
* and 'APWM mode' to put APWM output to low
* and 'APWM mode' to put APWM output to low
*/
*/
reg_val
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
value
=
readw
(
pc
->
mmio_base
+
ECCTL2
);
reg_val
&=
~
(
ECCTL2_TSCTR_FREERUN
|
ECCTL2_APWM_MODE
);
value
&=
~
(
ECCTL2_TSCTR_FREERUN
|
ECCTL2_APWM_MODE
);
writew
(
reg_val
,
pc
->
mmio_base
+
ECCTL2
);
writew
(
value
,
pc
->
mmio_base
+
ECCTL2
);
/* Disable clock on PWM disable */
/* Disable clock on PWM disable */
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
...
@@ -184,12 +190,12 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -184,12 +190,12 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
}
}
static
const
struct
pwm_ops
ecap_pwm_ops
=
{
static
const
struct
pwm_ops
ecap_pwm_ops
=
{
.
free
=
ecap_pwm_free
,
.
free
=
ecap_pwm_free
,
.
config
=
ecap_pwm_config
,
.
config
=
ecap_pwm_config
,
.
set_polarity
=
ecap_pwm_set_polarity
,
.
set_polarity
=
ecap_pwm_set_polarity
,
.
enable
=
ecap_pwm_enable
,
.
enable
=
ecap_pwm_enable
,
.
disable
=
ecap_pwm_disable
,
.
disable
=
ecap_pwm_disable
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
};
};
static
const
struct
of_device_id
ecap_of_match
[]
=
{
static
const
struct
of_device_id
ecap_of_match
[]
=
{
...
@@ -202,10 +208,10 @@ MODULE_DEVICE_TABLE(of, ecap_of_match);
...
@@ -202,10 +208,10 @@ MODULE_DEVICE_TABLE(of, ecap_of_match);
static
int
ecap_pwm_probe
(
struct
platform_device
*
pdev
)
static
int
ecap_pwm_probe
(
struct
platform_device
*
pdev
)
{
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
int
ret
;
struct
ecap_pwm_chip
*
pc
;
struct
resource
*
r
;
struct
resource
*
r
;
struct
clk
*
clk
;
struct
clk
*
clk
;
struct
ecap_pwm_chip
*
pc
;
int
ret
;
pc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pc
),
GFP_KERNEL
);
pc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pc
),
GFP_KERNEL
);
if
(
!
pc
)
if
(
!
pc
)
...
@@ -248,9 +254,9 @@ static int ecap_pwm_probe(struct platform_device *pdev)
...
@@ -248,9 +254,9 @@ static int ecap_pwm_probe(struct platform_device *pdev)
return
ret
;
return
ret
;
}
}
platform_set_drvdata
(
pdev
,
pc
);
pm_runtime_enable
(
&
pdev
->
dev
);
pm_runtime_enable
(
&
pdev
->
dev
);
platform_set_drvdata
(
pdev
,
pc
);
return
0
;
return
0
;
}
}
...
@@ -259,6 +265,7 @@ static int ecap_pwm_remove(struct platform_device *pdev)
...
@@ -259,6 +265,7 @@ static int ecap_pwm_remove(struct platform_device *pdev)
struct
ecap_pwm_chip
*
pc
=
platform_get_drvdata
(
pdev
);
struct
ecap_pwm_chip
*
pc
=
platform_get_drvdata
(
pdev
);
pm_runtime_disable
(
&
pdev
->
dev
);
pm_runtime_disable
(
&
pdev
->
dev
);
return
pwmchip_remove
(
&
pc
->
chip
);
return
pwmchip_remove
(
&
pc
->
chip
);
}
}
...
@@ -311,14 +318,13 @@ static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
...
@@ -311,14 +318,13 @@ static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
static
struct
platform_driver
ecap_pwm_driver
=
{
static
struct
platform_driver
ecap_pwm_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"ecap"
,
.
name
=
"ecap"
,
.
of_match_table
=
ecap_of_match
,
.
of_match_table
=
ecap_of_match
,
.
pm
=
&
ecap_pwm_pm_ops
,
.
pm
=
&
ecap_pwm_pm_ops
,
},
},
.
probe
=
ecap_pwm_probe
,
.
probe
=
ecap_pwm_probe
,
.
remove
=
ecap_pwm_remove
,
.
remove
=
ecap_pwm_remove
,
};
};
module_platform_driver
(
ecap_pwm_driver
);
module_platform_driver
(
ecap_pwm_driver
);
MODULE_DESCRIPTION
(
"ECAP PWM driver"
);
MODULE_DESCRIPTION
(
"ECAP PWM driver"
);
...
...
drivers/pwm/pwm-tiehrpwm.c
浏览文件 @
7755daf5
...
@@ -122,12 +122,12 @@ struct ehrpwm_context {
...
@@ -122,12 +122,12 @@ struct ehrpwm_context {
};
};
struct
ehrpwm_pwm_chip
{
struct
ehrpwm_pwm_chip
{
struct
pwm_chip
chip
;
struct
pwm_chip
chip
;
unsigned
int
clk_rate
;
unsigned
long
clk_rate
;
void
__iomem
*
mmio_base
;
void
__iomem
*
mmio_base
;
unsigned
long
period_cycles
[
NUM_PWM_CHANNEL
];
unsigned
long
period_cycles
[
NUM_PWM_CHANNEL
];
enum
pwm_polarity
polarity
[
NUM_PWM_CHANNEL
];
enum
pwm_polarity
polarity
[
NUM_PWM_CHANNEL
];
struct
clk
*
tbclk
;
struct
clk
*
tbclk
;
struct
ehrpwm_context
ctx
;
struct
ehrpwm_context
ctx
;
};
};
...
@@ -136,25 +136,26 @@ static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
...
@@ -136,25 +136,26 @@ static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
return
container_of
(
chip
,
struct
ehrpwm_pwm_chip
,
chip
);
return
container_of
(
chip
,
struct
ehrpwm_pwm_chip
,
chip
);
}
}
static
inline
u16
ehrpwm_read
(
void
__iomem
*
base
,
int
offset
)
static
inline
u16
ehrpwm_read
(
void
__iomem
*
base
,
unsigned
int
offset
)
{
{
return
readw
(
base
+
offset
);
return
readw
(
base
+
offset
);
}
}
static
inline
void
ehrpwm_write
(
void
__iomem
*
base
,
int
offset
,
unsigned
int
val
)
static
inline
void
ehrpwm_write
(
void
__iomem
*
base
,
unsigned
int
offset
,
u16
value
)
{
{
writew
(
val
&
0xFFFF
,
base
+
offset
);
writew
(
val
ue
,
base
+
offset
);
}
}
static
void
ehrpwm_modify
(
void
__iomem
*
base
,
int
offset
,
static
void
ehrpwm_modify
(
void
__iomem
*
base
,
unsigned
int
offset
,
u16
mask
,
unsigned
short
mask
,
unsigned
short
val
)
u16
value
)
{
{
unsigned
short
reg
val
;
unsigned
short
val
;
reg
val
=
readw
(
base
+
offset
);
val
=
readw
(
base
+
offset
);
reg
val
&=
~
mask
;
val
&=
~
mask
;
regval
|=
val
&
mask
;
val
|=
value
&
mask
;
writew
(
reg
val
,
base
+
offset
);
writew
(
val
,
base
+
offset
);
}
}
/**
/**
...
@@ -163,14 +164,13 @@ static void ehrpwm_modify(void __iomem *base, int offset,
...
@@ -163,14 +164,13 @@ static void ehrpwm_modify(void __iomem *base, int offset,
* @prescale_div: prescaler value set
* @prescale_div: prescaler value set
* @tb_clk_div: Time Base Control prescaler bits
* @tb_clk_div: Time Base Control prescaler bits
*/
*/
static
int
set_prescale_div
(
unsigned
long
rqst_prescaler
,
static
int
set_prescale_div
(
unsigned
long
rqst_prescaler
,
u16
*
prescale_div
,
unsigned
short
*
prescale_div
,
unsigned
short
*
tb_clk_div
)
u16
*
tb_clk_div
)
{
{
unsigned
int
clkdiv
,
hspclkdiv
;
unsigned
int
clkdiv
,
hspclkdiv
;
for
(
clkdiv
=
0
;
clkdiv
<=
CLKDIV_MAX
;
clkdiv
++
)
{
for
(
clkdiv
=
0
;
clkdiv
<=
CLKDIV_MAX
;
clkdiv
++
)
{
for
(
hspclkdiv
=
0
;
hspclkdiv
<=
HSPCLKDIV_MAX
;
hspclkdiv
++
)
{
for
(
hspclkdiv
=
0
;
hspclkdiv
<=
HSPCLKDIV_MAX
;
hspclkdiv
++
)
{
/*
/*
* calculations for prescaler value :
* calculations for prescaler value :
* prescale_div = HSPCLKDIVIDER * CLKDIVIDER.
* prescale_div = HSPCLKDIVIDER * CLKDIVIDER.
...
@@ -191,13 +191,14 @@ static int set_prescale_div(unsigned long rqst_prescaler,
...
@@ -191,13 +191,14 @@ static int set_prescale_div(unsigned long rqst_prescaler,
}
}
}
}
}
}
return
1
;
return
1
;
}
}
static
void
configure_polarity
(
struct
ehrpwm_pwm_chip
*
pc
,
int
chan
)
static
void
configure_polarity
(
struct
ehrpwm_pwm_chip
*
pc
,
int
chan
)
{
{
int
aqctl_reg
;
u16
aqctl_val
,
aqctl_mask
;
unsigned
short
aqctl_val
,
aqctl_mask
;
unsigned
int
aqctl_reg
;
/*
/*
* Configure PWM output to HIGH/LOW level on counter
* Configure PWM output to HIGH/LOW level on counter
...
@@ -232,13 +233,13 @@ static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)
...
@@ -232,13 +233,13 @@ static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)
* duty_ns = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE
* duty_ns = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE
*/
*/
static
int
ehrpwm_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
static
int
ehrpwm_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
int
duty_ns
,
int
period_ns
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
u32
period_cycles
,
duty_cycles
;
u16
ps_divval
,
tb_divval
;
unsigned
int
i
,
cmp_reg
;
unsigned
long
long
c
;
unsigned
long
long
c
;
unsigned
long
period_cycles
,
duty_cycles
;
unsigned
short
ps_divval
,
tb_divval
;
int
i
,
cmp_reg
;
if
(
period_ns
>
NSEC_PER_SEC
)
if
(
period_ns
>
NSEC_PER_SEC
)
return
-
ERANGE
;
return
-
ERANGE
;
...
@@ -272,8 +273,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -272,8 +273,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if
(
i
==
pwm
->
hwpwm
)
if
(
i
==
pwm
->
hwpwm
)
continue
;
continue
;
dev_err
(
chip
->
dev
,
"Period value conflicts with channel %d
\n
"
,
dev_err
(
chip
->
dev
,
i
);
"period value conflicts with channel %u
\n
"
,
i
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
}
}
...
@@ -282,7 +284,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -282,7 +284,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
/* Configure clock prescaler to support Low frequency PWM wave */
/* Configure clock prescaler to support Low frequency PWM wave */
if
(
set_prescale_div
(
period_cycles
/
PERIOD_MAX
,
&
ps_divval
,
if
(
set_prescale_div
(
period_cycles
/
PERIOD_MAX
,
&
ps_divval
,
&
tb_divval
))
{
&
tb_divval
))
{
dev_err
(
chip
->
dev
,
"Unsupported values
\n
"
);
dev_err
(
chip
->
dev
,
"Unsupported values
\n
"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
...
@@ -303,7 +305,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -303,7 +305,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
/* Configure ehrpwm counter for up-count mode */
/* Configure ehrpwm counter for up-count mode */
ehrpwm_modify
(
pc
->
mmio_base
,
TBCTL
,
TBCTL_CTRMODE_MASK
,
ehrpwm_modify
(
pc
->
mmio_base
,
TBCTL
,
TBCTL_CTRMODE_MASK
,
TBCTL_CTRMODE_UP
);
TBCTL_CTRMODE_UP
);
if
(
pwm
->
hwpwm
==
1
)
if
(
pwm
->
hwpwm
==
1
)
/* Channel 1 configured with compare B register */
/* Channel 1 configured with compare B register */
...
@@ -315,23 +317,26 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
...
@@ -315,23 +317,26 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ehrpwm_write
(
pc
->
mmio_base
,
cmp_reg
,
duty_cycles
);
ehrpwm_write
(
pc
->
mmio_base
,
cmp_reg
,
duty_cycles
);
pm_runtime_put_sync
(
chip
->
dev
);
pm_runtime_put_sync
(
chip
->
dev
);
return
0
;
return
0
;
}
}
static
int
ehrpwm_pwm_set_polarity
(
struct
pwm_chip
*
chip
,
static
int
ehrpwm_pwm_set_polarity
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
enum
pwm_polarity
polarity
)
struct
pwm_device
*
pwm
,
enum
pwm_polarity
polarity
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
/* Configuration of polarity in hardware delayed, do at enable */
/* Configuration of polarity in hardware delayed, do at enable */
pc
->
polarity
[
pwm
->
hwpwm
]
=
polarity
;
pc
->
polarity
[
pwm
->
hwpwm
]
=
polarity
;
return
0
;
return
0
;
}
}
static
int
ehrpwm_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
int
ehrpwm_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
u
nsigned
short
aqcsfrc_val
,
aqcsfrc_mask
;
u
16
aqcsfrc_val
,
aqcsfrc_mask
;
int
ret
;
int
ret
;
/* Leave clock enabled on enabling PWM */
/* Leave clock enabled on enabling PWM */
...
@@ -348,7 +353,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -348,7 +353,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
/* Changes to shadow mode */
/* Changes to shadow mode */
ehrpwm_modify
(
pc
->
mmio_base
,
AQSFRC
,
AQSFRC_RLDCSF_MASK
,
ehrpwm_modify
(
pc
->
mmio_base
,
AQSFRC
,
AQSFRC_RLDCSF_MASK
,
AQSFRC_RLDCSF_ZRO
);
AQSFRC_RLDCSF_ZRO
);
ehrpwm_modify
(
pc
->
mmio_base
,
AQCSFRC
,
aqcsfrc_mask
,
aqcsfrc_val
);
ehrpwm_modify
(
pc
->
mmio_base
,
AQCSFRC
,
aqcsfrc_mask
,
aqcsfrc_val
);
...
@@ -358,20 +363,21 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -358,20 +363,21 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
/* Enable TBCLK before enabling PWM device */
/* Enable TBCLK before enabling PWM device */
ret
=
clk_enable
(
pc
->
tbclk
);
ret
=
clk_enable
(
pc
->
tbclk
);
if
(
ret
)
{
if
(
ret
)
{
dev_err
(
chip
->
dev
,
"Failed to enable TBCLK for %s
\n
"
,
dev_err
(
chip
->
dev
,
"Failed to enable TBCLK for %s
: %d
\n
"
,
dev_name
(
pc
->
chip
.
dev
));
dev_name
(
pc
->
chip
.
dev
)
,
ret
);
return
ret
;
return
ret
;
}
}
/* Enable time counter for free_run */
/* Enable time counter for free_run */
ehrpwm_modify
(
pc
->
mmio_base
,
TBCTL
,
TBCTL_RUN_MASK
,
TBCTL_FREE_RUN
);
ehrpwm_modify
(
pc
->
mmio_base
,
TBCTL
,
TBCTL_RUN_MASK
,
TBCTL_FREE_RUN
);
return
0
;
return
0
;
}
}
static
void
ehrpwm_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
void
ehrpwm_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
struct
ehrpwm_pwm_chip
*
pc
=
to_ehrpwm_pwm_chip
(
chip
);
u
nsigned
short
aqcsfrc_val
,
aqcsfrc_mask
;
u
16
aqcsfrc_val
,
aqcsfrc_mask
;
/* Action Qualifier puts PWM output low forcefully */
/* Action Qualifier puts PWM output low forcefully */
if
(
pwm
->
hwpwm
)
{
if
(
pwm
->
hwpwm
)
{
...
@@ -387,7 +393,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -387,7 +393,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
* Action Qualifier control on PWM output from next TBCLK
* Action Qualifier control on PWM output from next TBCLK
*/
*/
ehrpwm_modify
(
pc
->
mmio_base
,
AQSFRC
,
AQSFRC_RLDCSF_MASK
,
ehrpwm_modify
(
pc
->
mmio_base
,
AQSFRC
,
AQSFRC_RLDCSF_MASK
,
AQSFRC_RLDCSF_IMDT
);
AQSFRC_RLDCSF_IMDT
);
ehrpwm_modify
(
pc
->
mmio_base
,
AQCSFRC
,
aqcsfrc_mask
,
aqcsfrc_val
);
ehrpwm_modify
(
pc
->
mmio_base
,
AQCSFRC
,
aqcsfrc_mask
,
aqcsfrc_val
);
...
@@ -415,17 +421,17 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
...
@@ -415,17 +421,17 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
}
}
static
const
struct
pwm_ops
ehrpwm_pwm_ops
=
{
static
const
struct
pwm_ops
ehrpwm_pwm_ops
=
{
.
free
=
ehrpwm_pwm_free
,
.
free
=
ehrpwm_pwm_free
,
.
config
=
ehrpwm_pwm_config
,
.
config
=
ehrpwm_pwm_config
,
.
set_polarity
=
ehrpwm_pwm_set_polarity
,
.
set_polarity
=
ehrpwm_pwm_set_polarity
,
.
enable
=
ehrpwm_pwm_enable
,
.
enable
=
ehrpwm_pwm_enable
,
.
disable
=
ehrpwm_pwm_disable
,
.
disable
=
ehrpwm_pwm_disable
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
};
};
static
const
struct
of_device_id
ehrpwm_of_match
[]
=
{
static
const
struct
of_device_id
ehrpwm_of_match
[]
=
{
{
.
compatible
=
"ti,am3352-ehrpwm"
},
{
.
compatible
=
"ti,am3352-ehrpwm"
},
{
.
compatible
=
"ti,am33xx-ehrpwm"
},
{
.
compatible
=
"ti,am33xx-ehrpwm"
},
{},
{},
};
};
MODULE_DEVICE_TABLE
(
of
,
ehrpwm_of_match
);
MODULE_DEVICE_TABLE
(
of
,
ehrpwm_of_match
);
...
@@ -433,10 +439,10 @@ MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
...
@@ -433,10 +439,10 @@ MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
static
int
ehrpwm_pwm_probe
(
struct
platform_device
*
pdev
)
static
int
ehrpwm_pwm_probe
(
struct
platform_device
*
pdev
)
{
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
int
ret
;
struct
ehrpwm_pwm_chip
*
pc
;
struct
resource
*
r
;
struct
resource
*
r
;
struct
clk
*
clk
;
struct
clk
*
clk
;
struct
ehrpwm_pwm_chip
*
pc
;
int
ret
;
pc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pc
),
GFP_KERNEL
);
pc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pc
),
GFP_KERNEL
);
if
(
!
pc
)
if
(
!
pc
)
...
@@ -489,13 +495,18 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
...
@@ -489,13 +495,18 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
ret
=
pwmchip_add
(
&
pc
->
chip
);
ret
=
pwmchip_add
(
&
pc
->
chip
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
dev_err
(
&
pdev
->
dev
,
"pwmchip_add() failed: %d
\n
"
,
ret
);
return
ret
;
goto
err_clk_unprepare
;
}
}
platform_set_drvdata
(
pdev
,
pc
);
pm_runtime_enable
(
&
pdev
->
dev
);
pm_runtime_enable
(
&
pdev
->
dev
);
platform_set_drvdata
(
pdev
,
pc
);
return
0
;
return
0
;
err_clk_unprepare:
clk_unprepare
(
pc
->
tbclk
);
return
ret
;
}
}
static
int
ehrpwm_pwm_remove
(
struct
platform_device
*
pdev
)
static
int
ehrpwm_pwm_remove
(
struct
platform_device
*
pdev
)
...
@@ -504,8 +515,8 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
...
@@ -504,8 +515,8 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
clk_unprepare
(
pc
->
tbclk
);
clk_unprepare
(
pc
->
tbclk
);
pm_runtime_put_sync
(
&
pdev
->
dev
);
pm_runtime_disable
(
&
pdev
->
dev
);
pm_runtime_disable
(
&
pdev
->
dev
);
return
pwmchip_remove
(
&
pc
->
chip
);
return
pwmchip_remove
(
&
pc
->
chip
);
}
}
...
@@ -513,6 +524,7 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
...
@@ -513,6 +524,7 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
static
void
ehrpwm_pwm_save_context
(
struct
ehrpwm_pwm_chip
*
pc
)
static
void
ehrpwm_pwm_save_context
(
struct
ehrpwm_pwm_chip
*
pc
)
{
{
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
pm_runtime_get_sync
(
pc
->
chip
.
dev
);
pc
->
ctx
.
tbctl
=
ehrpwm_read
(
pc
->
mmio_base
,
TBCTL
);
pc
->
ctx
.
tbctl
=
ehrpwm_read
(
pc
->
mmio_base
,
TBCTL
);
pc
->
ctx
.
tbprd
=
ehrpwm_read
(
pc
->
mmio_base
,
TBPRD
);
pc
->
ctx
.
tbprd
=
ehrpwm_read
(
pc
->
mmio_base
,
TBPRD
);
pc
->
ctx
.
cmpa
=
ehrpwm_read
(
pc
->
mmio_base
,
CMPA
);
pc
->
ctx
.
cmpa
=
ehrpwm_read
(
pc
->
mmio_base
,
CMPA
);
...
@@ -521,6 +533,7 @@ static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
...
@@ -521,6 +533,7 @@ static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
pc
->
ctx
.
aqctlb
=
ehrpwm_read
(
pc
->
mmio_base
,
AQCTLB
);
pc
->
ctx
.
aqctlb
=
ehrpwm_read
(
pc
->
mmio_base
,
AQCTLB
);
pc
->
ctx
.
aqsfrc
=
ehrpwm_read
(
pc
->
mmio_base
,
AQSFRC
);
pc
->
ctx
.
aqsfrc
=
ehrpwm_read
(
pc
->
mmio_base
,
AQSFRC
);
pc
->
ctx
.
aqcsfrc
=
ehrpwm_read
(
pc
->
mmio_base
,
AQCSFRC
);
pc
->
ctx
.
aqcsfrc
=
ehrpwm_read
(
pc
->
mmio_base
,
AQCSFRC
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
pm_runtime_put_sync
(
pc
->
chip
.
dev
);
}
}
...
@@ -539,9 +552,10 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
...
@@ -539,9 +552,10 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
static
int
ehrpwm_pwm_suspend
(
struct
device
*
dev
)
static
int
ehrpwm_pwm_suspend
(
struct
device
*
dev
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
dev_get_drvdata
(
dev
);
struct
ehrpwm_pwm_chip
*
pc
=
dev_get_drvdata
(
dev
);
int
i
;
unsigned
int
i
;
ehrpwm_pwm_save_context
(
pc
);
ehrpwm_pwm_save_context
(
pc
);
for
(
i
=
0
;
i
<
pc
->
chip
.
npwm
;
i
++
)
{
for
(
i
=
0
;
i
<
pc
->
chip
.
npwm
;
i
++
)
{
struct
pwm_device
*
pwm
=
&
pc
->
chip
.
pwms
[
i
];
struct
pwm_device
*
pwm
=
&
pc
->
chip
.
pwms
[
i
];
...
@@ -551,13 +565,14 @@ static int ehrpwm_pwm_suspend(struct device *dev)
...
@@ -551,13 +565,14 @@ static int ehrpwm_pwm_suspend(struct device *dev)
/* Disable explicitly if PWM is running */
/* Disable explicitly if PWM is running */
pm_runtime_put_sync
(
dev
);
pm_runtime_put_sync
(
dev
);
}
}
return
0
;
return
0
;
}
}
static
int
ehrpwm_pwm_resume
(
struct
device
*
dev
)
static
int
ehrpwm_pwm_resume
(
struct
device
*
dev
)
{
{
struct
ehrpwm_pwm_chip
*
pc
=
dev_get_drvdata
(
dev
);
struct
ehrpwm_pwm_chip
*
pc
=
dev_get_drvdata
(
dev
);
int
i
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
pc
->
chip
.
npwm
;
i
++
)
{
for
(
i
=
0
;
i
<
pc
->
chip
.
npwm
;
i
++
)
{
struct
pwm_device
*
pwm
=
&
pc
->
chip
.
pwms
[
i
];
struct
pwm_device
*
pwm
=
&
pc
->
chip
.
pwms
[
i
];
...
@@ -568,24 +583,25 @@ static int ehrpwm_pwm_resume(struct device *dev)
...
@@ -568,24 +583,25 @@ static int ehrpwm_pwm_resume(struct device *dev)
/* Enable explicitly if PWM was running */
/* Enable explicitly if PWM was running */
pm_runtime_get_sync
(
dev
);
pm_runtime_get_sync
(
dev
);
}
}
ehrpwm_pwm_restore_context
(
pc
);
ehrpwm_pwm_restore_context
(
pc
);
return
0
;
return
0
;
}
}
#endif
#endif
static
SIMPLE_DEV_PM_OPS
(
ehrpwm_pwm_pm_ops
,
ehrpwm_pwm_suspend
,
static
SIMPLE_DEV_PM_OPS
(
ehrpwm_pwm_pm_ops
,
ehrpwm_pwm_suspend
,
ehrpwm_pwm_resume
);
ehrpwm_pwm_resume
);
static
struct
platform_driver
ehrpwm_pwm_driver
=
{
static
struct
platform_driver
ehrpwm_pwm_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"ehrpwm"
,
.
name
=
"ehrpwm"
,
.
of_match_table
=
ehrpwm_of_match
,
.
of_match_table
=
ehrpwm_of_match
,
.
pm
=
&
ehrpwm_pwm_pm_ops
,
.
pm
=
&
ehrpwm_pwm_pm_ops
,
},
},
.
probe
=
ehrpwm_pwm_probe
,
.
probe
=
ehrpwm_pwm_probe
,
.
remove
=
ehrpwm_pwm_remove
,
.
remove
=
ehrpwm_pwm_remove
,
};
};
module_platform_driver
(
ehrpwm_pwm_driver
);
module_platform_driver
(
ehrpwm_pwm_driver
);
MODULE_DESCRIPTION
(
"EHRPWM PWM driver"
);
MODULE_DESCRIPTION
(
"EHRPWM PWM driver"
);
...
...
drivers/pwm/pwm-vt8500.c
浏览文件 @
7755daf5
...
@@ -241,6 +241,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
...
@@ -241,6 +241,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
ret
=
pwmchip_add
(
&
chip
->
chip
);
ret
=
pwmchip_add
(
&
chip
->
chip
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"failed to add PWM chip
\n
"
);
dev_err
(
&
pdev
->
dev
,
"failed to add PWM chip
\n
"
);
clk_unprepare
(
chip
->
clk
);
return
ret
;
return
ret
;
}
}
...
...
drivers/pwm/pwm-zx.c
0 → 100644
浏览文件 @
7755daf5
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#define ZX_PWM_MODE 0x0
#define ZX_PWM_CLKDIV_SHIFT 2
#define ZX_PWM_CLKDIV_MASK GENMASK(11, 2)
#define ZX_PWM_CLKDIV(x) (((x) << ZX_PWM_CLKDIV_SHIFT) & \
ZX_PWM_CLKDIV_MASK)
#define ZX_PWM_POLAR BIT(1)
#define ZX_PWM_EN BIT(0)
#define ZX_PWM_PERIOD 0x4
#define ZX_PWM_DUTY 0x8
#define ZX_PWM_CLKDIV_MAX 1023
#define ZX_PWM_PERIOD_MAX 65535
struct
zx_pwm_chip
{
struct
pwm_chip
chip
;
struct
clk
*
pclk
;
struct
clk
*
wclk
;
void
__iomem
*
base
;
};
static
inline
struct
zx_pwm_chip
*
to_zx_pwm_chip
(
struct
pwm_chip
*
chip
)
{
return
container_of
(
chip
,
struct
zx_pwm_chip
,
chip
);
}
static
inline
u32
zx_pwm_readl
(
struct
zx_pwm_chip
*
zpc
,
unsigned
int
hwpwm
,
unsigned
int
offset
)
{
return
readl
(
zpc
->
base
+
(
hwpwm
+
1
)
*
0x10
+
offset
);
}
static
inline
void
zx_pwm_writel
(
struct
zx_pwm_chip
*
zpc
,
unsigned
int
hwpwm
,
unsigned
int
offset
,
u32
value
)
{
writel
(
value
,
zpc
->
base
+
(
hwpwm
+
1
)
*
0x10
+
offset
);
}
static
void
zx_pwm_set_mask
(
struct
zx_pwm_chip
*
zpc
,
unsigned
int
hwpwm
,
unsigned
int
offset
,
u32
mask
,
u32
value
)
{
u32
data
;
data
=
zx_pwm_readl
(
zpc
,
hwpwm
,
offset
);
data
&=
~
mask
;
data
|=
value
&
mask
;
zx_pwm_writel
(
zpc
,
hwpwm
,
offset
,
data
);
}
static
void
zx_pwm_get_state
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
zx_pwm_chip
*
zpc
=
to_zx_pwm_chip
(
chip
);
unsigned
long
rate
;
unsigned
int
div
;
u32
value
;
u64
tmp
;
value
=
zx_pwm_readl
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
);
if
(
value
&
ZX_PWM_POLAR
)
state
->
polarity
=
PWM_POLARITY_NORMAL
;
else
state
->
polarity
=
PWM_POLARITY_INVERSED
;
if
(
value
&
ZX_PWM_EN
)
state
->
enabled
=
true
;
else
state
->
enabled
=
false
;
div
=
(
value
&
ZX_PWM_CLKDIV_MASK
)
>>
ZX_PWM_CLKDIV_SHIFT
;
rate
=
clk_get_rate
(
zpc
->
wclk
);
tmp
=
zx_pwm_readl
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_PERIOD
);
tmp
*=
div
*
NSEC_PER_SEC
;
state
->
period
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
rate
);
tmp
=
zx_pwm_readl
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_DUTY
);
tmp
*=
div
*
NSEC_PER_SEC
;
state
->
duty_cycle
=
DIV_ROUND_CLOSEST_ULL
(
tmp
,
rate
);
}
static
int
zx_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
unsigned
int
duty_ns
,
unsigned
int
period_ns
)
{
struct
zx_pwm_chip
*
zpc
=
to_zx_pwm_chip
(
chip
);
unsigned
int
period_cycles
,
duty_cycles
;
unsigned
long
long
c
;
unsigned
int
div
=
1
;
unsigned
long
rate
;
/* Find out the best divider */
rate
=
clk_get_rate
(
zpc
->
wclk
);
while
(
1
)
{
c
=
rate
/
div
;
c
=
c
*
period_ns
;
do_div
(
c
,
NSEC_PER_SEC
);
if
(
c
<
ZX_PWM_PERIOD_MAX
)
break
;
div
++
;
if
(
div
>
ZX_PWM_CLKDIV_MAX
)
return
-
ERANGE
;
}
/* Calculate duty cycles */
period_cycles
=
c
;
c
*=
duty_ns
;
do_div
(
c
,
period_ns
);
duty_cycles
=
c
;
/*
* If the PWM is being enabled, we have to temporarily disable it
* before configuring the registers.
*/
if
(
pwm_is_enabled
(
pwm
))
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_EN
,
0
);
/* Set up registers */
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_CLKDIV_MASK
,
ZX_PWM_CLKDIV
(
div
));
zx_pwm_writel
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_PERIOD
,
period_cycles
);
zx_pwm_writel
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_DUTY
,
duty_cycles
);
/* Re-enable the PWM if needed */
if
(
pwm_is_enabled
(
pwm
))
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_EN
,
ZX_PWM_EN
);
return
0
;
}
static
int
zx_pwm_apply
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
struct
zx_pwm_chip
*
zpc
=
to_zx_pwm_chip
(
chip
);
struct
pwm_state
cstate
;
int
ret
;
pwm_get_state
(
pwm
,
&
cstate
);
if
(
state
->
polarity
!=
cstate
.
polarity
)
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_POLAR
,
(
state
->
polarity
==
PWM_POLARITY_INVERSED
)
?
0
:
ZX_PWM_POLAR
);
if
(
state
->
period
!=
cstate
.
period
||
state
->
duty_cycle
!=
cstate
.
duty_cycle
)
{
ret
=
zx_pwm_config
(
chip
,
pwm
,
state
->
duty_cycle
,
state
->
period
);
if
(
ret
)
return
ret
;
}
if
(
state
->
enabled
!=
cstate
.
enabled
)
{
if
(
state
->
enabled
)
{
ret
=
clk_prepare_enable
(
zpc
->
wclk
);
if
(
ret
)
return
ret
;
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_EN
,
ZX_PWM_EN
);
}
else
{
zx_pwm_set_mask
(
zpc
,
pwm
->
hwpwm
,
ZX_PWM_MODE
,
ZX_PWM_EN
,
0
);
clk_disable_unprepare
(
zpc
->
wclk
);
}
}
return
0
;
}
static
const
struct
pwm_ops
zx_pwm_ops
=
{
.
apply
=
zx_pwm_apply
,
.
get_state
=
zx_pwm_get_state
,
.
owner
=
THIS_MODULE
,
};
static
int
zx_pwm_probe
(
struct
platform_device
*
pdev
)
{
struct
zx_pwm_chip
*
zpc
;
struct
resource
*
res
;
unsigned
int
i
;
int
ret
;
zpc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
zpc
),
GFP_KERNEL
);
if
(
!
zpc
)
return
-
ENOMEM
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
zpc
->
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
zpc
->
base
))
return
PTR_ERR
(
zpc
->
base
);
zpc
->
pclk
=
devm_clk_get
(
&
pdev
->
dev
,
"pclk"
);
if
(
IS_ERR
(
zpc
->
pclk
))
return
PTR_ERR
(
zpc
->
pclk
);
zpc
->
wclk
=
devm_clk_get
(
&
pdev
->
dev
,
"wclk"
);
if
(
IS_ERR
(
zpc
->
wclk
))
return
PTR_ERR
(
zpc
->
wclk
);
ret
=
clk_prepare_enable
(
zpc
->
pclk
);
if
(
ret
)
return
ret
;
zpc
->
chip
.
dev
=
&
pdev
->
dev
;
zpc
->
chip
.
ops
=
&
zx_pwm_ops
;
zpc
->
chip
.
base
=
-
1
;
zpc
->
chip
.
npwm
=
4
;
zpc
->
chip
.
of_xlate
=
of_pwm_xlate_with_flags
;
zpc
->
chip
.
of_pwm_n_cells
=
3
;
/*
* PWM devices may be enabled by firmware, and let's disable all of
* them initially to save power.
*/
for
(
i
=
0
;
i
<
zpc
->
chip
.
npwm
;
i
++
)
zx_pwm_set_mask
(
zpc
,
i
,
ZX_PWM_MODE
,
ZX_PWM_EN
,
0
);
ret
=
pwmchip_add
(
&
zpc
->
chip
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"failed to add PWM chip: %d
\n
"
,
ret
);
return
ret
;
}
platform_set_drvdata
(
pdev
,
zpc
);
return
0
;
}
static
int
zx_pwm_remove
(
struct
platform_device
*
pdev
)
{
struct
zx_pwm_chip
*
zpc
=
platform_get_drvdata
(
pdev
);
int
ret
;
ret
=
pwmchip_remove
(
&
zpc
->
chip
);
clk_disable_unprepare
(
zpc
->
pclk
);
return
ret
;
}
static
const
struct
of_device_id
zx_pwm_dt_ids
[]
=
{
{
.
compatible
=
"zte,zx296718-pwm"
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
zx_pwm_dt_ids
);
static
struct
platform_driver
zx_pwm_driver
=
{
.
driver
=
{
.
name
=
"zx-pwm"
,
.
of_match_table
=
zx_pwm_dt_ids
,
},
.
probe
=
zx_pwm_probe
,
.
remove
=
zx_pwm_remove
,
};
module_platform_driver
(
zx_pwm_driver
);
MODULE_ALIAS
(
"platform:zx-pwm"
);
MODULE_AUTHOR
(
"Shawn Guo <shawn.guo@linaro.org>"
);
MODULE_DESCRIPTION
(
"ZTE ZX PWM Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录