Commit 5414b1d7 authored by Andrey Filippov's avatar Andrey Filippov

more debugging

parent 406266d1
......@@ -37,6 +37,7 @@
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
//#include <asm/system.h>
......@@ -122,7 +123,7 @@
/* 393: sFrameParsAll is an array of 4per-port structures */
static struct framepars_all_t sFrameParsAll[SENSOR_PORTS] __attribute__ ((aligned(PAGE_SIZE))); ///< Sensor Parameters, currently 16 pages all and 2048 pages some, static struct
unsigned long frameParsInitialized[SENSOR_PORTS]; // set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
unsigned int frameParsInitialized[SENSOR_PORTS]; // set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
#define thisFrameNumber(p) GLOBALPARS(p,G_THIS_FRAME) // Current frame number (may lag from the hardware)
#define thisCompressorFrameNumber(p) GLOBALPARS(p,G_COMPRESSOR_FRAME) // Current compressed frame number (lags from thisFrameNumber)
......@@ -146,6 +147,16 @@ unsigned long *amultiSensIndex[SENSOR_PORTS]; // index for per-se
unsigned long *amultiSensRvrsIndex[SENSOR_PORTS]; // reverse index (to parent) for the multiSensIndex
wait_queue_head_t aframepars_wait_queue[SENSOR_PORTS];// used to wait for the frame to be acquired
static DEFINE_SPINLOCK(framepars_lock_0); ///<
static DEFINE_SPINLOCK(framepars_lock_1); ///<
static DEFINE_SPINLOCK(framepars_lock_2); ///<
static DEFINE_SPINLOCK(framepars_lock_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * framepars_locks[4] = {&framepars_lock_0, &framepars_lock_1, &framepars_lock_2, &framepars_lock_3};
/* Remove after compilation OK */
//struct sensorproc_t * sensorproc = NULL;
//void compressor_interrupts (int on) {}
......@@ -184,7 +195,7 @@ struct framepars_pd {
// something else to be added here?
};
static u32 debug_flags = 0;
/**
* @brief assign non-static pointers to static data to be used as extern
......@@ -232,7 +243,6 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
int hreset) ///< Reset hardware sequencer itself
{
int i;
// Setup update mode for
x393_cmdseqmux_status_t stat;
x393_status_ctrl_t stat_ctrl;
x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0};
......@@ -245,6 +255,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
cmdframeseq_mode.d32 = 0;
cmdframeseq_mode.run_cmd = 3; // Run
x393_cmdframeseq_ctrl(cmdframeseq_mode, sensor_port);
dev_dbg(g_devfp_ptr,"Reset command sequencer (all channels !): port= %d, thisFrameNumber=0x%lx\n", sensor_port, thisFrameNumber(sensor_port));
}
/* Check if the status update mode for command sequencer is not 3 (auto), set/wait if needed */
......@@ -274,7 +285,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
#ifdef NC353
thisFrameNumber(sensor_port) = X3X3_I2C_FRAME;
#endif
dev_dbg(g_devfp_ptr,"%s : port= %d, thisFrameNumber=0x%lx\n",__func__, sensor_port, thisFrameNumber(sensor_port));
dev_dbg(g_devfp_ptr,"Resetting frame number, port= %d, thisFrameNumber=0x%lx\n", sensor_port, thisFrameNumber(sensor_port));
// write absolute frame numbers
// for (i = thisFrameNumber(sensor_port); i < (thisFrameNumber(sensor_port) + PARS_FRAMES); i++) aframepars[sensor_port][i & PARS_FRAMES_MASK].pars[P_FRAME] = i;
for (i = 0; i < PARS_FRAMES; i++) aframepars[sensor_port][(i+frame16) & PARS_FRAMES_MASK].pars[P_FRAME] = thisFrameNumber(sensor_port) + i;
......@@ -287,6 +298,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
void initFramePars(int sensor_port)
{
int i;
spin_lock_bh(framepars_locks[sensor_port]);
memset(aframepars[sensor_port], 0, sizeof(struct framepars_t) * PARS_FRAMES);
resetFrameNumber(sensor_port, 0, 1);
// initialize frameParsDeps.pars masks:
......@@ -300,7 +312,8 @@ void initFramePars(int sensor_port)
initMultiPars(sensor_port); // initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
frameParsInitialized[sensor_port] = 1;
dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%d\n",__func__, sensor_port, sensor_port, frameParsInitialized[sensor_port]);
spin_unlock_bh(framepars_locks[sensor_port]);
dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%ld\n",__func__, sensor_port, sensor_port, frameParsInitialized[sensor_port]);
}
/**
......@@ -438,19 +451,20 @@ inline void set_imageParamsR_all(int sensor_port, int n, unsigned long
*/
void updateInterFrame(int sensor_port, ///< Sensor port number (0..3)
int frame16, ///< number of frame just compressed (lower 4 bits, from FPGA), always >= sensor frame number,
u32 compressed_frame, ///< number of frame just compressed
///< interrupt should be processed after frame sync interrupt
struct interframe_params_t * interframe_pars) ///< pointer to the area in circbuf to save parameters
{
int findex_this, findex_prev, findex_future, findex_next;
int index, index32;
unsigned long bmask, bmask32;
// int findex_this, findex_prev, findex_future, findex_next;
// int index;
// int index32;
// unsigned long bmask, bmask32;
int pastParsIndex;
struct framepars_t *framepars = aframepars[sensor_port];
u32 compressed_frame; ///< absolute number of compressed frame , matching frame16
compressed_frame = (thisFrameNumber(sensor_port) & ~PARS_FRAMES_MASK) | (frame16 & PARS_FRAMES_MASK);
if (compressed_frame > thisFrameNumber(sensor_port)) // compressor frame number can never be higher than sesnor one
compressed_frame -= PARS_FRAMES;
// struct framepars_t *framepars = aframepars[sensor_port];
// u32 compressed_frame; ///< absolute number of compressed frame , matching frame16
// compressed_frame = (thisFrameNumber(sensor_port) & ~PARS_FRAMES_MASK) | (frame16 & PARS_FRAMES_MASK);
// if (compressed_frame > thisFrameNumber(sensor_port)) // compressor frame number can never be higher than sesnor one
// compressed_frame -= PARS_FRAMES;
thisCompressorFrameNumber(sensor_port) = compressed_frame;
// pastParsIndex = (thisFrameNumber(sensor_port) - 1) & PASTPARS_SAVE_ENTRIES_MASK; // copying from what was past frame that might include histogram data
pastParsIndex = compressed_frame & PASTPARS_SAVE_ENTRIES_MASK; // copying from what was past frame that might include histogram data
......@@ -566,14 +580,12 @@ void updateFramePars(int sensor_port, int frame16)
}
}
/**
* @brief process parameters that are overdue or due in ASAP mode (not through the sequencer)
/** Process parameters that are overdue or due in ASAP mode (not through the sequencer)
* Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
* @param sensor_port sensor port number (0..3)
* @param sensorproc
* @param frame16
*/
inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, int frame16)
* Should never be called from outside processPars() where there is a per-port lock */
inline void _processParsASAP(int sensor_port, ///< sensor port number (0..3)
struct sensorproc_t * sensorproc, ///< per-port array of sensor capabilities and 32+32 on-change functions
int frame16) ///< Hardware sequencer frame number, or -1 for ASAP
{
unsigned long todo, mask, remain;
int pars_ahead; // considering parameter "pars_ahead" of the (frame16+job_ahead) mod 8
......@@ -591,9 +603,13 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions,
framepars[6].functions, framepars[7].functions));
#endif
dev_dbg(g_devfp_ptr,"%s port=%d frame16=%d\n", __func__, sensor_port, frame16);
if (debug_flags)
dev_dbg(g_devfp_ptr,"ASAP: port=%d frame16=%d\n", sensor_port, frame16);
else
dev_dbg(g_devfp_ptr,"ASAP: port=%d frame16=%d\n", sensor_port, frame16);
if (!sensorproc){
dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16);
dev_err(g_devfp_ptr,"sensorproc==NULL !!!! port=%d frame16=%d \n", sensor_port, frame16);
return;
}
......@@ -606,6 +622,20 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
i = 0;
mask = 1;
remain = 0xffffffff;
if (debug_flags) {
todo = (pars_ahead) ?
(p_nasap[pars_ahead] & (procpars->functions) & remain) :
(procpars->functions & remain);
dev_dbg(g_devfp_ptr,"port=%d frame16=%d todo=0x%08lx,p_nasap[%d]=0x%08x procpars->functions=0x%08lx\n",
sensor_port, frame16, todo, pars_ahead, procpars->functions);
} else {
todo = (pars_ahead) ?
(p_nasap[pars_ahead] & (procpars->functions) & remain) :
(procpars->functions & remain);
dev_dbg(g_devfp_ptr,"port=%d frame16=%d todo=0x%08lx,p_nasap[%d]=0x%08x procpars->functions=0x%08lx\n",
sensor_port, frame16, todo, pars_ahead, procpars->functions);
}
while ((todo = (pars_ahead) ?
(p_nasap[pars_ahead] & (procpars->functions) & remain) :
(procpars->functions & remain) )) { //none, *1, *2,*3,*4
......@@ -616,6 +646,15 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
remain <<= 1;
}
// now (todo & mask) !=0
if (debug_flags) {
dev_dbg(g_devfp_ptr,"port= %d, todo=0x%08lx (curr=0x%08lx) frame16=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx func=0x%08x\n",
sensor_port, todo, procpars->functions, frame16, pars_ahead, frame_proc, i, mask, (int)sensorproc->pgm_func[i]);
dev_dbg(g_devfp_ptr,"port= %d, %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
sensor_port,
framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions,
framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
} else {
dev_dbg(g_devfp_ptr,"port= %d, todo=0x%08lx (curr=0x%08lx) frame16=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx func=0x%08x\n",
sensor_port, todo, procpars->functions, frame16, pars_ahead, frame_proc, i, mask, (int)sensorproc->pgm_func[i]);
......@@ -623,6 +662,7 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
sensor_port,
framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions,
framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
}
if (sensorproc->pgm_func[i]) {
dev_dbg(g_devfp_ptr,"port= %d, Calling GENERIC pgm_func[%d] ASAP\n",sensor_port,i);
rslt = sensorproc->pgm_func[i] (sensor_port, &(sensorproc->sensor), procpars, prevpars, -1);
......@@ -649,8 +689,14 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
//#define G_CALLNEXT3 122 // bitmask of actions to be three or more frames ahead of the programmed one (OR-ed with G_CALLNEXT4)
//#define G_CALLNEXT4 123 // bitmask of actions to be four or more frames ahead of the programmed one
/** Process parameters that are overdue or due in ASAP mode (not through the sequencer)
* Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
* Should never be called from outside processPars() where there is a per-port lock */
inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
inline void _processParsSeq(int sensor_port, ///< sensor port number (0..3)
struct sensorproc_t * sensorproc, ///< per-port array of sensor capabilities and 32+32 on-change functions
int frame16, ///< Hardware sequencer frame number, or -1 for ASAP
int maxahead) ///< Maximal number of frames ahead to process. TODO NC393: Set G_MAXAHEAD >0 (max latency, was 2 in NC353!),
{
unsigned long todo, mask, remain;
int job_ahead; // doing job "job_ahead" ahead of needed
......@@ -665,14 +711,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
int rslt;
int max_par_ahead;
int this_ahead;
dev_dbg(g_devfp_ptr,"%s port=%d frame16=%d, maxahead=0 %d\n", __func__, sensor_port, frame16, maxahead);
dev_dbg(g_devfp_ptr,"%s port=%d frame16=%d, maxahead=%d\n", __func__, sensor_port, frame16, maxahead);
if (maxahead > (PARS_FRAMES - 3)) maxahead = PARS_FRAMES - 3; // use 5 if maxahead >5
// commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
// Modifying - as soon as found the frame to process with non-zero masked .functions - process all functions for that
// frame with appropriate sequencer frame.
// For now - scan p_nasap[i] to find latency - improve that later
for (job_ahead = 0; job_ahead <= maxahead; job_ahead++ ) {
for (job_ahead = 0; job_ahead <= maxahead; job_ahead++ ) { // If have some time - do future job (not required just now)
max_par_ahead = min(5, (PARS_FRAMES - 3) - job_ahead);
for (pars_ahead = 0; pars_ahead < max_par_ahead; pars_ahead++ ) {
frame_proc = (frame16 + job_ahead + pars_ahead + 1) & PARS_FRAMES_MASK; //
......@@ -730,7 +776,7 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
/**
* @brief Program image acquisition, according to the parameters changed
* Called from ISR?
* Called from tasklet and user (setFrameParsAtomic) and LSEEK_SENSORPROC
* @param sensor_port sensor port number (0..3)
* @param sensorproc pointer to sensor static parameters and functions
* @param frame16 current hardware frame number
......@@ -739,31 +785,62 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
*/
//TODO: "Do it later" should be the only reason not to erase todo bit
//#define P_CALLASAP 107 // bitmask - what functions work only in the current frame (ASAP) mode
void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
void _processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
{
frame16 &= PARS_FRAMES_MASK;
dev_dbg(g_devfp_ptr,"%s : port= %d, frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
dev_dbg(g_devfp_ptr,"port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
if (!sensorproc){
dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16);
return;
}
// int spin_trylock(spinlock_t *lock);
// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
// dev_dbg(g_devfp_ptr,"%s before first processParsASAP\n",__func__);
processParsASAP(sensor_port, sensorproc, frame16);
dev_dbg(g_devfp_ptr,"%s : port= %d (after first processParsASAP), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
// dev_dbg(g_devfp_ptr,"%s before first _processParsASAP\n",__func__);
_processParsASAP(sensor_port, sensorproc, frame16); // NC393: never gets here ? Only after _processParsSeq?
dev_dbg(g_devfp_ptr,"%s : port= %d (after first _processParsASAP), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
// now - the rest commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
// for jobahead =0 it is still possible to have some functions in ASAP mode with non-zero latency
// dev_dbg(g_devfp_ptr,"%s before processParsSeq\n",__func__);
processParsSeq(sensor_port, sensorproc, frame16, maxahead);
dev_dbg(g_devfp_ptr,"%s : port= %d (after processParsSeq), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
// dev_dbg(g_devfp_ptr,"%s before _processParsSeq\n",__func__);
_processParsSeq(sensor_port, sensorproc, frame16, maxahead);
dev_dbg(g_devfp_ptr,"%s : port= %d (after _processParsSeq), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
// re-test ASAP tasks - they might appear as a result of other commands executed
// dev_dbg(g_devfp_ptr,"%s before second processParsASAP\n",__func__);
processParsASAP(sensor_port, sensorproc, frame16);
dev_dbg(g_devfp_ptr,"%s : port= %d (after second processParsASAP), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
// dev_dbg(g_devfp_ptr,"%s before second _processParsASAP\n",__func__);
_processParsASAP(sensor_port, sensorproc, frame16);
dev_dbg(g_devfp_ptr,"%s : port= %d (after second _processParsASAP), frame16=%d, maxahead=%d\n",__func__, sensor_port, frame16, maxahead);
if (debug_flags) debug_flags--;
}
#undef LOCK_BH_PROCESSPARS
void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
{
frame16 &= PARS_FRAMES_MASK;
dev_dbg(g_devfp_ptr,"port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
if (!sensorproc){
dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16);
return;
}
#ifdef LOCK_BH_PROCESSPARS
spin_lock_bh(framepars_locks[sensor_port]);
// WARNING: CPU: 1 PID: 2329 at /home/eyesis/git/elphel393/poky/build/tmp/work-shared/elphel393/kernel-source/kernel/softirq.c:150 __local_bh_enable_ip+0xb0/0x100()
#else
// Here we can get from both a tasklet and from LSEEK_SENSORPROC. We do not need to do this twice - if processPars() is ran by
// somebody else - that is OK not to do it again (what about maxahead?)
if (!spin_trylock(framepars_locks[sensor_port])) {
dev_dbg(g_devfp_ptr,"framepars_locks[%d] is locked, we do not need to re-run it. frame16=%d maxahead=%d \n", sensor_port, frame16, maxahead);
return;
}
#endif
_processPars(sensor_port, sensorproc, frame16, maxahead);
#ifdef LOCK_BH_PROCESSPARS
spin_unlock_bh(framepars_locks[sensor_port]); // removed, see above
#else
spin_unlock(framepars_locks[sensor_port]);
#endif
}
/**
* @brief schedule pgm_func to be executed for selected frame (frame16)
* @param sensor_port sensor port number (0..3)
......@@ -823,18 +900,16 @@ int setFrameParsStatic(int sensor_port, int numPars, struct frameparspair_t * pa
return 0;
}
/**
* @brief set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write
* @param sensor_port sensor port number (0..3)
* @param frameno absolute (full) frame number parameters should be applied to
* @param maxLatency maximal command latency (parameters should be set not less than maxLatency ahead of the current frame)
* maxLatency < 0 - don't check latency (i.e.only commands that are not releted to particular frames)
* @param numPars number of parameters to set (0 is OK to just test if it is too early/too late)
* @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
* @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE
*/
//TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed). Have seen just_this to flood all
int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars)
/** Set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write */
//TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed -> 14 of 16). Have seen just_this to flood all
int setFrameParsAtomic(int sensor_port, ///< sensor port number (0..3)
unsigned long frameno, ///< absolute (full) frame number parameters should be applied to
int maxLatency, ///< maximal command latency (parameters should be set not less than maxLatency ahead of the current frame)
///< maxLatency < 0 - don't check latency (i.e. only commands that are not releted to particular frames),
///< with negative and frameno< current frame will make it current, to use with ASAP
int numPars, ///< number of parameters to set (0 is OK to just test if it is too early/too late)
struct frameparspair_t * pars) ///< array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
///< @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE
{
unsigned long flags;
int npar, nframe;
......@@ -843,37 +918,52 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
struct framepars_t *framepars = aframepars[sensor_port];
unsigned long *funcs2call =afuncs2call[sensor_port];
int findex_this, findex_prev, findex_future, frame16;
dev_dbg(g_devfp_ptr,"%s : port= %d, frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
__func__, sensor_port, frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port]);
dev_dbg(g_devfp_ptr,"port= %d, frameno=0x%lx, findex_this=%ld (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
sensor_port, frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port]);
if (!frameParsInitialized[sensor_port]) {
initSequencers(sensor_port); // Will call initFramePars(); and initialize functions
}
findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
findex_prev = (findex_this - 1) & PARS_FRAMES_MASK;
findex_future = (findex_this - 2) & PARS_FRAMES_MASK; // actually - fartherst in the future??
D1I(local_irq_save(flags));
// D1I(local_irq_save(flags));
spin_lock_irqsave(framepars_locks[sensor_port], flags);
PROFILE_NOW(5); // Was 6, but no 7 in NC393
if (maxLatency >= 0) {
if (frameno <= (thisFrameNumber(sensor_port) + maxLatency)) {
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_TOOLATE, frameno = 0x%x\n",sensor_port, (int)frameno);
return -ERR_FRAMEPARS_TOOLATE;
}else if (frameno >= (thisFrameNumber(sensor_port) + (PARS_FRAMES - 1))) {
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_TOOEARLY, frameno = 0x%x\n",sensor_port, (int)frameno);
return -ERR_FRAMEPARS_TOOEARLY;
}
} else {
dev_dbg(g_devfp_ptr,"port=%d, Using negative maxLatency, frameno = 0x%x, thisFrameNumber(%d) = 0x%x\n",
sensor_port, (int)frameno, sensor_port, (int) thisFrameNumber(sensor_port));
if (frameno < thisFrameNumber(sensor_port)){
dev_dbg(g_devfp_ptr,"port=%d, Replacing earlier supplied frame number = 0x%x with the current one= 0x%x\n",
sensor_port, (int)frameno, (int) thisFrameNumber(sensor_port));
frameno = thisFrameNumber(sensor_port);
}
}
// not too late, not too early, go ahead
// not too late, not too early, go ahead (or maxlatency <0 - ASAP only)
for (npar = 0; npar < numPars; npar++) {
D5(printk(" --pars[%d].num=0x%lx, pars[%d].val=0x%lx", npar, pars[npar].num, npar, pars[npar].val));
dev_dbg(g_devfp_ptr,"port= %d, --pars[%d].num=0x%lx, pars[%d].val=0x%lx", sensor_port, npar, pars[npar].num, npar, pars[npar].val);
// frame16= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK);
frame16 = frameno & PARS_FRAMES_MASK;
val = pars[npar].val;
index = pars[npar].num & 0xffff;
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_BADINDEX, frameno = 0x%x\n",sensor_port, (int)frameno);
return -ERR_FRAMEPARS_BADINDEX;
}
D5(printk(" index=0x%x, val=0x%lx", index, val));
dev_dbg(g_devfp_ptr,"port= %d, ndex=0x%x, val=0x%lx", index, val, sensor_port);
if (index >= FRAMEPAR_GLOBALS) { // ignore frame logic, set "static" parameters to frame 0
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { // combine new value with the old one
val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(sensor_port,index), val);
......@@ -882,14 +972,14 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n", index, val));
} else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
funcs2call[index] = val;
D5(printk(" set funcs2call[0x%x]=0x%lx\n", index, val));
dev_dbg(g_devfp_ptr,"port= %d, set funcs2call[0x%x]=0x%lx\n", index, val, sensor_port);
// } else if ((frameno !=findex_prev) && (frameno != findex_future)) { // do not write parameters in the future otherwise
} else if ((frame16 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0)) { // do not write "JUST_THIS" parameters in the future otherwise they'll stick
if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { // combine new value with the old one
val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame16].pars[index], val);
}
//TODO: optimize to use mask several parameters together
D5(printk(" frame16=0x%x\n", frame16));
dev_dbg(g_devfp_ptr,"port= %d, frame16=0x%x\n", frame16, sensor_port);
if ((framepars[frame16].pars[index] != val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)) {
bmask = 1 << (index & 31);
bindex = index >> 5;
......@@ -899,16 +989,16 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
framepars[frame16].mod[bindex] |= bmask;
framepars[frame16].mod32 |= bmask32;
framepars[frame16].functions |= funcs2call[index]; //Mark which functions will be needed to process the parameters
D5(printk(" bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n", bindex, bmask, bmask32, framepars[frame16].functions));
dev_dbg(g_devfp_ptr,"port= %d, bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n", sensor_port, bindex, bmask, bmask32, framepars[frame16].functions);
// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
if ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0) {
MDF5(printk(": --- setting next frames"));
dev_dbg(g_devfp_ptr,"port= %d, --- setting next frames\n",sensor_port);
for (nframe = (frame16 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) {
framepars[nframe].pars[index] = val;
D5(printk(" %d", nframe));
dev_dbg(g_devfp_ptr,"port= %d, %d", sensor_port, nframe);
}
frame16 = (frame16 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
D5(printk("\n"));
// D5(printk("\n"));
}
// Mark this parameter in all previous frames as "modified since"
// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
......@@ -918,38 +1008,46 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
}
}
} else { // error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
// D1I(local_irq_restore(flags));
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_dbg(g_devfp_ptr,"port= %d, Tried to write JUST_THIS parameter (0x%lx) too far in the future", sensor_port, pars[npar].num);
dev_err(g_devfp_ptr,"port= %d, Tried to write JUST_THIS parameter (0x%lx) too far in the future", sensor_port, pars[npar].num);
return -ERR_FRAMEPARS_TOOEARLY;
}
}
// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
// effects of uncertainty of when was it called relative to frame sync
// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
debug_flags = 5; // enable debug print several times
if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_NOSAME))) {
// processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
dev_dbg(g_devfp_ptr,"%s port=%d, G_TASKLET_CTL -> 0x%x \n",__func__, sensor_port, (int) get_globalParam(sensor_port, G_TASKLET_CTL));
processPars(sensor_port, &asensorproc[sensor_port], thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
// _processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
dev_dbg(g_devfp_ptr,"G_TASKLET_CTL -> 0x%x (port = %d )\n", (int) get_globalParam(sensor_port, G_TASKLET_CTL),sensor_port);
// processPars(sensor_port, &asensorproc[sensor_port], thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
// Already having lock, call inner function. When called from tasklet, it will have to acquire lock
_processPars(sensor_port, &asensorproc[sensor_port], thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
dev_dbg(g_devfp_ptr,"kthread _processPars(%d, .., 0x%x) DONE\n",sensor_port, thisFrameNumber(sensor_port));
} else {
dev_dbg(g_devfp_ptr,"kthread: NOT calling _processPars(%d, .., 0x%lx) DONE\n",sensor_port, thisFrameNumber(sensor_port));
}
PROFILE_NOW(6); // 7); // no (7) in NC393
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return 0;
}
//#define FRAMEPAIR_JUST_THIS 0x40000 // write only to this frame, don't propagate
// (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS
/**
* @brief set a single output (calculated) parameter for the frame referenced by this_framepars structure.
/** Set a single output (calculated) parameter for the frame referenced by this_framepars structure.
* Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
* @param sensor_port sensor port number (0..3)
* @param this_framepars pointer to the current parameters structure
* @param mindex parameter number (with optional modifiers in high bits)
* @param val parameter value to set
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
*/
int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned long mindex, unsigned long val)
* Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that) */
int setFramePar(int sensor_port, ///< sensor port number (0..3)
struct framepars_t * this_framepars, ///< pointer to the current parameters structure
unsigned long mindex, ///< parameter number (with optional modifiers in high bits)
unsigned long val) ///< parameter value to set
///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
{
int frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
unsigned long flags;
// unsigned long flags; should only be called when interruypts disabled and lock obtained
int nframe;
unsigned long bmask, bmask32, bindex;
int findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
......@@ -960,10 +1058,13 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
unsigned long *funcs2call =afuncs2call[sensor_port];
dev_dbg(g_devfp_ptr, "%s: port=%d, thisFrameNumber=0x%lx frame16=%d index= %d (0x%lx), val=0x%lx\n",__func__, sensor_port, thisFrameNumber(sensor_port), frame16, index, mindex, val);
D1I(local_irq_save(flags));
// D1I(local_irq_save(flags));
// spin_lock_irqsave(framepars_locks[sensor_port], flags);
// if (index > P_MAX_PAR) {
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return -ERR_FRAMEPARS_BADINDEX;
}
//TODO: optimize to use mask several parameters together
......@@ -1015,26 +1116,52 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
D8(printk("\n"));
}
} else { // error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_dbg(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex);
dev_err(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex);
return -ERR_FRAMEPARS_TOOEARLY;
}
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return 0;
}
/**
* @brief set multiple output (calculated) parameters for the frame referenced by this_framepars structure.
/** Set a single output (calculated) parameter for the frame referenced by this_framepars structure from the user program
* Obtain lock, disable IRQ and call setFramePar
* Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
* Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that) */
int setFrameParLocked(int sensor_port, ///< sensor port number (0..3)
struct framepars_t * this_framepars, ///< pointer to the current parameters structure
unsigned long mindex, ///< parameter number (with optional modifiers in high bits)
unsigned long val) ///< parameter value to set
///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
{
unsigned long flags;
int rslt;
spin_lock_irqsave(framepars_locks[sensor_port], flags);
rslt = setFramePar(sensor_port, // sensor port number (0..3)
this_framepars, // pointer to the current parameters structure
mindex, // parameter number (with optional modifiers in high bits)
val); // parameter value to set
// @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return rslt;
}
/** Set multiple output (calculated) parameters for the frame referenced by this_framepars structure.
* Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in the particular parameter index
* @param sensor_port sensor port number (0..3)
* @param this_framepars pointer to the current parameters structure
* @param numPars number of parameters to set
* @param pars array of parameters (number/value pairs). Parameter numbers accept modifiers
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
*/
int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars)
* Called from tasklets (while executing (*_)pgm_* functions
* Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that) */
int setFramePars(int sensor_port, ///< sensor port number (0..3)
struct framepars_t * this_framepars, ///< this_framepars pointer to the current parameters structure
int numPars, ///< number of parameters to set
struct frameparspair_t * pars) ///<array of parameters (number/value pairs). Parameter numbers accept modifiers
///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
{
int frame16;
unsigned long flags;
// unsigned long flags; should only be called when interruypts disabled and lock obtained
int npar, nframe;
unsigned long val, bmask, bmask32;
int index, bindex;
......@@ -1045,7 +1172,8 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
unsigned long *funcs2call =afuncs2call[sensor_port];
dev_dbg(g_devfp_ptr, "%s : port= %d, this_framepars=0x%x numPars=%d\n",__func__, sensor_port, (int)this_framepars, numPars);
D1I(local_irq_save(flags));
// D1I(local_irq_save(flags));
// spin_lock_irqsave(framepars_locks[sensor_port], flags);
for (npar = 0; npar < numPars; npar++) {
frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
val = pars[npar].val;
......@@ -1053,7 +1181,8 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
dev_dbg(g_devfp_ptr, ": --- frame16=%d index=%d (0x%x) val=0x%x\n", frame16, index, (int)pars[npar].num, (int)val);
// remark: code below looks similar to setFramePar function, call it instead
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_err(g_devfp_ptr, " bad index=%d > %d\n", index, P_MAX_PAR);
return -ERR_FRAMEPARS_BADINDEX;
}
......@@ -1100,12 +1229,14 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
}
}
} else { // error - trying to write "just this" to the "future" - that would stick if allowed
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
dev_err(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num);
return -ERR_FRAMEPARS_TOOEARLY;
}
}
D1I(local_irq_restore(flags));
// D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return 0;
}
......@@ -1371,9 +1502,9 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
}
last = first + 1;
while ((last < count) && ((pars[last].num & 0xff00) != 0xff00)) last++; // skip to the end or next special instructions
result = setFrameParsAtomic(sensor_port,frame, latency, last - first, &pars[first]);
dev_dbg(g_devfp_ptr, "%s 0x%x: setFrameParsAtomic(%ld, %d, %d)\n",
__func__, (int) privData->minor, frame, latency, last - first);
result = setFrameParsAtomic(sensor_port,frame, latency, last - first, &pars[first]);
if (result < 0) {
if (count > sizeof(pars_static)) kfree(pars);
return -EFAULT;
......@@ -1385,7 +1516,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
return count << 3; // *sizeof(struct frameparspair_t);
default: return -EINVAL;
}
}
} // the frame size of 2080 bytes is larger than 1024 bytes [-Wframe-larger-than=]
/**
* @brief Driver MMAP method (should be used read only)
......@@ -1461,9 +1592,9 @@ static ssize_t store_fpga_time(struct device *dev, struct device_attribute *attr
{
sec_usec_t sec_usec={.sec=0, .usec=0};
// avoiding floating point calcualtions in the kernel
char *cp;
char *cp = buf;
int i;
if (sscanf(buf, "%u.%s", &sec_usec.sec, cp)>0){
if (sscanf(buf, "%lu.%s", &sec_usec.sec, cp)>0){
sscanf(cp,"%lu",&sec_usec.usec);
for (i=strlen(cp); i<6;i++)
sec_usec.usec *=10;
......
......@@ -30,7 +30,7 @@ unsigned long get_globalParam (int sensor_port, int n);
void set_globalParam (int sensor_port, int n, unsigned long d);
void set_imageParamsR_all(int sensor_port, int n, unsigned long d);
//Next 2 called from ISR
void updateInterFrame(int sensor_port, int frame16, struct interframe_params_t * interframe_pars);
void updateInterFrame(int sensor_port, u32 compressed_frame, struct interframe_params_t * interframe_pars);
void updateFramePars (int sensor_port, int frame16);
int setFrameParsStatic (int sensor_port, int numPars, struct frameparspair_t * pars);
......@@ -40,28 +40,32 @@ unsigned long getThisFrameNumber (int sensor_port); /// just return current thi
/// Return - 0 if OK, -ERR_FRAMEPARS_TOOEARLY or -ERR_FRAMEPARS_TOOLATE if it is too early or too late to set parameters (numPars may be 0 to just test)
///
/// NOTE: When writing parameter to P_SENSOR_RUN or P_COMPRESSOR_RUN "*_RUN_SINGLE", first write "*SENSOR_RUN_STOP" (it will propagate to all next frames) and then
/// write "*_RUN_SINGLE", to (P_*_RUN | FRAMEPAIR_JUST_THIS) - then this *_RUN_SINGLE will not propagate to the next frames (they will stay stopped)
// write "*_RUN_SINGLE", to (P_*_RUN | FRAMEPAIR_JUST_THIS) - then this *_RUN_SINGLE will not propagate to the next frames (they will stay stopped)
/// TODO: Make (an "unlimited") future commands que based on lists and a tree frame index
// TODO: Make (an "unlimited") future commands que based on lists and a tree frame index
int setFrameParsAtomic (int sensor_port, unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars);
/// set output/calculated parameter and propagate changes - will not trigger any actions
// set output/calculated parameter and propagate changes - will not trigger any actions
int setFramePar (int sensor_port, struct framepars_t * this_framepars, unsigned long mindex, unsigned long val);
// Same, but adds lock to call from user thread
int setFrameParLocked (int sensor_port, struct framepars_t * this_framepars, unsigned long mindex, unsigned long val);
///same for several pars at once
int setFramePars (int sensor_port, struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars);
/// schedule pgm_func to be executed for selected frame
void schedule_pgm_func (int sensor_port, int frame8, int func_num);
/// schedule pgm_func to be executed for the current frame
// schedule pgm_func to be executed for the current frame
void schedule_this_pgm_func (int sensor_port, struct framepars_t * this_framepars, int func_num);
/// program acquisition, according to the parameters changed.
/// maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...)
/// make maxahead - P_* parameter?
/* 393: See if sesnor port is needed here */
inline void processParsASAP (int sensor_port, struct sensorproc_t * sensorproc, int frame8);
inline void processParsSeq (int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead);
// program acquisition, according to the parameters changed.
// maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...)
// make maxahead - P_* parameter?
/* 393: See if sensor port is needed here */
/* NC393: Removed, should not be called from outside the lock-ed processPars() */
//inline void _processParsASAP (int sensor_port, struct sensorproc_t * sensorproc, int frame8);
//inline void _processParsSeq (int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead);
void processPars (int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead);
///*** TODO: Add option (flag?) to write "single" (like single compress, single sensor) so it will not make all the next frames "single"
......
......@@ -173,10 +173,7 @@ static DEFINE_SPINLOCK(gamma_lock_1); ///<
static DEFINE_SPINLOCK(gamma_lock_2); ///<
static DEFINE_SPINLOCK(gamma_lock_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * gamma_locks[4] = {&gamma_lock_0,
&gamma_lock_1,
&gamma_lock_2,
&gamma_lock_3};
spinlock_t * gamma_locks[4] = {&gamma_lock_0, &gamma_lock_1, &gamma_lock_2, &gamma_lock_3};
static struct gamma_stuct_t gammas[GAMMA_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE)));
struct gamma_stuct_t * gammas_p; // to use with mmap
......
......@@ -622,11 +622,11 @@ loff_t histograms_lseek (struct file * file,
}
// request histogram(s)
// setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
setFramePar(privData->port, &aframepars[privData->port][reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
setFrameParLocked(privData->port, &aframepars[privData->port][reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
// make sure (harmful) interrupt did not happen since getThisFrameNumber()
if (reqFrame < getThisFrameNumber(privData->port)) {
// setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1);
setFramePar(privData->port, &aframepars[privData->port][getThisFrameNumber(privData->port) & PARS_FRAMES_MASK], reqAddr, 1);
setFrameParLocked(privData->port, &aframepars[privData->port][getThisFrameNumber(privData->port) & PARS_FRAMES_MASK], reqAddr, 1);
}
}
......
......@@ -344,6 +344,9 @@
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <uapi/elphel/c313a.h>
#include <uapi/elphel/x393_devices.h> // For sysfs
#include <linux/platform_device.h> // For sysfs
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "x3x3.h" // detect sensor
//#include "cci2c.h"
......@@ -388,9 +391,9 @@
#endif
static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
void mt9x001_set_device(struct device *dev)
void mt9x001_set_device(struct device *dev) // do nothing, now it has it's own device
{
g_dev_ptr = dev;
//g_dev_ptr = dev;
}
......@@ -548,6 +551,14 @@ struct sensor_t mt9p001={
.needReset= SENSOR_NEED_RESET_CLK | SENSOR_NEED_RESET_PHASE ///< bit 0 - need reset after clock frequency change, bit 1 - need reset after phase change
};
// Sysfs Interface for debugging the driver
static int first_sensor_sa7 [SENSOR_PORTS] = {0,0,0,0};
static unsigned int debug_delays = 0x0; // 0x6464; // udelay() values for mrst (low 8 - mrst on), [15:8] - after mrst
static unsigned int debug_modes = 3;
static unsigned short sensor_reg_copy[SENSOR_PORTS][256]; ///< Read all 256 sensor registers here - during initialization and on demand
///< Later may increase to include multiple subchannels on 10359
// a place to add some general purpose register writes to sensors during init
/** Register initial writes for MT9M001 */
......@@ -885,7 +896,6 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
int nupdate=0;
int i,color;
int regval, regnum, mreg, j;
dev_dbg(g_dev_ptr,"Resetting MT9X001 sensor\n");
// reset sensor by applying MRST (low):
#ifdef NC353
CCAM_MRST_ON;
......@@ -918,24 +928,31 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
}
#else
// CCAM_MRST_ON;
if (debug_delays & 0xff) {
dev_dbg(g_dev_ptr,"Resetting MT9X001 sensor, port=%d\n",sensor_port);
sensio_ctl.mrst = 0;
sensio_ctl.mrst_set = 1;
x393_sensio_ctrl(sensio_ctl,sensor_port);
udelay (100);
// CCAM_MRST_OFF;
udelay (debug_delays & 0xff) ; // 100);
// CCAM_MRST_OFF;
sensio_ctl.mrst = 1;
x393_sensio_ctrl(sensio_ctl,sensor_port);
sensio_ctl.d32=0;
}
// NC393: both sequencers started in pgm_detectsensor
udelay (100);
dev_dbg(g_dev_ptr,"Reading sensor registers to the shadows:\n");
if (debug_delays & 0xff00) {
udelay ((debug_delays >> 8) & 0xff); // 100);
}
first_sensor_i2c=sensor->i2c_addr;
if (GLOBALPARS(sensor_port, G_SENS_AVAIL)) {
first_sensor_i2c+= I2C359_INC * ((GLOBALPARS(sensor_port, G_SENS_AVAIL) & 1)?1:((GLOBALPARS(sensor_port, G_SENS_AVAIL) & 2)?2:3));
}
dev_dbg(g_dev_ptr,"Reading sensor (port=%d) registers to the shadows, sa7=0x%x:\n",sensor_port,first_sensor_i2c);
first_sensor_sa7[sensor_port] = first_sensor_i2c;
for (i=0; i<256; i++) { // read all registers, one at a time (slower than in 353)
X3X3_I2C_RCV2(sensor_port, first_sensor_i2c, i, &(i2c_read_data_dw[i]));
}
dev_dbg(g_dev_ptr,"Read 256 registers (port=%d) ID=0x%x:\n",sensor_port,i2c_read_data_dw[0]);
for (i=0; i<256; i++) { // possible to modify register range to save (that is why nupdate is separate from i)
regval=i2c_read_data_dw[i];
regnum=P_SENSOR_REGS+i;
......@@ -944,6 +961,10 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
SETFRAMEPARS_SET(mreg+j,regval);
}
}
for (i=0;i<256;i++) {
sensor_reg_copy[sensor_port][i] = i2c_read_data_dw[i];
}
#endif
if (nupdate) setFramePars(sensor_port,thispars, nupdate, pars_to_update); // save changes to sensor register shadows
dev_dbg(g_dev_ptr,"Initializing MT9X001 registers with default values:\n");
......@@ -2070,10 +2091,147 @@ int mt9x001_pgm_sensorregs (int sensor_port, ///< sensor port
return 0;
}
//#define MAX_SENSORS 3 // maximal number of sensor attached (modify some hard-wired constants below if this to be changed)
//#define G_MULTI_NUM (FRAMEPAR_GLOBALS + 34) // Actual number of parameters that are individual for different channels (limited by P_MULTI_NUMREGS)
//#define P_MULTI_NUMREGS 32 // up to 32 sensor register may have individual values
//#define P_MULTI_REGS (P_SENSOR_REGS + P_SENSOR_NUMREGS) // 32-words aligned
//I2C359_INC
//#define FRAMEPAR_MODIFIED(x) (thispars->mod[(x) >> 5] & (1<<((x) & 0x1f)))
// #define MULTIRVRSREG(x) (multiSensRvrsIndex[x])
//static short sensor_reg_copy[SENSOR_PORTS][256]; // Read all 256 sensor registers here - during initialization and on demand
// // Later may increase to include multiple subchannels on 10359
// SysFS interface to mt9x001
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
/** Sysfs helper function - get channel number from the last character of the attribute name*/
static int get_channel_from_name(struct device_attribute *attr) ///< Linux kernel interface for exporting device attributes
///< @return channel number
{
int reg = 0;
sscanf(attr->attr.name + (strlen(attr->attr.name)-1), "%du", &reg);
return reg;
}
// Dump 256 16-bit sensor registers */
static ssize_t show_sensor_regs(struct device *dev, struct device_attribute *attr, char *buf)
{
int chn = get_channel_from_name(attr);
char * cp = buf;
int i,j, ij=0;
for (i=0; i < 16; i++){
cp += sprintf(cp,"%02x:",i*16);
for (j=0;j<16;j++) cp += sprintf(cp," %04x", sensor_reg_copy[chn][ij++]);
cp += sprintf(cp,"\n");
}
return cp - buf;
}
/** Ignore data, re-read 256 sensor registers */
static ssize_t store_sensor_regs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int chn = get_channel_from_name(attr);
u32 datai2c;
int i;
if (first_sensor_sa7[chn]) for (i = 0; i< 256;i++) {
X3X3_I2C_RCV2(chn, first_sensor_sa7[chn], i, &datai2c);
sensor_reg_copy[chn][i] = datai2c;
}
return count;
}
static ssize_t show_debug_delays(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%08x\n", debug_delays);
}
static ssize_t store_debug_delays(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
if (!sscanf(buf, "%x", &debug_delays)) {
return - EINVAL;
}
return count;
}
static ssize_t show_debug_modes(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%08x\n", debug_modes);
}
static ssize_t store_debug_modes(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
if (!sscanf(buf, "%x", &debug_modes)) {
return - EINVAL;
}
return count;
}
static DEVICE_ATTR(sensor_regs0, SYSFS_PERMISSIONS, show_sensor_regs, store_sensor_regs);
static DEVICE_ATTR(sensor_regs1, SYSFS_PERMISSIONS, show_sensor_regs, store_sensor_regs);
static DEVICE_ATTR(sensor_regs2, SYSFS_PERMISSIONS, show_sensor_regs, store_sensor_regs);
static DEVICE_ATTR(sensor_regs3, SYSFS_PERMISSIONS, show_sensor_regs, store_sensor_regs);
static DEVICE_ATTR(debug_delays, SYSFS_PERMISSIONS, show_debug_delays, store_debug_delays);
static DEVICE_ATTR(debug_modes, SYSFS_PERMISSIONS, show_debug_modes, store_debug_modes);
static struct attribute *root_dev_attrs[] = {
&dev_attr_sensor_regs0.attr,
&dev_attr_sensor_regs1.attr,
&dev_attr_sensor_regs2.attr,
&dev_attr_sensor_regs3.attr,
&dev_attr_debug_delays.attr,
&dev_attr_debug_modes.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int elphel393_mt9x001_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
}
return retval;
}
int mt9x001_init(struct platform_device *pdev)
{
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
int sensor_port;
for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
first_sensor_sa7[sensor_port] = 0;
}
elphel393_mt9x001_sysfs_register(pdev);
dev_info(dev, DEV393_NAME(DEV393_MT9X001)": registered sysfs\n");
g_dev_ptr = dev;
return 0;
}
int mt9x001_remove(struct platform_device *pdev)
{
unregister_chrdev(DEV393_MAJOR(DEV393_MT9X001), DEV393_NAME(DEV393_MT9X001));
return 0;
}
static const struct of_device_id elphel393_mt9x001_of_match[] = {
{ .compatible = "elphel,elphel393-mt9x001-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_mt9x001_of_match);
static struct platform_driver elphel393_mt9x001 = {
.probe = mt9x001_init,
.remove = mt9x001_remove,
.driver = {
.name = DEV393_NAME(DEV393_MT9X001),
.of_match_table = elphel393_mt9x001_of_match,
},
};
module_platform_driver(elphel393_mt9x001);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION("Driver for parallel interface image sensors Micron/Aptina/On Semi MT9M*, MT9D*, MT9T* and MT9P* in Elphel cameras");
......@@ -131,11 +131,3 @@ each dibit:
//#define I2C359_CLK_NUMBER 4 // system clock number for the 10359A on-board clock generator
void multi10359_set_device(struct device *dev);
int multisensor_pgm_detectsensor (int sensor_port, struct sensor_t * sensor, struct framepars_t * thispars, struct framepars_t * prevpars, int frame16);
//int legacy_i2c (int ports);
/*
struct frameparspair_t pars_to_update[8];
int nupdate=0;
...
if (nupdate) setFramePars(thispars, nupdate, pars_to_update); /// save changes to sensor register shadows
*/
......@@ -391,7 +391,7 @@ int pgm_detectsensor (int sensor_port, ///< sensor port number (
dev_dbg(g_dev_ptr,"Setting i2c drive mode for port %d\n",sensor_port);
i2c_drive_mode (sensor_port, SDA_DRIVE_HIGH, SDA_RELEASE);
i2c_stop_run_reset (sensor_port, I2C_CMD_RUN); // also programs status update
legacy_i2c(1<<sensor_port);// Setup i2c pages for legacy i2c commands. TODO NC393: update for compatibility with 14MPix
camsync_mode.trig = 0;
camsync_mode.trig_set = 1;
camsync_mode.ext = 1; // use external timestamp (default)
......
......@@ -209,7 +209,8 @@ struct sensorproc_t * asensorproc = NULL;
//wait_queue_head_t image_acq_wait_queue; // queue for the sensor frame interrupts
void tasklet_fpga_function(unsigned long arg);
void tasklet_cmdseq_function(unsigned long arg);
void tasklet_compressor_function(unsigned long arg);
/**
* @brief Copy #sensorproc structure, needed for multisensor board to be able
......@@ -241,12 +242,18 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co
//
int init_acq_sensor(void); // Never used?
//DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_0, tasklet_fpga_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_1, tasklet_fpga_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_2, tasklet_fpga_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_3, tasklet_fpga_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklets[SENSOR_PORTS] = {&tasklet_fpga_0, &tasklet_fpga_1, &tasklet_fpga_2, &tasklet_fpga_3};
//DECLARE_TASKLET(tasklet_cmdseq, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_0, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_1, tasklet_cmdseq_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_2, tasklet_cmdseq_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_3, tasklet_cmdseq_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklet_cmdseq[SENSOR_PORTS] = {&tasklet_cmdseq_0, &tasklet_cmdseq_1, &tasklet_cmdseq_2, &tasklet_cmdseq_3};
DECLARE_TASKLET(tasklet_compressor_0, tasklet_compressor_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_1, tasklet_compressor_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_2, tasklet_compressor_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_3, tasklet_compressor_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklets_compressor[SENSOR_PORTS] = {&tasklet_compressor_0, &tasklet_compressor_1, &tasklet_compressor_2, &tasklet_compressor_3};
/**
......@@ -363,18 +370,17 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
}
/**
* @brief Calculate/update CIRCBUF parameters available after compressor interrupt
* Calculate/update CIRCBUF parameters available after compressor interrupt
*/
inline void update_irq_circbuf(struct jpeg_ptr_t *jptr) {
/*set_globalParam (G_CIRCBUFWP, JPEG_wp<<2);
set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
/*set_globalParam (G_CIRCBUFWP, JPEG_wp<<2);set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));*/
/* the concept of global parameters will be changed, use one channel only for testing */
set_globalParam(jptr->chn_num, G_CIRCBUFWP, jptr->jpeg_wp);
set_globalParam (jptr->chn_num, G_FREECIRCBUF, (((get_globalParam (jptr->chn_num, G_CIRCBUFRP) <= get_globalParam (jptr->chn_num, G_CIRCBUFWP))? get_globalParam (jptr->chn_num, G_CIRCBUFSIZE):0)+
set_globalParam (jptr->chn_num, G_FREECIRCBUF,
(((get_globalParam (jptr->chn_num, G_CIRCBUFRP) <= get_globalParam (jptr->chn_num, G_CIRCBUFWP))?get_globalParam (jptr->chn_num, G_CIRCBUFSIZE):0)+
get_globalParam (jptr->chn_num, G_CIRCBUFRP)) - get_globalParam (jptr->chn_num, G_CIRCBUFWP));
}
/**
* @brief Calculate/update focus parameters available after compressor interrupt
* NOTE: currently global (latest), not per-frame
......@@ -432,7 +438,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
interframe->signffff = 0xffff;
/* debug code follows */
set_default_interframe(interframe);
set_default_interframe(interframe); // TODO: Production NC393: should be removed?
/* end of debug code */
set_globalParam(jptr->chn_num, G_FRAME_SIZE, jpeg_len);
......@@ -588,7 +594,7 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, ///< pointer
}
PROFILE_NOW(1);
wake_up_interruptible(&framepars_wait_queue); // all interrupts, not just frames acquired
tasklet_schedule(&tasklet_fpga); // trigger software interrupt
tasklet_schedule(&tasklet_cmdseq); // trigger software interrupt
EN_INTERRUPT(SMART);
......@@ -616,8 +622,8 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
updateFramePars (jptr->chn_num,
frame16);
wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]);
// tasklet_schedule(&tasklet_fpga);
tasklet_schedule(tasklets[jptr->chn_num]);
// tasklet_schedule(&tasklet_cmdseq);
tasklet_schedule(tasklet_cmdseq[jptr->chn_num]);
x393_cmdframeseq_ctrl(cmdframeseq_mode, jptr->chn_num);
local_irq_restore(flags);
return IRQ_HANDLED;
......@@ -640,21 +646,27 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
unsigned long flags;
local_irq_save(flags);
if (updateIRQJPEG_wp(jptr)) {
update_irq_circbuf(jptr);
updateIRQFocus(jptr);
interframe = updateIRQ_interframe(jptr);
updateIRQ_Exif(jptr, interframe);
if (updateIRQJPEG_wp(jptr)) { // Updates write pointer, invalidates cache, calculates absolute frame number (compressed)
update_irq_circbuf(jptr); // Update global parameters (accessible over mmap): G_CIRCBUFWP, G_FREECIRCBUF (depends on user-set G_CIRCBUFRP)
updateIRQFocus(jptr); // Reads FPGA and updates both G_GFOCUS_VALUE and P_FOCUS_VALUE
interframe = updateIRQ_interframe(jptr); // updates SOME data in the 32-byte gaps between the images:
// Calculates frame size, adds 0xffff signature to detect buffer overrun
// invalidates cache
updateIRQ_Exif(jptr, interframe); // Updates Exif data for compressed frame (separate ring buffer), extending interframe data
frame16 = getHardFrameNumber(jptr->chn_num, 1); // Use compressor frame number
// Updarte G_COMPRESSOR_FRAME (from jptr->frame, set other interframe data from past parameters (subset of all parameters preserved after the frame)
updateInterFrame(jptr->chn_num, // Sensor port number (0..3)
frame16, // number of frame just compressed (lower 4 bits, from FPGA), always >= sensor frame number,
jptr->frame, // absolute compressed frame number, updated in updateIRQJPEG_wp
// interrupt should be processed after frame sync interrupt
interframe); // pointer to the area in circbuf to save parameters
wake_up_interruptible(&circbuf_wait_queue);
tasklet_schedule(tasklets_compressor[jptr->chn_num]);
// wake_up_interruptible(&circbuf_wait_queue); // should be done in tasklet (after cache invalidation)
}
//wake_up_interruptible(&framepars_wait_queue);
// tasklet_schedule(&tasklet_fpga);
tasklet_schedule(tasklets[jptr->chn_num]);
// tasklet_schedule(&tasklet_cmdseq);
// tasklet_schedule(tasklets_compressor[jptr->chn_num]);
irq_ctrl.interrupt_cmd = IRQ_CLEAR;
x393_cmprs_interrupts(irq_ctrl, jptr->chn_num);
local_irq_restore(flags);
......@@ -668,6 +680,35 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
* @param arg not used
*/
void tasklet_compressor_function(unsigned long arg)
{
dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start;
int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num; // == arg & 3
const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
unsigned int sz;
/* invalidate L2 cache lines in the beginning of current frame */
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->fpga_cntr_prev);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr + jptr->fpga_cntr_prev;
sz = DW2BYTE(jptr->fpga_cntr_prev) + L2_INVAL_SIZE;
if (sz < CCAM_DMA_SIZE) {
phys_addr_end = phys_addr_start + L2_INVAL_SIZE - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, L2_INVAL_SIZE);
} else {
phys_addr_end = phys_addr_start + (CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev) - 1);
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev));
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr;
phys_addr_end = phys_addr_start + (sz - CCAM_DMA_SIZE - 1);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE);
}
wake_up_interruptible(&circbuf_wait_queue); // should be done in here (after cache invalidation), not in ISR
}
/*!TODO:
implement 2 modes of controlling when to calculate histograms:
......@@ -686,7 +727,7 @@ For displaying histograms - try use latest available - not waiting fro a particu
// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled
// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0
void tasklet_fpga_function(unsigned long arg)
void tasklet_cmdseq_function(unsigned long arg)
{
// int is_compressor_irq = 1; // TODO: add interrupts from frame sync if compressor is off
int hist_en;
......@@ -696,31 +737,12 @@ void tasklet_fpga_function(unsigned long arg)
unsigned long prevFrameNumber=thisFrameNumber-1;
unsigned long * hash32p=&(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]); // same gamma for all sub-channels
unsigned long * framep= &(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start;
unsigned int sz;
// const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
// dma_addr_t phys_addr_start, phys_addr_end;
// void *virt_addr_start;
// unsigned int sz;
int subchn,hist_indx;
/* invalidate L2 cache lines in the beginning of current frame */
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->fpga_cntr_prev);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr + jptr->fpga_cntr_prev;
sz = DW2BYTE(jptr->fpga_cntr_prev) + L2_INVAL_SIZE;
if (sz < CCAM_DMA_SIZE) {
phys_addr_end = phys_addr_start + L2_INVAL_SIZE - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, L2_INVAL_SIZE);
} else {
phys_addr_end = phys_addr_start + (CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev) - 1);
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev));
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr;
phys_addr_end = phys_addr_start + (sz - CCAM_DMA_SIZE - 1);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE);
}
// Time is out?
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0)) & PARS_FRAMES_MASK) {
......@@ -878,7 +900,7 @@ void compressor_interrupts (int on, ///< 0 -interrupt disable, 1 - interrupt e
x393_cmprs_interrupts_t irq_ctrl = {.d32=0};
//MDF2(printk ("compressor_interrupts(%d)\n",on));
dev_dbg(g_dev_ptr, "set camera interrupts status: %d\n", on);
dev_dbg(g_dev_ptr, "Set compressor interrupts for channel %d: %d\n",chn, on);
#ifdef TEST_DISABLE_CODE
if (on) {
EN_INTERRUPT(SMART);
......@@ -1054,7 +1076,6 @@ int image_acq_stop(struct platform_device *pdev)
{
return 0;
}
//#define I2C359_INC 2 ///< slave address increment between sensors in 10359A board (broadcast, 1,2,3)
/** Register i2c pages equal to slave address,
* Use to convert 353 code */
......@@ -1068,7 +1089,9 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use
class_sensor= xi2c_dev_get(name_sensor);
BUG_ON(!class_sensor);
memcpy(&dev_sensor, class_sensor, sizeof(x393_i2c_device_t));
for (sensor_port=1; sensor_port< SENSOR_PORTS; sensor_port++) if (ports & (1 << sensor_port)) {
dev_dbg(g_dev_ptr, "Initializing sensor i2c for legacy commands, ports bit-mask= 0x%x\n",ports);
for (sensor_port=0; sensor_port< SENSOR_PORTS; sensor_port++) if (ports & (1 << sensor_port)) {
i2c_page_alloc_init(sensor_port); // reset all pages allocation
i2c_page_register(sensor_port, class_10359->slave7);
set_xi2c_wrc(class_10359, sensor_port, class_10359->slave7, 0);
for (subchn = 0; subchn <4; subchn++){ // subchn == 0 - broadcast
......@@ -1078,9 +1101,12 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use
}
// Now register one page for reading 10359 and the sensor using sensor speed data
memcpy(&dev_sensor, class_sensor, sizeof(x393_i2c_device_t)); // dev_sensor));
i2c_page_register(sensor_port, LEGACY_READ_PAGE2);
set_xi2c_rdc(&dev_sensor, sensor_port, LEGACY_READ_PAGE2);
i2c_page_register(sensor_port, LEGACY_READ_PAGE4);
dev_sensor.data_bytes=4; // for reading 10359 in 32-bit mode
set_xi2c_rdc(&dev_sensor, sensor_port, LEGACY_READ_PAGE4);
dev_dbg(g_dev_ptr, "Initialized sensor i2c for legacy commands, sensor_port= 0x%x\n",sensor_port);
}
return 0;
/*
......@@ -1092,9 +1118,6 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use
invalid type argument of unary '*' (have 'x393_i2c_device_t {aka struct <anonymous>}')
*/
}
//static const struct of_device_id elphel393_sensor_of_match[] = {
// { .compatible = "elphel,elphel393-sensor-1.00" },
// { /* end of list */ }
......
/***************************************************************************//**
* @file sensor_i2c.c
* @brief Interface to FPGA-based i2c sequencer for sensor ports
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
* @file sensor_i2c.c
* @brief Interface to FPGA-based i2c sequencer for sensor ports
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
//#define DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include <linux/module.h>
......@@ -53,7 +53,8 @@
#define SYSFS_WRITEONLY 0222
//#define DRV_NAME "elphel_sensor_i2c"
// FIXME: Warnoings in softtirq.c, do not understand why. using LOCK_BH_SENSORI2C to enable spin_lock_bh, otherwise use spin_lock_irqsave
#undef LOCK_BH_SENSORI2C
struct x393_i2c_device_list {
x393_i2c_device_t i2c_dev;
struct list_head list;
......@@ -69,17 +70,25 @@ const int tenth_sec = 2;
static LIST_HEAD(i2c_class_list);
static u32 free_i2c_groups[4]; ///< Number of channels is hard-wired to 4
static u32 free_i2c_pages [32];
static DEFINE_SPINLOCK(lock);
static u32 i2c_pages_shadow[1024]; ///< Mostly for debugging to analyze i2c pages allocation
static u32 free_i2c_pages [4][8];
static u32 i2c_pages_shadow[4][256]; ///< Mostly for debugging to analyze i2c pages allocation
static int sysfs_page[4]; ///< when positive - page locked for exclusive access
static struct device *sdev = NULL; ///< store this device here
static u32 i2c_read_data[4]; ///< last data read from i2c device
//static DEFINE_SPINLOCK(lock);
static DEFINE_SPINLOCK(sensori2c_lock_0); ///<
static DEFINE_SPINLOCK(sensori2c_lock_1); ///<
static DEFINE_SPINLOCK(sensori2c_lock_2); ///<
static DEFINE_SPINLOCK(sensori2c_lock_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * sensori2c_locks[4] = {&sensori2c_lock_0, &sensori2c_lock_1, &sensori2c_lock_2, &sensori2c_lock_3};
/** I2C sequencer stop/run/reset (also programs status if run)*/
int i2c_stop_run_reset(int chn, ///< Sensor port
int cmd) ///< Command: I2C_CMD_STOP=0 - stop, I2C_CMD_RUN=1 - run, I2C_CMD_RESET=2 - reset
///< @return always 0
///< @return always 0
{
x393_i2c_ctltbl_t i2c_ctl = {.d32=0};
x393_status_ctrl_t status_ctrl = {.d32=0};
......@@ -109,7 +118,7 @@ EXPORT_SYMBOL_GPL(i2c_stop_run_reset);
int i2c_drive_mode(int chn, ///< Sensor port
int sda_drive_high, ///< Actively drive SDA=1 during second half of SCL=1
int sda_release) ///< Release SDA early if next bit is SDA=1
///< @return always 0
///< @return always 0
{
x393_i2c_ctltbl_t i2c_ctl = {.d32=0};
i2c_ctl.sda_drive_high = sda_drive_high;
......@@ -121,14 +130,21 @@ int i2c_drive_mode(int chn, ///< Sensor port
EXPORT_SYMBOL_GPL(i2c_drive_mode);
/** Mark all i2c pages for each channel as free */
void i2c_page_alloc_init(void)
void i2c_page_alloc_init( int chn)
{
int i;
for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000;
for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff;
for (i = 0; i < sizeof(i2c_pages_shadow)/sizeof(i2c_pages_shadow[0]); i++) i2c_pages_shadow[i] = 0;
for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1;
free_i2c_groups[chn] = 0xff000000; // Should it be different?
for (i = 0; i < sizeof(free_i2c_pages[chn])/ sizeof(free_i2c_pages[chn][0]); i++) free_i2c_pages[chn][i] = 0xffffffff;
for (i = 0; i < sizeof(i2c_pages_shadow[chn])/sizeof(i2c_pages_shadow[chn][0]); i++) i2c_pages_shadow[chn][i] = 0;
sysfs_page[chn] = -1;
dev_dbg(sdev, "All I2c page allocation for sensor port %d, is RESET( group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
chn,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
}
EXPORT_SYMBOL_GPL(i2c_page_alloc_init);
/** Reserve i2c page (1 of 256) for a sensor port
......@@ -139,19 +155,46 @@ int i2c_page_alloc(int chn)
{
int g, b;
u32 * fb;
spin_lock_bh(&lock);
g = __builtin_clz(free_i2c_groups[chn]);
if (unlikely(g > 7)) {
spin_unlock_bh(&lock);
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
// if (unlikely(g > 7)) {
if (unlikely(!free_i2c_groups[chn])) {
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "-ENOMEM(chn=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
chn,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
return -ENOMEM; // no free i2c pages left
}
fb = free_i2c_pages + ((chn << 3) + g);
g = __builtin_clz(free_i2c_groups[chn]);
// fb = free_i2c_pages + ((chn << 3) + g);
fb = &free_i2c_pages[chn][g];
b = __builtin_clz(*fb);
*fb &= ~ (1 << (31-b));
if (unlikely(*fb == 0)){
free_i2c_groups[chn] &= ~(1 << (31 - g));
}
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "Allocated page= %d for port %d, is RESET(chn=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
(g << 5) + b, chn,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
return (g << 5) + b;
}
EXPORT_SYMBOL_GPL(i2c_page_alloc);
......@@ -160,27 +203,54 @@ EXPORT_SYMBOL_GPL(i2c_page_alloc);
* and use 0xff for reading. Works with 1byhte addresses and 16-bit data */
int i2c_page_register(int chn, ///< Sensor port
int page) ///< page to register (for legacy software, use 7-bit slave address
///< @return 0 on success, -ENOMEM if page is already registered
///< @return 0 on success, -ENOMEM if page is already registered
{
int g = page >> 5;
int b = page & 0x1f;
u32 * fb = free_i2c_pages + ((chn << 3) + g);
spin_lock_bh(&lock);
// u32 * fb = free_i2c_pages + ((chn << 3) + g);
u32 * fb = &free_i2c_pages[chn][g];
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
dev_dbg(sdev, "i2c_page_register( %d, %d): g=%d, b=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
chn,page, g, b, free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
if (unlikely(!(*fb & (1 << (31-b))))) {
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "-ENOMEM(chn=%d, page=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
chn,page,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
return -ENOMEM; // page is already registered
}
*fb &= (1 << (31-b));
*fb &= ~(1 << (31-b));
if (unlikely(*fb == 0)){
free_i2c_groups[chn] &= ~(1 << (31 - g));
}
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "DONE (chn=%d, page=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
chn,page,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
return 0;
}
EXPORT_SYMBOL_GPL(i2c_page_register);
/** Free i2c page
* @param chn sensor port number (0..3)
* @param page i2c configuration page to release
......@@ -189,11 +259,24 @@ void i2c_page_free(int chn, int page)
{
int g = page >> 5;
int b = page & 0x1f;
u32 * fb = free_i2c_pages + ((chn << 3) + g);
spin_lock_bh(&lock);
// u32 * fb = free_i2c_pages + ((chn << 3) + g);
u32 * fb = &free_i2c_pages[chn][g];
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
free_i2c_groups[chn] |= 1 << (31 - g);
*fb |= 1 << (31-b);
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
}
EXPORT_SYMBOL_GPL(i2c_page_free);
......@@ -216,17 +299,29 @@ void set_xi2c_raw(int chn, ///< Sensor port number
int page, ///< index in lookup table
u32 data) ///< Raw table data (bits 27:0), bits 29:28 will be set to 2
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
tb_data.d32 = data;
tb_data.tbl_mode = 2; //
/* Table address and data should not interleave with others */
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
// i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
i2c_pages_shadow[chn][page] =tb_data.d32;
}
EXPORT_SYMBOL_GPL(set_xi2c_raw);
......@@ -239,6 +334,9 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, ///< device class
int page, ///< index in lookup table
int rah) ///< High byte of the i2c register address
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
......@@ -250,15 +348,25 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, ///< device class
tb_data.nbwr = dc -> address_bytes + dc -> data_bytes;
tb_data.dly = get_bit_delay(dc -> scl_khz);
tb_data.tbl_mode = 2;
dev_dbg(sdev, "device name %s : port= %d, page = 0x%x, rah = 0x%x\n",dc->name, chn, page,rah);
/* Table address and data should not interleave with others */
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
// i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
i2c_pages_shadow[chn][page] =tb_data.d32;
dev_dbg(sdev, "DONE: device name %s : port= %d, page = 0x%x, rah = 0x%x\n",dc->name, chn, page,rah);
}
EXPORT_SYMBOL_GPL(set_xi2c_wrc);
/** Set i2c table entry for read operation using known devices
* Get device with xi2c_dev_get(), copy and modify, if needed to
* offset slave address or change number of bytes to write, SCL frequency
......@@ -267,6 +375,9 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, ///< device class
int chn, ///< sensor port
int page)///< index in lookup table
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
......@@ -279,11 +390,21 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, ///< device class
tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */
dev_dbg(sdev, "set_xi2c_rdc(*, %d, %d), tb_addr.d32=0x%08x, tb_data.d32 = 0x%08x\n",chn,page,tb_addr.d32,tb_data.d32);
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock);
i2c_pages_shadow[(chn << 8) + page] = tb_data.d32;
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
// i2c_pages_shadow[(chn << 8) + page] = tb_data.d32;
i2c_pages_shadow[chn][page] =tb_data.d32;
dev_dbg(sdev, "DONE: set_xi2c_rdc(*, %d, %d), tb_addr.d32=0x%08x, tb_data.d32 = 0x%08x\n",chn,page,tb_addr.d32,tb_data.d32);
}
EXPORT_SYMBOL_GPL(set_xi2c_rdc);
......@@ -296,6 +417,9 @@ void set_xi2c_wr(int chn, ///< sensor port
int num_bytes, ///< Number of bytes to write (1..10)
int bit_delay) ///< Bit delay - number of mclk periods in 1/4 of the SCL period
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
......@@ -308,11 +432,20 @@ void set_xi2c_wr(int chn, ///< sensor port
tb_data.dly = bit_delay;
tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
// i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
i2c_pages_shadow[chn][page] =tb_data.d32;
}
EXPORT_SYMBOL_GPL(set_xi2c_wr);
......@@ -324,6 +457,9 @@ void set_xi2c_rd(int chn, ///< sensor port
int num_bytes, ///< Number of bytes to read (1..8, 0 means 8)
int bit_delay) ///< Bit delay - number of mclk periods in 1/4 of the SCL period
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0;
tb_addr.tbl_mode = 3;
......@@ -335,11 +471,20 @@ void set_xi2c_rd(int chn, ///< sensor port
tb_data.dly = bit_delay;
tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
x393_sensi2c_ctrl (tb_addr, chn);
x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock);
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
// i2c_pages_shadow[(chn << 8) + page] =tb_data.d32;
i2c_pages_shadow[chn][page] =tb_data.d32;
}
EXPORT_SYMBOL_GPL(set_xi2c_rd);
......@@ -365,24 +510,36 @@ EXPORT_SYMBOL_GPL(set_xi2c_rd);
int write_xi2c_rel (int chn, ///< sensor port
int offs, ///< relative frame number modulo 16
u32 * data) ///< data array. Length written is defined by the pre-configured table entry.
///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data;
int len;
int i;
tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)];
// tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)];
tb_data.d32 = i2c_pages_shadow[chn][data[0] >> 24];
if (tb_data.tbl_mode !=2) return -EBADR;
len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) {
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
for (i = 0; i <len; i++){
x393_sensi2c_rel (data[i], chn, offs);
}
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
} else {
x393_sensi2c_rel (data[0], chn, offs);
}
spin_unlock_bh(&lock);
return 0;
}
EXPORT_SYMBOL_GPL(write_xi2c_rel);
......@@ -394,24 +551,37 @@ EXPORT_SYMBOL_GPL(write_xi2c_rel);
int write_xi2c_abs (int chn, ///< sensor port
int offs, ///< absolute frame number modulo 16
u32 * data) ///< data array. Length written is defined by the pre-configured table entry.
///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data;
int len;
int i;
tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)];
// tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)];
tb_data.d32 = i2c_pages_shadow[chn][data[0] >> 24];
if (tb_data.tbl_mode !=2) return -EBADR;
len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) {
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
for (i = 0; i <len; i++){
x393_sensi2c_abs (data[i], chn, offs);
}
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
} else {
x393_sensi2c_abs (data[0], chn, offs);
}
spin_unlock_bh(&lock);
return 0;
}
EXPORT_SYMBOL_GPL(write_xi2c_abs);
......@@ -495,13 +665,20 @@ EXPORT_SYMBOL_GPL(read_xi2c_sa7);
/** Read i2c sequencer frame number (4 bits). Make sure it is equal to the cmdseq one */
int read_xi2c_frame(int chn) ///< sensor port number
///< @return i2c sequencer frame number (4 bits)
///< @return i2c sequencer frame number (4 bits)
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
int i;
x393_status_sens_i2c_t status;
x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */
if (status_ctrl.mode != 3){
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
status = x393_sensi2c_status (chn);
status_ctrl.mode = 3;
status_ctrl.seq_num = status.seq_num ^ 0x20;
......@@ -510,7 +687,11 @@ int read_xi2c_frame(int chn) ///< sensor port number
status = x393_sensi2c_status(chn);
if (likely(status.seq_num = status_ctrl.seq_num)) break;
}
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "read_xi2c_frame(%d): mode set to 3, status updated to 0x%08x\n",chn, (int) status.d32);
}
status = x393_sensi2c_status (chn);
......@@ -521,14 +702,21 @@ EXPORT_SYMBOL_GPL(read_xi2c_frame);
/** Read next byte from the channel i2c read FIFO.
* Sensor channel status will be set to auto update mode (3) if it was in different mode */
int read_xi2c_fifo(int chn) ///< sensor port
///< @return byte or -1 if no data available, -EIO - error
///< @return byte or -1 if no data available, -EIO - error
{
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
int fifo_lsb, rslt,i;
x393_i2c_ctltbl_t i2c_cmd;
x393_status_sens_i2c_t status;
x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */
if (status_ctrl.mode != 3){
spin_lock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_lock_bh(sensori2c_locks[chn]);
#else
spin_lock_irqsave(sensori2c_locks[chn],flags);
#endif
status = x393_sensi2c_status (chn);
status_ctrl.mode = 3;
status_ctrl.seq_num = status.seq_num ^ 0x20;
......@@ -537,11 +725,15 @@ int read_xi2c_fifo(int chn) ///< sensor port
status = x393_sensi2c_status(chn);
if (likely(status.seq_num = status_ctrl.seq_num)) break;
}
spin_unlock_bh(&lock);
#ifdef LOCK_BH_SENSORI2C
spin_unlock_bh(sensori2c_locks[chn]);
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "read_xi2c_fifo(%d): mode set to 3, status updated to 0x%08x\n",chn, (int) status.d32);
}
status = x393_sensi2c_status (chn);
// dev_dbg(sdev, "read_xi2c_fifo(%d): status = 0x%08x\n",chn, (int) status.d32);
// dev_dbg(sdev, "read_xi2c_fifo(%d): status = 0x%08x\n",chn, (int) status.d32);
if (!status.i2c_fifo_nempty) return -1; // No data available
fifo_lsb = status.i2c_fifo_lsb;
rslt = status.i2c_fifo_dout;
......@@ -567,7 +759,7 @@ int x393_xi2c_write_reg(const char * cname, ///< device class name
///< used when multiple instances of the same class devices are present.
int reg_addr, ///< register address (width is defined by class)
int data) ///< data to write (width is defined by class)
///< @return 0 on success, < 0 - error
///< @return 0 on success, < 0 - error
{
x393_i2c_device_t * dc;
x393_i2c_device_t ds;
......@@ -610,7 +802,7 @@ int x393_xi2c_read_reg( const char * cname, ///< device class name
///< Offset is non-zero when multiple devices of the same class are present.
int reg_addr, ///< register address (width is defined by class)
int * datap) ///< pointer to a data receiver (read data width is defined by class)
///< @return 0 on success, < 0 - error
///< @return 0 on success, < 0 - error
{
x393_i2c_device_t * dc;
int page, i, db=-1;
......@@ -676,17 +868,23 @@ EXPORT_SYMBOL_GPL(x393_xi2c_read_reg);
/** Single-command i2c read register compatible with legacy code. Device class(es) should already be registered, len parameter should
* match pre-programmed length */
int legacy_read_i2c_reg( int chn, ///< sensor port number
int page, ///< i2c table page registerd for read operation
int page, ///< i2c table page registered for read operation
int sa7, ///< slave address (7-bit) of the device
///< Offset is non-zero when multiple devices of the same class are present.
int reg_addr, ///< register address (width is defined by class)
int len, ///< number of bytes to read.
int * datap) ///< pointer to a data receiver (read data width is defined by class)
///< @return 0 on success, < 0 - error (ETIMEDOUT)
///< @return 0 on success, < 0 - error (ETIMEDOUT)
{
int i, db=-1;
unsigned long timeout_end;
*datap = 0;
/* Flush channel i2c read FIFO to make sure it is empty, status mode will be set, if needed */
// Seems after sensor re-init it was getting some stray data?
while (read_xi2c_fifo(chn) >= 0) ; // includes waiting for status propagate
dev_dbg(sdev, "Flushed i2c read fifo for channel %d\n",chn);
/* Initiate i2c read */
read_xi2c_sa7 (chn,
page & 0xff, // page (8 bits)
......@@ -721,7 +919,7 @@ EXPORT_SYMBOL_GPL(legacy_read_i2c_reg);
/* Handling classes of i2c devices */
/** Find device list entry by device class name */
struct x393_i2c_device_list * i2c_dev_get(const char * name) ///< Device class name as string
///< @return list entry or NULL (if not found)
///< @return list entry or NULL (if not found)
{
struct list_head *p;
struct x393_i2c_device_list * sp;
......@@ -736,7 +934,7 @@ struct x393_i2c_device_list * i2c_dev_get(const char * name) ///< Device class n
}
/** Find device list entry by device class name */
x393_i2c_device_t * xi2c_dev_get(const char * name) ///< Device class name as string
///< @return i2c device or NULL (if not found)
///< @return i2c device or NULL (if not found)
{
struct x393_i2c_device_list * dl = i2c_dev_get(name);
if (dl)
......@@ -748,7 +946,7 @@ x393_i2c_device_t * xi2c_dev_get(const char * name) ///< Device class name as st
EXPORT_SYMBOL_GPL(xi2c_dev_get);
/** Add new i2c device class, OK to provide existing name */
struct x393_i2c_device_list * i2c_dev_add(const char * name) ///< Device class name (<32 characters)
///< @return pointer to a device list entry
///< @return pointer to a device list entry
{
struct x393_i2c_device_list * sp = i2c_dev_get(name);
if (sp) return sp; /* already exists */
......@@ -767,7 +965,7 @@ struct x393_i2c_device_list * i2c_dev_add(const char * name) ///< Device class n
/** Remove i2c device class by name */
int i2c_dev_remove(const char * name) ///< existing device class name
///< @return 0 if OK, -ENOENT if specified device class does not exist
///< @return 0 if OK, -ENOENT if specified device class does not exist
{
struct x393_i2c_device_list * sp = i2c_dev_get(name);
if (!sp) return - ENOENT;
......@@ -783,7 +981,7 @@ int i2c_dev_remove(const char * name) ///< existing device class name
/** Sysfs helper function - get channel number from the last character of the attribute name*/
static int get_channel_from_name(struct device_attribute *attr) ///< Linux kernel interface for exporting device attributes
///< @return channel number
///< @return channel number
{
int reg = 0;
sscanf(attr->attr.name + (strlen(attr->attr.name)-1), "%du", &reg);
......@@ -794,7 +992,7 @@ static ssize_t i2c_member_store(struct device *dev, ///< Linux kern
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
dev_warn(dev,"i2c_member_store(): not implemented\n");
return count;
......@@ -804,7 +1002,7 @@ static ssize_t i2c_member_store(struct device *dev, ///< Linux kern
static ssize_t i2c_member_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
struct x393_i2c_device_list * sp;
sp = i2c_dev_get(attr->attr.name);
......@@ -828,7 +1026,7 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
struct x393_i2c_device_list * dl;
char name[32];
......@@ -844,13 +1042,13 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne
dl = i2c_dev_get(name);
if (!dl){
dl = i2c_dev_add (name);
// create sysfs group member
//group_name
// create sysfs group member
//group_name
new_attr = devm_kzalloc(dev, sizeof(new_attr[0]), GFP_KERNEL);
if (!new_attr)
return -ENOMEM;
// new_attr->attr.name = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL);
// strcpy(new_attr->attr.name, (const char *) name); // warning that it disqualifies const
// new_attr->attr.name = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL);
// strcpy(new_attr->attr.name, (const char *) name); // warning that it disqualifies const
dname = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL);
strcpy(dname, name);
new_attr->attr.name= (const char *) dname;
......@@ -883,7 +1081,7 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne
static ssize_t i2c_class_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
struct list_head *p;
struct x393_i2c_device_list * sp;
......@@ -911,7 +1109,7 @@ static ssize_t i2c_class_show(struct device *dev, ///< Linux kernel
static ssize_t get_i2c_page_alloc(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENOMEM
///< @return offset to the end of the output data in the *buf buffer, or -ENOMEM
{
int chn = get_channel_from_name(attr) ;
int page;
......@@ -927,7 +1125,7 @@ static ssize_t free_i2c_page(struct device *dev, ///< Linux kernel
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
int page;
......@@ -942,7 +1140,7 @@ static ssize_t set_i2c_page_inuse(struct device *dev, ///< Linux ke
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
int page;
......@@ -956,7 +1154,7 @@ static ssize_t set_i2c_page_inuse(struct device *dev, ///< Linux ke
static ssize_t get_i2c_page_inuse(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
int chn = get_channel_from_name(attr) ;
return sprintf(buf,"%d\n",sysfs_page[chn]);
......@@ -968,14 +1166,15 @@ static ssize_t get_i2c_page_inuse(struct device *dev, ///< Linux ke
static ssize_t get_i2c_tbl_raw(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
{
int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0)
return -ENXIO; /* No such device or address */
return sprintf(buf,"0x%08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]);
// return sprintf(buf,"0x%08x\n",i2c_pages_shadow[(chn << 8) + (page &0xff)]);
return sprintf(buf,"0x%08x\n",i2c_pages_shadow[chn][page &0xff]);
}
/** Sysfs function - set i2c table entry as raw value. Buffer string *buf should contain space-separated
......@@ -984,7 +1183,7 @@ static ssize_t set_i2c_tbl_raw(struct device *dev, ///< Linux kerne
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
int ni, page, data;
......@@ -1003,14 +1202,15 @@ static ssize_t set_i2c_tbl_raw(struct device *dev, ///< Linux kerne
static ssize_t get_i2c_tbl_human(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
{
x393_i2c_ctltbl_t tb_data;
int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0)
return -ENXIO; /* No such device or address */
tb_data.d32 = i2c_pages_shadow[(chn << 8) + (page &0xff)];
// tb_data.d32 = i2c_pages_shadow[(chn << 8) + (page & 0xff)];
tb_data.d32 = i2c_pages_shadow[chn][page & 0xff];
if (tb_data.rnw){
return sprintf(buf,"Read entry: chn=%d page=%d(0x%x) two_byte_addr=%d number bytes to read=%d bit_duration=%d\n",
chn, page,page, tb_data.nabrd,tb_data.nbrd, tb_data.dly);
......@@ -1033,7 +1233,7 @@ static ssize_t set_i2c_tbl_wr_human(struct device *dev, ///< Linux
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
int ni, page, rah,sa7,nbwr,dly,khz;
......@@ -1094,7 +1294,7 @@ static ssize_t set_i2c_tbl_rd_human(struct device *dev, ///< Linux
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
int ni, page, two_byte_addr, num_bytes, bit_delay, khz;
......@@ -1149,7 +1349,7 @@ static ssize_t i2c_store(struct device *dev, ///< Linux kernel basi
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int chn = get_channel_from_name(attr) ;
char cname[32];
......@@ -1192,7 +1392,7 @@ static ssize_t i2c_store(struct device *dev, ///< Linux kernel basi
static ssize_t i2c_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
int chn = get_channel_from_name(attr) ;
dev_dbg(sdev, "i2c_show(), chn=%d\n",chn);
......@@ -1204,7 +1404,7 @@ static ssize_t i2c_show(struct device *dev, ///< Linux kernel basic
static ssize_t get_i2c_help(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
return sprintf(buf,"Numeric suffix in the file names selects sensor port\n"
"i2c_all: read - list classes of i2c devices, write - add new (name, sa7, address bytes, data bytes, SCL kHz)\n"
......@@ -1229,7 +1429,7 @@ static ssize_t get_i2c_help(struct device *dev, ///< Linux kernel b
static ssize_t i2c_frame_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
///< @return offset to the end of the output data in the *buf buffer
{
return sprintf(buf,"%d\n",read_xi2c_frame(get_channel_from_name(attr)));
}
......@@ -1238,7 +1438,7 @@ static ssize_t i2c_frame_store(struct device *dev, ///< Linux kerne
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
///< @return new offset to the end of buffer data
{
int cmd;
int chn = get_channel_from_name(attr) ;
......@@ -1344,7 +1544,7 @@ static const struct attribute_group dev_attr_root_group = {
/** Add a named group (subdirectory) with the specified name*/
static int make_group (struct device *dev, ///< Linux kernel basic device structure
const char * name) ///< Group name
///< @return 0 on success, or negative error.
///< @return 0 on success, or negative error.
{
int retval=-1;
struct attribute *pattrs[max_i2c_classes]; /* array of pointers to attibutes */
......@@ -1363,7 +1563,7 @@ static int make_group (struct device *dev, ///< Linux kernel basic device struct
/** Register this driver to implement sysfs interface */
static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
///< @return 0 on success, or negative error.
{
int retval=0;
struct device *dev = &pdev->dev;
......@@ -1380,7 +1580,7 @@ static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///<
/** Initialize this driver from the Device Tree.
* Configures some i2c device classes specified in the DT. */
static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
///< @return 0 on success, or negative error.
{
const char * config_string;
struct x393_i2c_device_list * dl;
......@@ -1440,11 +1640,14 @@ static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ///< Plat
/** Probe this driver, register it with sysfs and initialize from the Device Tree */
static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
///< @return 0 on success, or negative error.
{
int chn;
sdev =&pdev->dev;
dev_dbg(&pdev->dev,"Probing elphel393-sensor-i2c\n");
i2c_page_alloc_init();
for (chn =0; chn<4;chn++) {
i2c_page_alloc_init(chn);
}
dev_dbg(&pdev->dev,"i2c_page_alloc_init() done\n");
elphel393_sens_i2c_sysfs_register(pdev);
......@@ -1458,7 +1661,7 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ///< Platfor
/** Remove device driver - does nothing, just pretends.*/
static int elphel393_sensor_i2c_remove(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
///< @return 0 on success, or negative error.
{
dev_info(&pdev->dev,"Removing elphel393-sensor-i2c");
return 0;
......
......@@ -34,7 +34,7 @@ typedef struct{
u8 data_bytes; ///< Number of data bytes (1..10), for writes it includes register address bytes
int scl_khz; ///< maximal SCL frequency in KHz (currently limited by 200KHz slowest)
} x393_i2c_device_t;
void i2c_page_alloc_init( int chn); // reset page allocation for selscted channel
int i2c_stop_run_reset(int chn, int cmd);
int i2c_drive_mode (int chn, int sda_drive_high, int sda_release);
int read_xi2c_frame (int chn);
......
......@@ -79,6 +79,9 @@ int setup_sensor_memory (int num_sensor, ///< sensor port number (0..3)
window_width_height.height = window_height;
window_left_top.left = window_left;
window_left_top.top = window_top;
dev_dbg(g_dev_ptr,"{%d} frame16=%d, command=%d\n",num_sensor,frame16, (int) x393cmd);
dev_dbg(g_dev_ptr,"sa=0x%08x sa_inc=0x%08x lfn=0x%08x fw=0x%08x wh=0x%08x lt=0x%08x\n",
window_frame_sa.d32,window_frame_sa_inc.d32, window_last_frame_num, window_full_width.d32,window_width_height.d32,window_left_top.d32);
switch (x393cmd){
case ASAP:
......@@ -210,6 +213,10 @@ int setup_compressor_memory (int num_sensor, ///< sensor port number (0..3
window_tile_whs.vert_step = tile_vstep;
window_tile_whs.tile_height = tile_height;
dev_dbg(g_dev_ptr,"{%d} frame16=%d, command=%d\n",num_sensor,frame16, (int) x393cmd);
dev_dbg(g_dev_ptr,"sa=0x%08x sa_inc=0x%08x lfn=0x%08x fw=0x%08x wh=0x%08x lt=0x%08x whs=0x%08x\n",
window_frame_sa.d32,window_frame_sa_inc.d32, window_last_frame_num.d32, window_full_width.d32,window_width_height.d32,window_left_top.d32, window_tile_whs.d32);
switch (x393cmd){
case ASAP:
frame16 = 0;
......
......@@ -90,6 +90,7 @@
#define DEV393_DETECT_SENSORS ("detect_sensors", "detect_sensors",143, 1, "0666", "c") ///< Probably not needed, only sysfs is used
#define DEV393_I2C_SENSORS ("", "elphel393-sensor-i2c",-1, -1, "0666", "c") ///< Used only in sysfs, no character device (yet?)
#define DEV393_MT9X001 ("", "elphel393-mt9x001", -1, -1, "0666", "c") ///< Used only in sysfs, no character device (yet?)
#define _DEV393_PATH(n, ...) "/dev/"n
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment