Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
de2ea581
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看板
提交
de2ea581
编写于
7月 23, 2014
作者:
D
Daniel Lezcano
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'clockevents/renesas-timers-dt' into clockevents/3.17
上级
afdb0943
cca8d059
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
309 addition
and
327 deletion
+309
-327
Documentation/devicetree/bindings/timer/renesas,cmt.txt
Documentation/devicetree/bindings/timer/renesas,cmt.txt
+47
-0
Documentation/devicetree/bindings/timer/renesas,mtu2.txt
Documentation/devicetree/bindings/timer/renesas,mtu2.txt
+39
-0
Documentation/devicetree/bindings/timer/renesas,tmu.txt
Documentation/devicetree/bindings/timer/renesas,tmu.txt
+39
-0
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_cmt.c
+86
-147
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_mtu2.c
+44
-102
drivers/clocksource/sh_tmu.c
drivers/clocksource/sh_tmu.c
+54
-73
include/linux/sh_timer.h
include/linux/sh_timer.h
+0
-5
未找到文件。
Documentation/devicetree/bindings/timer/renesas,cmt.txt
0 → 100644
浏览文件 @
de2ea581
* Renesas R-Car Compare Match Timer (CMT)
The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock
inputs and programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. A particular CMT instance can implement only a subset of the
channels supported by the CMT model. Channel indices represent the hardware
position of the channel in the CMT and don't match the channel numbers in the
datasheets.
Required Properties:
- compatible: must contain one of the following.
- "renesas,cmt-32" for the 32-bit CMT
(CMT0 on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support
(CMT[234] on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-48" for the 48-bit CMT
(CMT1 on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-48-gen2" for the second generation 48-bit CMT
(CMT[01] on r8a73a4, r8a7790 and r8a7791)
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
- renesas,channels-mask: bitmask of the available channels.
Example: R8A7790 (R-Car H2) CMT0 node
CMT0 on R8A7790 implements hardware channels 5 and 6 only and names
them channels 0 and 1 in the documentation.
cmt0: timer@ffca0000 {
compatible = "renesas,cmt-48-gen2";
reg = <0 0xffca0000 0 0x1004>;
interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>,
<0 142 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_CMT0>;
clock-names = "fck";
renesas,channels-mask = <0x60>;
};
Documentation/devicetree/bindings/timer/renesas,mtu2.txt
0 → 100644
浏览文件 @
de2ea581
* Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2)
The MTU2 is a multi-purpose, multi-channel timer/counter with configurable
clock inputs and programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The MTU2 hardware supports five channels indexed from 0 to 4.
Required Properties:
- compatible: must contain "renesas,mtu2"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt specifiers for the timer, one for each entry in
interrupt-names.
- interrupt-names: must contain one entry named "tgi?a" for each enabled
channel, where "?" is the channel index expressed as one digit from "0" to
"4".
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Example: R7S72100 (RZ/A1H) MTU2 node
mtu2: timer@fcff0000 {
compatible = "renesas,mtu2";
reg = <0xfcff0000 0x400>;
interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>,
<0 146 IRQ_TYPE_LEVEL_HIGH>,
<0 150 IRQ_TYPE_LEVEL_HIGH>,
<0 154 IRQ_TYPE_LEVEL_HIGH>,
<0 159 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tgi0a", "tgi1a", "tgi2a", "tgi3a", "tgi4a";
clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
clock-names = "fck";
};
Documentation/devicetree/bindings/timer/renesas,tmu.txt
0 → 100644
浏览文件 @
de2ea581
* Renesas R-Car Timer Unit (TMU)
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
Required Properties:
- compatible: must contain "renesas,tmu"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Optional Properties:
- #renesas,channels: number of channels implemented by the timer, must be 2
or 3 (if not specified the value defaults to 3).
Example: R8A7779 (R-Car H1) TMU0 node
tmu0: timer@ffd80000 {
compatible = "renesas,tmu";
reg = <0xffd80000 0x30>;
interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>,
<0 33 IRQ_TYPE_LEVEL_HIGH>,
<0 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
#renesas,channels = <3>;
};
drivers/clocksource/sh_cmt.c
浏览文件 @
de2ea581
...
...
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
...
...
@@ -114,14 +115,15 @@ struct sh_cmt_device {
struct
platform_device
*
pdev
;
const
struct
sh_cmt_info
*
info
;
bool
legacy
;
void
__iomem
*
mapbase_ch
;
void
__iomem
*
mapbase
;
struct
clk
*
clk
;
raw_spinlock_t
lock
;
/* Protect the shared start/stop register */
struct
sh_cmt_channel
*
channels
;
unsigned
int
num_channels
;
unsigned
int
hw_channels
;
bool
has_clockevent
;
bool
has_clocksource
;
...
...
@@ -301,14 +303,12 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
return
v2
;
}
static
DEFINE_RAW_SPINLOCK
(
sh_cmt_lock
);
static
void
sh_cmt_start_stop_ch
(
struct
sh_cmt_channel
*
ch
,
int
start
)
{
unsigned
long
flags
,
value
;
/* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave
(
&
sh_cmt_
lock
,
flags
);
raw_spin_lock_irqsave
(
&
ch
->
cmt
->
lock
,
flags
);
value
=
sh_cmt_read_cmstr
(
ch
);
if
(
start
)
...
...
@@ -317,7 +317,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
value
&=
~
(
1
<<
ch
->
timer_bit
);
sh_cmt_write_cmstr
(
ch
,
value
);
raw_spin_unlock_irqrestore
(
&
sh_cmt_
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
ch
->
cmt
->
lock
,
flags
);
}
static
int
sh_cmt_enable
(
struct
sh_cmt_channel
*
ch
,
unsigned
long
*
rate
)
...
...
@@ -792,7 +792,7 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
int
irq
;
int
ret
;
irq
=
platform_get_irq
(
ch
->
cmt
->
pdev
,
ch
->
cmt
->
legacy
?
0
:
ch
->
index
);
irq
=
platform_get_irq
(
ch
->
cmt
->
pdev
,
ch
->
index
);
if
(
irq
<
0
)
{
dev_err
(
&
ch
->
cmt
->
pdev
->
dev
,
"ch%u: failed to get irq
\n
"
,
ch
->
index
);
...
...
@@ -863,33 +863,26 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
* Compute the address of the channel control register block. For the
* timers with a per-channel start/stop register, compute its address
* as well.
*
* For legacy configuration the address has been mapped explicitly.
*/
if
(
cmt
->
legacy
)
{
ch
->
ioctrl
=
cmt
->
mapbase_ch
;
}
else
{
switch
(
cmt
->
info
->
model
)
{
case
SH_CMT_16BIT
:
ch
->
ioctrl
=
cmt
->
mapbase
+
2
+
ch
->
hwidx
*
6
;
break
;
case
SH_CMT_32BIT
:
case
SH_CMT_48BIT
:
ch
->
ioctrl
=
cmt
->
mapbase
+
0x10
+
ch
->
hwidx
*
0x10
;
break
;
case
SH_CMT_32BIT_FAST
:
/*
* The 32-bit "fast" timer has a single channel at hwidx
* 5 but is located at offset 0x40 instead of 0x60 for
* some reason.
*/
ch
->
ioctrl
=
cmt
->
mapbase
+
0x40
;
break
;
case
SH_CMT_48BIT_GEN2
:
ch
->
iostart
=
cmt
->
mapbase
+
ch
->
hwidx
*
0x100
;
ch
->
ioctrl
=
ch
->
iostart
+
0x10
;
break
;
}
switch
(
cmt
->
info
->
model
)
{
case
SH_CMT_16BIT
:
ch
->
ioctrl
=
cmt
->
mapbase
+
2
+
ch
->
hwidx
*
6
;
break
;
case
SH_CMT_32BIT
:
case
SH_CMT_48BIT
:
ch
->
ioctrl
=
cmt
->
mapbase
+
0x10
+
ch
->
hwidx
*
0x10
;
break
;
case
SH_CMT_32BIT_FAST
:
/*
* The 32-bit "fast" timer has a single channel at hwidx 5 but
* is located at offset 0x40 instead of 0x60 for some reason.
*/
ch
->
ioctrl
=
cmt
->
mapbase
+
0x40
;
break
;
case
SH_CMT_48BIT_GEN2
:
ch
->
iostart
=
cmt
->
mapbase
+
ch
->
hwidx
*
0x100
;
ch
->
ioctrl
=
ch
->
iostart
+
0x10
;
break
;
}
if
(
cmt
->
info
->
width
==
(
sizeof
(
ch
->
max_match_value
)
*
8
))
...
...
@@ -900,12 +893,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
ch
->
match_value
=
ch
->
max_match_value
;
raw_spin_lock_init
(
&
ch
->
lock
);
if
(
cmt
->
legacy
)
{
ch
->
timer_bit
=
ch
->
hwidx
;
}
else
{
ch
->
timer_bit
=
cmt
->
info
->
model
==
SH_CMT_48BIT_GEN2
?
0
:
ch
->
hwidx
;
}
ch
->
timer_bit
=
cmt
->
info
->
model
==
SH_CMT_48BIT_GEN2
?
0
:
ch
->
hwidx
;
ret
=
sh_cmt_register
(
ch
,
dev_name
(
&
cmt
->
pdev
->
dev
),
clockevent
,
clocksource
);
...
...
@@ -938,75 +926,65 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt)
return
0
;
}
static
int
sh_cmt_map_memory_legacy
(
struct
sh_cmt_device
*
cmt
)
{
struct
sh_timer_config
*
cfg
=
cmt
->
pdev
->
dev
.
platform_data
;
struct
resource
*
res
,
*
res2
;
/* map memory, let mapbase_ch point to our channel */
res
=
platform_get_resource
(
cmt
->
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
dev_err
(
&
cmt
->
pdev
->
dev
,
"failed to get I/O memory
\n
"
);
return
-
ENXIO
;
}
cmt
->
mapbase_ch
=
ioremap_nocache
(
res
->
start
,
resource_size
(
res
));
if
(
cmt
->
mapbase_ch
==
NULL
)
{
dev_err
(
&
cmt
->
pdev
->
dev
,
"failed to remap I/O memory
\n
"
);
return
-
ENXIO
;
}
/* optional resource for the shared timer start/stop register */
res2
=
platform_get_resource
(
cmt
->
pdev
,
IORESOURCE_MEM
,
1
);
/* map second resource for CMSTR */
cmt
->
mapbase
=
ioremap_nocache
(
res2
?
res2
->
start
:
res
->
start
-
cfg
->
channel_offset
,
res2
?
resource_size
(
res2
)
:
2
);
if
(
cmt
->
mapbase
==
NULL
)
{
dev_err
(
&
cmt
->
pdev
->
dev
,
"failed to remap I/O second memory
\n
"
);
iounmap
(
cmt
->
mapbase_ch
);
return
-
ENXIO
;
}
/* identify the model based on the resources */
if
(
resource_size
(
res
)
==
6
)
cmt
->
info
=
&
sh_cmt_info
[
SH_CMT_16BIT
];
else
if
(
res2
&&
(
resource_size
(
res2
)
==
4
))
cmt
->
info
=
&
sh_cmt_info
[
SH_CMT_48BIT_GEN2
];
else
cmt
->
info
=
&
sh_cmt_info
[
SH_CMT_32BIT
];
static
const
struct
platform_device_id
sh_cmt_id_table
[]
=
{
{
"sh-cmt-16"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_16BIT
]
},
{
"sh-cmt-32"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_32BIT
]
},
{
"sh-cmt-32-fast"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_32BIT_FAST
]
},
{
"sh-cmt-48"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_48BIT
]
},
{
"sh-cmt-48-gen2"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_48BIT_GEN2
]
},
{
}
};
MODULE_DEVICE_TABLE
(
platform
,
sh_cmt_id_table
);
return
0
;
}
static
const
struct
of_device_id
sh_cmt_of_table
[]
__maybe_unused
=
{
{
.
compatible
=
"renesas,cmt-32"
,
.
data
=
&
sh_cmt_info
[
SH_CMT_32BIT
]
},
{
.
compatible
=
"renesas,cmt-32-fast"
,
.
data
=
&
sh_cmt_info
[
SH_CMT_32BIT_FAST
]
},
{
.
compatible
=
"renesas,cmt-48"
,
.
data
=
&
sh_cmt_info
[
SH_CMT_48BIT
]
},
{
.
compatible
=
"renesas,cmt-48-gen2"
,
.
data
=
&
sh_cmt_info
[
SH_CMT_48BIT_GEN2
]
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
sh_cmt_of_table
);
static
void
sh_cmt_unmap_memory
(
struct
sh_cmt_device
*
cmt
)
static
int
sh_cmt_parse_dt
(
struct
sh_cmt_device
*
cmt
)
{
iounmap
(
cmt
->
mapbase
);
if
(
cmt
->
mapbase_ch
)
iounmap
(
cmt
->
mapbase_ch
);
struct
device_node
*
np
=
cmt
->
pdev
->
dev
.
of_node
;
return
of_property_read_u32
(
np
,
"renesas,channels-mask"
,
&
cmt
->
hw_channels
);
}
static
int
sh_cmt_setup
(
struct
sh_cmt_device
*
cmt
,
struct
platform_device
*
pdev
)
{
struct
sh_timer_config
*
cfg
=
pdev
->
dev
.
platform_data
;
const
struct
platform_device_id
*
id
=
pdev
->
id_entry
;
unsigned
int
hw_channels
;
unsigned
int
mask
;
unsigned
int
i
;
int
ret
;
memset
(
cmt
,
0
,
sizeof
(
*
cmt
));
cmt
->
pdev
=
pdev
;
raw_spin_lock_init
(
&
cmt
->
lock
);
if
(
IS_ENABLED
(
CONFIG_OF
)
&&
pdev
->
dev
.
of_node
)
{
const
struct
of_device_id
*
id
;
id
=
of_match_node
(
sh_cmt_of_table
,
pdev
->
dev
.
of_node
);
cmt
->
info
=
id
->
data
;
if
(
!
cfg
)
{
ret
=
sh_cmt_parse_dt
(
cmt
);
if
(
ret
<
0
)
return
ret
;
}
else
if
(
pdev
->
dev
.
platform_data
)
{
struct
sh_timer_config
*
cfg
=
pdev
->
dev
.
platform_data
;
const
struct
platform_device_id
*
id
=
pdev
->
id_entry
;
cmt
->
info
=
(
const
struct
sh_cmt_info
*
)
id
->
driver_data
;
cmt
->
hw_channels
=
cfg
->
channels_mask
;
}
else
{
dev_err
(
&
cmt
->
pdev
->
dev
,
"missing platform data
\n
"
);
return
-
ENXIO
;
}
cmt
->
info
=
(
const
struct
sh_cmt_info
*
)
id
->
driver_data
;
cmt
->
legacy
=
cmt
->
info
?
false
:
true
;
/* Get hold of clock. */
cmt
->
clk
=
clk_get
(
&
cmt
->
pdev
->
dev
,
cmt
->
legacy
?
"cmt_fck"
:
"fck"
);
cmt
->
clk
=
clk_get
(
&
cmt
->
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
cmt
->
clk
))
{
dev_err
(
&
cmt
->
pdev
->
dev
,
"cannot get clock
\n
"
);
return
PTR_ERR
(
cmt
->
clk
);
...
...
@@ -1016,28 +994,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
if
(
ret
<
0
)
goto
err_clk_put
;
/*
* Map the memory resource(s). We need to support both the legacy
* platform device configuration (with one device per channel) and the
* new version (with multiple channels per device).
*/
if
(
cmt
->
legacy
)
ret
=
sh_cmt_map_memory_legacy
(
cmt
);
else
ret
=
sh_cmt_map_memory
(
cmt
);
/* Map the memory resource(s). */
ret
=
sh_cmt_map_memory
(
cmt
);
if
(
ret
<
0
)
goto
err_clk_unprepare
;
/* Allocate and setup the channels. */
if
(
cmt
->
legacy
)
{
cmt
->
num_channels
=
1
;
hw_channels
=
0
;
}
else
{
cmt
->
num_channels
=
hweight8
(
cfg
->
channels_mask
);
hw_channels
=
cfg
->
channels_mask
;
}
cmt
->
num_channels
=
hweight8
(
cmt
->
hw_channels
);
cmt
->
channels
=
kzalloc
(
cmt
->
num_channels
*
sizeof
(
*
cmt
->
channels
),
GFP_KERNEL
);
if
(
cmt
->
channels
==
NULL
)
{
...
...
@@ -1045,35 +1008,21 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
goto
err_unmap
;
}
if
(
cmt
->
legacy
)
{
ret
=
sh_cmt_setup_channel
(
&
cmt
->
channels
[
0
],
cfg
->
timer_bit
,
cfg
->
timer_bit
,
cfg
->
clockevent_rating
!=
0
,
cfg
->
clocksource_rating
!=
0
,
cmt
);
/*
* Use the first channel as a clock event device and the second channel
* as a clock source. If only one channel is available use it for both.
*/
for
(
i
=
0
,
mask
=
cmt
->
hw_channels
;
i
<
cmt
->
num_channels
;
++
i
)
{
unsigned
int
hwidx
=
ffs
(
mask
)
-
1
;
bool
clocksource
=
i
==
1
||
cmt
->
num_channels
==
1
;
bool
clockevent
=
i
==
0
;
ret
=
sh_cmt_setup_channel
(
&
cmt
->
channels
[
i
],
i
,
hwidx
,
clockevent
,
clocksource
,
cmt
);
if
(
ret
<
0
)
goto
err_unmap
;
}
else
{
unsigned
int
mask
=
hw_channels
;
unsigned
int
i
;
/*
* Use the first channel as a clock event device and the second
* channel as a clock source. If only one channel is available
* use it for both.
*/
for
(
i
=
0
;
i
<
cmt
->
num_channels
;
++
i
)
{
unsigned
int
hwidx
=
ffs
(
mask
)
-
1
;
bool
clocksource
=
i
==
1
||
cmt
->
num_channels
==
1
;
bool
clockevent
=
i
==
0
;
ret
=
sh_cmt_setup_channel
(
&
cmt
->
channels
[
i
],
i
,
hwidx
,
clockevent
,
clocksource
,
cmt
);
if
(
ret
<
0
)
goto
err_unmap
;
mask
&=
~
(
1
<<
hwidx
);
}
mask
&=
~
(
1
<<
hwidx
);
}
platform_set_drvdata
(
pdev
,
cmt
);
...
...
@@ -1082,7 +1031,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
err_unmap:
kfree
(
cmt
->
channels
);
sh_cmt_unmap_memory
(
cmt
);
iounmap
(
cmt
->
mapbase
);
err_clk_unprepare:
clk_unprepare
(
cmt
->
clk
);
err_clk_put:
...
...
@@ -1132,22 +1081,12 @@ static int sh_cmt_remove(struct platform_device *pdev)
return
-
EBUSY
;
/* cannot unregister clockevent and clocksource */
}
static
const
struct
platform_device_id
sh_cmt_id_table
[]
=
{
{
"sh_cmt"
,
0
},
{
"sh-cmt-16"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_16BIT
]
},
{
"sh-cmt-32"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_32BIT
]
},
{
"sh-cmt-32-fast"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_32BIT_FAST
]
},
{
"sh-cmt-48"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_48BIT
]
},
{
"sh-cmt-48-gen2"
,
(
kernel_ulong_t
)
&
sh_cmt_info
[
SH_CMT_48BIT_GEN2
]
},
{
}
};
MODULE_DEVICE_TABLE
(
platform
,
sh_cmt_id_table
);
static
struct
platform_driver
sh_cmt_device_driver
=
{
.
probe
=
sh_cmt_probe
,
.
remove
=
sh_cmt_remove
,
.
driver
=
{
.
name
=
"sh_cmt"
,
.
of_match_table
=
of_match_ptr
(
sh_cmt_of_table
),
},
.
id_table
=
sh_cmt_id_table
,
};
...
...
drivers/clocksource/sh_mtu2.c
浏览文件 @
de2ea581
...
...
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
...
...
@@ -37,7 +38,6 @@ struct sh_mtu2_channel {
unsigned
int
index
;
void
__iomem
*
base
;
int
irq
;
struct
clock_event_device
ced
;
};
...
...
@@ -48,15 +48,14 @@ struct sh_mtu2_device {
void
__iomem
*
mapbase
;
struct
clk
*
clk
;
raw_spinlock_t
lock
;
/* Protect the shared registers */
struct
sh_mtu2_channel
*
channels
;
unsigned
int
num_channels
;
bool
legacy
;
bool
has_clockevent
;
};
static
DEFINE_RAW_SPINLOCK
(
sh_mtu2_lock
);
#define TSTR -1
/* shared register */
#define TCR 0
/* channel register */
#define TMDR 1
/* channel register */
...
...
@@ -162,12 +161,8 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr)
{
unsigned
long
offs
;
if
(
reg_nr
==
TSTR
)
{
if
(
ch
->
mtu
->
legacy
)
return
ioread8
(
ch
->
mtu
->
mapbase
);
else
return
ioread8
(
ch
->
mtu
->
mapbase
+
0x280
);
}
if
(
reg_nr
==
TSTR
)
return
ioread8
(
ch
->
mtu
->
mapbase
+
0x280
);
offs
=
mtu2_reg_offs
[
reg_nr
];
...
...
@@ -182,12 +177,8 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr,
{
unsigned
long
offs
;
if
(
reg_nr
==
TSTR
)
{
if
(
ch
->
mtu
->
legacy
)
return
iowrite8
(
value
,
ch
->
mtu
->
mapbase
);
else
return
iowrite8
(
value
,
ch
->
mtu
->
mapbase
+
0x280
);
}
if
(
reg_nr
==
TSTR
)
return
iowrite8
(
value
,
ch
->
mtu
->
mapbase
+
0x280
);
offs
=
mtu2_reg_offs
[
reg_nr
];
...
...
@@ -202,7 +193,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start)
unsigned
long
flags
,
value
;
/* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave
(
&
sh_mtu2_
lock
,
flags
);
raw_spin_lock_irqsave
(
&
ch
->
mtu
->
lock
,
flags
);
value
=
sh_mtu2_read
(
ch
,
TSTR
);
if
(
start
)
...
...
@@ -211,7 +202,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start)
value
&=
~
(
1
<<
ch
->
index
);
sh_mtu2_write
(
ch
,
TSTR
,
value
);
raw_spin_unlock_irqrestore
(
&
sh_mtu2_
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
ch
->
mtu
->
lock
,
flags
);
}
static
int
sh_mtu2_enable
(
struct
sh_mtu2_channel
*
ch
)
...
...
@@ -331,7 +322,6 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
const
char
*
name
)
{
struct
clock_event_device
*
ced
=
&
ch
->
ced
;
int
ret
;
ced
->
name
=
name
;
ced
->
features
=
CLOCK_EVT_FEAT_PERIODIC
;
...
...
@@ -344,24 +334,12 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
dev_info
(
&
ch
->
mtu
->
pdev
->
dev
,
"ch%u: used for clock events
\n
"
,
ch
->
index
);
clockevents_register_device
(
ced
);
ret
=
request_irq
(
ch
->
irq
,
sh_mtu2_interrupt
,
IRQF_TIMER
|
IRQF_IRQPOLL
|
IRQF_NOBALANCING
,
dev_name
(
&
ch
->
mtu
->
pdev
->
dev
),
ch
);
if
(
ret
)
{
dev_err
(
&
ch
->
mtu
->
pdev
->
dev
,
"ch%u: failed to request irq %d
\n
"
,
ch
->
index
,
ch
->
irq
);
return
;
}
}
static
int
sh_mtu2_register
(
struct
sh_mtu2_channel
*
ch
,
const
char
*
name
,
bool
clockevent
)
static
int
sh_mtu2_register
(
struct
sh_mtu2_channel
*
ch
,
const
char
*
name
)
{
if
(
clockevent
)
{
ch
->
mtu
->
has_clockevent
=
true
;
sh_mtu2_register_clockevent
(
ch
,
name
);
}
ch
->
mtu
->
has_clockevent
=
true
;
sh_mtu2_register_clockevent
(
ch
,
name
);
return
0
;
}
...
...
@@ -372,40 +350,32 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index,
static
const
unsigned
int
channel_offsets
[]
=
{
0x300
,
0x380
,
0x000
,
};
bool
clockevent
;
char
name
[
6
];
int
irq
;
int
ret
;
ch
->
mtu
=
mtu
;
if
(
mtu
->
legacy
)
{
struct
sh_timer_config
*
cfg
=
mtu
->
pdev
->
dev
.
platform_data
;
clockevent
=
cfg
->
clockevent_rating
!=
0
;
ch
->
irq
=
platform_get_irq
(
mtu
->
pdev
,
0
);
ch
->
base
=
mtu
->
mapbase
-
cfg
->
channel_offset
;
ch
->
index
=
cfg
->
timer_bit
;
}
else
{
char
name
[
6
];
clockevent
=
true
;
sprintf
(
name
,
"tgi%ua"
,
index
);
ch
->
irq
=
platform_get_irq_byname
(
mtu
->
pdev
,
name
);
ch
->
base
=
mtu
->
mapbase
+
channel_offsets
[
index
];
ch
->
index
=
index
;
}
if
(
ch
->
irq
<
0
)
{
sprintf
(
name
,
"tgi%ua"
,
index
);
irq
=
platform_get_irq_byname
(
mtu
->
pdev
,
name
);
if
(
irq
<
0
)
{
/* Skip channels with no declared interrupt. */
if
(
!
mtu
->
legacy
)
return
0
;
return
0
;
}
dev_err
(
&
mtu
->
pdev
->
dev
,
"ch%u: failed to get irq
\n
"
,
ch
->
index
);
return
ch
->
irq
;
ret
=
request_irq
(
irq
,
sh_mtu2_interrupt
,
IRQF_TIMER
|
IRQF_IRQPOLL
|
IRQF_NOBALANCING
,
dev_name
(
&
ch
->
mtu
->
pdev
->
dev
),
ch
);
if
(
ret
)
{
dev_err
(
&
ch
->
mtu
->
pdev
->
dev
,
"ch%u: failed to request irq %d
\n
"
,
index
,
irq
);
return
ret
;
}
return
sh_mtu2_register
(
ch
,
dev_name
(
&
mtu
->
pdev
->
dev
),
clockevent
);
ch
->
base
=
mtu
->
mapbase
+
channel_offsets
[
index
];
ch
->
index
=
index
;
return
sh_mtu2_register
(
ch
,
dev_name
(
&
mtu
->
pdev
->
dev
));
}
static
int
sh_mtu2_map_memory
(
struct
sh_mtu2_device
*
mtu
)
...
...
@@ -422,46 +392,21 @@ static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu)
if
(
mtu
->
mapbase
==
NULL
)
return
-
ENXIO
;
/*
* In legacy platform device configuration (with one device per channel)
* the resource points to the channel base address.
*/
if
(
mtu
->
legacy
)
{
struct
sh_timer_config
*
cfg
=
mtu
->
pdev
->
dev
.
platform_data
;
mtu
->
mapbase
+=
cfg
->
channel_offset
;
}
return
0
;
}
static
void
sh_mtu2_unmap_memory
(
struct
sh_mtu2_device
*
mtu
)
{
if
(
mtu
->
legacy
)
{
struct
sh_timer_config
*
cfg
=
mtu
->
pdev
->
dev
.
platform_data
;
mtu
->
mapbase
-=
cfg
->
channel_offset
;
}
iounmap
(
mtu
->
mapbase
);
}
static
int
sh_mtu2_setup
(
struct
sh_mtu2_device
*
mtu
,
struct
platform_device
*
pdev
)
{
struct
sh_timer_config
*
cfg
=
pdev
->
dev
.
platform_data
;
const
struct
platform_device_id
*
id
=
pdev
->
id_entry
;
unsigned
int
i
;
int
ret
;
mtu
->
pdev
=
pdev
;
mtu
->
legacy
=
id
->
driver_data
;
if
(
mtu
->
legacy
&&
!
cfg
)
{
dev_err
(
&
mtu
->
pdev
->
dev
,
"missing platform data
\n
"
);
return
-
ENXIO
;
}
raw_spin_lock_init
(
&
mtu
->
lock
);
/* Get hold of clock. */
mtu
->
clk
=
clk_get
(
&
mtu
->
pdev
->
dev
,
mtu
->
legacy
?
"mtu2_fck"
:
"fck"
);
mtu
->
clk
=
clk_get
(
&
mtu
->
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
mtu
->
clk
))
{
dev_err
(
&
mtu
->
pdev
->
dev
,
"cannot get clock
\n
"
);
return
PTR_ERR
(
mtu
->
clk
);
...
...
@@ -479,10 +424,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
}
/* Allocate and setup the channels. */
if
(
mtu
->
legacy
)
mtu
->
num_channels
=
1
;
else
mtu
->
num_channels
=
3
;
mtu
->
num_channels
=
3
;
mtu
->
channels
=
kzalloc
(
sizeof
(
*
mtu
->
channels
)
*
mtu
->
num_channels
,
GFP_KERNEL
);
...
...
@@ -491,16 +433,10 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
goto
err_unmap
;
}
if
(
mtu
->
legacy
)
{
ret
=
sh_mtu2_setup_channel
(
&
mtu
->
channels
[
0
],
0
,
mtu
);
for
(
i
=
0
;
i
<
mtu
->
num_channels
;
++
i
)
{
ret
=
sh_mtu2_setup_channel
(
&
mtu
->
channels
[
i
],
i
,
mtu
);
if
(
ret
<
0
)
goto
err_unmap
;
}
else
{
for
(
i
=
0
;
i
<
mtu
->
num_channels
;
++
i
)
{
ret
=
sh_mtu2_setup_channel
(
&
mtu
->
channels
[
i
],
i
,
mtu
);
if
(
ret
<
0
)
goto
err_unmap
;
}
}
platform_set_drvdata
(
pdev
,
mtu
);
...
...
@@ -509,7 +445,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
err_unmap:
kfree
(
mtu
->
channels
);
sh_mtu2_unmap_memory
(
mtu
);
iounmap
(
mtu
->
mapbase
);
err_clk_unprepare:
clk_unprepare
(
mtu
->
clk
);
err_clk_put:
...
...
@@ -560,17 +496,23 @@ static int sh_mtu2_remove(struct platform_device *pdev)
}
static
const
struct
platform_device_id
sh_mtu2_id_table
[]
=
{
{
"sh_mtu2"
,
1
},
{
"sh-mtu2"
,
0
},
{
},
};
MODULE_DEVICE_TABLE
(
platform
,
sh_mtu2_id_table
);
static
const
struct
of_device_id
sh_mtu2_of_table
[]
__maybe_unused
=
{
{
.
compatible
=
"renesas,mtu2"
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
sh_mtu2_of_table
);
static
struct
platform_driver
sh_mtu2_device_driver
=
{
.
probe
=
sh_mtu2_probe
,
.
remove
=
sh_mtu2_remove
,
.
driver
=
{
.
name
=
"sh_mtu2"
,
.
of_match_table
=
of_match_ptr
(
sh_mtu2_of_table
),
},
.
id_table
=
sh_mtu2_id_table
,
};
...
...
drivers/clocksource/sh_tmu.c
浏览文件 @
de2ea581
...
...
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
...
...
@@ -32,7 +33,6 @@
#include <linux/spinlock.h>
enum
sh_tmu_model
{
SH_TMU_LEGACY
,
SH_TMU
,
SH_TMU_SH3
,
};
...
...
@@ -62,6 +62,8 @@ struct sh_tmu_device {
enum
sh_tmu_model
model
;
raw_spinlock_t
lock
;
/* Protect the shared start/stop register */
struct
sh_tmu_channel
*
channels
;
unsigned
int
num_channels
;
...
...
@@ -69,8 +71,6 @@ struct sh_tmu_device {
bool
has_clocksource
;
};
static
DEFINE_RAW_SPINLOCK
(
sh_tmu_lock
);
#define TSTR -1
/* shared register */
#define TCOR 0
/* channel register */
#define TCNT 1
/* channel register */
...
...
@@ -91,8 +91,6 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_channel *ch, int reg_nr)
if
(
reg_nr
==
TSTR
)
{
switch
(
ch
->
tmu
->
model
)
{
case
SH_TMU_LEGACY
:
return
ioread8
(
ch
->
tmu
->
mapbase
);
case
SH_TMU_SH3
:
return
ioread8
(
ch
->
tmu
->
mapbase
+
2
);
case
SH_TMU
:
...
...
@@ -115,8 +113,6 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr,
if
(
reg_nr
==
TSTR
)
{
switch
(
ch
->
tmu
->
model
)
{
case
SH_TMU_LEGACY
:
return
iowrite8
(
value
,
ch
->
tmu
->
mapbase
);
case
SH_TMU_SH3
:
return
iowrite8
(
value
,
ch
->
tmu
->
mapbase
+
2
);
case
SH_TMU
:
...
...
@@ -137,7 +133,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
unsigned
long
flags
,
value
;
/* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave
(
&
sh_tmu_
lock
,
flags
);
raw_spin_lock_irqsave
(
&
ch
->
tmu
->
lock
,
flags
);
value
=
sh_tmu_read
(
ch
,
TSTR
);
if
(
start
)
...
...
@@ -146,7 +142,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
value
&=
~
(
1
<<
ch
->
index
);
sh_tmu_write
(
ch
,
TSTR
,
value
);
raw_spin_unlock_irqrestore
(
&
sh_tmu_
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
ch
->
tmu
->
lock
,
flags
);
}
static
int
__sh_tmu_enable
(
struct
sh_tmu_channel
*
ch
)
...
...
@@ -476,27 +472,12 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index,
return
0
;
ch
->
tmu
=
tmu
;
ch
->
index
=
index
;
if
(
tmu
->
model
==
SH_TMU_LEGACY
)
{
struct
sh_timer_config
*
cfg
=
tmu
->
pdev
->
dev
.
platform_data
;
/*
* The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps
* channel registers blocks at base + 2 + 12 * index, while all
* other variants map them at base + 4 + 12 * index. We can
* compute the index by just dividing by 12, the 2 bytes or 4
* bytes offset being hidden by the integer division.
*/
ch
->
index
=
cfg
->
channel_offset
/
12
;
ch
->
base
=
tmu
->
mapbase
+
cfg
->
channel_offset
;
}
else
{
ch
->
index
=
index
;
if
(
tmu
->
model
==
SH_TMU_SH3
)
ch
->
base
=
tmu
->
mapbase
+
4
+
ch
->
index
*
12
;
else
ch
->
base
=
tmu
->
mapbase
+
8
+
ch
->
index
*
12
;
}
if
(
tmu
->
model
==
SH_TMU_SH3
)
ch
->
base
=
tmu
->
mapbase
+
4
+
ch
->
index
*
12
;
else
ch
->
base
=
tmu
->
mapbase
+
8
+
ch
->
index
*
12
;
ch
->
irq
=
platform_get_irq
(
tmu
->
pdev
,
index
);
if
(
ch
->
irq
<
0
)
{
...
...
@@ -526,46 +507,53 @@ static int sh_tmu_map_memory(struct sh_tmu_device *tmu)
if
(
tmu
->
mapbase
==
NULL
)
return
-
ENXIO
;
/*
* In legacy platform device configuration (with one device per channel)
* the resource points to the channel base address.
*/
if
(
tmu
->
model
==
SH_TMU_LEGACY
)
{
struct
sh_timer_config
*
cfg
=
tmu
->
pdev
->
dev
.
platform_data
;
tmu
->
mapbase
-=
cfg
->
channel_offset
;
}
return
0
;
}
static
void
sh_tmu_unmap_memory
(
struct
sh_tmu_device
*
tmu
)
static
int
sh_tmu_parse_dt
(
struct
sh_tmu_device
*
tmu
)
{
if
(
tmu
->
model
==
SH_TMU_LEGACY
)
{
struct
sh_timer_config
*
cfg
=
tmu
->
pdev
->
dev
.
platform_data
;
tmu
->
mapbase
+=
cfg
->
channel_offset
;
struct
device_node
*
np
=
tmu
->
pdev
->
dev
.
of_node
;
tmu
->
model
=
SH_TMU
;
tmu
->
num_channels
=
3
;
of_property_read_u32
(
np
,
"#renesas,channels"
,
&
tmu
->
num_channels
);
if
(
tmu
->
num_channels
!=
2
&&
tmu
->
num_channels
!=
3
)
{
dev_err
(
&
tmu
->
pdev
->
dev
,
"invalid number of channels %u
\n
"
,
tmu
->
num_channels
);
return
-
EINVAL
;
}
iounmap
(
tmu
->
mapbase
)
;
return
0
;
}
static
int
sh_tmu_setup
(
struct
sh_tmu_device
*
tmu
,
struct
platform_device
*
pdev
)
{
struct
sh_timer_config
*
cfg
=
pdev
->
dev
.
platform_data
;
const
struct
platform_device_id
*
id
=
pdev
->
id_entry
;
unsigned
int
i
;
int
ret
;
if
(
!
cfg
)
{
tmu
->
pdev
=
pdev
;
raw_spin_lock_init
(
&
tmu
->
lock
);
if
(
IS_ENABLED
(
CONFIG_OF
)
&&
pdev
->
dev
.
of_node
)
{
ret
=
sh_tmu_parse_dt
(
tmu
);
if
(
ret
<
0
)
return
ret
;
}
else
if
(
pdev
->
dev
.
platform_data
)
{
const
struct
platform_device_id
*
id
=
pdev
->
id_entry
;
struct
sh_timer_config
*
cfg
=
pdev
->
dev
.
platform_data
;
tmu
->
model
=
id
->
driver_data
;
tmu
->
num_channels
=
hweight8
(
cfg
->
channels_mask
);
}
else
{
dev_err
(
&
tmu
->
pdev
->
dev
,
"missing platform data
\n
"
);
return
-
ENXIO
;
}
tmu
->
pdev
=
pdev
;
tmu
->
model
=
id
->
driver_data
;
/* Get hold of clock. */
tmu
->
clk
=
clk_get
(
&
tmu
->
pdev
->
dev
,
tmu
->
model
==
SH_TMU_LEGACY
?
"tmu_fck"
:
"fck"
);
tmu
->
clk
=
clk_get
(
&
tmu
->
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
tmu
->
clk
))
{
dev_err
(
&
tmu
->
pdev
->
dev
,
"cannot get clock
\n
"
);
return
PTR_ERR
(
tmu
->
clk
);
...
...
@@ -583,11 +571,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
}
/* Allocate and setup the channels. */
if
(
tmu
->
model
==
SH_TMU_LEGACY
)
tmu
->
num_channels
=
1
;
else
tmu
->
num_channels
=
hweight8
(
cfg
->
channels_mask
);
tmu
->
channels
=
kzalloc
(
sizeof
(
*
tmu
->
channels
)
*
tmu
->
num_channels
,
GFP_KERNEL
);
if
(
tmu
->
channels
==
NULL
)
{
...
...
@@ -595,23 +578,15 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
goto
err_unmap
;
}
if
(
tmu
->
model
==
SH_TMU_LEGACY
)
{
ret
=
sh_tmu_channel_setup
(
&
tmu
->
channels
[
0
],
0
,
cfg
->
clockevent_rating
!=
0
,
cfg
->
clocksource_rating
!=
0
,
tmu
);
/*
* Use the first channel as a clock event device and the second channel
* as a clock source.
*/
for
(
i
=
0
;
i
<
tmu
->
num_channels
;
++
i
)
{
ret
=
sh_tmu_channel_setup
(
&
tmu
->
channels
[
i
],
i
,
i
==
0
,
i
==
1
,
tmu
);
if
(
ret
<
0
)
goto
err_unmap
;
}
else
{
/*
* Use the first channel as a clock event device and the second
* channel as a clock source.
*/
for
(
i
=
0
;
i
<
tmu
->
num_channels
;
++
i
)
{
ret
=
sh_tmu_channel_setup
(
&
tmu
->
channels
[
i
],
i
,
i
==
0
,
i
==
1
,
tmu
);
if
(
ret
<
0
)
goto
err_unmap
;
}
}
platform_set_drvdata
(
pdev
,
tmu
);
...
...
@@ -620,7 +595,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
err_unmap:
kfree
(
tmu
->
channels
);
sh_tmu_unmap_memory
(
tmu
);
iounmap
(
tmu
->
mapbase
);
err_clk_unprepare:
clk_unprepare
(
tmu
->
clk
);
err_clk_put:
...
...
@@ -671,18 +646,24 @@ static int sh_tmu_remove(struct platform_device *pdev)
}
static
const
struct
platform_device_id
sh_tmu_id_table
[]
=
{
{
"sh_tmu"
,
SH_TMU_LEGACY
},
{
"sh-tmu"
,
SH_TMU
},
{
"sh-tmu-sh3"
,
SH_TMU_SH3
},
{
}
};
MODULE_DEVICE_TABLE
(
platform
,
sh_tmu_id_table
);
static
const
struct
of_device_id
sh_tmu_of_table
[]
__maybe_unused
=
{
{
.
compatible
=
"renesas,tmu"
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
sh_tmu_of_table
);
static
struct
platform_driver
sh_tmu_device_driver
=
{
.
probe
=
sh_tmu_probe
,
.
remove
=
sh_tmu_remove
,
.
driver
=
{
.
name
=
"sh_tmu"
,
.
of_match_table
=
of_match_ptr
(
sh_tmu_of_table
),
},
.
id_table
=
sh_tmu_id_table
,
};
...
...
include/linux/sh_timer.h
浏览文件 @
de2ea581
...
...
@@ -2,11 +2,6 @@
#define __SH_TIMER_H__
struct
sh_timer_config
{
char
*
name
;
long
channel_offset
;
int
timer_bit
;
unsigned
long
clockevent_rating
;
unsigned
long
clocksource_rating
;
unsigned
int
channels_mask
;
};
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录