Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
38b0a526
cloud-kernel
项目概览
openanolis
/
cloud-kernel
大约 1 年 前同步成功
通知
155
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
38b0a526
编写于
2月 10, 2017
作者:
T
Thierry Reding
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-4.11/drivers' into for-next
上级
776906ff
326ed314
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
411 addition
and
230 deletion
+411
-230
Documentation/devicetree/bindings/pwm/imx-pwm.txt
Documentation/devicetree/bindings/pwm/imx-pwm.txt
+3
-3
drivers/pwm/Kconfig
drivers/pwm/Kconfig
+3
-1
drivers/pwm/pwm-bfin.c
drivers/pwm/pwm-bfin.c
+1
-1
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-imx.c
+129
-142
drivers/pwm/pwm-lpss-pci.c
drivers/pwm/pwm-lpss-pci.c
+22
-0
drivers/pwm/pwm-lpss-platform.c
drivers/pwm/pwm-lpss-platform.c
+21
-0
drivers/pwm/pwm-lpss.c
drivers/pwm/pwm-lpss.c
+67
-65
drivers/pwm/pwm-lpss.h
drivers/pwm/pwm-lpss.h
+0
-4
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-pca9685.c
+163
-12
drivers/pwm/pwm-pxa.c
drivers/pwm/pwm-pxa.c
+1
-1
drivers/pwm/pwm-vt8500.c
drivers/pwm/pwm-vt8500.c
+1
-1
未找到文件。
Documentation/devicetree/bindings/pwm/imx-pwm.txt
浏览文件 @
38b0a526
...
...
@@ -6,8 +6,8 @@ Required properties:
- "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1
- "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27
- reg: physical base address and length of the controller's registers
- #pwm-cells:
should be 2. See pwm.txt in this directory for a description of
the cells format.
- #pwm-cells:
2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.txt
in this directory for a description of
the cells format.
- clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per"
See the clock consumer binding,
...
...
@@ -17,7 +17,7 @@ See the clock consumer binding,
Example:
pwm1: pwm@53fb4000 {
#pwm-cells = <
2
>;
#pwm-cells = <
3
>;
compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
reg = <0x53fb4000 0x4000>;
clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
...
...
drivers/pwm/Kconfig
浏览文件 @
38b0a526
...
...
@@ -76,7 +76,9 @@ config PWM_ATMEL_TCB
config PWM_BCM_IPROC
tristate "iProc PWM support"
depends on ARCH_BCM_IPROC
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on COMMON_CLK
default ARCH_BCM_IPROC
help
Generic PWM framework driver for Broadcom iProc PWM block. This
block is used in Broadcom iProc SoC's.
...
...
drivers/pwm/pwm-bfin.c
浏览文件 @
38b0a526
...
...
@@ -103,7 +103,7 @@ static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
disable_gptimer
(
priv
->
pin
);
}
static
struct
pwm_ops
bfin_pwm_ops
=
{
static
const
struct
pwm_ops
bfin_pwm_ops
=
{
.
request
=
bfin_pwm_request
,
.
free
=
bfin_pwm_free
,
.
config
=
bfin_pwm_config
,
...
...
drivers/pwm/pwm-imx.c
浏览文件 @
38b0a526
...
...
@@ -38,6 +38,7 @@
#define MX3_PWMCR_DOZEEN (1 << 24)
#define MX3_PWMCR_WAITEN (1 << 23)
#define MX3_PWMCR_DBGEN (1 << 22)
#define MX3_PWMCR_POUTC (1 << 18)
#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_SWR (1 << 3)
...
...
@@ -49,15 +50,10 @@
struct
imx_chip
{
struct
clk
*
clk_per
;
struct
clk
*
clk_ipg
;
void
__iomem
*
mmio_base
;
struct
pwm_chip
chip
;
int
(
*
config
)(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
);
void
(
*
set_enable
)(
struct
pwm_chip
*
chip
,
bool
enable
);
};
#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
...
...
@@ -91,176 +87,170 @@ static int imx_pwm_config_v1(struct pwm_chip *chip,
return
0
;
}
static
void
imx_pwm_set_enable_v1
(
struct
pwm_chip
*
chip
,
bool
enable
)
static
int
imx_pwm_enable_v1
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
u32
val
;
int
ret
;
val
=
readl
(
imx
->
mmio_base
+
MX1_PWMC
);
if
(
enable
)
val
|=
MX1_PWMC_EN
;
else
val
&=
~
MX1_PWMC_EN
;
ret
=
clk_prepare_enable
(
imx
->
clk_per
);
if
(
ret
<
0
)
return
ret
;
val
=
readl
(
imx
->
mmio_base
+
MX1_PWMC
);
val
|=
MX1_PWMC_EN
;
writel
(
val
,
imx
->
mmio_base
+
MX1_PWMC
);
}
static
int
imx_pwm_config_v2
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
struct
device
*
dev
=
chip
->
dev
;
unsigned
long
long
c
;
unsigned
long
period_cycles
,
duty_cycles
,
prescale
;
unsigned
int
period_ms
;
bool
enable
=
pwm_is_enabled
(
pwm
);
int
wait_count
=
0
,
fifoav
;
u32
cr
,
sr
;
/*
* i.MX PWMv2 has a 4-word sample FIFO.
* In order to avoid FIFO overflow issue, we do software reset
* to clear all sample FIFO if the controller is disabled or
* wait for a full PWM cycle to get a relinquished FIFO slot
* when the controller is enabled and the FIFO is fully loaded.
*/
if
(
enable
)
{
sr
=
readl
(
imx
->
mmio_base
+
MX3_PWMSR
);
fifoav
=
sr
&
MX3_PWMSR_FIFOAV_MASK
;
if
(
fifoav
==
MX3_PWMSR_FIFOAV_4WORDS
)
{
period_ms
=
DIV_ROUND_UP
(
pwm_get_period
(
pwm
),
NSEC_PER_MSEC
);
msleep
(
period_ms
);
sr
=
readl
(
imx
->
mmio_base
+
MX3_PWMSR
);
if
(
fifoav
==
(
sr
&
MX3_PWMSR_FIFOAV_MASK
))
dev_warn
(
dev
,
"there is no free FIFO slot
\n
"
);
}
}
else
{
writel
(
MX3_PWMCR_SWR
,
imx
->
mmio_base
+
MX3_PWMCR
);
do
{
usleep_range
(
200
,
1000
);
cr
=
readl
(
imx
->
mmio_base
+
MX3_PWMCR
);
}
while
((
cr
&
MX3_PWMCR_SWR
)
&&
(
wait_count
++
<
MX3_PWM_SWR_LOOP
));
if
(
cr
&
MX3_PWMCR_SWR
)
dev_warn
(
dev
,
"software reset timeout
\n
"
);
}
c
=
clk_get_rate
(
imx
->
clk_per
);
c
=
c
*
period_ns
;
do_div
(
c
,
1000000000
);
period_cycles
=
c
;
prescale
=
period_cycles
/
0x10000
+
1
;
period_cycles
/=
prescale
;
c
=
(
unsigned
long
long
)
period_cycles
*
duty_ns
;
do_div
(
c
,
period_ns
);
duty_cycles
=
c
;
/*
* according to imx pwm RM, the real period value should be
* PERIOD value in PWMPR plus 2.
*/
if
(
period_cycles
>
2
)
period_cycles
-=
2
;
else
period_cycles
=
0
;
writel
(
duty_cycles
,
imx
->
mmio_base
+
MX3_PWMSAR
);
writel
(
period_cycles
,
imx
->
mmio_base
+
MX3_PWMPR
);
cr
=
MX3_PWMCR_PRESCALER
(
prescale
)
|
MX3_PWMCR_DOZEEN
|
MX3_PWMCR_WAITEN
|
MX3_PWMCR_DBGEN
|
MX3_PWMCR_CLKSRC_IPG_HIGH
;
if
(
enable
)
cr
|=
MX3_PWMCR_EN
;
writel
(
cr
,
imx
->
mmio_base
+
MX3_PWMCR
);
return
0
;
}
static
void
imx_pwm_
set_enable_v2
(
struct
pwm_chip
*
chip
,
bool
enable
)
static
void
imx_pwm_
disable_v1
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
u32
val
;
val
=
readl
(
imx
->
mmio_base
+
MX3_PWMCR
);
if
(
enable
)
val
|=
MX3_PWMCR_EN
;
else
val
&=
~
MX3_PWMCR_EN
;
val
=
readl
(
imx
->
mmio_base
+
MX1_PWMC
);
val
&=
~
MX1_PWMC_EN
;
writel
(
val
,
imx
->
mmio_base
+
MX1_PWMC
);
writel
(
val
,
imx
->
mmio_base
+
MX3_PWMCR
);
clk_disable_unprepare
(
imx
->
clk_per
);
}
static
int
imx_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
static
void
imx_pwm_sw_reset
(
struct
pwm_chip
*
chip
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
int
ret
;
ret
=
clk_prepare_enable
(
imx
->
clk_ipg
);
if
(
ret
)
return
ret
;
struct
device
*
dev
=
chip
->
dev
;
int
wait_count
=
0
;
u32
cr
;
writel
(
MX3_PWMCR_SWR
,
imx
->
mmio_base
+
MX3_PWMCR
);
do
{
usleep_range
(
200
,
1000
);
cr
=
readl
(
imx
->
mmio_base
+
MX3_PWMCR
);
}
while
((
cr
&
MX3_PWMCR_SWR
)
&&
(
wait_count
++
<
MX3_PWM_SWR_LOOP
));
if
(
cr
&
MX3_PWMCR_SWR
)
dev_warn
(
dev
,
"software reset timeout
\n
"
);
}
ret
=
imx
->
config
(
chip
,
pwm
,
duty_ns
,
period_ns
);
static
void
imx_pwm_wait_fifo_slot
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
struct
device
*
dev
=
chip
->
dev
;
unsigned
int
period_ms
;
int
fifoav
;
u32
sr
;
clk_disable_unprepare
(
imx
->
clk_ipg
);
sr
=
readl
(
imx
->
mmio_base
+
MX3_PWMSR
);
fifoav
=
sr
&
MX3_PWMSR_FIFOAV_MASK
;
if
(
fifoav
==
MX3_PWMSR_FIFOAV_4WORDS
)
{
period_ms
=
DIV_ROUND_UP
(
pwm_get_period
(
pwm
),
NSEC_PER_MSEC
);
msleep
(
period_ms
);
return
ret
;
sr
=
readl
(
imx
->
mmio_base
+
MX3_PWMSR
);
if
(
fifoav
==
(
sr
&
MX3_PWMSR_FIFOAV_MASK
))
dev_warn
(
dev
,
"there is no free FIFO slot
\n
"
);
}
}
static
int
imx_pwm_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
int
imx_pwm_apply_v2
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
unsigned
long
period_cycles
,
duty_cycles
,
prescale
;
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
struct
pwm_state
cstate
;
unsigned
long
long
c
;
int
ret
;
u32
cr
;
pwm_get_state
(
pwm
,
&
cstate
);
if
(
state
->
enabled
)
{
c
=
clk_get_rate
(
imx
->
clk_per
);
c
*=
state
->
period
;
do_div
(
c
,
1000000000
);
period_cycles
=
c
;
prescale
=
period_cycles
/
0x10000
+
1
;
period_cycles
/=
prescale
;
c
=
(
unsigned
long
long
)
period_cycles
*
state
->
duty_cycle
;
do_div
(
c
,
state
->
period
);
duty_cycles
=
c
;
/*
* according to imx pwm RM, the real period value should be
* PERIOD value in PWMPR plus 2.
*/
if
(
period_cycles
>
2
)
period_cycles
-=
2
;
else
period_cycles
=
0
;
/*
* Wait for a free FIFO slot if the PWM is already enabled, and
* flush the FIFO if the PWM was disabled and is about to be
* enabled.
*/
if
(
cstate
.
enabled
)
{
imx_pwm_wait_fifo_slot
(
chip
,
pwm
);
}
else
{
ret
=
clk_prepare_enable
(
imx
->
clk_per
);
if
(
ret
)
return
ret
;
imx_pwm_sw_reset
(
chip
);
}
ret
=
clk_prepare_enable
(
imx
->
clk_per
);
if
(
ret
)
return
ret
;
writel
(
duty_cycles
,
imx
->
mmio_base
+
MX3_PWMSAR
);
writel
(
period_cycles
,
imx
->
mmio_base
+
MX3_PWMPR
);
imx
->
set_enable
(
chip
,
true
);
cr
=
MX3_PWMCR_PRESCALER
(
prescale
)
|
MX3_PWMCR_DOZEEN
|
MX3_PWMCR_WAITEN
|
MX3_PWMCR_DBGEN
|
MX3_PWMCR_CLKSRC_IPG_HIGH
|
MX3_PWMCR_EN
;
return
0
;
}
if
(
state
->
polarity
==
PWM_POLARITY_INVERSED
)
cr
|=
MX3_PWMCR_POUTC
;
static
void
imx_pwm_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
struct
imx_chip
*
imx
=
to_imx_chip
(
chip
);
writel
(
cr
,
imx
->
mmio_base
+
MX3_PWMCR
);
}
else
if
(
cstate
.
enabled
)
{
writel
(
0
,
imx
->
mmio_base
+
MX3_PWMCR
);
imx
->
set_enable
(
chip
,
false
);
clk_disable_unprepare
(
imx
->
clk_per
);
}
clk_disable_unprepare
(
imx
->
clk_per
)
;
return
0
;
}
static
struct
pwm_ops
imx_pwm_ops
=
{
.
enable
=
imx_pwm_enable
,
.
disable
=
imx_pwm_disable
,
.
config
=
imx_pwm_config
,
static
const
struct
pwm_ops
imx_pwm_ops_v1
=
{
.
enable
=
imx_pwm_enable_v1
,
.
disable
=
imx_pwm_disable_v1
,
.
config
=
imx_pwm_config_v1
,
.
owner
=
THIS_MODULE
,
};
static
const
struct
pwm_ops
imx_pwm_ops_v2
=
{
.
apply
=
imx_pwm_apply_v2
,
.
owner
=
THIS_MODULE
,
};
struct
imx_pwm_data
{
int
(
*
config
)(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
);
void
(
*
set_enable
)(
struct
pwm_chip
*
chip
,
bool
enable
);
bool
polarity_supported
;
const
struct
pwm_ops
*
ops
;
};
static
struct
imx_pwm_data
imx_pwm_data_v1
=
{
.
config
=
imx_pwm_config_v1
,
.
set_enable
=
imx_pwm_set_enable_v1
,
.
ops
=
&
imx_pwm_ops_v1
,
};
static
struct
imx_pwm_data
imx_pwm_data_v2
=
{
.
config
=
imx_pwm_config_v2
,
.
set_enable
=
imx_pwm_set_enable
_v2
,
.
polarity_supported
=
true
,
.
ops
=
&
imx_pwm_ops
_v2
,
};
static
const
struct
of_device_id
imx_pwm_dt_ids
[]
=
{
...
...
@@ -282,6 +272,8 @@ static int imx_pwm_probe(struct platform_device *pdev)
if
(
!
of_id
)
return
-
ENODEV
;
data
=
of_id
->
data
;
imx
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
imx
),
GFP_KERNEL
);
if
(
imx
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -293,27 +285,22 @@ static int imx_pwm_probe(struct platform_device *pdev)
return
PTR_ERR
(
imx
->
clk_per
);
}
imx
->
clk_ipg
=
devm_clk_get
(
&
pdev
->
dev
,
"ipg"
);
if
(
IS_ERR
(
imx
->
clk_ipg
))
{
dev_err
(
&
pdev
->
dev
,
"getting ipg clock failed with %ld
\n
"
,
PTR_ERR
(
imx
->
clk_ipg
));
return
PTR_ERR
(
imx
->
clk_ipg
);
}
imx
->
chip
.
ops
=
&
imx_pwm_ops
;
imx
->
chip
.
ops
=
data
->
ops
;
imx
->
chip
.
dev
=
&
pdev
->
dev
;
imx
->
chip
.
base
=
-
1
;
imx
->
chip
.
npwm
=
1
;
if
(
data
->
polarity_supported
)
{
dev_dbg
(
&
pdev
->
dev
,
"PWM supports output inversion
\n
"
);
imx
->
chip
.
of_xlate
=
of_pwm_xlate_with_flags
;
imx
->
chip
.
of_pwm_n_cells
=
3
;
}
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
imx
->
mmio_base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
r
);
if
(
IS_ERR
(
imx
->
mmio_base
))
return
PTR_ERR
(
imx
->
mmio_base
);
data
=
of_id
->
data
;
imx
->
config
=
data
->
config
;
imx
->
set_enable
=
data
->
set_enable
;
ret
=
pwmchip_add
(
&
imx
->
chip
);
if
(
ret
<
0
)
return
ret
;
...
...
drivers/pwm/pwm-lpss-pci.c
浏览文件 @
38b0a526
...
...
@@ -17,6 +17,27 @@
#include "pwm-lpss.h"
/* BayTrail */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_byt_info
=
{
.
clk_rate
=
25000000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
/* Braswell */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_bsw_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
/* Broxton */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_bxt_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
4
,
.
base_unit_bits
=
22
,
};
static
int
pwm_lpss_probe_pci
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
id
)
{
...
...
@@ -80,6 +101,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
{
PCI_VDEVICE
(
INTEL
,
0x1ac8
),
(
unsigned
long
)
&
pwm_lpss_bxt_info
},
{
PCI_VDEVICE
(
INTEL
,
0x2288
),
(
unsigned
long
)
&
pwm_lpss_bsw_info
},
{
PCI_VDEVICE
(
INTEL
,
0x2289
),
(
unsigned
long
)
&
pwm_lpss_bsw_info
},
{
PCI_VDEVICE
(
INTEL
,
0x31c8
),
(
unsigned
long
)
&
pwm_lpss_bxt_info
},
{
PCI_VDEVICE
(
INTEL
,
0x5ac8
),
(
unsigned
long
)
&
pwm_lpss_bxt_info
},
{
},
};
...
...
drivers/pwm/pwm-lpss-platform.c
浏览文件 @
38b0a526
...
...
@@ -18,6 +18,27 @@
#include "pwm-lpss.h"
/* BayTrail */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_byt_info
=
{
.
clk_rate
=
25000000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
/* Braswell */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_bsw_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
/* Broxton */
static
const
struct
pwm_lpss_boardinfo
pwm_lpss_bxt_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
4
,
.
base_unit_bits
=
22
,
};
static
int
pwm_lpss_probe_platform
(
struct
platform_device
*
pdev
)
{
const
struct
pwm_lpss_boardinfo
*
info
;
...
...
drivers/pwm/pwm-lpss.c
浏览文件 @
38b0a526
...
...
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
...
...
@@ -37,30 +38,6 @@ struct pwm_lpss_chip {
const
struct
pwm_lpss_boardinfo
*
info
;
};
/* BayTrail */
const
struct
pwm_lpss_boardinfo
pwm_lpss_byt_info
=
{
.
clk_rate
=
25000000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
EXPORT_SYMBOL_GPL
(
pwm_lpss_byt_info
);
/* Braswell */
const
struct
pwm_lpss_boardinfo
pwm_lpss_bsw_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
1
,
.
base_unit_bits
=
16
,
};
EXPORT_SYMBOL_GPL
(
pwm_lpss_bsw_info
);
/* Broxton */
const
struct
pwm_lpss_boardinfo
pwm_lpss_bxt_info
=
{
.
clk_rate
=
19200000
,
.
npwm
=
4
,
.
base_unit_bits
=
22
,
};
EXPORT_SYMBOL_GPL
(
pwm_lpss_bxt_info
);
static
inline
struct
pwm_lpss_chip
*
to_lpwm
(
struct
pwm_chip
*
chip
)
{
return
container_of
(
chip
,
struct
pwm_lpss_chip
,
chip
);
...
...
@@ -80,17 +57,42 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
writel
(
value
,
lpwm
->
regs
+
pwm
->
hwpwm
*
PWM_SIZE
+
PWM
);
}
static
void
pwm_lpss_update
(
struct
pwm_device
*
pwm
)
static
int
pwm_lpss_update
(
struct
pwm_device
*
pwm
)
{
struct
pwm_lpss_chip
*
lpwm
=
to_lpwm
(
pwm
->
chip
);
const
void
__iomem
*
addr
=
lpwm
->
regs
+
pwm
->
hwpwm
*
PWM_SIZE
+
PWM
;
const
unsigned
int
ms
=
500
*
USEC_PER_MSEC
;
u32
val
;
int
err
;
pwm_lpss_write
(
pwm
,
pwm_lpss_read
(
pwm
)
|
PWM_SW_UPDATE
);
/* Give it some time to propagate */
usleep_range
(
10
,
50
);
/*
* PWM Configuration register has SW_UPDATE bit that is set when a new
* configuration is written to the register. The bit is automatically
* cleared at the start of the next output cycle by the IP block.
*
* If one writes a new configuration to the register while it still has
* the bit enabled, PWM may freeze. That is, while one can still write
* to the register, it won't have an effect. Thus, we try to sleep long
* enough that the bit gets cleared and make sure the bit is not
* enabled while we update the configuration.
*/
err
=
readl_poll_timeout
(
addr
,
val
,
!
(
val
&
PWM_SW_UPDATE
),
40
,
ms
);
if
(
err
)
dev_err
(
pwm
->
chip
->
dev
,
"PWM_SW_UPDATE was not cleared
\n
"
);
return
err
;
}
static
int
pwm_lpss_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
static
inline
int
pwm_lpss_is_updating
(
struct
pwm_device
*
pwm
)
{
return
(
pwm_lpss_read
(
pwm
)
&
PWM_SW_UPDATE
)
?
-
EBUSY
:
0
;
}
static
void
pwm_lpss_prepare
(
struct
pwm_lpss_chip
*
lpwm
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
{
struct
pwm_lpss_chip
*
lpwm
=
to_lpwm
(
chip
);
unsigned
long
long
on_time_div
;
unsigned
long
c
=
lpwm
->
info
->
clk_rate
,
base_unit_range
;
unsigned
long
long
base_unit
,
freq
=
NSEC_PER_SEC
;
...
...
@@ -102,62 +104,62 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
* The equation is:
* base_unit = round(base_unit_range * freq / c)
*/
base_unit_range
=
BIT
(
lpwm
->
info
->
base_unit_bits
);
base_unit_range
=
BIT
(
lpwm
->
info
->
base_unit_bits
)
-
1
;
freq
*=
base_unit_range
;
base_unit
=
DIV_ROUND_CLOSEST_ULL
(
freq
,
c
);
if
(
duty_ns
<=
0
)
duty_ns
=
1
;
on_time_div
=
255ULL
*
duty_ns
;
do_div
(
on_time_div
,
period_ns
);
on_time_div
=
255ULL
-
on_time_div
;
pm_runtime_get_sync
(
chip
->
dev
);
ctrl
=
pwm_lpss_read
(
pwm
);
ctrl
&=
~
PWM_ON_TIME_DIV_MASK
;
ctrl
&=
~
(
(
base_unit_range
-
1
)
<<
PWM_BASE_UNIT_SHIFT
);
base_unit
&=
(
base_unit_range
-
1
)
;
ctrl
&=
~
(
base_unit_range
<<
PWM_BASE_UNIT_SHIFT
);
base_unit
&=
base_unit_range
;
ctrl
|=
(
u32
)
base_unit
<<
PWM_BASE_UNIT_SHIFT
;
ctrl
|=
on_time_div
;
pwm_lpss_write
(
pwm
,
ctrl
);
/*
* If the PWM is already enabled we need to notify the hardware
* about the change by setting PWM_SW_UPDATE.
*/
if
(
pwm_is_enabled
(
pwm
))
pwm_lpss_update
(
pwm
);
pm_runtime_put
(
chip
->
dev
);
return
0
;
}
static
int
pwm_lpss_enable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
static
int
pwm_lpss_apply
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
pm_runtime_get_sync
(
chip
->
dev
);
struct
pwm_lpss_chip
*
lpwm
=
to_lpwm
(
chip
);
int
ret
;
/*
* Hardware must first see PWM_SW_UPDATE before the PWM can be
* enabled.
*/
pwm_lpss_update
(
pwm
);
pwm_lpss_write
(
pwm
,
pwm_lpss_read
(
pwm
)
|
PWM_ENABLE
);
return
0
;
}
if
(
state
->
enabled
)
{
if
(
!
pwm_is_enabled
(
pwm
))
{
pm_runtime_get_sync
(
chip
->
dev
);
ret
=
pwm_lpss_is_updating
(
pwm
);
if
(
ret
)
{
pm_runtime_put
(
chip
->
dev
);
return
ret
;
}
pwm_lpss_prepare
(
lpwm
,
pwm
,
state
->
duty_cycle
,
state
->
period
);
ret
=
pwm_lpss_update
(
pwm
);
if
(
ret
)
{
pm_runtime_put
(
chip
->
dev
);
return
ret
;
}
pwm_lpss_write
(
pwm
,
pwm_lpss_read
(
pwm
)
|
PWM_ENABLE
);
}
else
{
ret
=
pwm_lpss_is_updating
(
pwm
);
if
(
ret
)
return
ret
;
pwm_lpss_prepare
(
lpwm
,
pwm
,
state
->
duty_cycle
,
state
->
period
);
return
pwm_lpss_update
(
pwm
);
}
}
else
if
(
pwm_is_enabled
(
pwm
))
{
pwm_lpss_write
(
pwm
,
pwm_lpss_read
(
pwm
)
&
~
PWM_ENABLE
);
pm_runtime_put
(
chip
->
dev
);
}
static
void
pwm_lpss_disable
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
)
{
pwm_lpss_write
(
pwm
,
pwm_lpss_read
(
pwm
)
&
~
PWM_ENABLE
);
pm_runtime_put
(
chip
->
dev
);
return
0
;
}
static
const
struct
pwm_ops
pwm_lpss_ops
=
{
.
config
=
pwm_lpss_config
,
.
enable
=
pwm_lpss_enable
,
.
disable
=
pwm_lpss_disable
,
.
apply
=
pwm_lpss_apply
,
.
owner
=
THIS_MODULE
,
};
...
...
drivers/pwm/pwm-lpss.h
浏览文件 @
38b0a526
...
...
@@ -24,10 +24,6 @@ struct pwm_lpss_boardinfo {
unsigned
long
base_unit_bits
;
};
extern
const
struct
pwm_lpss_boardinfo
pwm_lpss_byt_info
;
extern
const
struct
pwm_lpss_boardinfo
pwm_lpss_bsw_info
;
extern
const
struct
pwm_lpss_boardinfo
pwm_lpss_bxt_info
;
struct
pwm_lpss_chip
*
pwm_lpss_probe
(
struct
device
*
dev
,
struct
resource
*
r
,
const
struct
pwm_lpss_boardinfo
*
info
);
int
pwm_lpss_remove
(
struct
pwm_lpss_chip
*
lpwm
);
...
...
drivers/pwm/pwm-pca9685.c
浏览文件 @
38b0a526
...
...
@@ -20,8 +20,10 @@
*/
#include <linux/acpi.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
...
...
@@ -65,7 +67,6 @@
#define PCA9685_MAXCHAN 0x10
#define LED_FULL (1 << 4)
#define MODE1_RESTART (1 << 7)
#define MODE1_SLEEP (1 << 4)
#define MODE2_INVRT (1 << 4)
#define MODE2_OUTDRV (1 << 2)
...
...
@@ -81,6 +82,10 @@ struct pca9685 {
int
active_cnt
;
int
duty_ns
;
int
period_ns
;
#if IS_ENABLED(CONFIG_GPIOLIB)
struct
mutex
lock
;
struct
gpio_chip
gpio
;
#endif
};
static
inline
struct
pca9685
*
to_pca
(
struct
pwm_chip
*
chip
)
...
...
@@ -88,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return
container_of
(
chip
,
struct
pca9685
,
chip
);
}
#if IS_ENABLED(CONFIG_GPIOLIB)
static
int
pca9685_pwm_gpio_request
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
)
{
struct
pca9685
*
pca
=
gpiochip_get_data
(
gpio
);
struct
pwm_device
*
pwm
;
mutex_lock
(
&
pca
->
lock
);
pwm
=
&
pca
->
chip
.
pwms
[
offset
];
if
(
pwm
->
flags
&
(
PWMF_REQUESTED
|
PWMF_EXPORTED
))
{
mutex_unlock
(
&
pca
->
lock
);
return
-
EBUSY
;
}
pwm_set_chip_data
(
pwm
,
(
void
*
)
1
);
mutex_unlock
(
&
pca
->
lock
);
return
0
;
}
static
void
pca9685_pwm_gpio_free
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
)
{
struct
pca9685
*
pca
=
gpiochip_get_data
(
gpio
);
struct
pwm_device
*
pwm
;
mutex_lock
(
&
pca
->
lock
);
pwm
=
&
pca
->
chip
.
pwms
[
offset
];
pwm_set_chip_data
(
pwm
,
NULL
);
mutex_unlock
(
&
pca
->
lock
);
}
static
bool
pca9685_pwm_is_gpio
(
struct
pca9685
*
pca
,
struct
pwm_device
*
pwm
)
{
bool
is_gpio
=
false
;
mutex_lock
(
&
pca
->
lock
);
if
(
pwm
->
hwpwm
>=
PCA9685_MAXCHAN
)
{
unsigned
int
i
;
/*
* Check if any of the GPIOs are requested and in that case
* prevent using the "all LEDs" channel.
*/
for
(
i
=
0
;
i
<
pca
->
gpio
.
ngpio
;
i
++
)
if
(
gpiochip_is_requested
(
&
pca
->
gpio
,
i
))
{
is_gpio
=
true
;
break
;
}
}
else
if
(
pwm_get_chip_data
(
pwm
))
{
is_gpio
=
true
;
}
mutex_unlock
(
&
pca
->
lock
);
return
is_gpio
;
}
static
int
pca9685_pwm_gpio_get
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
)
{
struct
pca9685
*
pca
=
gpiochip_get_data
(
gpio
);
struct
pwm_device
*
pwm
=
&
pca
->
chip
.
pwms
[
offset
];
unsigned
int
value
;
regmap_read
(
pca
->
regmap
,
LED_N_ON_H
(
pwm
->
hwpwm
),
&
value
);
return
value
&
LED_FULL
;
}
static
void
pca9685_pwm_gpio_set
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
,
int
value
)
{
struct
pca9685
*
pca
=
gpiochip_get_data
(
gpio
);
struct
pwm_device
*
pwm
=
&
pca
->
chip
.
pwms
[
offset
];
unsigned
int
on
=
value
?
LED_FULL
:
0
;
/* Clear both OFF registers */
regmap_write
(
pca
->
regmap
,
LED_N_OFF_L
(
pwm
->
hwpwm
),
0
);
regmap_write
(
pca
->
regmap
,
LED_N_OFF_H
(
pwm
->
hwpwm
),
0
);
/* Set the full ON bit */
regmap_write
(
pca
->
regmap
,
LED_N_ON_H
(
pwm
->
hwpwm
),
on
);
}
static
int
pca9685_pwm_gpio_get_direction
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
/* Always out */
return
0
;
}
static
int
pca9685_pwm_gpio_direction_input
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
)
{
return
-
EINVAL
;
}
static
int
pca9685_pwm_gpio_direction_output
(
struct
gpio_chip
*
gpio
,
unsigned
int
offset
,
int
value
)
{
pca9685_pwm_gpio_set
(
gpio
,
offset
,
value
);
return
0
;
}
/*
* The PCA9685 has a bit for turning the PWM output full off or on. Some
* boards like Intel Galileo actually uses these as normal GPIOs so we
* expose a GPIO chip here which can exclusively take over the underlying
* PWM channel.
*/
static
int
pca9685_pwm_gpio_probe
(
struct
pca9685
*
pca
)
{
struct
device
*
dev
=
pca
->
chip
.
dev
;
mutex_init
(
&
pca
->
lock
);
pca
->
gpio
.
label
=
dev_name
(
dev
);
pca
->
gpio
.
parent
=
dev
;
pca
->
gpio
.
request
=
pca9685_pwm_gpio_request
;
pca
->
gpio
.
free
=
pca9685_pwm_gpio_free
;
pca
->
gpio
.
get_direction
=
pca9685_pwm_gpio_get_direction
;
pca
->
gpio
.
direction_input
=
pca9685_pwm_gpio_direction_input
;
pca
->
gpio
.
direction_output
=
pca9685_pwm_gpio_direction_output
;
pca
->
gpio
.
get
=
pca9685_pwm_gpio_get
;
pca
->
gpio
.
set
=
pca9685_pwm_gpio_set
;
pca
->
gpio
.
base
=
-
1
;
pca
->
gpio
.
ngpio
=
PCA9685_MAXCHAN
;
pca
->
gpio
.
can_sleep
=
true
;
return
devm_gpiochip_add_data
(
dev
,
&
pca
->
gpio
,
pca
);
}
#else
static
inline
bool
pca9685_pwm_is_gpio
(
struct
pca9685
*
pca
,
struct
pwm_device
*
pwm
)
{
return
false
;
}
static
inline
int
pca9685_pwm_gpio_probe
(
struct
pca9685
*
pca
)
{
return
0
;
}
#endif
static
int
pca9685_pwm_config
(
struct
pwm_chip
*
chip
,
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
{
...
...
@@ -117,16 +267,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
udelay
(
500
);
pca
->
period_ns
=
period_ns
;
/*
* If the duty cycle did not change, restart PWM with
* the same duty cycle to period ratio and return.
*/
if
(
duty_ns
==
pca
->
duty_ns
)
{
regmap_update_bits
(
pca
->
regmap
,
PCA9685_MODE1
,
MODE1_RESTART
,
0x1
);
return
0
;
}
}
else
{
dev_err
(
chip
->
dev
,
"prescaler not set: period out of bounds!
\n
"
);
...
...
@@ -264,6 +404,9 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct
pca9685
*
pca
=
to_pca
(
chip
);
if
(
pca9685_pwm_is_gpio
(
pca
,
pwm
))
return
-
EBUSY
;
if
(
pca
->
active_cnt
++
==
0
)
return
regmap_update_bits
(
pca
->
regmap
,
PCA9685_MODE1
,
MODE1_SLEEP
,
0x0
);
...
...
@@ -344,7 +487,15 @@ static int pca9685_pwm_probe(struct i2c_client *client,
pca
->
chip
.
dev
=
&
client
->
dev
;
pca
->
chip
.
base
=
-
1
;
return
pwmchip_add
(
&
pca
->
chip
);
ret
=
pwmchip_add
(
&
pca
->
chip
);
if
(
ret
<
0
)
return
ret
;
ret
=
pca9685_pwm_gpio_probe
(
pca
);
if
(
ret
<
0
)
pwmchip_remove
(
&
pca
->
chip
);
return
ret
;
}
static
int
pca9685_pwm_remove
(
struct
i2c_client
*
client
)
...
...
drivers/pwm/pwm-pxa.c
浏览文件 @
38b0a526
...
...
@@ -118,7 +118,7 @@ static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable_unprepare
(
pc
->
clk
);
}
static
struct
pwm_ops
pxa_pwm_ops
=
{
static
const
struct
pwm_ops
pxa_pwm_ops
=
{
.
config
=
pxa_pwm_config
,
.
enable
=
pxa_pwm_enable
,
.
disable
=
pxa_pwm_disable
,
...
...
drivers/pwm/pwm-vt8500.c
浏览文件 @
38b0a526
...
...
@@ -184,7 +184,7 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
return
0
;
}
static
struct
pwm_ops
vt8500_pwm_ops
=
{
static
const
struct
pwm_ops
vt8500_pwm_ops
=
{
.
enable
=
vt8500_pwm_enable
,
.
disable
=
vt8500_pwm_disable
,
.
config
=
vt8500_pwm_config
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录