Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC ADC 100M 14b 4cha
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 ADC 100M 14b 4cha
Commits
cf9bcbc4
Commit
cf9bcbc4
authored
Feb 18, 2019
by
Federico Vaga
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/calibration' into develop
parents
c8eccabe
1cf4b8e0
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
329 additions
and
14 deletions
+329
-14
fa-calibration.c
kernel/fa-calibration.c
+65
-0
fa-core.c
kernel/fa-core.c
+3
-2
fa-zio-drv.c
kernel/fa-zio-drv.c
+6
-0
fmc-adc-100m14b4cha.h
kernel/fmc-adc-100m14b4cha.h
+19
-12
.gitignore
tools/.gitignore
+1
-0
Makefile
tools/Makefile
+1
-0
fau-calibration.c
tools/fau-calibration.c
+234
-0
No files found.
kernel/fa-calibration.c
View file @
cf9bcbc4
...
...
@@ -91,3 +91,68 @@ void fa_read_eeprom_calib(struct fa_dev *fa)
fa_endian_calib
(
&
fa
->
calib
);
fa_verify_calib
(
&
fa
->
fmc
->
dev
,
&
fa
->
calib
,
&
fa_identity_calib
);
}
/**
* Calculate calibrated values for offset and range using current values
* @fa: FMC ADC device
* @chan: channel
*/
static
void
fa_apply_calib
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
)
{
int
reg
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
int
range
=
fa_readl
(
fa
,
fa
->
fa_adc_csr_base
,
&
zfad_regs
[
reg
]);
zfad_set_range
(
fa
,
chan
,
range
);
zfad_apply_offset
(
chan
);
}
static
ssize_t
fa_write_eeprom
(
struct
file
*
file
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
fa_dev
*
fa
=
get_zfadc
(
dev
);
struct
fa_calib
*
calib
=
(
struct
fa_calib
*
)
buf
;
int
i
;
if
(
off
!=
0
||
count
!=
sizeof
(
*
calib
))
return
-
EINVAL
;
fa_endian_calib
(
calib
);
fa_verify_calib
(
dev
,
calib
,
&
fa_identity_calib
);
/*
* The user should be careful enough to not change calibration
* values while running an acquisition
*/
memcpy
(
&
fa
->
calib
,
calib
,
sizeof
(
*
calib
));
for
(
i
=
0
;
i
<
FA100M14B4C_NCHAN
;
++
i
)
fa_apply_calib
(
fa
,
&
fa
->
zdev
->
cset
->
chan
[
i
]);
return
count
;
}
static
ssize_t
fa_read_eeprom
(
struct
file
*
file
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
fa_dev
*
fa
=
get_zfadc
(
dev
);
if
(
off
!=
0
||
count
<
sizeof
(
fa
->
calib
))
return
-
EINVAL
;
memcpy
(
buf
,
&
fa
->
calib
,
sizeof
(
fa
->
calib
));
return
count
;
}
struct
bin_attribute
dev_attr_calibration
=
{
.
attr
=
{
.
name
=
"calibration_data"
,
.
mode
=
0744
,
},
.
size
=
sizeof
(
struct
fa_calib
),
.
write
=
fa_write_eeprom
,
.
read
=
fa_read_eeprom
,
};
kernel/fa-core.c
View file @
cf9bcbc4
...
...
@@ -394,7 +394,7 @@ static int __fa_init(struct fa_dev *fa)
}
}
/*
Retrieve calibration from the eeprom and validate
*/
/*
Use identity calibration
*/
fa_read_eeprom_calib
(
fa
);
fa
->
mshot_max_samples
=
fa_readl
(
fa
,
fa
->
fa_adc_csr_base
,
&
zfad_regs
[
ZFA_MULT_MAX_SAMP
]);
...
...
@@ -557,7 +557,7 @@ int fa_probe(struct fmc_device *fmc)
err
=
fa_setup_irqs
(
fa
);
if
(
err
<
0
)
goto
out
;
goto
out
_irq
;
/* Pin the carrier */
if
(
!
try_module_get
(
fmc
->
owner
))
...
...
@@ -567,6 +567,7 @@ int fa_probe(struct fmc_device *fmc)
out_mod:
fa_free_irqs
(
fa
);
out_irq:
out:
while
(
--
m
,
--
i
>=
0
)
if
(
m
->
exit
)
...
...
kernel/fa-zio-drv.c
View file @
cf9bcbc4
...
...
@@ -544,6 +544,10 @@ static int zfad_zio_probe(struct zio_device *zdev)
if
(
err
)
return
err
;
err
=
device_create_bin_file
(
&
zdev
->
cset
->
head
.
dev
,
&
dev_attr_calibration
);
if
(
err
)
return
err
;
/* We don't have csets at this point, so don't do anything more */
return
0
;
}
...
...
@@ -556,6 +560,8 @@ static int zfad_zio_probe(struct zio_device *zdev)
*/
static
int
zfad_zio_remove
(
struct
zio_device
*
zdev
)
{
device_remove_bin_file
(
&
zdev
->
cset
->
head
.
dev
,
&
dev_attr_calibration
);
return
0
;
}
...
...
kernel/fmc-adc-100m14b4cha.h
View file @
cf9bcbc4
...
...
@@ -8,6 +8,12 @@
#ifndef FMC_ADC_100M14B4C_H_
#define FMC_ADC_100M14B4C_H_
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#ifndef BIT
#define BIT(nr) (1UL << (nr))
#endif
...
...
@@ -128,6 +134,17 @@ enum fa100m14b4c_fsm_state {
FA100M14B4C_STATE_DECR
,
};
/* ADC and DAC Calibration, from EEPROM */
struct
fa_calib_stanza
{
int16_t
offset
[
4
];
/* One per channel */
uint16_t
gain
[
4
];
/* One per channel */
uint16_t
temperature
;
};
struct
fa_calib
{
struct
fa_calib_stanza
adc
[
3
];
/* For input, one per range */
struct
fa_calib_stanza
dac
[
3
];
/* For user offset, one per range */
};
#ifdef __KERNEL__
/* All the rest is only of kernel users */
#include <linux/dma-mapping.h>
...
...
@@ -350,18 +367,6 @@ struct fa_carrier_op {
void
(
*
dma_error
)(
struct
zio_cset
*
cset
);
};
/* ADC and DAC Calibration, from EEPROM */
struct
fa_calib_stanza
{
int16_t
offset
[
4
];
/* One per channel */
uint16_t
gain
[
4
];
/* One per channel */
uint16_t
temperature
;
};
struct
fa_calib
{
struct
fa_calib_stanza
adc
[
3
];
/* For input, one per range */
struct
fa_calib_stanza
dac
[
3
];
/* For user offset, one per range */
};
/*
* fa_dev: is the descriptor of the FMC ADC mezzanine
*
...
...
@@ -540,6 +545,8 @@ static inline void fa_writel(struct fa_dev *fa,
fa_iowrite
(
fa
,
val
,
base_off
+
field
->
offset
);
}
extern
struct
bin_attribute
dev_attr_calibration
;
/* Global variable exported by fa-core.c */
extern
struct
workqueue_struct
*
fa_workqueue
;
...
...
tools/.gitignore
View file @
cf9bcbc4
fau-acq-time
fau-trg-config
fau-calibration
parport-burst
tools/Makefile
View file @
cf9bcbc4
...
...
@@ -18,6 +18,7 @@ CC ?= $(CROSS_COMPILE)gcc
progs
:=
fau-trg-config
progs
+=
fau-acq-time
progs
+=
fau-calibration
progs
+=
parport-burst
# we are not in the kernel, so we need to piggy-back on "make modules"
...
...
tools/fau-calibration.c
0 → 100644
View file @
cf9bcbc4
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* It lists all VME devices
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fmc-adc-100m14b4cha.h>
static
const
char
program_name
[]
=
"fau-calibration"
;
static
char
options
[]
=
"hf:o:D:b"
;
static
const
char
help_msg
[]
=
"Usage: fau-calibration [options]
\n
"
"
\n
"
"It reads calibration data from a file that contains it in binary
\n
"
"form and it shows it on STDOUT in binary form or in human readable
\n
"
"one (default).
\n
"
"This could be used to change the ADC calibration data at runtime
\n
"
"by redirectiong the binary output of this program to the proper
\n
"
"sysfs binary attribute
\n
"
"
\n
"
"General options:
\n
"
"-h Print this message
\n
"
"-b Show Calibration in binary form
\n
"
"
\n
"
"Read options:
\n
"
"-f Source file where to read calibration data from
\n
"
"-o Offset in bytes within the file (default 0)
\n
"
"Write options:
\n
"
"-D FMC ADC Target Device ID
\n
"
"
\n
"
;
/**
* Read calibration data from file
* @path: file path
* @data: data location
* @size: data size
* @offset: offset in file
*
* Return: number of bytes read
*/
static
int
fau_calibration_read
(
char
*
path
,
void
*
data
,
size_t
size
,
off_t
offset
)
{
int
fd
;
int
ret
=
0
;
fd
=
open
(
path
,
O_RDONLY
);
if
(
fd
<
0
)
return
-
1
;
ret
=
lseek
(
fd
,
offset
,
SEEK_SET
);
if
(
ret
>=
0
)
ret
=
read
(
fd
,
data
,
size
);
close
(
fd
);
return
ret
;
}
static
void
fau_calibration_dump_stanza
(
struct
fa_calib_stanza
*
stanza
)
{
fprintf
(
stdout
,
" temperature: 0x%x
\n
"
,
stanza
->
temperature
);
fprintf
(
stdout
,
" gain: [0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
"]
\n
"
,
stanza
->
gain
[
0
],
stanza
->
gain
[
1
],
stanza
->
gain
[
2
],
stanza
->
gain
[
3
]);
fprintf
(
stdout
,
" offset: [0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
"]
\n
"
,
stanza
->
offset
[
0
],
stanza
->
offset
[
1
],
stanza
->
offset
[
2
],
stanza
->
offset
[
3
]);
}
/**
* Print calibration data on stdout in humand readable format
* @calib: calibration data
*/
static
void
fau_calibration_dump_human
(
struct
fa_calib
*
calib
)
{
fputs
(
"ADC Range 10V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_10V
]);
fputs
(
"DAC Range 10V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_10V
]);
fputs
(
"ADC Range 1V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_1V
]);
fputs
(
"DAC Range 1V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_1V
]);
fputs
(
"ADC Range 100mV
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_100mV
]);
fputs
(
"DAC Range 100mV
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_100mV
]);
fputc
(
'\n'
,
stdout
);
}
/**
* Print binary calibration data on stdout
* @calib: calibration data
*/
static
void
fau_calibration_dump_machine
(
struct
fa_calib
*
calib
)
{
write
(
fileno
(
stdout
),
calib
,
sizeof
(
*
calib
));
}
/**
* Write calibration data to device
* @devid: Device ID
* @data: data location
* @size: data size
*
* Return: number of bytes wrote
*/
static
int
fau_calibration_write
(
unsigned
int
devid
,
void
*
data
,
size_t
size
)
{
char
path
[
128
];
int
fd
;
int
ret
;
sprintf
(
path
,
"/sys/bus/zio/devices/adc-100m14b-%04x/cset0/calibration_data"
,
devid
);
fd
=
open
(
path
,
O_WRONLY
);
if
(
fd
<
0
)
return
-
1
;
ret
=
write
(
fd
,
data
,
size
);
close
(
fd
);
return
ret
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
char
c
;
int
ret
;
char
*
path
=
NULL
;
unsigned
int
offset
=
0
;
unsigned
int
devid
=
0
;
int
show_bin
=
0
,
write
=
0
;
struct
fa_calib
calib
;
while
((
c
=
getopt
(
argc
,
argv
,
options
))
!=
-
1
)
{
switch
(
c
)
{
default:
case
'h'
:
fprintf
(
stderr
,
help_msg
);
exit
(
EXIT_SUCCESS
);
case
'D'
:
ret
=
sscanf
(
optarg
,
"0x%x"
,
&
devid
);
if
(
ret
!=
1
)
{
fprintf
(
stderr
,
"Invalid devid %s
\n
"
,
optarg
);
exit
(
EXIT_FAILURE
);
}
write
=
1
;
break
;
case
'f'
:
path
=
optarg
;
break
;
case
'o'
:
ret
=
sscanf
(
optarg
,
"0x%x"
,
&
offset
);
if
(
ret
!=
1
)
{
ret
=
sscanf
(
optarg
,
"%u"
,
&
offset
);
if
(
ret
!=
1
)
{
fprintf
(
stderr
,
"Invalid offset %s
\n
"
,
optarg
);
exit
(
EXIT_FAILURE
);
}
}
break
;
case
'b'
:
show_bin
=
1
;
break
;
}
}
if
(
!
path
)
{
fputs
(
"Calibration file is mandatory
\n
"
,
stderr
);
exit
(
EXIT_FAILURE
);
}
/* Read EEPROM file */
ret
=
fau_calibration_read
(
path
,
&
calib
,
sizeof
(
calib
),
offset
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Can't read calibration data from '%s'. %s
\n
"
,
path
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
if
(
ret
!=
sizeof
(
calib
))
{
fprintf
(
stderr
,
"Can't read all calibration data from '%s'. %s
\n
"
,
path
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
/* Show calibration data*/
if
(
show_bin
)
fau_calibration_dump_machine
(
&
calib
);
else
if
(
!
write
)
fau_calibration_dump_human
(
&
calib
);
/* Write calibration data */
if
(
write
)
{
ret
=
fau_calibration_write
(
devid
,
&
calib
,
sizeof
(
calib
));
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Can't write calibration data to '0x%x'. %s
\n
"
,
devid
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
if
(
ret
!=
sizeof
(
calib
))
{
fprintf
(
stderr
,
"Can't write all calibration data to '0x%x'. %s
\n
"
,
devid
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
}
exit
(
EXIT_SUCCESS
);
}
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