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

more debugging

parent 406266d1
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
//#include <linux/autoconf.h> //#include <linux/autoconf.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/delay.h> #include <linux/delay.h>
//#include <asm/system.h> //#include <asm/system.h>
...@@ -122,7 +123,7 @@ ...@@ -122,7 +123,7 @@
/* 393: sFrameParsAll is an array of 4per-port structures */ /* 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 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 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) #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 ...@@ -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 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 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 */ /* Remove after compilation OK */
//struct sensorproc_t * sensorproc = NULL; //struct sensorproc_t * sensorproc = NULL;
//void compressor_interrupts (int on) {} //void compressor_interrupts (int on) {}
...@@ -184,7 +195,7 @@ struct framepars_pd { ...@@ -184,7 +195,7 @@ struct framepars_pd {
// something else to be added here? // something else to be added here?
}; };
static u32 debug_flags = 0;
/** /**
* @brief assign non-static pointers to static data to be used as extern * @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 ...@@ -232,7 +243,6 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
int hreset) ///< Reset hardware sequencer itself int hreset) ///< Reset hardware sequencer itself
{ {
int i; int i;
// Setup update mode for
x393_cmdseqmux_status_t stat; x393_cmdseqmux_status_t stat;
x393_status_ctrl_t stat_ctrl; x393_status_ctrl_t stat_ctrl;
x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0}; x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0};
...@@ -245,6 +255,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3 ...@@ -245,6 +255,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
cmdframeseq_mode.d32 = 0; cmdframeseq_mode.d32 = 0;
cmdframeseq_mode.run_cmd = 3; // Run cmdframeseq_mode.run_cmd = 3; // Run
x393_cmdframeseq_ctrl(cmdframeseq_mode, sensor_port); 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 */ /* 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 ...@@ -274,7 +285,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
#ifdef NC353 #ifdef NC353
thisFrameNumber(sensor_port) = X3X3_I2C_FRAME; thisFrameNumber(sensor_port) = X3X3_I2C_FRAME;
#endif #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 // 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 = 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; 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 ...@@ -287,6 +298,7 @@ void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3
void initFramePars(int sensor_port) void initFramePars(int sensor_port)
{ {
int i; int i;
spin_lock_bh(framepars_locks[sensor_port]);
memset(aframepars[sensor_port], 0, sizeof(struct framepars_t) * PARS_FRAMES); memset(aframepars[sensor_port], 0, sizeof(struct framepars_t) * PARS_FRAMES);
resetFrameNumber(sensor_port, 0, 1); resetFrameNumber(sensor_port, 0, 1);
// initialize frameParsDeps.pars masks: // initialize frameParsDeps.pars masks:
...@@ -300,7 +312,8 @@ void initFramePars(int sensor_port) ...@@ -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 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; 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 ...@@ -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) 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 ///< interrupt should be processed after frame sync interrupt
struct interframe_params_t * interframe_pars) ///< pointer to the area in circbuf to save parameters 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 findex_this, findex_prev, findex_future, findex_next;
int index, index32; // int index;
unsigned long bmask, bmask32; // int index32;
// unsigned long bmask, bmask32;
int pastParsIndex; int pastParsIndex;
struct framepars_t *framepars = aframepars[sensor_port]; // struct framepars_t *framepars = aframepars[sensor_port];
u32 compressed_frame; ///< absolute number of compressed frame , matching frame16 // u32 compressed_frame; ///< absolute number of compressed frame , matching frame16
compressed_frame = (thisFrameNumber(sensor_port) & ~PARS_FRAMES_MASK) | (frame16 & PARS_FRAMES_MASK); // 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 // if (compressed_frame > thisFrameNumber(sensor_port)) // compressor frame number can never be higher than sesnor one
compressed_frame -= PARS_FRAMES; // compressed_frame -= PARS_FRAMES;
thisCompressorFrameNumber(sensor_port) = compressed_frame; 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 = (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 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) ...@@ -566,14 +580,12 @@ void updateFramePars(int sensor_port, int frame16)
} }
} }
/** /** Process parameters that are overdue or due in ASAP mode (not through the sequencer)
* @brief 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?) * 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) * Should never be called from outside processPars() where there is a per-port lock */
* @param sensorproc inline void _processParsASAP(int sensor_port, ///< sensor port number (0..3)
* @param frame16 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
inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, int frame16)
{ {
unsigned long todo, mask, remain; unsigned long todo, mask, remain;
int pars_ahead; // considering parameter "pars_ahead" of the (frame16+job_ahead) mod 8 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 ...@@ -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[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions,
framepars[6].functions, framepars[7].functions)); framepars[6].functions, framepars[7].functions));
#endif #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){ 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; return;
} }
...@@ -606,6 +622,20 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -606,6 +622,20 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
i = 0; i = 0;
mask = 1; mask = 1;
remain = 0xffffffff; 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) ? while ((todo = (pars_ahead) ?
(p_nasap[pars_ahead] & (procpars->functions) & remain) : (p_nasap[pars_ahead] & (procpars->functions) & remain) :
(procpars->functions & remain) )) { //none, *1, *2,*3,*4 (procpars->functions & remain) )) { //none, *1, *2,*3,*4
...@@ -616,6 +646,15 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -616,6 +646,15 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
remain <<= 1; remain <<= 1;
} }
// now (todo & mask) !=0 // 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", 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]); 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 ...@@ -623,6 +662,7 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
sensor_port, sensor_port,
framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions,
framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions); framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
}
if (sensorproc->pgm_func[i]) { if (sensorproc->pgm_func[i]) {
dev_dbg(g_devfp_ptr,"port= %d, Calling GENERIC pgm_func[%d] ASAP\n",sensor_port,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); 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 ...@@ -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_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 //#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; unsigned long todo, mask, remain;
int job_ahead; // doing job "job_ahead" ahead of needed 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 ...@@ -665,14 +711,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
int rslt; int rslt;
int max_par_ahead; int max_par_ahead;
int this_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 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 // 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 // Modifying - as soon as found the frame to process with non-zero masked .functions - process all functions for that
// frame with appropriate sequencer frame. // frame with appropriate sequencer frame.
// For now - scan p_nasap[i] to find latency - improve that later // 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); max_par_ahead = min(5, (PARS_FRAMES - 3) - job_ahead);
for (pars_ahead = 0; pars_ahead < max_par_ahead; pars_ahead++ ) { for (pars_ahead = 0; pars_ahead < max_par_ahead; pars_ahead++ ) {
frame_proc = (frame16 + job_ahead + pars_ahead + 1) & PARS_FRAMES_MASK; // 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 ...@@ -730,7 +776,7 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
/** /**
* @brief Program image acquisition, according to the parameters changed * @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 sensor_port sensor port number (0..3)
* @param sensorproc pointer to sensor static parameters and functions * @param sensorproc pointer to sensor static parameters and functions
* @param frame16 current hardware frame number * @param frame16 current hardware frame number
...@@ -739,31 +785,62 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in ...@@ -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 //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 //#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; 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){ if (!sensorproc){
dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16); dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16);
return; return;
} }
// int spin_trylock(spinlock_t *lock);
// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!) // 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__); // dev_dbg(g_devfp_ptr,"%s before first _processParsASAP\n",__func__);
processParsASAP(sensor_port, sensorproc, frame16); _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); 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 // 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 // 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__); // dev_dbg(g_devfp_ptr,"%s before _processParsSeq\n",__func__);
processParsSeq(sensor_port, sensorproc, frame16, maxahead); _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 : 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 // 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__); // dev_dbg(g_devfp_ptr,"%s before second _processParsASAP\n",__func__);
processParsASAP(sensor_port, sensorproc, frame16); _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 : 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) * @brief schedule pgm_func to be executed for selected frame (frame16)
* @param sensor_port sensor port number (0..3) * @param sensor_port sensor port number (0..3)
...@@ -823,18 +900,16 @@ int setFrameParsStatic(int sensor_port, int numPars, struct frameparspair_t * pa ...@@ -823,18 +900,16 @@ int setFrameParsStatic(int sensor_port, int numPars, struct frameparspair_t * pa
return 0; return 0;
} }
/** /** Set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write */
* @brief 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
* @param sensor_port sensor port number (0..3) int setFrameParsAtomic(int sensor_port, ///< sensor port number (0..3)
* @param frameno absolute (full) frame number parameters should be applied to unsigned long 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) 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) ///< 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) ///< with negative and frameno< current frame will make it current, to use with ASAP
* @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number int numPars, ///< number of parameters to set (0 is OK to just test if it is too early/too late)
* @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE 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
//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)
{ {
unsigned long flags; unsigned long flags;
int npar, nframe; int npar, nframe;
...@@ -843,37 +918,52 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -843,37 +918,52 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
struct framepars_t *framepars = aframepars[sensor_port]; struct framepars_t *framepars = aframepars[sensor_port];
unsigned long *funcs2call =afuncs2call[sensor_port]; unsigned long *funcs2call =afuncs2call[sensor_port];
int findex_this, findex_prev, findex_future, frame16; 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", dev_dbg(g_devfp_ptr,"port= %d, frameno=0x%lx, findex_this=%ld (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]); sensor_port, frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port]);
if (!frameParsInitialized[sensor_port]) { if (!frameParsInitialized[sensor_port]) {
initSequencers(sensor_port); // Will call initFramePars(); and initialize functions initSequencers(sensor_port); // Will call initFramePars(); and initialize functions
} }
findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK; findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
findex_prev = (findex_this - 1) & PARS_FRAMES_MASK; findex_prev = (findex_this - 1) & PARS_FRAMES_MASK;
findex_future = (findex_this - 2) & PARS_FRAMES_MASK; // actually - fartherst in the future?? 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 PROFILE_NOW(5); // Was 6, but no 7 in NC393
if (maxLatency >= 0) { if (maxLatency >= 0) {
if (frameno <= (thisFrameNumber(sensor_port) + maxLatency)) { 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; return -ERR_FRAMEPARS_TOOLATE;
}else if (frameno >= (thisFrameNumber(sensor_port) + (PARS_FRAMES - 1))) { }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; 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++) { 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= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK);
frame16 = frameno & PARS_FRAMES_MASK; frame16 = frameno & PARS_FRAMES_MASK;
val = pars[npar].val; val = pars[npar].val;
index = pars[npar].num & 0xffff; index = pars[npar].num & 0xffff;
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : 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);
dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_BADINDEX, frameno = 0x%x\n",sensor_port, (int)frameno);
return -ERR_FRAMEPARS_BADINDEX; 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 (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 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); 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 ...@@ -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)); D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n", index, val));
} else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) { } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
funcs2call[index] = val; 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 ((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 } 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 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); val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame16].pars[index], val);
} }
//TODO: optimize to use mask several parameters together //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)) { if ((framepars[frame16].pars[index] != val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)) {
bmask = 1 << (index & 31); bmask = 1 << (index & 31);
bindex = index >> 5; bindex = index >> 5;
...@@ -899,16 +989,16 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -899,16 +989,16 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
framepars[frame16].mod[bindex] |= bmask; framepars[frame16].mod[bindex] |= bmask;
framepars[frame16].mod32 |= bmask32; framepars[frame16].mod32 |= bmask32;
framepars[frame16].functions |= funcs2call[index]; //Mark which functions will be needed to process the parameters 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) // 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) { 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) { 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; 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 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" // Mark this parameter in all previous frames as "modified since"
// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them // 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 ...@@ -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 } 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));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num)); 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; return -ERR_FRAMEPARS_TOOEARLY;
} }
} }
// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent // 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 // 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) // 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))) { 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 // _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)); 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 // 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 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; return 0;
} }
//#define FRAMEPAIR_JUST_THIS 0x40000 // write only to this frame, don't propagate //#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 // (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 * Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
* @param sensor_port sensor port number (0..3) * Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that) */
* @param this_framepars pointer to the current parameters structure int setFramePar(int sensor_port, ///< sensor port number (0..3)
* @param mindex parameter number (with optional modifiers in high bits) struct framepars_t * this_framepars, ///< pointer to the current parameters structure
* @param val parameter value to set unsigned long mindex, ///< parameter number (with optional modifiers in high bits)
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX unsigned long 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)
{ {
int frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK; 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; int nframe;
unsigned long bmask, bmask32, bindex; unsigned long bmask, bmask32, bindex;
int findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK; 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 ...@@ -960,10 +1058,13 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
unsigned long *funcs2call =afuncs2call[sensor_port]; 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); 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 > P_MAX_PAR) {
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : 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; return -ERR_FRAMEPARS_BADINDEX;
} }
//TODO: optimize to use mask several parameters together //TODO: optimize to use mask several parameters together
...@@ -1015,26 +1116,52 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l ...@@ -1015,26 +1116,52 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
D8(printk("\n")); D8(printk("\n"));
} }
} else { // error - trying to write "just this" to the "future" - that would stick if allowed } 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); dev_err(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex);
return -ERR_FRAMEPARS_TOOEARLY; return -ERR_FRAMEPARS_TOOEARLY;
} }
D1I(local_irq_restore(flags)); // D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return 0; 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 * 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) * Called from tasklets (while executing (*_)pgm_* functions
* @param this_framepars pointer to the current parameters structure * Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that) */
* @param numPars number of parameters to set
* @param pars array of parameters (number/value pairs). Parameter numbers accept modifiers int setFramePars(int sensor_port, ///< sensor port number (0..3)
* @return 0 - OK, -ERR_FRAMEPARS_BADINDEX struct framepars_t * this_framepars, ///< this_framepars pointer to the current parameters structure
*/ int numPars, ///< number of parameters to set
int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars) struct frameparspair_t * pars) ///<array of parameters (number/value pairs). Parameter numbers accept modifiers
///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
{ {
int frame16; int frame16;
unsigned long flags; // unsigned long flags; should only be called when interruypts disabled and lock obtained
int npar, nframe; int npar, nframe;
unsigned long val, bmask, bmask32; unsigned long val, bmask, bmask32;
int index, bindex; int index, bindex;
...@@ -1045,7 +1172,8 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -1045,7 +1172,8 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
unsigned long *funcs2call =afuncs2call[sensor_port]; 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); 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++) { for (npar = 0; npar < numPars; npar++) {
frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK; frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
val = pars[npar].val; val = pars[npar].val;
...@@ -1053,7 +1181,8 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -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); 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 // remark: code below looks similar to setFramePar function, call it instead
if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : 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);
dev_err(g_devfp_ptr, " bad index=%d > %d\n", index, P_MAX_PAR); dev_err(g_devfp_ptr, " bad index=%d > %d\n", index, P_MAX_PAR);
return -ERR_FRAMEPARS_BADINDEX; return -ERR_FRAMEPARS_BADINDEX;
} }
...@@ -1100,12 +1229,14 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -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 } 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); 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; return -ERR_FRAMEPARS_TOOEARLY;
} }
} }
D1I(local_irq_restore(flags)); // D1I(local_irq_restore(flags));
// spin_unlock_irqrestore(framepars_locks[sensor_port], flags);
return 0; return 0;
} }
...@@ -1371,9 +1502,9 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff ...@@ -1371,9 +1502,9 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
} }
last = first + 1; last = first + 1;
while ((last < count) && ((pars[last].num & 0xff00) != 0xff00)) last++; // skip to the end or next special instructions 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", dev_dbg(g_devfp_ptr, "%s 0x%x: setFrameParsAtomic(%ld, %d, %d)\n",
__func__, (int) privData->minor, frame, latency, last - first); __func__, (int) privData->minor, frame, latency, last - first);
result = setFrameParsAtomic(sensor_port,frame, latency, last - first, &pars[first]);
if (result < 0) { if (result < 0) {
if (count > sizeof(pars_static)) kfree(pars); if (count > sizeof(pars_static)) kfree(pars);
return -EFAULT; return -EFAULT;
...@@ -1385,7 +1516,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff ...@@ -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); return count << 3; // *sizeof(struct frameparspair_t);
default: return -EINVAL; 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) * @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 ...@@ -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}; sec_usec_t sec_usec={.sec=0, .usec=0};
// avoiding floating point calcualtions in the kernel // avoiding floating point calcualtions in the kernel
char *cp; char *cp = buf;
int i; 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); sscanf(cp,"%lu",&sec_usec.usec);
for (i=strlen(cp); i<6;i++) for (i=strlen(cp); i<6;i++)
sec_usec.usec *=10; sec_usec.usec *=10;
......
...@@ -30,7 +30,7 @@ unsigned long get_globalParam (int sensor_port, int n); ...@@ -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_globalParam (int sensor_port, int n, unsigned long d);
void set_imageParamsR_all(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 //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); void updateFramePars (int sensor_port, int frame16);
int setFrameParsStatic (int sensor_port, int numPars, struct frameparspair_t * pars); 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 ...@@ -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) /// 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 /// 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); 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); 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 ///same for several pars at once
int setFramePars (int sensor_port, struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars); 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 /// schedule pgm_func to be executed for selected frame
void schedule_pgm_func (int sensor_port, int frame8, int func_num); 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); void schedule_this_pgm_func (int sensor_port, struct framepars_t * this_framepars, int func_num);
/// program acquisition, according to the parameters changed. // program acquisition, according to the parameters changed.
/// maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...) // maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...)
/// make maxahead - P_* parameter? // make maxahead - P_* parameter?
/* 393: See if sesnor port is needed here */ /* 393: See if sensor port is needed here */
inline void processParsASAP (int sensor_port, struct sensorproc_t * sensorproc, int frame8); /* NC393: Removed, should not be called from outside the lock-ed processPars() */
inline void processParsSeq (int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead); //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); 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" ///*** 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); ///< ...@@ -173,10 +173,7 @@ static DEFINE_SPINLOCK(gamma_lock_1); ///<
static DEFINE_SPINLOCK(gamma_lock_2); ///< static DEFINE_SPINLOCK(gamma_lock_2); ///<
static DEFINE_SPINLOCK(gamma_lock_3); ///< static DEFINE_SPINLOCK(gamma_lock_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */ /** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * gamma_locks[4] = {&gamma_lock_0, spinlock_t * gamma_locks[4] = {&gamma_lock_0, &gamma_lock_1, &gamma_lock_2, &gamma_lock_3};
&gamma_lock_1,
&gamma_lock_2,
&gamma_lock_3};
static struct gamma_stuct_t gammas[GAMMA_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE))); static struct gamma_stuct_t gammas[GAMMA_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE)));
struct gamma_stuct_t * gammas_p; // to use with mmap struct gamma_stuct_t * gammas_p; // to use with mmap
......
...@@ -622,11 +622,11 @@ loff_t histograms_lseek (struct file * file, ...@@ -622,11 +622,11 @@ loff_t histograms_lseek (struct file * file,
} }
// request histogram(s) // request histogram(s)
// setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1); // 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() // make sure (harmful) interrupt did not happen since getThisFrameNumber()
if (reqFrame < getThisFrameNumber(privData->port)) { if (reqFrame < getThisFrameNumber(privData->port)) {
// setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1); // 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 @@ ...@@ -344,6 +344,9 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <uapi/elphel/c313a.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 "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "x3x3.h" // detect sensor //#include "x3x3.h" // detect sensor
//#include "cci2c.h" //#include "cci2c.h"
...@@ -388,9 +391,9 @@ ...@@ -388,9 +391,9 @@
#endif #endif
static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions 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={ ...@@ -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 .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 // a place to add some general purpose register writes to sensors during init
/** Register initial writes for MT9M001 */ /** Register initial writes for MT9M001 */
...@@ -885,7 +896,6 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port ...@@ -885,7 +896,6 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
int nupdate=0; int nupdate=0;
int i,color; int i,color;
int regval, regnum, mreg, j; int regval, regnum, mreg, j;
dev_dbg(g_dev_ptr,"Resetting MT9X001 sensor\n");
// reset sensor by applying MRST (low): // reset sensor by applying MRST (low):
#ifdef NC353 #ifdef NC353
CCAM_MRST_ON; CCAM_MRST_ON;
...@@ -918,24 +928,31 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port ...@@ -918,24 +928,31 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
} }
#else #else
// CCAM_MRST_ON; // 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 = 0;
sensio_ctl.mrst_set = 1; sensio_ctl.mrst_set = 1;
x393_sensio_ctrl(sensio_ctl,sensor_port); x393_sensio_ctrl(sensio_ctl,sensor_port);
udelay (100); udelay (debug_delays & 0xff) ; // 100);
// CCAM_MRST_OFF; // CCAM_MRST_OFF;
sensio_ctl.mrst = 1; sensio_ctl.mrst = 1;
x393_sensio_ctrl(sensio_ctl,sensor_port); x393_sensio_ctrl(sensio_ctl,sensor_port);
sensio_ctl.d32=0; sensio_ctl.d32=0;
}
// NC393: both sequencers started in pgm_detectsensor // NC393: both sequencers started in pgm_detectsensor
udelay (100); if (debug_delays & 0xff00) {
dev_dbg(g_dev_ptr,"Reading sensor registers to the shadows:\n"); udelay ((debug_delays >> 8) & 0xff); // 100);
}
first_sensor_i2c=sensor->i2c_addr; first_sensor_i2c=sensor->i2c_addr;
if (GLOBALPARS(sensor_port, G_SENS_AVAIL)) { 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)); 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) 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])); 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) 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]; regval=i2c_read_data_dw[i];
regnum=P_SENSOR_REGS+i; regnum=P_SENSOR_REGS+i;
...@@ -944,6 +961,10 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port ...@@ -944,6 +961,10 @@ int mt9x001_pgm_initsensor (int sensor_port, ///< sensor port
SETFRAMEPARS_SET(mreg+j,regval); SETFRAMEPARS_SET(mreg+j,regval);
} }
} }
for (i=0;i<256;i++) {
sensor_reg_copy[sensor_port][i] = i2c_read_data_dw[i];
}
#endif #endif
if (nupdate) setFramePars(sensor_port,thispars, nupdate, pars_to_update); // save changes to sensor register shadows 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"); 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 ...@@ -2070,10 +2091,147 @@ int mt9x001_pgm_sensorregs (int sensor_port, ///< sensor port
return 0; return 0;
} }
//#define MAX_SENSORS 3 // maximal number of sensor attached (modify some hard-wired constants below if this to be changed) //static short sensor_reg_copy[SENSOR_PORTS][256]; // Read all 256 sensor registers here - during initialization and on demand
//#define G_MULTI_NUM (FRAMEPAR_GLOBALS + 34) // Actual number of parameters that are individual for different channels (limited by P_MULTI_NUMREGS) // // Later may increase to include multiple subchannels on 10359
//#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 // SysFS interface to mt9x001
//I2C359_INC #define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
//#define FRAMEPAR_MODIFIED(x) (thispars->mod[(x) >> 5] & (1<<((x) & 0x1f))) #define SYSFS_READONLY 0444
// #define MULTIRVRSREG(x) (multiSensRvrsIndex[x]) #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: ...@@ -131,11 +131,3 @@ each dibit:
//#define I2C359_CLK_NUMBER 4 // system clock number for the 10359A on-board clock generator //#define I2C359_CLK_NUMBER 4 // system clock number for the 10359A on-board clock generator
void multi10359_set_device(struct device *dev); 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 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 ( ...@@ -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); 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_drive_mode (sensor_port, SDA_DRIVE_HIGH, SDA_RELEASE);
i2c_stop_run_reset (sensor_port, I2C_CMD_RUN); // also programs status update 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 = 0;
camsync_mode.trig_set = 1; camsync_mode.trig_set = 1;
camsync_mode.ext = 1; // use external timestamp (default) camsync_mode.ext = 1; // use external timestamp (default)
......
...@@ -209,7 +209,8 @@ struct sensorproc_t * asensorproc = NULL; ...@@ -209,7 +209,8 @@ struct sensorproc_t * asensorproc = NULL;
//wait_queue_head_t image_acq_wait_queue; // queue for the sensor frame interrupts //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 * @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 ...@@ -241,12 +242,18 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co
// //
int init_acq_sensor(void); // Never used? int init_acq_sensor(void); // Never used?
//DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); // 0 - no arguments for now //DECLARE_TASKLET(tasklet_cmdseq, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_0, tasklet_fpga_function, 0); // 0 - no arguments for now DECLARE_TASKLET(tasklet_cmdseq_0, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_1, tasklet_fpga_function, 1); // 0 - no arguments for now DECLARE_TASKLET(tasklet_cmdseq_1, tasklet_cmdseq_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_2, tasklet_fpga_function, 2); // 0 - no arguments for now DECLARE_TASKLET(tasklet_cmdseq_2, tasklet_cmdseq_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_3, tasklet_fpga_function, 3); // 0 - no arguments for now DECLARE_TASKLET(tasklet_cmdseq_3, tasklet_cmdseq_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}; 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) ...@@ -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) { inline void update_irq_circbuf(struct jpeg_ptr_t *jptr) {
/*set_globalParam (G_CIRCBUFWP, JPEG_wp<<2); /*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_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));*/ get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));*/
/* the concept of global parameters will be changed, use one channel only for testing */ /* 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_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)); get_globalParam (jptr->chn_num, G_CIRCBUFRP)) - get_globalParam (jptr->chn_num, G_CIRCBUFWP));
} }
/** /**
* @brief Calculate/update focus parameters available after compressor interrupt * @brief Calculate/update focus parameters available after compressor interrupt
* NOTE: currently global (latest), not per-frame * NOTE: currently global (latest), not per-frame
...@@ -432,7 +438,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr) ...@@ -432,7 +438,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
interframe->signffff = 0xffff; interframe->signffff = 0xffff;
/* debug code follows */ /* debug code follows */
set_default_interframe(interframe); set_default_interframe(interframe); // TODO: Production NC393: should be removed?
/* end of debug code */ /* end of debug code */
set_globalParam(jptr->chn_num, G_FRAME_SIZE, jpeg_len); set_globalParam(jptr->chn_num, G_FRAME_SIZE, jpeg_len);
...@@ -588,7 +594,7 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, ///< pointer ...@@ -588,7 +594,7 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, ///< pointer
} }
PROFILE_NOW(1); PROFILE_NOW(1);
wake_up_interruptible(&framepars_wait_queue); // all interrupts, not just frames acquired 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); EN_INTERRUPT(SMART);
...@@ -616,8 +622,8 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id) ...@@ -616,8 +622,8 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
updateFramePars (jptr->chn_num, updateFramePars (jptr->chn_num,
frame16); frame16);
wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]); wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]);
// tasklet_schedule(&tasklet_fpga); // tasklet_schedule(&tasklet_cmdseq);
tasklet_schedule(tasklets[jptr->chn_num]); tasklet_schedule(tasklet_cmdseq[jptr->chn_num]);
x393_cmdframeseq_ctrl(cmdframeseq_mode, jptr->chn_num); x393_cmdframeseq_ctrl(cmdframeseq_mode, jptr->chn_num);
local_irq_restore(flags); local_irq_restore(flags);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -640,21 +646,27 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id) ...@@ -640,21 +646,27 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
if (updateIRQJPEG_wp(jptr)) { if (updateIRQJPEG_wp(jptr)) { // Updates write pointer, invalidates cache, calculates absolute frame number (compressed)
update_irq_circbuf(jptr); update_irq_circbuf(jptr); // Update global parameters (accessible over mmap): G_CIRCBUFWP, G_FREECIRCBUF (depends on user-set G_CIRCBUFRP)
updateIRQFocus(jptr); updateIRQFocus(jptr); // Reads FPGA and updates both G_GFOCUS_VALUE and P_FOCUS_VALUE
interframe = updateIRQ_interframe(jptr); interframe = updateIRQ_interframe(jptr); // updates SOME data in the 32-byte gaps between the images:
updateIRQ_Exif(jptr, interframe); // 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 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) 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 // interrupt should be processed after frame sync interrupt
interframe); // pointer to the area in circbuf to save parameters 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); //wake_up_interruptible(&framepars_wait_queue);
// tasklet_schedule(&tasklet_fpga); // tasklet_schedule(&tasklet_cmdseq);
tasklet_schedule(tasklets[jptr->chn_num]); // tasklet_schedule(tasklets_compressor[jptr->chn_num]);
irq_ctrl.interrupt_cmd = IRQ_CLEAR; irq_ctrl.interrupt_cmd = IRQ_CLEAR;
x393_cmprs_interrupts(irq_ctrl, jptr->chn_num); x393_cmprs_interrupts(irq_ctrl, jptr->chn_num);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -668,6 +680,35 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id) ...@@ -668,6 +680,35 @@ static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
* @param arg not used * @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: /*!TODO:
implement 2 modes of controlling when to calculate histograms: 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 ...@@ -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 // 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 // if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0 //#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 is_compressor_irq = 1; // TODO: add interrupts from frame sync if compressor is off
int hist_en; int hist_en;
...@@ -696,31 +737,12 @@ void tasklet_fpga_function(unsigned long arg) ...@@ -696,31 +737,12 @@ void tasklet_fpga_function(unsigned long arg)
unsigned long prevFrameNumber=thisFrameNumber-1; 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 * 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]); 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]; // const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
dma_addr_t phys_addr_start, phys_addr_end; // dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start; // void *virt_addr_start;
unsigned int sz; // unsigned int sz;
int subchn,hist_indx; 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? // Time is out?
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0)) & PARS_FRAMES_MASK) { 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 ...@@ -878,7 +900,7 @@ void compressor_interrupts (int on, ///< 0 -interrupt disable, 1 - interrupt e
x393_cmprs_interrupts_t irq_ctrl = {.d32=0}; x393_cmprs_interrupts_t irq_ctrl = {.d32=0};
//MDF2(printk ("compressor_interrupts(%d)\n",on)); //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 #ifdef TEST_DISABLE_CODE
if (on) { if (on) {
EN_INTERRUPT(SMART); EN_INTERRUPT(SMART);
...@@ -1054,7 +1076,6 @@ int image_acq_stop(struct platform_device *pdev) ...@@ -1054,7 +1076,6 @@ int image_acq_stop(struct platform_device *pdev)
{ {
return 0; return 0;
} }
//#define I2C359_INC 2 ///< slave address increment between sensors in 10359A board (broadcast, 1,2,3) //#define I2C359_INC 2 ///< slave address increment between sensors in 10359A board (broadcast, 1,2,3)
/** Register i2c pages equal to slave address, /** Register i2c pages equal to slave address,
* Use to convert 353 code */ * Use to convert 353 code */
...@@ -1068,7 +1089,9 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use ...@@ -1068,7 +1089,9 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use
class_sensor= xi2c_dev_get(name_sensor); class_sensor= xi2c_dev_get(name_sensor);
BUG_ON(!class_sensor); BUG_ON(!class_sensor);
memcpy(&dev_sensor, class_sensor, sizeof(x393_i2c_device_t)); 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); i2c_page_register(sensor_port, class_10359->slave7);
set_xi2c_wrc(class_10359, sensor_port, class_10359->slave7, 0); set_xi2c_wrc(class_10359, sensor_port, class_10359->slave7, 0);
for (subchn = 0; subchn <4; subchn++){ // subchn == 0 - broadcast 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 ...@@ -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 // 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)); 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); 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 dev_sensor.data_bytes=4; // for reading 10359 in 32-bit mode
set_xi2c_rdc(&dev_sensor, sensor_port, LEGACY_READ_PAGE4); 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; return 0;
/* /*
...@@ -1092,9 +1118,6 @@ int legacy_i2c(int ports) ///< bitmask of the sensor ports to use ...@@ -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>}') invalid type argument of unary '*' (have 'x393_i2c_device_t {aka struct <anonymous>}')
*/ */
} }
//static const struct of_device_id elphel393_sensor_of_match[] = { //static const struct of_device_id elphel393_sensor_of_match[] = {
// { .compatible = "elphel,elphel393-sensor-1.00" }, // { .compatible = "elphel,elphel393-sensor-1.00" },
// { /* end of list */ } // { /* end of list */ }
......
/***************************************************************************//** /***************************************************************************//**
* @file sensor_i2c.c * @file sensor_i2c.c
* @brief Interface to FPGA-based i2c sequencer for sensor ports * @brief Interface to FPGA-based i2c sequencer for sensor ports
* @copyright Copyright 2016 (C) Elphel, Inc. * @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b> * @par <b>License</b>
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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 */ //#define DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include <linux/module.h> #include <linux/module.h>
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
#define SYSFS_WRITEONLY 0222 #define SYSFS_WRITEONLY 0222
//#define DRV_NAME "elphel_sensor_i2c" //#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 { struct x393_i2c_device_list {
x393_i2c_device_t i2c_dev; x393_i2c_device_t i2c_dev;
struct list_head list; struct list_head list;
...@@ -69,17 +70,25 @@ const int tenth_sec = 2; ...@@ -69,17 +70,25 @@ const int tenth_sec = 2;
static LIST_HEAD(i2c_class_list); static LIST_HEAD(i2c_class_list);
static u32 free_i2c_groups[4]; ///< Number of channels is hard-wired to 4 static u32 free_i2c_groups[4]; ///< Number of channels is hard-wired to 4
static u32 free_i2c_pages [32]; static u32 free_i2c_pages [4][8];
static DEFINE_SPINLOCK(lock); static u32 i2c_pages_shadow[4][256]; ///< Mostly for debugging to analyze i2c pages allocation
static u32 i2c_pages_shadow[1024]; ///< Mostly for debugging to analyze i2c pages allocation
static int sysfs_page[4]; ///< when positive - page locked for exclusive access static int sysfs_page[4]; ///< when positive - page locked for exclusive access
static struct device *sdev = NULL; ///< store this device here static struct device *sdev = NULL; ///< store this device here
static u32 i2c_read_data[4]; ///< last data read from i2c device 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)*/ /** I2C sequencer stop/run/reset (also programs status if run)*/
int i2c_stop_run_reset(int chn, ///< Sensor port 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 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_i2c_ctltbl_t i2c_ctl = {.d32=0};
x393_status_ctrl_t status_ctrl = {.d32=0}; x393_status_ctrl_t status_ctrl = {.d32=0};
...@@ -109,7 +118,7 @@ EXPORT_SYMBOL_GPL(i2c_stop_run_reset); ...@@ -109,7 +118,7 @@ EXPORT_SYMBOL_GPL(i2c_stop_run_reset);
int i2c_drive_mode(int chn, ///< Sensor port int i2c_drive_mode(int chn, ///< Sensor port
int sda_drive_high, ///< Actively drive SDA=1 during second half of SCL=1 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 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}; x393_i2c_ctltbl_t i2c_ctl = {.d32=0};
i2c_ctl.sda_drive_high = sda_drive_high; i2c_ctl.sda_drive_high = sda_drive_high;
...@@ -121,14 +130,21 @@ int i2c_drive_mode(int chn, ///< Sensor port ...@@ -121,14 +130,21 @@ int i2c_drive_mode(int chn, ///< Sensor port
EXPORT_SYMBOL_GPL(i2c_drive_mode); EXPORT_SYMBOL_GPL(i2c_drive_mode);
/** Mark all i2c pages for each channel as free */ /** Mark all i2c pages for each channel as free */
void i2c_page_alloc_init(void) void i2c_page_alloc_init( int chn)
{ {
int i; int i;
for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000; free_i2c_groups[chn] = 0xff000000; // Should it be different?
for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff; 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)/sizeof(i2c_pages_shadow[0]); i++) i2c_pages_shadow[i] = 0; for (i = 0; i < sizeof(i2c_pages_shadow[chn])/sizeof(i2c_pages_shadow[chn][0]); i++) i2c_pages_shadow[chn][i] = 0;
for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1; 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 /** Reserve i2c page (1 of 256) for a sensor port
...@@ -139,19 +155,46 @@ int i2c_page_alloc(int chn) ...@@ -139,19 +155,46 @@ int i2c_page_alloc(int chn)
{ {
int g, b; int g, b;
u32 * fb; u32 * fb;
spin_lock_bh(&lock); #ifndef LOCK_BH_SENSORI2C
g = __builtin_clz(free_i2c_groups[chn]); unsigned long flags;
if (unlikely(g > 7)) { #endif
spin_unlock_bh(&lock); #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 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); b = __builtin_clz(*fb);
*fb &= ~ (1 << (31-b)); *fb &= ~ (1 << (31-b));
if (unlikely(*fb == 0)){ if (unlikely(*fb == 0)){
free_i2c_groups[chn] &= ~(1 << (31 - g)); 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; return (g << 5) + b;
} }
EXPORT_SYMBOL_GPL(i2c_page_alloc); EXPORT_SYMBOL_GPL(i2c_page_alloc);
...@@ -160,27 +203,54 @@ 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 */ * and use 0xff for reading. Works with 1byhte addresses and 16-bit data */
int i2c_page_register(int chn, ///< Sensor port int i2c_page_register(int chn, ///< Sensor port
int page) ///< page to register (for legacy software, use 7-bit slave address 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 g = page >> 5;
int b = page & 0x1f; int b = page & 0x1f;
u32 * fb = free_i2c_pages + ((chn << 3) + g); // u32 * fb = free_i2c_pages + ((chn << 3) + g);
spin_lock_bh(&lock); 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))))) { 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 return -ENOMEM; // page is already registered
} }
*fb &= (1 << (31-b)); *fb &= ~(1 << (31-b));
if (unlikely(*fb == 0)){ if (unlikely(*fb == 0)){
free_i2c_groups[chn] &= ~(1 << (31 - g)); 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; return 0;
} }
EXPORT_SYMBOL_GPL(i2c_page_register); EXPORT_SYMBOL_GPL(i2c_page_register);
/** Free i2c page /** Free i2c page
* @param chn sensor port number (0..3) * @param chn sensor port number (0..3)
* @param page i2c configuration page to release * @param page i2c configuration page to release
...@@ -189,11 +259,24 @@ void i2c_page_free(int chn, int page) ...@@ -189,11 +259,24 @@ void i2c_page_free(int chn, int page)
{ {
int g = page >> 5; int g = page >> 5;
int b = page & 0x1f; int b = page & 0x1f;
u32 * fb = free_i2c_pages + ((chn << 3) + g); // u32 * fb = free_i2c_pages + ((chn << 3) + g);
spin_lock_bh(&lock); 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); free_i2c_groups[chn] |= 1 << (31 - g);
*fb |= 1 << (31-b); *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); EXPORT_SYMBOL_GPL(i2c_page_free);
...@@ -216,17 +299,29 @@ void set_xi2c_raw(int chn, ///< Sensor port number ...@@ -216,17 +299,29 @@ void set_xi2c_raw(int chn, ///< Sensor port number
int page, ///< index in lookup table int page, ///< index in lookup table
u32 data) ///< Raw table data (bits 27:0), bits 29:28 will be set to 2 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; x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0; tb_addr.d32 = 0;
tb_addr.tbl_mode = 3; tb_addr.tbl_mode = 3;
tb_data.d32 = data; tb_data.d32 = data;
tb_data.tbl_mode = 2; // tb_data.tbl_mode = 2; //
/* Table address and data should not interleave with others */ /* 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_addr, chn);
x393_sensi2c_ctrl (tb_data, chn); x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock); #ifdef LOCK_BH_SENSORI2C
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; 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); EXPORT_SYMBOL_GPL(set_xi2c_raw);
...@@ -239,6 +334,9 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, ///< device class ...@@ -239,6 +334,9 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, ///< device class
int page, ///< index in lookup table int page, ///< index in lookup table
int rah) ///< High byte of the i2c register address 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; x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0; tb_addr.d32 = 0;
tb_addr.tbl_mode = 3; tb_addr.tbl_mode = 3;
...@@ -250,15 +348,25 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, ///< device class ...@@ -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.nbwr = dc -> address_bytes + dc -> data_bytes;
tb_data.dly = get_bit_delay(dc -> scl_khz); tb_data.dly = get_bit_delay(dc -> scl_khz);
tb_data.tbl_mode = 2; 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 */ /* 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_addr, chn);
x393_sensi2c_ctrl (tb_data, chn); x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock); #ifdef LOCK_BH_SENSORI2C
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; 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); EXPORT_SYMBOL_GPL(set_xi2c_wrc);
/** Set i2c table entry for read operation using known devices /** Set i2c table entry for read operation using known devices
* Get device with xi2c_dev_get(), copy and modify, if needed to * Get device with xi2c_dev_get(), copy and modify, if needed to
* offset slave address or change number of bytes to write, SCL frequency * 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 ...@@ -267,6 +375,9 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, ///< device class
int chn, ///< sensor port int chn, ///< sensor port
int page)///< index in lookup table int page)///< index in lookup table
{ {
#ifndef LOCK_BH_SENSORI2C
unsigned long flags;
#endif
x393_i2c_ctltbl_t tb_data, tb_addr; x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0; tb_addr.d32 = 0;
tb_addr.tbl_mode = 3; tb_addr.tbl_mode = 3;
...@@ -279,11 +390,21 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, ///< device class ...@@ -279,11 +390,21 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, ///< device class
tb_data.tbl_mode = 2; tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */ /* 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); 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_addr, chn);
x393_sensi2c_ctrl (tb_data, chn); x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock); #ifdef LOCK_BH_SENSORI2C
i2c_pages_shadow[(chn << 8) + page] = tb_data.d32; 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); EXPORT_SYMBOL_GPL(set_xi2c_rdc);
...@@ -296,6 +417,9 @@ void set_xi2c_wr(int chn, ///< sensor port ...@@ -296,6 +417,9 @@ void set_xi2c_wr(int chn, ///< sensor port
int num_bytes, ///< Number of bytes to write (1..10) 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 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; x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0; tb_addr.d32 = 0;
tb_addr.tbl_mode = 3; tb_addr.tbl_mode = 3;
...@@ -308,11 +432,20 @@ void set_xi2c_wr(int chn, ///< sensor port ...@@ -308,11 +432,20 @@ void set_xi2c_wr(int chn, ///< sensor port
tb_data.dly = bit_delay; tb_data.dly = bit_delay;
tb_data.tbl_mode = 2; tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */ /* 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_addr, chn);
x393_sensi2c_ctrl (tb_data, chn); x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock); #ifdef LOCK_BH_SENSORI2C
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; 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); EXPORT_SYMBOL_GPL(set_xi2c_wr);
...@@ -324,6 +457,9 @@ void set_xi2c_rd(int chn, ///< sensor port ...@@ -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 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 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; x393_i2c_ctltbl_t tb_data, tb_addr;
tb_addr.d32 = 0; tb_addr.d32 = 0;
tb_addr.tbl_mode = 3; tb_addr.tbl_mode = 3;
...@@ -335,11 +471,20 @@ void set_xi2c_rd(int chn, ///< sensor port ...@@ -335,11 +471,20 @@ void set_xi2c_rd(int chn, ///< sensor port
tb_data.dly = bit_delay; tb_data.dly = bit_delay;
tb_data.tbl_mode = 2; tb_data.tbl_mode = 2;
/* Table address and data should not interleave with others */ /* 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_addr, chn);
x393_sensi2c_ctrl (tb_data, chn); x393_sensi2c_ctrl (tb_data, chn);
spin_unlock_bh(&lock); #ifdef LOCK_BH_SENSORI2C
i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; 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); EXPORT_SYMBOL_GPL(set_xi2c_rd);
...@@ -365,24 +510,36 @@ 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 write_xi2c_rel (int chn, ///< sensor port
int offs, ///< relative frame number modulo 16 int offs, ///< relative frame number modulo 16
u32 * data) ///< data array. Length written is defined by the pre-configured table entry. 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. ///< 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 ///< @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; x393_i2c_ctltbl_t tb_data;
int len; int len;
int i; 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; 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 len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) { 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++){ for (i = 0; i <len; i++){
x393_sensi2c_rel (data[i], chn, offs); 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 { } else {
x393_sensi2c_rel (data[0], chn, offs); x393_sensi2c_rel (data[0], chn, offs);
} }
spin_unlock_bh(&lock);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(write_xi2c_rel); EXPORT_SYMBOL_GPL(write_xi2c_rel);
...@@ -394,24 +551,37 @@ 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 write_xi2c_abs (int chn, ///< sensor port
int offs, ///< absolute frame number modulo 16 int offs, ///< absolute frame number modulo 16
u32 * data) ///< data array. Length written is defined by the pre-configured table entry. 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. ///< 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 ///< @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; x393_i2c_ctltbl_t tb_data;
int len; int len;
int i; 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; 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 len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3
if (len > 1) { 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++){ for (i = 0; i <len; i++){
x393_sensi2c_abs (data[i], chn, offs); 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 { } else {
x393_sensi2c_abs (data[0], chn, offs); x393_sensi2c_abs (data[0], chn, offs);
} }
spin_unlock_bh(&lock);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(write_xi2c_abs); EXPORT_SYMBOL_GPL(write_xi2c_abs);
...@@ -495,13 +665,20 @@ EXPORT_SYMBOL_GPL(read_xi2c_sa7); ...@@ -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 */ /** 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 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; int i;
x393_status_sens_i2c_t status; x393_status_sens_i2c_t status;
x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */ x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */
if (status_ctrl.mode != 3){ 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 = x393_sensi2c_status (chn);
status_ctrl.mode = 3; status_ctrl.mode = 3;
status_ctrl.seq_num = status.seq_num ^ 0x20; status_ctrl.seq_num = status.seq_num ^ 0x20;
...@@ -510,7 +687,11 @@ int read_xi2c_frame(int chn) ///< sensor port number ...@@ -510,7 +687,11 @@ int read_xi2c_frame(int chn) ///< sensor port number
status = x393_sensi2c_status(chn); status = x393_sensi2c_status(chn);
if (likely(status.seq_num = status_ctrl.seq_num)) break; 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); 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); status = x393_sensi2c_status (chn);
...@@ -521,14 +702,21 @@ EXPORT_SYMBOL_GPL(read_xi2c_frame); ...@@ -521,14 +702,21 @@ EXPORT_SYMBOL_GPL(read_xi2c_frame);
/** Read next byte from the channel i2c read FIFO. /** 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 */ * 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 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; int fifo_lsb, rslt,i;
x393_i2c_ctltbl_t i2c_cmd; x393_i2c_ctltbl_t i2c_cmd;
x393_status_sens_i2c_t status; x393_status_sens_i2c_t status;
x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */ x393_status_ctrl_t status_ctrl = get_x393_sensi2c_status_ctrl(chn); /* last written data to status_cntrl */
if (status_ctrl.mode != 3){ 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 = x393_sensi2c_status (chn);
status_ctrl.mode = 3; status_ctrl.mode = 3;
status_ctrl.seq_num = status.seq_num ^ 0x20; status_ctrl.seq_num = status.seq_num ^ 0x20;
...@@ -537,11 +725,15 @@ int read_xi2c_fifo(int chn) ///< sensor port ...@@ -537,11 +725,15 @@ int read_xi2c_fifo(int chn) ///< sensor port
status = x393_sensi2c_status(chn); status = x393_sensi2c_status(chn);
if (likely(status.seq_num = status_ctrl.seq_num)) break; 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); 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); 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 if (!status.i2c_fifo_nempty) return -1; // No data available
fifo_lsb = status.i2c_fifo_lsb; fifo_lsb = status.i2c_fifo_lsb;
rslt = status.i2c_fifo_dout; rslt = status.i2c_fifo_dout;
...@@ -567,7 +759,7 @@ int x393_xi2c_write_reg(const char * cname, ///< device class name ...@@ -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. ///< used when multiple instances of the same class devices are present.
int reg_addr, ///< register address (width is defined by class) int reg_addr, ///< register address (width is defined by class)
int data) ///< data to write (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 * dc;
x393_i2c_device_t ds; x393_i2c_device_t ds;
...@@ -610,7 +802,7 @@ int x393_xi2c_read_reg( const char * cname, ///< device class name ...@@ -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. ///< Offset is non-zero when multiple devices of the same class are present.
int reg_addr, ///< register address (width is defined by class) int reg_addr, ///< register address (width is defined by class)
int * datap) ///< pointer to a data receiver (read data 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; x393_i2c_device_t * dc;
int page, i, db=-1; int page, i, db=-1;
...@@ -676,17 +868,23 @@ EXPORT_SYMBOL_GPL(x393_xi2c_read_reg); ...@@ -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 /** Single-command i2c read register compatible with legacy code. Device class(es) should already be registered, len parameter should
* match pre-programmed length */ * match pre-programmed length */
int legacy_read_i2c_reg( int chn, ///< sensor port number 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 int sa7, ///< slave address (7-bit) of the device
///< Offset is non-zero when multiple devices of the same class are present. ///< Offset is non-zero when multiple devices of the same class are present.
int reg_addr, ///< register address (width is defined by class) int reg_addr, ///< register address (width is defined by class)
int len, ///< number of bytes to read. int len, ///< number of bytes to read.
int * datap) ///< pointer to a data receiver (read data 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 (ETIMEDOUT) ///< @return 0 on success, < 0 - error (ETIMEDOUT)
{ {
int i, db=-1; int i, db=-1;
unsigned long timeout_end; unsigned long timeout_end;
*datap = 0; *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 */ /* Initiate i2c read */
read_xi2c_sa7 (chn, read_xi2c_sa7 (chn,
page & 0xff, // page (8 bits) page & 0xff, // page (8 bits)
...@@ -721,7 +919,7 @@ EXPORT_SYMBOL_GPL(legacy_read_i2c_reg); ...@@ -721,7 +919,7 @@ EXPORT_SYMBOL_GPL(legacy_read_i2c_reg);
/* Handling classes of i2c devices */ /* Handling classes of i2c devices */
/** Find device list entry by device class name */ /** Find device list entry by device class name */
struct x393_i2c_device_list * i2c_dev_get(const char * name) ///< Device class name as string 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 list_head *p;
struct x393_i2c_device_list * sp; struct x393_i2c_device_list * sp;
...@@ -736,7 +934,7 @@ struct x393_i2c_device_list * i2c_dev_get(const char * name) ///< Device class n ...@@ -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 */ /** Find device list entry by device class name */
x393_i2c_device_t * xi2c_dev_get(const char * name) ///< Device class name as string 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); struct x393_i2c_device_list * dl = i2c_dev_get(name);
if (dl) if (dl)
...@@ -748,7 +946,7 @@ x393_i2c_device_t * xi2c_dev_get(const char * name) ///< Device class name as st ...@@ -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); EXPORT_SYMBOL_GPL(xi2c_dev_get);
/** Add new i2c device class, OK to provide existing name */ /** 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) 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); struct x393_i2c_device_list * sp = i2c_dev_get(name);
if (sp) return sp; /* already exists */ if (sp) return sp; /* already exists */
...@@ -767,7 +965,7 @@ struct x393_i2c_device_list * i2c_dev_add(const char * name) ///< Device class n ...@@ -767,7 +965,7 @@ struct x393_i2c_device_list * i2c_dev_add(const char * name) ///< Device class n
/** Remove i2c device class by name */ /** Remove i2c device class by name */
int i2c_dev_remove(const char * name) ///< existing device class 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); struct x393_i2c_device_list * sp = i2c_dev_get(name);
if (!sp) return - ENOENT; if (!sp) return - ENOENT;
...@@ -783,7 +981,7 @@ int i2c_dev_remove(const char * name) ///< existing device class name ...@@ -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*/ /** 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 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; int reg = 0;
sscanf(attr->attr.name + (strlen(attr->attr.name)-1), "%du", &reg); 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 ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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"); dev_warn(dev,"i2c_member_store(): not implemented\n");
return count; return count;
...@@ -804,7 +1002,7 @@ static ssize_t i2c_member_store(struct device *dev, ///< Linux kern ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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; struct x393_i2c_device_list * sp;
sp = i2c_dev_get(attr->attr.name); sp = i2c_dev_get(attr->attr.name);
...@@ -828,7 +1026,7 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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; struct x393_i2c_device_list * dl;
char name[32]; char name[32];
...@@ -844,13 +1042,13 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne ...@@ -844,13 +1042,13 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne
dl = i2c_dev_get(name); dl = i2c_dev_get(name);
if (!dl){ if (!dl){
dl = i2c_dev_add (name); dl = i2c_dev_add (name);
// create sysfs group member // create sysfs group member
//group_name //group_name
new_attr = devm_kzalloc(dev, sizeof(new_attr[0]), GFP_KERNEL); new_attr = devm_kzalloc(dev, sizeof(new_attr[0]), GFP_KERNEL);
if (!new_attr) if (!new_attr)
return -ENOMEM; return -ENOMEM;
// new_attr->attr.name = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL); // 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 // strcpy(new_attr->attr.name, (const char *) name); // warning that it disqualifies const
dname = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL); dname = devm_kzalloc(dev, strlen(name)+1, GFP_KERNEL);
strcpy(dname, name); strcpy(dname, name);
new_attr->attr.name= (const char *) dname; new_attr->attr.name= (const char *) dname;
...@@ -883,7 +1081,7 @@ static ssize_t i2c_class_store(struct device *dev, ///< Linux kerne ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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 list_head *p;
struct x393_i2c_device_list * sp; struct x393_i2c_device_list * sp;
...@@ -911,7 +1109,7 @@ static ssize_t i2c_class_show(struct device *dev, ///< Linux kernel ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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 chn = get_channel_from_name(attr) ;
int page; int page;
...@@ -927,7 +1125,7 @@ static ssize_t free_i2c_page(struct device *dev, ///< Linux kernel ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
int page; int page;
...@@ -942,7 +1140,7 @@ static ssize_t set_i2c_page_inuse(struct device *dev, ///< Linux ke ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
int page; int page;
...@@ -956,7 +1154,7 @@ static ssize_t set_i2c_page_inuse(struct device *dev, ///< Linux ke ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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) ; int chn = get_channel_from_name(attr) ;
return sprintf(buf,"%d\n",sysfs_page[chn]); return sprintf(buf,"%d\n",sysfs_page[chn]);
...@@ -968,14 +1166,15 @@ static ssize_t get_i2c_page_inuse(struct device *dev, ///< Linux ke ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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 chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0) if (page < 0)
return -ENXIO; /* No such device or address */ 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 /** 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 ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
int ni, page, data; int ni, page, data;
...@@ -1003,14 +1202,15 @@ static ssize_t set_i2c_tbl_raw(struct device *dev, ///< Linux kerne ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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; x393_i2c_ctltbl_t tb_data;
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
int page = sysfs_page[chn]; // currently selected page for sysfs reads int page = sysfs_page[chn]; // currently selected page for sysfs reads
if (page < 0) if (page < 0)
return -ENXIO; /* No such device or address */ 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){ 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", 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); 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 ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
int ni, page, rah,sa7,nbwr,dly,khz; int ni, page, rah,sa7,nbwr,dly,khz;
...@@ -1094,7 +1294,7 @@ static ssize_t set_i2c_tbl_rd_human(struct device *dev, ///< Linux ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
int ni, page, two_byte_addr, num_bytes, bit_delay, khz; 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 ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 chn = get_channel_from_name(attr) ;
char cname[32]; char cname[32];
...@@ -1192,7 +1392,7 @@ static ssize_t i2c_store(struct device *dev, ///< Linux kernel basi ...@@ -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 static ssize_t i2c_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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) ; int chn = get_channel_from_name(attr) ;
dev_dbg(sdev, "i2c_show(), chn=%d\n",chn); dev_dbg(sdev, "i2c_show(), chn=%d\n",chn);
...@@ -1204,7 +1404,7 @@ static ssize_t i2c_show(struct device *dev, ///< Linux kernel basic ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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" 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" "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 ...@@ -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 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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response 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))); 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 ...@@ -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 struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data 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 cmd;
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
...@@ -1344,7 +1544,7 @@ static const struct attribute_group dev_attr_root_group = { ...@@ -1344,7 +1544,7 @@ static const struct attribute_group dev_attr_root_group = {
/** Add a named group (subdirectory) with the specified name*/ /** Add a named group (subdirectory) with the specified name*/
static int make_group (struct device *dev, ///< Linux kernel basic device structure static int make_group (struct device *dev, ///< Linux kernel basic device structure
const char * name) ///< Group name const char * name) ///< Group name
///< @return 0 on success, or negative error. ///< @return 0 on success, or negative error.
{ {
int retval=-1; int retval=-1;
struct attribute *pattrs[max_i2c_classes]; /* array of pointers to attibutes */ 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 ...@@ -1363,7 +1563,7 @@ static int make_group (struct device *dev, ///< Linux kernel basic device struct
/** Register this driver to implement sysfs interface */ /** Register this driver to implement sysfs interface */
static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///< Platform device structure for this driver 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; int retval=0;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -1380,7 +1580,7 @@ static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///< ...@@ -1380,7 +1580,7 @@ static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///<
/** Initialize this driver from the Device Tree. /** Initialize this driver from the Device Tree.
* Configures some i2c device classes specified in the DT. */ * 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 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; const char * config_string;
struct x393_i2c_device_list * dl; struct x393_i2c_device_list * dl;
...@@ -1440,11 +1640,14 @@ static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ///< Plat ...@@ -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 */ /** 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 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; sdev =&pdev->dev;
dev_dbg(&pdev->dev,"Probing elphel393-sensor-i2c\n"); 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"); dev_dbg(&pdev->dev,"i2c_page_alloc_init() done\n");
elphel393_sens_i2c_sysfs_register(pdev); elphel393_sens_i2c_sysfs_register(pdev);
...@@ -1458,7 +1661,7 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ///< Platfor ...@@ -1458,7 +1661,7 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ///< Platfor
/** Remove device driver - does nothing, just pretends.*/ /** Remove device driver - does nothing, just pretends.*/
static int elphel393_sensor_i2c_remove(struct platform_device *pdev) ///< Platform device structure for this driver 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"); dev_info(&pdev->dev,"Removing elphel393-sensor-i2c");
return 0; return 0;
......
...@@ -34,7 +34,7 @@ typedef struct{ ...@@ -34,7 +34,7 @@ typedef struct{
u8 data_bytes; ///< Number of data bytes (1..10), for writes it includes register address bytes 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) int scl_khz; ///< maximal SCL frequency in KHz (currently limited by 200KHz slowest)
} x393_i2c_device_t; } 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_stop_run_reset(int chn, int cmd);
int i2c_drive_mode (int chn, int sda_drive_high, int sda_release); int i2c_drive_mode (int chn, int sda_drive_high, int sda_release);
int read_xi2c_frame (int chn); int read_xi2c_frame (int chn);
......
...@@ -79,6 +79,9 @@ int setup_sensor_memory (int num_sensor, ///< sensor port number (0..3) ...@@ -79,6 +79,9 @@ int setup_sensor_memory (int num_sensor, ///< sensor port number (0..3)
window_width_height.height = window_height; window_width_height.height = window_height;
window_left_top.left = window_left; window_left_top.left = window_left;
window_left_top.top = window_top; 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){ switch (x393cmd){
case ASAP: case ASAP:
...@@ -210,6 +213,10 @@ int setup_compressor_memory (int num_sensor, ///< sensor port number (0..3 ...@@ -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.vert_step = tile_vstep;
window_tile_whs.tile_height = tile_height; 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){ switch (x393cmd){
case ASAP: case ASAP:
frame16 = 0; frame16 = 0;
......
...@@ -90,6 +90,7 @@ ...@@ -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_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_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 #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