Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC DEL 1ns 4cha - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC DEL 1ns 4cha - Software
Commits
50929814
Commit
50929814
authored
Oct 25, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel: added interrupt support
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
a40dfd76
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
106 additions
and
18 deletions
+106
-18
fd-irq.c
kernel/fd-irq.c
+104
-18
fine-delay.h
kernel/fine-delay.h
+2
-0
No files found.
kernel/fd-irq.c
View file @
50929814
...
...
@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/io.h>
...
...
@@ -29,6 +30,7 @@
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
#include "hw/fd_channel_regs.h"
#include "hw/vic_regs.h"
static
int
fd_sw_fifo_len
=
FD_SW_FIFO_LEN
;
module_param_named
(
fifo_len
,
fd_sw_fifo_len
,
int
,
0444
);
...
...
@@ -156,16 +158,18 @@ static int fd_read_hw_fifo(struct fd_dev *fd)
* We have a timer, used to poll for input samples, until the interrupt
* is there. A timer duration of 0 selects the interrupt.
*/
static
int
fd_timer_period_ms
=
1
0
;
static
int
fd_timer_period_ms
=
0
;
module_param_named
(
timer_ms
,
fd_timer_period_ms
,
int
,
0444
);
static
int
fd_timer_period_jiffies
;
/* converted from ms at init time */
static
void
fd_timer_fn
(
unsigned
long
arg
)
/* This acts as either a timer or an interrupt tasklet */
static
void
fd_tlet
(
unsigned
long
arg
)
{
struct
fd_dev
*
fd
=
(
void
*
)
arg
;
struct
zio_channel
*
chan
=
NULL
;
struct
zio_device
*
zdev
=
fd
->
zdev
;
struct
fmc_device
*
fmc
=
fd
->
fmc
;
int
i
;
/* Always read the hardware fifo until empty */
...
...
@@ -179,6 +183,7 @@ static void fd_timer_fn(unsigned long arg)
goto
out
;
}
/* FIXME: race condition */
if
(
!
test_bit
(
FD_FLAG_INPUT_READY
,
&
fd
->
flags
))
goto
out
;
...
...
@@ -197,25 +202,67 @@ out:
pr_debug
(
"called data_done
\n
"
);
}
mod_timer
(
&
fd
->
fifo_timer
,
jiffies
+
fd_timer_period_jiffies
);
if
(
fd_timer_period_ms
)
mod_timer
(
&
fd
->
fifo_timer
,
jiffies
+
fd_timer_period_jiffies
);
else
{
/* ack at this point, but may be redundant */
fmc
->
op
->
irq_ack
(
fmc
);
fmc_writel
(
fmc
,
0
,
FD_VIC_BASE
+
VIC_REG_EOIR
);
}
}
int
fd_irq_init
(
struct
fd_dev
*
fd
)
irqreturn_t
fd_irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
fmc_device
*
fmc
=
dev_id
;
struct
fd_dev
*
fd
=
fmc
->
mezzanine_data
;
/* This is not per-device, but it works anyways */
fd_timer_period_jiffies
=
msecs_to_jiffies
(
fd_timer_period_ms
);
if
(
fd_timer_period_ms
)
{
pr_info
(
"%s: using a timer for input stamps (%i ms)
\n
"
,
KBUILD_MODNAME
,
fd_timer_period_ms
);
}
else
{
pr_info
(
"%s: NOT using interrupt (not implemented)
\n
"
,
KBUILD_MODNAME
);
return
-
EINVAL
;
if
((
fd_readl
(
fd
,
FD_REG_TSBCR
)
&
FD_TSBCR_EMPTY
))
goto
out_unexpected
;
/* bah! */
/*
* We must empty the fifo in hardware, and ack at this point.
* I used to disable_irq() and empty the fifo in the tasklet,
* but it doesn't work because the hw request is still pending
*/
while
(
!
fd_read_hw_fifo
(
fd
))
;
tasklet_schedule
(
&
fd
->
tlet
);
out_unexpected:
/*
* This may be an unexpected interrupt (it may not even be
* use, but still on the SPEC we must ack, or the system locks
* up, entering the interrupt again and again
*/
fmc
->
op
->
irq_ack
(
fmc
);
fmc_writel
(
fmc
,
0
,
FD_VIC_BASE
+
VIC_REG_EOIR
);
return
IRQ_HANDLED
;
}
/* Unfortunately, on the spec this is GPIO9, i.e. IRQ(1) */
static
struct
fmc_gpio
fd_gpio_on
[]
=
{
{
.
gpio
=
FMC_GPIO_IRQ
(
1
),
.
mode
=
GPIOF_DIR_IN
,
.
irqmode
=
IRQF_TRIGGER_RISING
,
}
};
static
struct
fmc_gpio
fd_gpio_off
[]
=
{
{
.
gpio
=
FMC_GPIO_IRQ
(
1
),
.
mode
=
GPIOF_DIR_IN
,
.
irqmode
=
0
,
}
};
/* Also, check that the sw fifo size is a power of two */
int
fd_irq_init
(
struct
fd_dev
*
fd
)
{
struct
fmc_device
*
fmc
=
fd
->
fmc
;
uint32_t
vic_ctl
;
/* Check that the sw fifo size is a power of two */
if
(
fd_sw_fifo_len
&
(
fd_sw_fifo_len
-
1
))
{
pr_err
(
"%s: fifo len must be a power of 2 (not %d = 0x%x)
\n
"
,
KBUILD_MODNAME
,
fd_sw_fifo_len
,
fd_sw_fifo_len
);
...
...
@@ -227,16 +274,55 @@ int fd_irq_init(struct fd_dev *fd)
if
(
!
fd
->
sw_fifo
.
t
)
return
-
ENOMEM
;
setup_timer
(
&
fd
->
fifo_timer
,
fd_timer_fn
,
(
unsigned
long
)
fd
);
if
(
fd_timer_period_ms
)
fd_timer_period_jiffies
=
msecs_to_jiffies
(
fd_timer_period_ms
);
/*
* According to the period, this can work with a timer (old way)
* or a custom tasklet (newer). Init both anyways, no harm is done.
*/
setup_timer
(
&
fd
->
fifo_timer
,
fd_tlet
,
(
unsigned
long
)
fd
);
tasklet_init
(
&
fd
->
tlet
,
fd_tlet
,
(
unsigned
long
)
fd
);
if
(
fd_timer_period_ms
)
{
dev_info
(
fd
->
fmc
->
hwdev
,
"Using a timer for input (%i ms)
\n
"
,
jiffies_to_msecs
(
fd_timer_period_jiffies
));
mod_timer
(
&
fd
->
fifo_timer
,
jiffies
+
fd_timer_period_jiffies
);
}
else
{
dev_info
(
fd
->
fmc
->
hwdev
,
"Using interrupts for input
\n
"
);
fmc
->
op
->
irq_request
(
fmc
,
fd_irq_handler
,
"fine-delay"
,
IRQF_SHARED
);
/* Then, configure hardware: fd, then vic, finally carrier */
fd_writel
(
fd
,
FD_EIC_IER_TS_BUF_NOTEMPTY
,
FD_REG_EIC_IER
);
/* 4us edge emulation timer (counts in 16ns steps) */
vic_ctl
=
VIC_CTL_EMU_EDGE
|
VIC_CTL_EMU_LEN_W
(
4000
/
16
);
fmc_writel
(
fmc
,
vic_ctl
|
VIC_CTL_ENABLE
|
VIC_CTL_POL
,
FD_VIC_BASE
+
VIC_REG_CTL
);
fmc_writel
(
fmc
,
1
,
FD_VIC_BASE
+
VIC_REG_IER
);
fmc
->
op
->
gpio_config
(
fmc
,
fd_gpio_on
,
ARRAY_SIZE
(
fd_gpio_on
));
}
/* let it run... */
fd_writel
(
fd
,
FD_GCR_INPUT_EN
,
FD_REG_GCR
);
return
0
;
}
void
fd_irq_exit
(
struct
fd_dev
*
fd
)
{
del_timer_sync
(
&
fd
->
fifo_timer
);
struct
fmc_device
*
fmc
=
fd
->
fmc
;
if
(
fd_timer_period_ms
)
{
del_timer_sync
(
&
fd
->
fifo_timer
);
}
else
{
/* disable interrupts: first carrier, than vic, then fd */
fmc
->
op
->
gpio_config
(
fmc
,
fd_gpio_off
,
ARRAY_SIZE
(
fd_gpio_off
));
fmc_writel
(
fmc
,
1
,
FD_VIC_BASE
+
VIC_REG_IDR
);
fd_writel
(
fd
,
~
0
,
FD_REG_EIC_IDR
);
fmc_writel
(
fmc
,
VIC_CTL_POL
,
FD_VIC_BASE
+
VIC_REG_CTL
);
fmc
->
op
->
irq_free
(
fmc
);
}
kfree
(
fd
->
sw_fifo
.
t
);
}
kernel/fine-delay.h
View file @
50929814
...
...
@@ -127,6 +127,7 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
#define FD_REGS_BASE 0x80000
/* sdb_find_device(cern, f19ede1a) */
#define FD_OWREGS_BASE (FD_REGS_BASE + 0x500)
#define FD_VIC_BASE 0x90000
/* sdb_find_device(cern, 00000013) */
struct
fd_calib
{
int64_t
frr_poly
[
3
];
/* SY89295 delay/temp poly coeffs */
...
...
@@ -190,6 +191,7 @@ struct fd_dev {
struct
zio_device
*
zdev
,
*
hwzdev
;
struct
timer_list
fifo_timer
;
struct
timer_list
temp_timer
;
struct
tasklet_struct
tlet
;
struct
fd_calib
calib
;
struct
fd_ch
ch
[
FD_CH_NUMBER
];
uint32_t
bin
;
...
...
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