Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1c2f21be
Commit
1c2f21be
authored
Jul 22, 2020
by
Jonathan Cameron
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-5.8-tcb' into HEAD
Series needed as base for a clocksource tree hence immutable branch
parents
d0d7c584
106b1041
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
595 additions
and
56 deletions
+595
-56
Documentation/devicetree/bindings/mfd/atmel-tcb.txt
Documentation/devicetree/bindings/mfd/atmel-tcb.txt
+0
-56
Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml
...vicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml
+181
-0
drivers/counter/Kconfig
drivers/counter/Kconfig
+11
-0
drivers/counter/Makefile
drivers/counter/Makefile
+1
-0
drivers/counter/microchip-tcb-capture.c
drivers/counter/microchip-tcb-capture.c
+397
-0
include/soc/at91/atmel_tcb.h
include/soc/at91/atmel_tcb.h
+5
-0
No files found.
Documentation/devicetree/bindings/mfd/atmel-tcb.txt
deleted
100644 → 0
View file @
d0d7c584
* Device tree bindings for Atmel Timer Counter Blocks
- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
<chip> can be "at91rm9200" or "at91sam9x5"
- reg: Should contain registers location and length
- #address-cells: has to be 1
- #size-cells: has to be 0
- interrupts: Should contain all interrupts for the TC block
Note that you can specify several interrupt cells if the TC
block has one interrupt per channel.
- clock-names: tuple listing input clock names.
Required elements: "t0_clk", "slow_clk"
Optional elements: "t1_clk", "t2_clk"
- clocks: phandles to input clocks.
The TCB can expose multiple subdevices:
* a timer
- compatible: Should be "atmel,tcb-timer"
- reg: Should contain the TCB channels to be used. If the
counter width is 16 bits (at91rm9200-tcb), two consecutive
channels are needed. Else, only one channel will be used.
Examples:
One interrupt per TC block:
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
clocks = <&tcb0_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>, <1>;
};
timer@2 {
compatible = "atmel,tcb-timer";
reg = <2>;
};
};
One interrupt per TC channel in a TC block:
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfffdc000 0x100>;
interrupts = <26 4>, <27 4>, <28 4>;
clocks = <&tcb1_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
};
Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml
0 → 100644
View file @
1c2f21be
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML
1.2
---
$id
:
"
http://devicetree.org/schemas/soc/microchip/atmel,at91rm9200-tcb.yaml#"
$schema
:
"
http://devicetree.org/meta-schemas/core.yaml#"
title
:
Atmel Timer Counter Block
maintainers
:
-
Alexandre Belloni <alexandre.belloni@bootlin.com>
description
:
|
The Atmel (now Microchip) SoCs have timers named Timer Counter Block. Each
timer has three channels with two counters each.
properties
:
compatible
:
items
:
-
enum
:
-
atmel,at91rm9200-tcb
-
atmel,at91sam9x5-tcb
-
atmel,sama5d2-tcb
-
const
:
simple-mfd
-
const
:
syscon
reg
:
maxItems
:
1
interrupts
:
description
:
List of interrupts. One interrupt per TCB channel if available or one
interrupt for the TC block
minItems
:
1
maxItems
:
3
clock-names
:
description
:
List of clock names. Always includes t0_clk and slow clk. Also includes
t1_clk and t2_clk if a clock per channel is available.
minItems
:
2
maxItems
:
4
clocks
:
minItems
:
2
maxItems
:
4
'
#address-cells'
:
const
:
1
'
#size-cells'
:
const
:
0
patternProperties
:
"
^timer@[0-2]$"
:
description
:
The timer block channels that are used as timers or counters.
type
:
object
properties
:
compatible
:
items
:
-
enum
:
-
atmel,tcb-timer
-
microchip,tcb-capture
reg
:
description
:
List of channels to use for this particular timer. In Microchip TCB capture
mode channels are registered as a counter devices, for the qdec mode TCB0's
channel <0> and <1> are required.
minItems
:
1
maxItems
:
3
required
:
-
compatible
-
reg
allOf
:
-
if
:
properties
:
compatible
:
contains
:
const
:
atmel,sama5d2-tcb
then
:
properties
:
clocks
:
minItems
:
3
maxItems
:
3
clock-names
:
items
:
-
const
:
t0_clk
-
const
:
gclk
-
const
:
slow_clk
else
:
properties
:
clocks
:
minItems
:
2
maxItems
:
4
clock-names
:
oneOf
:
-
items
:
-
const
:
t0_clk
-
const
:
slow_clk
-
items
:
-
const
:
t0_clk
-
const
:
t1_clk
-
const
:
t2_clk
-
const
:
slow_clk
required
:
-
compatible
-
reg
-
interrupts
-
clocks
-
clock-names
-
'
#address-cells'
-
'
#size-cells'
additionalProperties
:
false
examples
:
-
|
/* One interrupt per TC block: */
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
clocks = <&tcb0_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>, <1>;
};
timer@2 {
compatible = "atmel,tcb-timer";
reg = <2>;
};
};
/* One interrupt per TC channel in a TC block: */
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfffdc000 0x100>;
interrupts = <26 4>, <27 4>, <28 4>;
clocks = <&tcb1_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "atmel,tcb-timer";
reg = <0>;
};
timer@1 {
compatible = "atmel,tcb-timer";
reg = <1>;
};
};
/* TCB0 Capture with QDEC: */
timer@f800c000 {
compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
clocks = <&tcb0_clk>, <&clk32k>;
clock-names = "t0_clk", "slow_clk";
timer@0 {
compatible = "microchip,tcb-capture";
reg = <0>, <1>;
};
timer@2 {
compatible = "atmel,tcb-timer";
reg = <2>;
};
};
drivers/counter/Kconfig
View file @
1c2f21be
...
@@ -70,4 +70,15 @@ config FTM_QUADDEC
...
@@ -70,4 +70,15 @@ config FTM_QUADDEC
To compile this driver as a module, choose M here: the
To compile this driver as a module, choose M here: the
module will be called ftm-quaddec.
module will be called ftm-quaddec.
config MICROCHIP_TCB_CAPTURE
tristate "Microchip Timer Counter Capture driver"
depends on HAS_IOMEM && OF
select REGMAP_MMIO
help
Select this option to enable the Microchip Timer Counter Block
capture driver.
To compile this driver as a module, choose M here: the
module will be called microchip-tcb-capture.
endif # COUNTER
endif # COUNTER
drivers/counter/Makefile
View file @
1c2f21be
...
@@ -10,3 +10,4 @@ obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
...
@@ -10,3 +10,4 @@ obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
obj-$(CONFIG_STM32_LPTIMER_CNT)
+=
stm32-lptimer-cnt.o
obj-$(CONFIG_STM32_LPTIMER_CNT)
+=
stm32-lptimer-cnt.o
obj-$(CONFIG_TI_EQEP)
+=
ti-eqep.o
obj-$(CONFIG_TI_EQEP)
+=
ti-eqep.o
obj-$(CONFIG_FTM_QUADDEC)
+=
ftm-quaddec.o
obj-$(CONFIG_FTM_QUADDEC)
+=
ftm-quaddec.o
obj-$(CONFIG_MICROCHIP_TCB_CAPTURE)
+=
microchip-tcb-capture.o
drivers/counter/microchip-tcb-capture.c
0 → 100644
View file @
1c2f21be
// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (C) 2020 Microchip
*
* Author: Kamel Bouhara <kamel.bouhara@bootlin.com>
*/
#include <linux/clk.h>
#include <linux/counter.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <soc/at91/atmel_tcb.h>
#define ATMEL_TC_CMR_MASK (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
ATMEL_TC_LDBSTOP)
#define ATMEL_TC_QDEN BIT(8)
#define ATMEL_TC_POSEN BIT(9)
struct
mchp_tc_data
{
const
struct
atmel_tcb_config
*
tc_cfg
;
struct
counter_device
counter
;
struct
regmap
*
regmap
;
int
qdec_mode
;
int
num_channels
;
int
channel
[
2
];
bool
trig_inverted
;
};
enum
mchp_tc_count_function
{
MCHP_TC_FUNCTION_INCREASE
,
MCHP_TC_FUNCTION_QUADRATURE
,
};
static
enum
counter_count_function
mchp_tc_count_functions
[]
=
{
[
MCHP_TC_FUNCTION_INCREASE
]
=
COUNTER_COUNT_FUNCTION_INCREASE
,
[
MCHP_TC_FUNCTION_QUADRATURE
]
=
COUNTER_COUNT_FUNCTION_QUADRATURE_X4
,
};
enum
mchp_tc_synapse_action
{
MCHP_TC_SYNAPSE_ACTION_NONE
=
0
,
MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
,
MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
,
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
};
static
enum
counter_synapse_action
mchp_tc_synapse_actions
[]
=
{
[
MCHP_TC_SYNAPSE_ACTION_NONE
]
=
COUNTER_SYNAPSE_ACTION_NONE
,
[
MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
]
=
COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
[
MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
]
=
COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
[
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
]
=
COUNTER_SYNAPSE_ACTION_BOTH_EDGES
,
};
static
struct
counter_signal
mchp_tc_count_signals
[]
=
{
{
.
id
=
0
,
.
name
=
"Channel A"
,
},
{
.
id
=
1
,
.
name
=
"Channel B"
,
}
};
static
struct
counter_synapse
mchp_tc_count_synapses
[]
=
{
{
.
actions_list
=
mchp_tc_synapse_actions
,
.
num_actions
=
ARRAY_SIZE
(
mchp_tc_synapse_actions
),
.
signal
=
&
mchp_tc_count_signals
[
0
]
},
{
.
actions_list
=
mchp_tc_synapse_actions
,
.
num_actions
=
ARRAY_SIZE
(
mchp_tc_synapse_actions
),
.
signal
=
&
mchp_tc_count_signals
[
1
]
}
};
static
int
mchp_tc_count_function_get
(
struct
counter_device
*
counter
,
struct
counter_count
*
count
,
size_t
*
function
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
if
(
priv
->
qdec_mode
)
*
function
=
MCHP_TC_FUNCTION_QUADRATURE
;
else
*
function
=
MCHP_TC_FUNCTION_INCREASE
;
return
0
;
}
static
int
mchp_tc_count_function_set
(
struct
counter_device
*
counter
,
struct
counter_count
*
count
,
size_t
function
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
u32
bmr
,
cmr
;
regmap_read
(
priv
->
regmap
,
ATMEL_TC_BMR
,
&
bmr
);
regmap_read
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CMR
),
&
cmr
);
/* Set capture mode */
cmr
&=
~
ATMEL_TC_WAVE
;
switch
(
function
)
{
case
MCHP_TC_FUNCTION_INCREASE
:
priv
->
qdec_mode
=
0
;
/* Set highest rate based on whether soc has gclk or not */
bmr
&=
~
(
ATMEL_TC_QDEN
|
ATMEL_TC_POSEN
);
if
(
priv
->
tc_cfg
->
has_gclk
)
cmr
|=
ATMEL_TC_TIMER_CLOCK2
;
else
cmr
|=
ATMEL_TC_TIMER_CLOCK1
;
/* Setup the period capture mode */
cmr
|=
ATMEL_TC_CMR_MASK
;
cmr
&=
~
(
ATMEL_TC_ABETRG
|
ATMEL_TC_XC0
);
break
;
case
MCHP_TC_FUNCTION_QUADRATURE
:
if
(
!
priv
->
tc_cfg
->
has_qdec
)
return
-
EINVAL
;
/* In QDEC mode settings both channels 0 and 1 are required */
if
(
priv
->
num_channels
<
2
||
priv
->
channel
[
0
]
!=
0
||
priv
->
channel
[
1
]
!=
1
)
{
pr_err
(
"Invalid channels number or id for quadrature mode
\n
"
);
return
-
EINVAL
;
}
priv
->
qdec_mode
=
1
;
bmr
|=
ATMEL_TC_QDEN
|
ATMEL_TC_POSEN
;
cmr
|=
ATMEL_TC_ETRGEDG_RISING
|
ATMEL_TC_ABETRG
|
ATMEL_TC_XC0
;
break
;
}
regmap_write
(
priv
->
regmap
,
ATMEL_TC_BMR
,
bmr
);
regmap_write
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CMR
),
cmr
);
/* Enable clock and trigger counter */
regmap_write
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CCR
),
ATMEL_TC_CLKEN
|
ATMEL_TC_SWTRG
);
if
(
priv
->
qdec_mode
)
{
regmap_write
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
1
],
CMR
),
cmr
);
regmap_write
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
1
],
CCR
),
ATMEL_TC_CLKEN
|
ATMEL_TC_SWTRG
);
}
return
0
;
}
static
int
mchp_tc_count_signal_read
(
struct
counter_device
*
counter
,
struct
counter_signal
*
signal
,
enum
counter_signal_value
*
val
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
bool
sigstatus
;
u32
sr
;
regmap_read
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
SR
),
&
sr
);
if
(
priv
->
trig_inverted
)
sigstatus
=
(
sr
&
ATMEL_TC_MTIOB
);
else
sigstatus
=
(
sr
&
ATMEL_TC_MTIOA
);
*
val
=
sigstatus
?
COUNTER_SIGNAL_HIGH
:
COUNTER_SIGNAL_LOW
;
return
0
;
}
static
int
mchp_tc_count_action_get
(
struct
counter_device
*
counter
,
struct
counter_count
*
count
,
struct
counter_synapse
*
synapse
,
size_t
*
action
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
u32
cmr
;
regmap_read
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CMR
),
&
cmr
);
*
action
=
MCHP_TC_SYNAPSE_ACTION_NONE
;
if
(
cmr
&
ATMEL_TC_ETRGEDG_NONE
)
*
action
=
MCHP_TC_SYNAPSE_ACTION_NONE
;
else
if
(
cmr
&
ATMEL_TC_ETRGEDG_RISING
)
*
action
=
MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
;
else
if
(
cmr
&
ATMEL_TC_ETRGEDG_FALLING
)
*
action
=
MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
;
else
if
(
cmr
&
ATMEL_TC_ETRGEDG_BOTH
)
*
action
=
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
;
return
0
;
}
static
int
mchp_tc_count_action_set
(
struct
counter_device
*
counter
,
struct
counter_count
*
count
,
struct
counter_synapse
*
synapse
,
size_t
action
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
u32
edge
=
ATMEL_TC_ETRGEDG_NONE
;
/* QDEC mode is rising edge only */
if
(
priv
->
qdec_mode
)
return
-
EINVAL
;
switch
(
action
)
{
case
MCHP_TC_SYNAPSE_ACTION_NONE
:
edge
=
ATMEL_TC_ETRGEDG_NONE
;
break
;
case
MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
:
edge
=
ATMEL_TC_ETRGEDG_RISING
;
break
;
case
MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
:
edge
=
ATMEL_TC_ETRGEDG_FALLING
;
break
;
case
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
:
edge
=
ATMEL_TC_ETRGEDG_BOTH
;
break
;
}
return
regmap_write_bits
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CMR
),
ATMEL_TC_ETRGEDG
,
edge
);
}
static
int
mchp_tc_count_read
(
struct
counter_device
*
counter
,
struct
counter_count
*
count
,
unsigned
long
*
val
)
{
struct
mchp_tc_data
*
const
priv
=
counter
->
priv
;
u32
cnt
;
regmap_read
(
priv
->
regmap
,
ATMEL_TC_REG
(
priv
->
channel
[
0
],
CV
),
&
cnt
);
*
val
=
cnt
;
return
0
;
}
static
struct
counter_count
mchp_tc_counts
[]
=
{
{
.
id
=
0
,
.
name
=
"Timer Counter"
,
.
functions_list
=
mchp_tc_count_functions
,
.
num_functions
=
ARRAY_SIZE
(
mchp_tc_count_functions
),
.
synapses
=
mchp_tc_count_synapses
,
.
num_synapses
=
ARRAY_SIZE
(
mchp_tc_count_synapses
),
},
};
static
struct
counter_ops
mchp_tc_ops
=
{
.
signal_read
=
mchp_tc_count_signal_read
,
.
count_read
=
mchp_tc_count_read
,
.
function_get
=
mchp_tc_count_function_get
,
.
function_set
=
mchp_tc_count_function_set
,
.
action_get
=
mchp_tc_count_action_get
,
.
action_set
=
mchp_tc_count_action_set
};
static
const
struct
atmel_tcb_config
tcb_rm9200_config
=
{
.
counter_width
=
16
,
};
static
const
struct
atmel_tcb_config
tcb_sam9x5_config
=
{
.
counter_width
=
32
,
};
static
const
struct
atmel_tcb_config
tcb_sama5d2_config
=
{
.
counter_width
=
32
,
.
has_gclk
=
true
,
.
has_qdec
=
true
,
};
static
const
struct
atmel_tcb_config
tcb_sama5d3_config
=
{
.
counter_width
=
32
,
.
has_qdec
=
true
,
};
static
const
struct
of_device_id
atmel_tc_of_match
[]
=
{
{
.
compatible
=
"atmel,at91rm9200-tcb"
,
.
data
=
&
tcb_rm9200_config
,
},
{
.
compatible
=
"atmel,at91sam9x5-tcb"
,
.
data
=
&
tcb_sam9x5_config
,
},
{
.
compatible
=
"atmel,sama5d2-tcb"
,
.
data
=
&
tcb_sama5d2_config
,
},
{
.
compatible
=
"atmel,sama5d3-tcb"
,
.
data
=
&
tcb_sama5d3_config
,
},
{
/* sentinel */
}
};
static
void
mchp_tc_clk_remove
(
void
*
ptr
)
{
clk_disable_unprepare
((
struct
clk
*
)
ptr
);
}
static
int
mchp_tc_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
const
struct
atmel_tcb_config
*
tcb_config
;
const
struct
of_device_id
*
match
;
struct
mchp_tc_data
*
priv
;
char
clk_name
[
7
];
struct
regmap
*
regmap
;
struct
clk
*
clk
[
3
];
int
channel
;
int
ret
,
i
;
priv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
platform_set_drvdata
(
pdev
,
priv
);
match
=
of_match_node
(
atmel_tc_of_match
,
np
->
parent
);
tcb_config
=
match
->
data
;
if
(
!
tcb_config
)
{
dev_err
(
&
pdev
->
dev
,
"No matching parent node found
\n
"
);
return
-
ENODEV
;
}
regmap
=
syscon_node_to_regmap
(
np
->
parent
);
if
(
IS_ERR
(
priv
->
regmap
))
return
PTR_ERR
(
priv
->
regmap
);
/* max. channels number is 2 when in QDEC mode */
priv
->
num_channels
=
of_property_count_u32_elems
(
np
,
"reg"
);
if
(
priv
->
num_channels
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Invalid or missing channel
\n
"
);
return
-
EINVAL
;
}
/* Register channels and initialize clocks */
for
(
i
=
0
;
i
<
priv
->
num_channels
;
i
++
)
{
ret
=
of_property_read_u32_index
(
np
,
"reg"
,
i
,
&
channel
);
if
(
ret
<
0
||
channel
>
2
)
return
-
ENODEV
;
priv
->
channel
[
i
]
=
channel
;
snprintf
(
clk_name
,
sizeof
(
clk_name
),
"t%d_clk"
,
channel
);
clk
[
i
]
=
of_clk_get_by_name
(
np
->
parent
,
clk_name
);
if
(
IS_ERR
(
clk
[
i
]))
{
/* Fallback to t0_clk */
clk
[
i
]
=
of_clk_get_by_name
(
np
->
parent
,
"t0_clk"
);
if
(
IS_ERR
(
clk
[
i
]))
return
PTR_ERR
(
clk
[
i
]);
}
ret
=
clk_prepare_enable
(
clk
[
i
]);
if
(
ret
)
return
ret
;
ret
=
devm_add_action_or_reset
(
&
pdev
->
dev
,
mchp_tc_clk_remove
,
clk
[
i
]);
if
(
ret
)
return
ret
;
dev_dbg
(
&
pdev
->
dev
,
"Initialized capture mode on channel %d
\n
"
,
channel
);
}
priv
->
tc_cfg
=
tcb_config
;
priv
->
regmap
=
regmap
;
priv
->
counter
.
name
=
dev_name
(
&
pdev
->
dev
);
priv
->
counter
.
parent
=
&
pdev
->
dev
;
priv
->
counter
.
ops
=
&
mchp_tc_ops
;
priv
->
counter
.
num_counts
=
ARRAY_SIZE
(
mchp_tc_counts
);
priv
->
counter
.
counts
=
mchp_tc_counts
;
priv
->
counter
.
num_signals
=
ARRAY_SIZE
(
mchp_tc_count_signals
);
priv
->
counter
.
signals
=
mchp_tc_count_signals
;
priv
->
counter
.
priv
=
priv
;
return
devm_counter_register
(
&
pdev
->
dev
,
&
priv
->
counter
);
}
static
const
struct
of_device_id
mchp_tc_dt_ids
[]
=
{
{
.
compatible
=
"microchip,tcb-capture"
,
},
{
/* sentinel */
},
};
MODULE_DEVICE_TABLE
(
of
,
mchp_tc_dt_ids
);
static
struct
platform_driver
mchp_tc_driver
=
{
.
probe
=
mchp_tc_probe
,
.
driver
=
{
.
name
=
"microchip-tcb-capture"
,
.
of_match_table
=
mchp_tc_dt_ids
,
},
};
module_platform_driver
(
mchp_tc_driver
);
MODULE_AUTHOR
(
"Kamel Bouhara <kamel.bouhara@bootlin.com>"
);
MODULE_DESCRIPTION
(
"Microchip TCB Capture driver"
);
MODULE_LICENSE
(
"GPL v2"
);
include/soc/at91/atmel_tcb.h
View file @
1c2f21be
...
@@ -36,9 +36,14 @@ struct clk;
...
@@ -36,9 +36,14 @@ struct clk;
/**
/**
* struct atmel_tcb_config - SoC data for a Timer/Counter Block
* struct atmel_tcb_config - SoC data for a Timer/Counter Block
* @counter_width: size in bits of a timer counter register
* @counter_width: size in bits of a timer counter register
* @has_gclk: boolean indicating if a timer counter has a generic clock
* @has_qdec: boolean indicating if a timer counter has a quadrature
* decoder.
*/
*/
struct
atmel_tcb_config
{
struct
atmel_tcb_config
{
size_t
counter_width
;
size_t
counter_width
;
bool
has_gclk
;
bool
has_qdec
;
};
};
/**
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment