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
500adba8
Commit
500adba8
authored
Apr 17, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
acam: initial (not complete) implementation
parent
d52abcd9
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
190 additions
and
1 deletion
+190
-1
acam.c
acam.c
+176
-0
fine-delay.h
fine-delay.h
+14
-1
No files found.
acam.c
View file @
500adba8
/*
* Accessing the ACAM chip and configuring it.
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
#include "hw/acam_gpx.h"
/*
* Calculation is fixed point: picoseconds and 16 decimals (i.e. ps << 16).
* We know the bin is small, but the Tref is several nanos so we need 64 bits
* (although our current values fit in 32 bits after the division)
*/
#define ACAM_FP_BIN ((int)(ACAM_DESIRED_BIN * (1 << 16)))
#define ACAM_FP_TREF (((1000LL * 1000 * 1000) << 16) / ACAM_CLOCK_FREQ_KHZ)
static
int
acam_calc_pll
(
uint64_t
tref
,
int
bin
,
int
*
hsdiv_out
,
int
*
refdiv_out
)
{
int
x
,
refdiv
,
hsdiv
;
/*
* Tbin(I-mode) = (Tref << refdiv) / (216 * hsdiv)
*
* so, calling X the value "hsdiv >> refdiv" we have
*
* X = Tref / (216 * Tbin)
*
* Then, we can choose refdiv == 7 to have the best bits,
* and then shift out the zeros to get smaller values.
*
*/
x
=
(
tref
<<
16
)
/
216
/
bin
;
//printf("x = %lf\n", (double)x / (1<<16));
/* Now, shift out the max bits (usually 7) and drop decimal part */
refdiv
=
ACAM_MAX_REFDIV
;
hsdiv
=
(
x
<<
refdiv
)
>>
16
;
/* Check the first decimal bit and approximate */
if
((
x
<<
refdiv
)
&
(
1
<<
15
))
hsdiv
++
;
/* until we have zeroes as LSB, shift out to decrease pll quotient */
while
(
refdiv
>
0
&&
!
(
hsdiv
&
1
))
{
refdiv
--
;
hsdiv
>>=
1
;
}
*
hsdiv_out
=
hsdiv
;
*
refdiv_out
=
refdiv
;
/* Finally, calculate what we really have */
return
(
tref
<<
refdiv
)
/
216
/
hsdiv
;
}
static
void
acam_set_address
(
struct
spec_fd
*
fd
,
int
addr
)
{
if
(
addr
==
fd
->
acam_addr
)
return
;
if
(
fd
->
acam_addr
==
-
1
)
{
/* first time */
fd_gpio_dir
(
fd
,
0xf00
,
FD_GPIO_OUT
);
}
fd_gpio_val
(
fd
,
0xf00
,
addr
<<
8
);
fd
->
acam_addr
=
addr
;
}
/* Warning: acam_readl and acam_writel only work if GCR.BYPASS is set */
static
uint32_t
acam_readl
(
struct
spec_fd
*
fd
,
int
reg
)
{
acam_set_address
(
fd
,
reg
);
writel
(
FD_TDCSR_READ
,
fd
->
regs
+
FD_REG_TDCSR
);
return
readl
(
fd
->
regs
+
FD_REG_TDR
)
&
ACAM_MASK
;
}
static
void
acam_writel
(
struct
spec_fd
*
fd
,
int
val
,
int
reg
)
{
writel
(
val
,
fd
->
regs
+
FD_REG_TDR
);
writel
(
FD_TDCSR_WRITE
,
fd
->
regs
+
FD_REG_TDCSR
);
}
static
inline
int
acam_is_pll_locked
(
struct
spec_fd
*
fd
)
{
return
!
(
acam_readl
(
fd
,
12
)
&
AR12_NotLocked
);
}
/* Two test functions to verify the bus is working -- Tom */
static
int
acam_test_addr_bit
(
struct
spec_fd
*
fd
,
int
base
,
int
bit
,
int
data
)
{
int
addr1
=
base
;
int
addr2
=
base
+
(
1
<<
bit
);
int
reg
;
reg
=
acam_readl
(
fd
,
addr1
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr2
)
|
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
0
)
return
-
EIO
;
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
data
)
return
-
EIO
;
/* the other way around */
reg
=
acam_readl
(
fd
,
addr2
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr1
)
|
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
0
)
goto
out
;
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
data
)
goto
out
;
return
0
;
out:
pr_err
(
"%s: ACAM address bit %i failure
\n
"
,
KBUILD_MODNAME
,
bit
);
return
-
EIO
;
}
static
int
acam_test_bus
(
struct
spec_fd
*
fd
)
{
int
err
=
0
,
i
,
v
;
/* Use register 5 to checke the data bits */
for
(
i
=
0
;
i
&
ACAM_MASK
;
i
<<=
1
)
{
acam_writel
(
fd
,
i
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
i
)
goto
out
;
acam_writel
(
fd
,
~
i
&
ACAM_MASK
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
(
~
i
&
ACAM_MASK
))
goto
out
;
}
err
+=
acam_test_addr_bit
(
fd
,
0
,
0
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
1
,
1
,
0x000008
);
err
+=
acam_test_addr_bit
(
fd
,
0
,
2
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
3
,
3
,
0x010000
);
if
(
err
)
return
-
EIO
;
return
0
;
out:
pr_err
(
"%s: ACAM data bit 0x%06x failure
\n
"
,
KBUILD_MODNAME
,
i
);
return
-
EIO
;
}
int
fd_acam_init
(
struct
spec_fd
*
fd
)
{
fd
->
acam_addr
=
-
1
;
/* First time must be activated */
return
0
;
}
void
fd_acam_exit
(
struct
spec_fd
*
fd
)
{
/* nothing to do */
}
fine-delay.h
View file @
500adba8
...
...
@@ -3,12 +3,25 @@
struct
spec_fd
{
struct
spec_dev
*
spec
;
unsigned
char
__iomem
*
base
;
/* regs files are byte-oriented */
unsigned
char
__iomem
*
base
;
/* regs files are byte-oriented */
unsigned
char
__iomem
*
regs
;
int
acam_addr
;
/* cache of currently active addr */
};
#define FD_REGS_OFFSET 0x84000
/* Values for the configuration of the acam PLL. Can be changed */
#define ACAM_DESIRED_BIN 80.9553
#define ACAM_CLOCK_FREQ_KHZ 31250
/*
* You can change the following value to have a pll with smaller divisor,
* at the cost of potentially less precision in the desired bin value.
*/
#define ACAM_MAX_REFDIV 7
#define ACAM_MASK ((1<<29) - 1)
/* 28 bits */
/* SPI Bus chip selects */
#define FD_CS_PLL 1
/* AD9516 PLL */
#define FD_CS_GPIO 2
/* MCP23S17 GPIO */
...
...
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