Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC ADC 100M 14b 4cha - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
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 ADC 100M 14b 4cha - Software
Commits
84c7786a
Commit
84c7786a
authored
Dec 06, 2013
by
Michel Arruat
Committed by
Alessandro Rubini
Mar 01, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
move code from zio-drv.c to fa-core.c (no technical change)
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
8fb1a9a6
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
232 additions
and
230 deletions
+232
-230
fa-core.c
kernel/fa-core.c
+223
-0
fa-zio-drv.c
kernel/fa-zio-drv.c
+0
-230
fmc-adc.h
kernel/fmc-adc.h
+9
-0
No files found.
kernel/fa-core.c
View file @
84c7786a
...
...
@@ -21,6 +21,229 @@ FMC_PARAM_BUSID(fa_dev_drv);
static
char
*
fa_binary
=
FA_GATEWARE_DEFAULT_NAME
;
module_param_named
(
file
,
fa_binary
,
charp
,
0444
);
static
const
int
zfad_hw_range
[]
=
{
[
ZFA_RANGE_10V
]
=
0x45
,
[
ZFA_RANGE_1V
]
=
0x11
,
[
ZFA_RANGE_100mV
]
=
0x23
,
[
ZFA_RANGE_OPEN
]
=
0x00
,
};
/*
* zfad_convert_hw_range
* @usr_val: range value
*
* return the enum associated to the range value
*/
int
zfad_convert_hw_range
(
uint32_t
bitmask
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
zfad_hw_range
);
i
++
)
if
(
zfad_hw_range
[
i
]
==
bitmask
)
return
i
;
return
-
EINVAL
;
}
/* Calculate correct index for channel from CHx indexes */
int
zfad_get_chx_index
(
unsigned
long
addr
,
struct
zio_channel
*
chan
)
{
int
offset
;
offset
=
ZFA_CHx_MULT
*
(
FA_NCHAN
-
chan
->
index
);
return
addr
-
offset
;
}
/*
* zfad_apply_user_offset
* @fa: the fmc-adc descriptor
* @chan: the channel where apply offset
* @usr_val: the offset value to apply, expressed as millivolts (-5000..5000)
*
* Apply user offset to the channel input. Before apply the user offset it must
* be corrected with offset and gain calibration value. An open input does not
* need any correction.
*/
int
zfad_apply_user_offset
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
uint32_t
usr_val
)
{
uint32_t
range_reg
;
int32_t
uval
=
(
int32_t
)
usr_val
;
int
offset
,
gain
,
hwval
,
i
,
range
;
if
(
uval
<
-
5000
||
uval
>
5000
)
return
-
EINVAL
;
i
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
zfa_hardware_read
(
fa
,
i
,
&
range_reg
);
range
=
zfad_convert_hw_range
(
range_reg
);
if
(
range
<
0
)
return
range
;
if
(
range
==
ZFA_RANGE_OPEN
)
{
offset
=
FA_CAL_NO_OFFSET
;
gain
=
FA_CAL_NO_GAIN
;
}
else
{
offset
=
fa
->
calib
.
dac
[
range
].
offset
[
chan
->
index
];
gain
=
fa
->
calib
.
dac
[
range
].
gain
[
chan
->
index
];
}
hwval
=
uval
*
0x8000
/
5000
;
if
(
hwval
==
0x8000
)
hwval
=
0x7fff
;
/* -32768 .. 32767 */
hwval
=
((
hwval
+
offset
)
*
gain
)
>>
15
;
/* signed */
hwval
+=
0x8000
;
/* offset binary */
if
(
hwval
<
0
)
hwval
=
0
;
if
(
hwval
>
0xffff
)
hwval
=
0xffff
;
/* Apply calibrated offset to DAC */
return
fa_spi_xfer
(
fa
,
FA_SPI_SS_DAC
(
chan
->
index
),
16
,
hwval
,
NULL
);
}
/*
* zfad_reset_offset
* @fa: the fmc-adc descriptor
*
* Reset channel's offsets
*/
void
zfad_reset_offset
(
struct
fa_dev
*
fa
)
{
int
i
;
for
(
i
=
0
;
i
<
FA_NCHAN
;
++
i
)
zfad_apply_user_offset
(
fa
,
&
fa
->
zdev
->
cset
->
chan
[
i
],
0
);
}
/*
* zfad_set_range
* @fa: the fmc-adc descriptor
* @chan: the channel to calibrate
* @usr_val: the volt range to set and calibrate
*
* When the input range changes, we must write new fixup values
*/
int
zfad_set_range
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
int
range
)
{
int
i
,
offset
,
gain
;
/* Actually set the range */
i
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
zfa_hardware_write
(
fa
,
i
,
zfad_hw_range
[
range
]);
if
(
range
==
ZFA_RANGE_OPEN
)
{
offset
=
FA_CAL_NO_OFFSET
;
gain
=
FA_CAL_NO_GAIN
;
}
else
{
if
(
range
<
0
||
range
>
ARRAY_SIZE
(
fa
->
calib
.
adc
))
{
dev_info
(
&
fa
->
fmc
->
dev
,
"Invalid range %i or ch %i
\n
"
,
range
,
chan
->
index
);
return
-
EINVAL
;
}
offset
=
fa
->
calib
.
adc
[
range
].
offset
[
chan
->
index
];
gain
=
fa
->
calib
.
adc
[
range
].
gain
[
chan
->
index
];
}
i
=
zfad_get_chx_index
(
ZFA_CHx_OFFSET
,
chan
);
zfa_hardware_write
(
fa
,
i
,
offset
&
0xffff
);
/* prevent warning */
i
=
zfad_get_chx_index
(
ZFA_CHx_GAIN
,
chan
);
zfa_hardware_write
(
fa
,
i
,
gain
);
/* recalculate user offset for the new range */
zfad_apply_user_offset
(
fa
,
chan
,
fa
->
user_offset
[
chan
->
index
]);
return
0
;
}
/*
* zfad_fsm_command
* @fa: the fmc-adc descriptor
* @command: the command to apply to FSM
*
* This function checks if the command can be done and performs some
* preliminary operation beforehand
*/
int
zfad_fsm_command
(
struct
fa_dev
*
fa
,
uint32_t
command
)
{
struct
device
*
dev
=
&
fa
->
fmc
->
dev
;
struct
zio_cset
*
cset
=
fa
->
zdev
->
cset
;
uint32_t
val
;
if
(
command
!=
ZFA_START
&&
command
!=
ZFA_STOP
)
{
dev_info
(
dev
,
"Invalid command %i
\n
"
,
command
);
return
-
EINVAL
;
}
/*
* When any command occurs we are ready to start a new acquisition, so
* we must abort any previous one. If it is STOP, we abort because we
* abort an acquisition. If it is START, we abort because if there was
* a previous start but the acquisition end interrupt doesn't occurs,
* START mean RESTART. If it is a clean START, the abort has not
* effects.
*
* This is done only if ADC is using its own trigger, otherwise it is
* not necessary.
*
* The case of fmc-adc-trg is optimized because is the most common
* case
*/
if
(
likely
(
cset
->
trig
==
&
zfat_type
||
command
==
ZFA_STOP
))
zio_trigger_abort_disable
(
cset
,
0
);
/* Reset counters */
fa
->
n_shots
=
0
;
fa
->
n_fires
=
0
;
/* If START, check if we can start */
if
(
command
==
ZFA_START
)
{
/* Verify that SerDes PLL is lockes */
zfa_hardware_read
(
fa
,
ZFA_STA_SERDES_PLL
,
&
val
);
if
(
!
val
)
{
dev_info
(
dev
,
"Cannot start acquisition: "
"SerDes PLL not locked
\n
"
);
return
-
EBUSY
;
}
/* Verify that SerDes is synched */
zfa_hardware_read
(
fa
,
ZFA_STA_SERDES_SYNCED
,
&
val
);
if
(
!
val
)
{
dev_info
(
dev
,
"Cannot start acquisition: "
"SerDes not synchronized
\n
"
);
return
-
EBUSY
;
}
/* Now we can arm the trigger for the incoming acquisition */
zio_arm_trigger
(
cset
->
ti
);
/*
* FIXME maybe zio_arm_trigger() can return an error when it
* is not able to arm a trigger.
*
* It returns -EPERM, but the error can be -ENOMEM or -EINVAL
* from zfat_arm_trigger() or zfad_input_cset()
*/
if
(
!
(
cset
->
ti
->
flags
&
ZIO_TI_ARMED
))
{
dev_info
(
dev
,
"Cannot start acquisition: "
"Trigger refuses to arm
\n
"
);
return
-
EIO
;
}
dev_dbg
(
dev
,
"FSM START Command, Enable interrupts
\n
"
);
zfa_hardware_write
(
fa
,
ZFA_IRQ_MASK
,
ZFAT_ALL
);
}
else
{
dev_dbg
(
dev
,
"FSM STOP Command, Disable interrupts
\n
"
);
zfa_hardware_write
(
fa
,
ZFA_IRQ_MASK
,
ZFAT_NONE
);
}
zfa_hardware_write
(
fa
,
ZFA_CTL_FMS_CMD
,
command
);
return
0
;
}
/* This structure lists the various subsystems */
struct
fa_modlist
{
char
*
name
;
...
...
kernel/fa-zio-drv.c
View file @
84c7786a
...
...
@@ -142,242 +142,12 @@ static struct zio_attribute zfad_dev_ext_zattr[] = {
ZIO_PARAM_EXT
(
"temperature"
,
ZIO_RO_PERM
,
ZFA_SW_R_NOADDRES_TEMP
,
0
),
};
/* Prototypes */
static
int
zfad_apply_user_offset
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
uint32_t
usr_val
);
/* Calculate correct index for channel from CHx indexes */
static
inline
int
zfad_get_chx_index
(
unsigned
long
addr
,
struct
zio_channel
*
chan
)
{
int
offset
;
offset
=
ZFA_CHx_MULT
*
(
FA_NCHAN
-
chan
->
index
);
return
addr
-
offset
;
}
/*
* zfad_fsm_command
* @fa: the fmc-adc descriptor
* @command: the command to apply to FSM
*
* This function checks if the command can be done and performs some
* preliminary operation beforehand
*/
int
zfad_fsm_command
(
struct
fa_dev
*
fa
,
uint32_t
command
)
{
struct
device
*
dev
=
&
fa
->
fmc
->
dev
;
struct
zio_cset
*
cset
=
fa
->
zdev
->
cset
;
uint32_t
val
;
if
(
command
!=
ZFA_START
&&
command
!=
ZFA_STOP
)
{
dev_info
(
dev
,
"Invalid command %i
\n
"
,
command
);
return
-
EINVAL
;
}
/*
* When any command occurs we are ready to start a new acquisition, so
* we must abort any previous one. If it is STOP, we abort because we
* abort an acquisition. If it is START, we abort because if there was
* a previous start but the acquisition end interrupt doesn't occurs,
* START mean RESTART. If it is a clean START, the abort has not
* effects.
*
* This is done only if ADC is using its own trigger, otherwise it is
* not necessary.
*
* The case of fmc-adc-trg is optimized because is the most common
* case
*/
if
(
likely
(
cset
->
trig
==
&
zfat_type
||
command
==
ZFA_STOP
))
zio_trigger_abort_disable
(
cset
,
0
);
/* Reset counters */
fa
->
n_shots
=
0
;
fa
->
n_fires
=
0
;
/* If START, check if we can start */
if
(
command
==
ZFA_START
)
{
/* Verify that SerDes PLL is lockes */
zfa_hardware_read
(
fa
,
ZFA_STA_SERDES_PLL
,
&
val
);
if
(
!
val
)
{
dev_info
(
dev
,
"Cannot start acquisition: "
"SerDes PLL not locked
\n
"
);
return
-
EBUSY
;
}
/* Verify that SerDes is synched */
zfa_hardware_read
(
fa
,
ZFA_STA_SERDES_SYNCED
,
&
val
);
if
(
!
val
)
{
dev_info
(
dev
,
"Cannot start acquisition: "
"SerDes not synchronized
\n
"
);
return
-
EBUSY
;
}
/* Now we can arm the trigger for the incoming acquisition */
zio_arm_trigger
(
cset
->
ti
);
/*
* FIXME maybe zio_arm_trigger() can return an error when it
* is not able to arm a trigger.
*
* It returns -EPERM, but the error can be -ENOMEM or -EINVAL
* from zfat_arm_trigger() or zfad_input_cset()
*/
if
(
!
(
cset
->
ti
->
flags
&
ZIO_TI_ARMED
))
{
dev_info
(
dev
,
"Cannot start acquisition: "
"Trigger refuses to arm
\n
"
);
return
-
EIO
;
}
dev_dbg
(
dev
,
"FSM START Command, Enable interrupts
\n
"
);
zfa_hardware_write
(
fa
,
ZFA_IRQ_MASK
,
ZFAT_ALL
);
}
else
{
dev_dbg
(
dev
,
"FSM STOP Command, Disable interrupts
\n
"
);
zfa_hardware_write
(
fa
,
ZFA_IRQ_MASK
,
ZFAT_NONE
);
}
zfa_hardware_write
(
fa
,
ZFA_CTL_FMS_CMD
,
command
);
return
0
;
}
static
const
int
zfad_hw_range
[]
=
{
[
ZFA_RANGE_10V
]
=
0x45
,
[
ZFA_RANGE_1V
]
=
0x11
,
[
ZFA_RANGE_100mV
]
=
0x23
,
[
ZFA_RANGE_OPEN
]
=
0x00
,
};
/*
* zfad_convert_hw_range
* @usr_val: range value
*
* return the enum associated to the range value
*/
static
int
zfad_convert_hw_range
(
uint32_t
bitmask
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
zfad_hw_range
);
i
++
)
if
(
zfad_hw_range
[
i
]
==
bitmask
)
return
i
;
return
-
EINVAL
;
}
/* Temporarily, user values are the same as hardware values */
static
int
zfad_convert_user_range
(
uint32_t
user_val
)
{
return
zfad_convert_hw_range
(
user_val
);
}
/*
* zfad_set_range
* @fa: the fmc-adc descriptor
* @chan: the channel to calibrate
* @usr_val: the volt range to set and calibrate
*
* When the input range changes, we must write new fixup values
*/
static
int
zfad_set_range
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
int
range
)
{
int
i
,
offset
,
gain
;
/* Actually set the range */
i
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
zfa_hardware_write
(
fa
,
i
,
zfad_hw_range
[
range
]);
if
(
range
==
ZFA_RANGE_OPEN
)
{
offset
=
FA_CAL_NO_OFFSET
;
gain
=
FA_CAL_NO_GAIN
;
}
else
{
if
(
range
<
0
||
range
>
ARRAY_SIZE
(
fa
->
calib
.
adc
))
{
dev_info
(
&
fa
->
fmc
->
dev
,
"Invalid range %i or ch %i
\n
"
,
range
,
chan
->
index
);
return
-
EINVAL
;
}
offset
=
fa
->
calib
.
adc
[
range
].
offset
[
chan
->
index
];
gain
=
fa
->
calib
.
adc
[
range
].
gain
[
chan
->
index
];
}
i
=
zfad_get_chx_index
(
ZFA_CHx_OFFSET
,
chan
);
zfa_hardware_write
(
fa
,
i
,
offset
&
0xffff
);
/* prevent warning */
i
=
zfad_get_chx_index
(
ZFA_CHx_GAIN
,
chan
);
zfa_hardware_write
(
fa
,
i
,
gain
);
/* recalculate user offset for the new range */
zfad_apply_user_offset
(
fa
,
chan
,
fa
->
user_offset
[
chan
->
index
]);
return
0
;
}
/*
* zfad_apply_user_offset
* @fa: the fmc-adc descriptor
* @chan: the channel where apply offset
* @usr_val: the offset value to apply, expressed as millivolts (-5000..5000)
*
* Apply user offset to the channel input. Before apply the user offset it must
* be corrected with offset and gain calibration value. An open input does not
* need any correction.
*/
static
int
zfad_apply_user_offset
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
uint32_t
usr_val
)
{
uint32_t
range_reg
;
int32_t
uval
=
(
int32_t
)
usr_val
;
int
offset
,
gain
,
hwval
,
i
,
range
;
if
(
uval
<
-
5000
||
uval
>
5000
)
return
-
EINVAL
;
i
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
zfa_hardware_read
(
fa
,
i
,
&
range_reg
);
range
=
zfad_convert_hw_range
(
range_reg
);
if
(
range
<
0
)
return
range
;
if
(
range
==
ZFA_RANGE_OPEN
)
{
offset
=
FA_CAL_NO_OFFSET
;
gain
=
FA_CAL_NO_GAIN
;
}
else
{
offset
=
fa
->
calib
.
dac
[
range
].
offset
[
chan
->
index
];
gain
=
fa
->
calib
.
dac
[
range
].
gain
[
chan
->
index
];
}
hwval
=
uval
*
0x8000
/
5000
;
if
(
hwval
==
0x8000
)
hwval
=
0x7fff
;
/* -32768 .. 32767 */
hwval
=
((
hwval
+
offset
)
*
gain
)
>>
15
;
/* signed */
hwval
+=
0x8000
;
/* offset binary */
if
(
hwval
<
0
)
hwval
=
0
;
if
(
hwval
>
0xffff
)
hwval
=
0xffff
;
/* Apply calibrated offset to DAC */
return
fa_spi_xfer
(
fa
,
FA_SPI_SS_DAC
(
chan
->
index
),
16
,
hwval
,
NULL
);
}
/*
* zfad_reset_offset
* @fa: the fmc-adc descriptor
*
* Reset channel's offsets
*/
static
void
zfad_reset_offset
(
struct
fa_dev
*
fa
)
{
int
i
;
for
(
i
=
0
;
i
<
FA_NCHAN
;
++
i
)
zfad_apply_user_offset
(
fa
,
&
fa
->
zdev
->
cset
->
chan
[
i
],
0
);
}
/*
* zfad_conf_set
*
...
...
kernel/fmc-adc.h
View file @
84c7786a
...
...
@@ -380,6 +380,15 @@ static inline void zfa_hardware_read(struct fa_dev *fa,
*
usr_val
=
zfa_get_field
(
&
zfad_regs
[
index
],
cur
);
}
/* Functions exported by fa-core.c */
extern
int
zfad_fsm_command
(
struct
fa_dev
*
fa
,
uint32_t
command
);
extern
int
zfad_apply_user_offset
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
uint32_t
usr_val
);
extern
void
zfad_reset_offset
(
struct
fa_dev
*
fa
);
extern
int
zfad_convert_hw_range
(
uint32_t
bitmask
);
extern
int
zfad_set_range
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
,
int
range
);
extern
int
zfad_get_chx_index
(
unsigned
long
addr
,
struct
zio_channel
*
chan
);
/* Functions exported by fa-zio-drv.c */
extern
int
fa_zio_register
(
void
);
...
...
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