Commit a9dd5e60 authored by Andrey Filippov's avatar Andrey Filippov

working on documentation

parent cb67914d
/** @file framepars.c /** @file framepars.c
* @brief Handling of frame parameters, making use of FPGA i2c * @brief Handling of frame parameters, making use of FPGA i2c
* and command sequencer that accepts commands up to 6 frames ahead. * and command sequencer that accepts commands up to 14 frames ahead.
* *
* This module includes parameter storage, code called from ISR, * This module includes parameter storage, code called from ISR,
* from other kernel drivers as well as from the user space * from other kernel drivers as well as from the user space
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
//copied from cxi2c.c - TODO:remove unneeded //copied from cxi2c.c - TODO:remove unneeded
#include <linux/types.h> /// div for 64 #include <linux/types.h> // div for 64
#include <asm/div64.h> /// div for 64 #include <asm/div64.h> // div for 64
#include <linux/module.h> #include <linux/module.h>
...@@ -58,13 +58,11 @@ ...@@ -58,13 +58,11 @@
#include "sensor_common.h" #include "sensor_common.h"
#include "framepars.h" #include "framepars.h"
#include "param_depend.h" // specifies what functions should be called for different parameters changed #include "param_depend.h" // specifies what functions should be called for different parameters changed
/// needed for lseek commands // needed for lseek commands
//#include "cxdma.h" // x313_dma_init //#include "cxdma.h" // x313_dma_init
//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on' //#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
#include "x393_macro.h" #include "x393_macro.h"
#include "x393.h" #include "x393.h"
//#undef _LINUX_WAIT_H
//#include <linux/wait.h>
/** /**
* \def MDF1(x) optional debug output * \def MDF1(x) optional debug output
...@@ -74,16 +72,16 @@ ...@@ -74,16 +72,16 @@
/* 393: program G_DEBUG through sensor port 0 */ /* 393: program G_DEBUG through sensor port 0 */
#define MDF(x) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } #define MDF(x) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; }
#define MDF2(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 2)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } } #define MDF2(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 2)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
/// setFrameParsAtomic // setFrameParsAtomic
#define MDF5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } } #define MDF5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
#define D5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { x; } } #define D5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { x; } }
/// processPars // processPars
#define MDF6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } } #define MDF6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
#define D6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { x; } } #define D6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { x; } }
///update FramePars //update FramePars
#define MDF7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } } #define MDF7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
#define D7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { x; } } #define D7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { x; } }
/// setFramePar[s] // setFramePar[s]
#define MDF8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } } #define MDF8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
#define D8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { x; } } #define D8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { x; } }
#define ELPHEL_DEBUG_THIS 0 #define ELPHEL_DEBUG_THIS 0
...@@ -123,28 +121,28 @@ ...@@ -123,28 +121,28 @@
/* 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; /// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic() unsigned long frameParsInitialized; // 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)
#ifdef NC353 #ifdef NC353
struct framepars_all_t *frameparsall = NULL; /// - will be mmap-ed struct framepars_all_t *frameparsall = NULL; // - will be mmap-ed
struct framepars_t *framepars = NULL; ///< getting rid of static to be able to use extern struct framepars_t *framepars = NULL; ///< getting rid of static to be able to use extern
struct framepars_past_t *pastpars = NULL; ///< getting rid of static to be able to use extern struct framepars_past_t *pastpars = NULL; ///< getting rid of static to be able to use extern
unsigned long *funcs2call = NULL; /// sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used unsigned long *funcs2call = NULL; // sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
unsigned long *globalPars = NULL; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both unsigned long *globalPars = NULL; // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
unsigned long *multiSensIndex = NULL; /// index for per-sensor alternatives unsigned long *multiSensIndex = NULL; // index for per-sensor alternatives
unsigned long *multiSensRvrsIndex = NULL; /// reverse index (to parent) for the multiSensIndex unsigned long *multiSensRvrsIndex = NULL; // reverse index (to parent) for the multiSensIndex
wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired wait_queue_head_t framepars_wait_queue; // used to wait for the frame to be acquired
#endif #endif
/* 393 : Changing to per-port */ /* 393 : Changing to per-port */
struct framepars_all_t *aframeparsall = NULL; /// - will be mmap-ed, in 393 points to an array of structures struct framepars_all_t *aframeparsall = NULL; // - will be mmap-ed, in 393 points to an array of structures
struct framepars_t *aframepars[SENSOR_PORTS]; ///< getting rid of static to be able to use extern struct framepars_t *aframepars[SENSOR_PORTS]; ///< getting rid of static to be able to use extern
struct framepars_past_t *apastpars[SENSOR_PORTS]; ///< getting rid of static to be able to use extern struct framepars_past_t *apastpars[SENSOR_PORTS]; ///< getting rid of static to be able to use extern
unsigned long *afuncs2call[SENSOR_PORTS]; /// sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used unsigned long *afuncs2call[SENSOR_PORTS]; // sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
unsigned long *aglobalPars[SENSOR_PORTS]; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both unsigned long *aglobalPars[SENSOR_PORTS]; // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
unsigned long *amultiSensIndex[SENSOR_PORTS]; /// index for per-sensor alternatives unsigned long *amultiSensIndex[SENSOR_PORTS]; // index for per-sensor alternatives
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
/* Remove after compilation OK */ /* Remove after compilation OK */
struct sensorproc_t * sensorproc = NULL; struct sensorproc_t * sensorproc = NULL;
...@@ -170,14 +168,14 @@ struct sensorproc_t * sensorproc = NULL; ...@@ -170,14 +168,14 @@ struct sensorproc_t * sensorproc = NULL;
#endif #endif
//wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired //wait_queue_head_t framepars_wait_queue; // used to wait for the frame to be acquired
/** /**
* @brief file private data * @brief file private data
*/ */
struct framepars_pd { struct framepars_pd {
int minor; ///< file minor value int minor; ///< file minor value
struct wait_queue *framepars_wait_queue; ///< wait queue (waiting for file number to increase) ///NOTE: not used at all? struct wait_queue *framepars_wait_queue; ///< wait queue (waiting for file number to increase) //NOTE: not used at all?
// something else to be added here? // something else to be added here?
}; };
...@@ -188,14 +186,14 @@ struct framepars_pd { ...@@ -188,14 +186,14 @@ struct framepars_pd {
*/ */
void init_framepars_ptr(int sensor_port) void init_framepars_ptr(int sensor_port)
{ {
// frameparsall = &sFrameParsAll; /// - will be mmap-ed // frameparsall = &sFrameParsAll; // - will be mmap-ed
aframeparsall = sFrameParsAll; /// - will be mmap-ed aframeparsall = sFrameParsAll; // - will be mmap-ed
aframepars[sensor_port] = sFrameParsAll[sensor_port].framePars; aframepars[sensor_port] = sFrameParsAll[sensor_port].framePars;
apastpars[sensor_port] = sFrameParsAll[sensor_port].pastPars; apastpars[sensor_port] = sFrameParsAll[sensor_port].pastPars;
afuncs2call[sensor_port] = sFrameParsAll[sensor_port].func2call.pars; /// each parameter has a 32-bit mask of what pgm_function to call - other fields not used afuncs2call[sensor_port] = sFrameParsAll[sensor_port].func2call.pars; // each parameter has a 32-bit mask of what pgm_function to call - other fields not used
aglobalPars[sensor_port] = sFrameParsAll[sensor_port].globalPars; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both aglobalPars[sensor_port] = sFrameParsAll[sensor_port].globalPars; // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
amultiSensIndex[sensor_port] = sFrameParsAll[sensor_port].multiSensIndex; /// indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones amultiSensIndex[sensor_port] = sFrameParsAll[sensor_port].multiSensIndex; // indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones
amultiSensRvrsIndex[sensor_port] = sFrameParsAll[sensor_port].multiSensRvrsIndex; /// reverse index (to parent) for the multiSensIndex amultiSensRvrsIndex[sensor_port] = sFrameParsAll[sensor_port].multiSensRvrsIndex; // reverse index (to parent) for the multiSensIndex
} }
...@@ -272,16 +270,16 @@ void initFramePars(int sensor_port) ...@@ -272,16 +270,16 @@ void initFramePars(int 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); resetFrameNumber(sensor_port);
/// initialize frameParsDeps.pars masks: // initialize frameParsDeps.pars masks:
for (i = 0; i < (sizeof(param_depend_tab) / 8); i++) { for (i = 0; i < (sizeof(param_depend_tab) / 8); i++) {
afuncs2call[sensor_port][param_depend_tab[2 * i] & 0xffff] = param_depend_tab[2 * i + 1]; /// remove possible flags afuncs2call[sensor_port][param_depend_tab[2 * i] & 0xffff] = param_depend_tab[2 * i + 1]; // remove possible flags
MDF2(printk("funcs2call[0x%lx]=0x%08lx\n", param_depend_tab[2 * i] & 0xffff, param_depend_tab[2 * i + 1])); MDF2(printk("funcs2call[0x%lx]=0x%08lx\n", param_depend_tab[2 * i] & 0xffff, param_depend_tab[2 * i + 1]));
} }
for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS; // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
/// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be changed, and if will be it wil cause no action // Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be changed, and if will be it wil cause no action
for (i = 0; i < P_M10359_NUMREGS; i++) afuncs2call[sensor_port][P_M10359_REGS + i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function for (i = 0; i < P_M10359_NUMREGS; i++) afuncs2call[sensor_port][P_M10359_REGS + i] = ONCHANGE_SENSORREGS; // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
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 = 1; frameParsInitialized = 1;
} }
...@@ -292,7 +290,7 @@ void initFramePars(int sensor_port) ...@@ -292,7 +290,7 @@ void initFramePars(int sensor_port)
void initGlobalPars(int sensor_port) void initGlobalPars(int sensor_port)
{ {
memset(&aglobalPars[sensor_port][GLOBALS_PRESERVE], 0, (NUM_GPAR - GLOBALS_PRESERVE) * sizeof(unsigned long)); memset(&aglobalPars[sensor_port][GLOBALS_PRESERVE], 0, (NUM_GPAR - GLOBALS_PRESERVE) * sizeof(unsigned long));
/// MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script // MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script
MDF(printk("GLOBALPARS(0,G_DEBUG)=%lx\n", GLOBALPARS(0,G_DEBUG))); MDF(printk("GLOBALPARS(0,G_DEBUG)=%lx\n", GLOBALPARS(0,G_DEBUG)));
} }
...@@ -304,7 +302,7 @@ void initGlobalPars(int sensor_port) ...@@ -304,7 +302,7 @@ void initGlobalPars(int sensor_port)
int initMultiPars(int sensor_port) int initMultiPars(int sensor_port)
{ {
int i, j, n; int i, j, n;
int ireg = P_MULTI_REGS; /// multi-reg shadows start index int ireg = P_MULTI_REGS; // multi-reg shadows start index
unsigned long m; unsigned long m;
// memset(amultiSensIndex[sensor_port], 0, sizeof(struct framepars_all_t.multiSensIndex)); // memset(amultiSensIndex[sensor_port], 0, sizeof(struct framepars_all_t.multiSensIndex));
...@@ -313,14 +311,14 @@ int initMultiPars(int sensor_port) ...@@ -313,14 +311,14 @@ int initMultiPars(int sensor_port)
memset(amultiSensRvrsIndex[sensor_port], 0, P_MAX_PAR_ROUNDUP * sizeof(int)); memset(amultiSensRvrsIndex[sensor_port], 0, P_MAX_PAR_ROUNDUP * sizeof(int));
GLOBALPARS(sensor_port,G_MULTI_NUM) = 0; GLOBALPARS(sensor_port,G_MULTI_NUM) = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
m = GLOBALPARS(sensor_port, G_MULTI_REGSM + i); /// 1 bit per register that need individual shadows m = GLOBALPARS(sensor_port, G_MULTI_REGSM + i); // 1 bit per register that need individual shadows
// MDF(printk("i=%d, m=0x%lx\n",i,m)); // MDF(printk("i=%d, m=0x%lx\n",i,m));
for (j = P_SENSOR_REGS + (i << 5); m && (GLOBALPARS(sensor_port,G_MULTI_NUM) < P_MULTI_NUMREGS); j++, m >>= 1) { for (j = P_SENSOR_REGS + (i << 5); m && (GLOBALPARS(sensor_port,G_MULTI_NUM) < P_MULTI_NUMREGS); j++, m >>= 1) {
if (m & 1) { if (m & 1) {
amultiSensIndex[j] = ireg; amultiSensIndex[j] = ireg;
// MDF(printk("j=0x%x ireg=0x%x\n",j,ireg)); // MDF(printk("j=0x%x ireg=0x%x\n",j,ireg));
for (n = 0; n < MAX_SENSORS; n++) { for (n = 0; n < MAX_SENSORS; n++) {
afuncs2call[sensor_port][ireg] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of these registers will trigger pgm_sensorreg function afuncs2call[sensor_port][ireg] = ONCHANGE_SENSORREGS; // by default each "manual" write to any of these registers will trigger pgm_sensorreg function
amultiSensRvrsIndex[sensor_port][ireg++] = j | ((n + 1) << 16); amultiSensRvrsIndex[sensor_port][ireg++] = j | ((n + 1) << 16);
} }
GLOBALPARS(sensor_port,G_MULTI_NUM)++; GLOBALPARS(sensor_port,G_MULTI_NUM)++;
...@@ -328,7 +326,7 @@ int initMultiPars(int sensor_port) ...@@ -328,7 +326,7 @@ int initMultiPars(int sensor_port)
} }
} }
// remark: the line below is called from initFramePars, consider removing it // remark: the line below is called from initFramePars, consider removing it
for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS; // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
MDF(printk("GLOBALPARS(G_MULTI_NUM)=%lx\n", GLOBALPARS(sensor_port, G_MULTI_NUM))); MDF(printk("GLOBALPARS(G_MULTI_NUM)=%lx\n", GLOBALPARS(sensor_port, G_MULTI_NUM)));
return GLOBALPARS(sensor_port, G_MULTI_NUM); return GLOBALPARS(sensor_port, G_MULTI_NUM);
} }
...@@ -403,7 +401,7 @@ inline void set_imageParamsR_all(int sensor_port, int n, unsigned long ...@@ -403,7 +401,7 @@ inline void set_imageParamsR_all(int sensor_port, int n, unsigned long
for (i = 0; i < PARS_FRAMES; i++) aframepars[sensor_port][i].pars[n] = d; for (i = 0; i < PARS_FRAMES; i++) aframepars[sensor_port][i].pars[n] = d;
} }
///++++++++++++++++++++++++++++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++
/*! /*!
* @brief called from ISR - advance thisFrameNumber to match hardware frame8, copy parameters as needed. * @brief called from ISR - advance thisFrameNumber to match hardware frame8, copy parameters as needed.
* before: (thisFrameNumber mod8 pointed to current (for the software) parameters frame (now behind by at least 1, maybe 2) * before: (thisFrameNumber mod8 pointed to current (for the software) parameters frame (now behind by at least 1, maybe 2)
...@@ -422,8 +420,8 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i ...@@ -422,8 +420,8 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
unsigned long bmask, bmask32; unsigned long bmask, bmask32;
int pastParsIndex; int pastParsIndex;
struct framepars_t *framepars = aframepars[sensor_port]; struct framepars_t *framepars = aframepars[sensor_port];
/// If interrupt was from compression done (circbuf advanced, interframe_pars!=null), the frame8 (hardware) maybe not yet advanced // If interrupt was from compression done (circbuf advanced, interframe_pars!=null), the frame8 (hardware) maybe not yet advanced
/// We can fix it here, but it will not work if some frames were not processed in time // We can fix it here, but it will not work if some frames were not processed in time
if ((interframe_pars != NULL) && (((frame8 ^ thisFrameNumber(sensor_port)) & PARS_FRAMES_MASK) == 0)) { if ((interframe_pars != NULL) && (((frame8 ^ thisFrameNumber(sensor_port)) & PARS_FRAMES_MASK) == 0)) {
findex_this = frame8 & PARS_FRAMES_MASK; findex_this = frame8 & PARS_FRAMES_MASK;
...@@ -432,32 +430,32 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i ...@@ -432,32 +430,32 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
if (framepars[findex_this].pars[P_IRQ_SMART] & 4) frame8 = (frame8 + 1) & PARS_FRAMES_MASK; // verify that this mode is enabled (together with bit0) if (framepars[findex_this].pars[P_IRQ_SMART] & 4) frame8 = (frame8 + 1) & PARS_FRAMES_MASK; // verify that this mode is enabled (together with bit0)
} }
while ((frame8 ^ thisFrameNumber(sensor_port)) & PARS_FRAMES_MASK) { while ((frame8 ^ thisFrameNumber(sensor_port)) & PARS_FRAMES_MASK) {
/// before update: // before update:
/// framepars[findex_prev] holds previous frame data (oldest availble) // framepars[findex_prev] holds previous frame data (oldest availble)
/// framepars[findex_future] holds farthest in the future one // framepars[findex_future] holds farthest in the future one
/// after update: // after update:
/// framepars[findex_prev] holds farthest in the future one ("this" will become "prev") // framepars[findex_prev] holds farthest in the future one ("this" will become "prev")
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; // farthest in the future findex_future = (findex_this - 2) & PARS_FRAMES_MASK; // farthest in the future
findex_next = (findex_this + 1) & PARS_FRAMES_MASK; findex_next = (findex_this + 1) & PARS_FRAMES_MASK;
/// copy subset of the parameters to the long buffer of past parameters. TODO: fill Exif also here? // copy subset of the parameters to the long buffer of past parameters. TODO: fill Exif also here?
/// TODO:DONE: Change - make pastpars be save for all frames, not just compressed ones // TODO:DONE: Change - make pastpars be save for all frames, not just compressed ones
/// With PASTPARS_SAVE_ENTRIES being multiple of PARS_FRAMES - make it possible to calculate past_index from thisFrameNumber // With PASTPARS_SAVE_ENTRIES being multiple of PARS_FRAMES - make it possible to calculate past_index from thisFrameNumber
// pastParsIndex= thisFrameNumber & PASTPARS_SAVE_ENTRIES_MASK; // pastParsIndex= thisFrameNumber & PASTPARS_SAVE_ENTRIES_MASK;
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
// memcpy (pastpars[pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], sizeof(pastpars[0].past_pars)); // memcpy (pastpars[pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], sizeof(pastpars[0].past_pars));
memcpy(apastpars[sensor_port][pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], PARS_SAVE_COPY * sizeof(int)); memcpy(apastpars[sensor_port][pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], PARS_SAVE_COPY * sizeof(int));
/// Now update interframe_pars (interframe area) used to create JPEG headers. Interframe area survives exactly as long as the frames themselves (not like pastpars) // Now update interframe_pars (interframe area) used to create JPEG headers. Interframe area survives exactly as long as the frames themselves (not like pastpars)
if (interframe_pars) { /// frame was compressed, not just vsync if (interframe_pars) { // frame was compressed, not just vsync
///TODO: get rid of *_prev, use it for the future. //TODO: get rid of *_prev, use it for the future.
memcpy(interframe_pars, &framepars[findex_this].pars[P_GTAB_R], 24); /// will leave some gaps, but copy [P_ACTUAL_WIDTH] memcpy(interframe_pars, &framepars[findex_this].pars[P_GTAB_R], 24); // will leave some gaps, but copy [P_ACTUAL_WIDTH]
interframe_pars->height = framepars[findex_this].pars[P_ACTUAL_HEIGHT]; /// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy interframe_pars->height = framepars[findex_this].pars[P_ACTUAL_HEIGHT]; // NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
interframe_pars->color = framepars[findex_this].pars[P_COLOR]; interframe_pars->color = framepars[findex_this].pars[P_COLOR];
interframe_pars->byrshift = framepars[findex_this].pars[P_COMPMOD_BYRSH]; interframe_pars->byrshift = framepars[findex_this].pars[P_COMPMOD_BYRSH];
interframe_pars->quality2 |= (framepars[findex_this].pars[P_PORTRAIT] & 1) << 7; interframe_pars->quality2 |= (framepars[findex_this].pars[P_PORTRAIT] & 1) << 7;
} }
/// copy parameters from findex_future (old "farthest in the future") to findex_prev (new "fartherst in the future") if it was changed since // copy parameters from findex_future (old "farthest in the future") to findex_prev (new "fartherst in the future") if it was changed since
if ((bmask32 = framepars[findex_prev].modsince32)) { if ((bmask32 = framepars[findex_prev].modsince32)) {
MDF7(printk("framepars[%d].modsince32=0x%lx\n", findex_prev, bmask32)); MDF7(printk("framepars[%d].modsince32=0x%lx\n", findex_prev, bmask32));
for (index32 = 0; bmask32; index32++, bmask32 >>= 1) { for (index32 = 0; bmask32; index32++, bmask32 >>= 1) {
...@@ -467,20 +465,20 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i ...@@ -467,20 +465,20 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
framepars[findex_prev].pars[index] = framepars[findex_future].pars[index]; framepars[findex_prev].pars[index] = framepars[findex_future].pars[index];
MDF7(printk("hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n", frame8, findex_prev, index, findex_future, index, framepars[findex_future].pars[index])); MDF7(printk("hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n", frame8, findex_prev, index, findex_future, index, framepars[findex_future].pars[index]));
} }
framepars[findex_prev].modsince[index32] = 0; /// mark as not "modified since" (yet) framepars[findex_prev].modsince[index32] = 0; // mark as not "modified since" (yet)
} }
} }
framepars[findex_prev].modsince32 = 0; /// mark as not "modified since" super index framepars[findex_prev].modsince32 = 0; // mark as not "modified since" super index
} }
/// clear "modified" and flags on the brand new future frame // clear "modified" and flags on the brand new future frame
// remark: framepars[findex_prev].mod is 31 dwords long abd here 32 dwords are cleared // remark: framepars[findex_prev].mod is 31 dwords long abd here 32 dwords are cleared
// explanation: mod32 goes after mod[31] and it is cleared too // explanation: mod32 goes after mod[31] and it is cleared too
if (framepars[findex_prev].mod32) memset(framepars[findex_prev].mod, 0, 32 * 4); /// .mod[0]-.mod[30], .mod32 if (framepars[findex_prev].mod32) memset(framepars[findex_prev].mod, 0, 32 * 4); // .mod[0]-.mod[30], .mod32
framepars[findex_prev].functions = 0; /// No functions yet needed on the brand new frame framepars[findex_prev].functions = 0; // No functions yet needed on the brand new frame
// remark: replace number 7 with named constant, it should correspond to total frame num (16 in new camera) // remark: replace number 7 with named constant, it should correspond to total frame num (16 in new camera)
framepars[findex_prev].pars[P_FRAME] = thisFrameNumber(sensor_port) + (PARS_FRAMES-1); /// that will be the full frame number framepars[findex_prev].pars[P_FRAME] = thisFrameNumber(sensor_port) + (PARS_FRAMES-1); // that will be the full frame number
/// NOTE: Handle past due - copy functions, and mod if functions were non-zero // NOTE: Handle past due - copy functions, and mod if functions were non-zero
if (framepars[findex_this].functions) { /// Some functions were not yet processed (past due) if (framepars[findex_this].functions) { // Some functions were not yet processed (past due)
if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) { if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) {
framepars[findex_next].functions |= framepars[findex_this].functions; framepars[findex_next].functions |= framepars[findex_this].functions;
if ((bmask32 = framepars[findex_this].mod32)) { if ((bmask32 = framepars[findex_this].mod32)) {
...@@ -510,10 +508,10 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i ...@@ -510,10 +508,10 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, int frame8) inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, int frame8)
{ {
unsigned long todo, mask, remain; unsigned long todo, mask, remain;
int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8 int pars_ahead; // considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
int frame_proc; /// current frame for which parameters are considered int frame_proc; // current frame for which parameters are considered
struct framepars_t * procpars; struct framepars_t * procpars;
struct framepars_t * prevpars; /// maybe - drop calculation for each function, move it to pgm_* where needed? struct framepars_t * prevpars; // maybe - drop calculation for each function, move it to pgm_* where needed?
struct framepars_t *framepars = aframepars[sensor_port]; struct framepars_t *framepars = aframepars[sensor_port];
unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP); unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP);
int i; int i;
...@@ -525,8 +523,8 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -525,8 +523,8 @@ 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
/// do all ASAP tasks (they should not be done ahead of the corresponding interrupt!) // do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
/// Now try overdue functions with latencies >=1 and try them in ASAP mode // Now try overdue functions with latencies >=1 and try them in ASAP mode
for (pars_ahead = 0; pars_ahead <= 4; pars_ahead++ ) { for (pars_ahead = 0; pars_ahead <= 4; pars_ahead++ ) {
frame_proc = (frame8 + pars_ahead) & PARS_FRAMES_MASK; frame_proc = (frame8 + pars_ahead) & PARS_FRAMES_MASK;
procpars = &framepars[frame_proc]; procpars = &framepars[frame_proc];
...@@ -536,14 +534,14 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -536,14 +534,14 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
remain = 0xffffffff; remain = 0xffffffff;
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
while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change while (!(todo & mask)) { // skip zeros - todo will stay current (.functions will not change
i++; i++;
mask <<= 1; mask <<= 1;
remain <<= 1; remain <<= 1;
} }
/// now (todo & mask) !=0 // now (todo & mask) !=0
MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx\n", MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx\n",
todo, procpars->functions, frame8, pars_ahead, frame_proc, i, mask)); todo, procpars->functions, frame8, pars_ahead, frame_proc, i, mask));
...@@ -553,11 +551,11 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -553,11 +551,11 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
if (sensorproc->pgm_func[i]) { if (sensorproc->pgm_func[i]) {
rslt = sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, -1); rslt = sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, -1);
} else rslt = 0; /// only sensor-specific function, nothing to do common to all sensors } else rslt = 0; // only sensor-specific function, nothing to do common to all sensors
if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) { /// sensor - specific functions, called after the main ones if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) { // sensor - specific functions, called after the main ones
rslt = sensorproc->pgm_func[i + 32] ( &(sensorproc->sensor), procpars, prevpars, -1); rslt = sensorproc->pgm_func[i + 32] ( &(sensorproc->sensor), procpars, prevpars, -1);
} }
/// Nothing to do with errors here - just report? // Nothing to do with errors here - just report?
if (rslt < 0) printk("%s:%d:%s - error=%d", __FILE__, __LINE__, __FUNCTION__, rslt); if (rslt < 0) printk("%s:%d:%s - error=%d", __FILE__, __LINE__, __FUNCTION__, rslt);
procpars->functions &= ~mask; procpars->functions &= ~mask;
MDF6(printk(".functions=0x%08lx)\n", procpars->functions)); MDF6(printk(".functions=0x%08lx)\n", procpars->functions));
...@@ -567,7 +565,7 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -567,7 +565,7 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
} }
} }
} }
/// Next 5 should go in that sequence // Next 5 should go in that sequence
//#define G_CALLNASAP 119 // bitmask - what functions can be used not only in the current frame (ASAP) mode //#define G_CALLNASAP 119 // bitmask - what functions can be used not only in the current frame (ASAP) mode
//#define G_CALLNEXT1 120 // bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4) //#define G_CALLNEXT1 120 // bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
//#define G_CALLNEXT2 121 // bitmask of actions to be two or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4) //#define G_CALLNEXT2 121 // bitmask of actions to be two or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4)
...@@ -578,32 +576,32 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i ...@@ -578,32 +576,32 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead) inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, int frame8, int maxahead)
{ {
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
int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8 int pars_ahead; // considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
int frame_proc; /// current frame for which parameters are considered int frame_proc; // current frame for which parameters are considered
struct framepars_t * procpars; struct framepars_t * procpars;
struct framepars_t * prevpars; /// maybe - drop calculation for each function, move it to pgm_* where needed? struct framepars_t * prevpars; // maybe - drop calculation for each function, move it to pgm_* where needed?
struct framepars_t *framepars = aframepars[sensor_port]; struct framepars_t *framepars = aframepars[sensor_port];
unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP); unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP);
int seq_frame; /// sequencer frame for which pgm_* function should schedule data int seq_frame; // sequencer frame for which pgm_* function should schedule data
int i; int i;
int rslt; int rslt;
int max_par_ahead; int max_par_ahead;
int this_ahead; int this_ahead;
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++ ) {
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 = (frame8 + job_ahead + pars_ahead + 1) & PARS_FRAMES_MASK; /// frame_proc = (frame8 + job_ahead + pars_ahead + 1) & PARS_FRAMES_MASK; //
procpars = &framepars[frame_proc]; procpars = &framepars[frame_proc];
/// Check if at least one function is needed for frame_proc // Check if at least one function is needed for frame_proc
if (procpars->functions & if (procpars->functions &
p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice p_nasap[pars_ahead] & //all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
p_nasap[0]) { p_nasap[0]) {
prevpars = &framepars[(frame_proc - 1) & PARS_FRAMES_MASK]; prevpars = &framepars[(frame_proc - 1) & PARS_FRAMES_MASK];
// seq_frame= (frame8+job_ahead+1) & PARS_FRAMES_MASK; // seq_frame= (frame8+job_ahead+1) & PARS_FRAMES_MASK;
...@@ -611,16 +609,16 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in ...@@ -611,16 +609,16 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
mask = 1; mask = 1;
remain = 0xffffffff; remain = 0xffffffff;
while ((todo = procpars->functions & while ((todo = procpars->functions &
/// p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice // p_nasap[pars_ahead] & //all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
p_nasap[0] & remain)) { /// eliminate ASAP-only function p_nasap[0] & remain)) { // eliminate ASAP-only function
while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change) while (!(todo & mask)) { // skip zeros - todo will stay current (.functions will not change)
i++; i++;
mask <<= 1; mask <<= 1;
remain <<= 1; remain <<= 1;
} }
/// now (todo & mask) !=0 // now (todo & mask) !=0
/// find the right latency // find the right latency
for (this_ahead = 1; (p_nasap[this_ahead] & todo & mask) && (this_ahead <= 4); this_ahead++) ; /// this_ahead==1..5 for (this_ahead = 1; (p_nasap[this_ahead] & todo & mask) && (this_ahead <= 4); this_ahead++) ; // this_ahead==1..5
// seq_frame= (frame8 + job_ahead + this_ahead) & PARS_FRAMES_MASK; // seq_frame= (frame8 + job_ahead + this_ahead) & PARS_FRAMES_MASK;
seq_frame = (frame_proc + 1 - this_ahead) & PARS_FRAMES_MASK; seq_frame = (frame_proc + 1 - this_ahead) & PARS_FRAMES_MASK;
...@@ -628,14 +626,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in ...@@ -628,14 +626,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions)); MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions));
if (sensorproc->pgm_func[i]) { if (sensorproc->pgm_func[i]) {
/// NOTE: Was (frame8+job_ahead +1) & PARS_FRAMES_MASK // NOTE: Was (frame8+job_ahead +1) & PARS_FRAMES_MASK
rslt = sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, seq_frame); rslt = sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
} else rslt = 0; /// only sensor-specific function, nothing to do common to all sensors } else rslt = 0; // only sensor-specific function, nothing to do common to all sensors
if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) { /// sensor - specific functions, called after the main ones if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) { // sensor - specific functions, called after the main ones
rslt = sensorproc->pgm_func[i + 32] ( &(sensorproc->sensor), procpars, prevpars, seq_frame); rslt = sensorproc->pgm_func[i + 32] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
} }
if (rslt >= 0) { if (rslt >= 0) {
procpars->functions &= ~mask; /// mark it done procpars->functions &= ~mask; // mark it done
} else { } else {
MDF6(printk("Error - function result was %d\n", rslt)); MDF6(printk("Error - function result was %d\n", rslt));
} }
...@@ -663,14 +661,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in ...@@ -663,14 +661,14 @@ inline void processParsSeq(int sensor_port, struct sensorproc_t * sensorproc, in
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)
{ {
frame8 &= PARS_FRAMES_MASK; frame8 &= PARS_FRAMES_MASK;
/// 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!)
// MDF6(printk("before first processParsASAP\n")); // MDF6(printk("before first processParsASAP\n"));
processParsASAP(sensor_port, sensorproc, frame8); processParsASAP(sensor_port, sensorproc, frame8);
/// 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
// MDF6(printk("before processParsSeq\n")); // MDF6(printk("before processParsSeq\n"));
processParsSeq(sensor_port, sensorproc, frame8, maxahead); processParsSeq(sensor_port, sensorproc, frame8, 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
// MDF6(printk("before second processParsASAP\n")); // MDF6(printk("before second processParsASAP\n"));
processParsASAP(sensor_port, sensorproc, frame8); processParsASAP(sensor_port, sensorproc, frame8);
} }
...@@ -744,7 +742,7 @@ int setFrameParsStatic(int sensor_port, int numPars, struct frameparspair_t * pa ...@@ -744,7 +742,7 @@ int setFrameParsStatic(int sensor_port, int numPars, struct frameparspair_t * pa
* @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number * @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
* @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE * @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 //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) int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars)
{ {
unsigned long flags; unsigned long flags;
...@@ -754,11 +752,11 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -754,11 +752,11 @@ 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];
if (!frameParsInitialized) { if (!frameParsInitialized) {
initSequencers(sensor_port); /// Will call initFramePars(); and initialize functions initSequencers(sensor_port); // Will call initFramePars(); and initialize functions
} }
int findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK; int findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
int findex_prev = (findex_this - 1) & PARS_FRAMES_MASK; int findex_prev = (findex_this - 1) & PARS_FRAMES_MASK;
int findex_future = (findex_this - 2) & PARS_FRAMES_MASK; /// actually - fartherst in the future?? int findex_future = (findex_this - 2) & PARS_FRAMES_MASK; // actually - fartherst in the future??
// int frame8= frameno & PARS_FRAMES_MASK; // int frame8= frameno & PARS_FRAMES_MASK;
int frame8; int frame8;
MDF2(printk(": frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d\n", frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars)); MDF2(printk(": frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d\n", frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars));
...@@ -773,7 +771,7 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -773,7 +771,7 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
return -ERR_FRAMEPARS_TOOEARLY; return -ERR_FRAMEPARS_TOOEARLY;
} }
} }
/// not too late, not too early, go ahead // not too late, not too early, go ahead
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)); D5(printk(" --pars[%d].num=0x%lx, pars[%d].val=0x%lx", npar, pars[npar].num, npar, pars[npar].val));
// frame8= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK); // frame8= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK);
...@@ -785,8 +783,8 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -785,8 +783,8 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
return -ERR_FRAMEPARS_BADINDEX; return -ERR_FRAMEPARS_BADINDEX;
} }
D5(printk(" index=0x%x, val=0x%lx", index, val)); D5(printk(" index=0x%x, val=0x%lx", index, val));
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);
} }
GLOBALPARS(sensor_port, index) = val; GLOBALPARS(sensor_port, index) = val;
...@@ -794,9 +792,9 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -794,9 +792,9 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
} 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)); D5(printk(" set funcs2call[0x%x]=0x%lx\n", index, val));
// } 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 ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick } else if ((frame8 != 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[frame8].pars[index], val); val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
} }
//TODO: optimize to use mask several parameters together //TODO: optimize to use mask several parameters together
...@@ -805,42 +803,42 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i ...@@ -805,42 +803,42 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
bmask = 1 << (index & 31); bmask = 1 << (index & 31);
bindex = index >> 5; bindex = index >> 5;
bmask32 = 1 << bindex; bmask32 = 1 << bindex;
/// Set this parameter for specified frame // Set this parameter for specified frame
framepars[frame8].pars[index] = val; framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32; framepars[frame8].mod32 |= bmask32;
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters framepars[frame8].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[frame8].functions)); D5(printk(" bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n", bindex, bmask, bmask32, framepars[frame8].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")); MDF5(printk(": --- setting next frames"));
for (nframe = (frame8 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) { for (nframe = (frame8 + 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)); D5(printk(" %d", nframe));
} }
frame8 = (frame8 - 1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does frame8 = (frame8 - 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
for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32; framepars[nframe].modsince32 |= bmask32;
} }
} }
} 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)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", 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)
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
MDF5(printk("\n")); MDF5(printk("\n"));
processPars(sensor_port, sensorproc, thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet processPars(sensor_port, sensorproc, thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
} }
PROFILE_NOW(7); PROFILE_NOW(7);
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
...@@ -878,32 +876,32 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l ...@@ -878,32 +876,32 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
return -ERR_FRAMEPARS_BADINDEX; return -ERR_FRAMEPARS_BADINDEX;
} }
//TODO: optimize to use mask several parameters together //TODO: optimize to use mask several parameters together
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 (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one if (mindex & FRAMEPAIR_MASK_BYTES) { // combine new value with the old one
val = FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(sensor_port,index), val); val = FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(sensor_port,index), val);
} }
GLOBALPARS(sensor_port,index) = val; GLOBALPARS(sensor_port,index) = val;
} else if (mindex & FRAMEPAIR_FRAME_FUNC) { /// write to func_proc[] instead } else if (mindex & FRAMEPAIR_FRAME_FUNC) { // write to func_proc[] instead
funcs2call[index] = val; funcs2call[index] = val;
// } else { // } else {
} else if ((frame8 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS) == 0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick } else if ((frame8 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS) == 0)) { // do not write "JUST_THIS" parameters in the future otherwise they'll stick
if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one if (mindex & FRAMEPAIR_MASK_BYTES) { // combine new value with the old one
val = FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame8].pars[index], val); val = FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame8].pars[index], val);
} }
if ((framepars[frame8].pars[index] != val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))) { if ((framepars[frame8].pars[index] != val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))) {
bmask = 1 << (index & 31); bmask = 1 << (index & 31);
bindex = index >> 5; bindex = index >> 5;
bmask32 = 1 << bindex; bmask32 = 1 << bindex;
/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED! // Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
framepars[frame8].pars[index] = val; framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32; framepars[frame8].mod32 |= bmask32;
if (mindex & FRAMEPAIR_FORCE_PROC) { if (mindex & FRAMEPAIR_FORCE_PROC) {
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters framepars[frame8].functions |= funcs2call[index]; //Mark which functions will be needed to process the parameters
} }
MDF8(printk(" bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n", bindex, bmask, bmask32, framepars[frame8].functions)); MDF8(printk(" bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n", bindex, bmask, bmask32, framepars[frame8].functions));
/// Write parameter to the next frames up to the one that have the same parameter already modified // Write parameter to the next frames up to the one that have the same parameter already modified
if ((mindex & FRAMEPAIR_JUST_THIS) == 0) { if ((mindex & FRAMEPAIR_JUST_THIS) == 0) {
MDF8(printk(": --- setting next frames")); MDF8(printk(": --- setting next frames"));
// for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame8].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) { // for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame8].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
...@@ -911,21 +909,21 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l ...@@ -911,21 +909,21 @@ int setFramePar(int sensor_port, struct framepars_t * this_framepars, unsigned l
framepars[nframe].pars[index] = val; framepars[nframe].pars[index] = val;
D8(printk(" %d", nframe)); D8(printk(" %d", nframe));
} }
frame8 = (frame8 - 1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does frame8 = (frame8 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
} }
// MDF1(printk("\n")); // MDF1(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
MDF8(printk(": >>> setting modsince")); MDF8(printk(": >>> setting modsince"));
// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { // for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32; framepars[nframe].modsince32 |= bmask32;
D8(printk(" %d", nframe)); D8(printk(" %d", nframe));
} }
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));
ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex));
return -ERR_FRAMEPARS_TOOEARLY; return -ERR_FRAMEPARS_TOOEARLY;
...@@ -968,16 +966,16 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -968,16 +966,16 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
ELP_KERR(printk(" bad index=%d > %d\n", index, P_MAX_PAR)); ELP_KERR(printk(" bad index=%d > %d\n", index, P_MAX_PAR));
return -ERR_FRAMEPARS_BADINDEX; return -ERR_FRAMEPARS_BADINDEX;
} }
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);
} }
GLOBALPARS(sensor_port,index) = val; GLOBALPARS(sensor_port,index) = val;
} else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) { } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
funcs2call[index] = val; funcs2call[index] = val;
// } else { // } else {
} else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick } else if ((frame8 != 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[frame8].pars[index], val); val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
} }
//TODO: optimize to use mask several parameters together //TODO: optimize to use mask several parameters together
...@@ -985,32 +983,32 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -985,32 +983,32 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
bmask = 1 << (index & 31); bmask = 1 << (index & 31);
bindex = index >> 5; bindex = index >> 5;
bmask32 = 1 << bindex; bmask32 = 1 << bindex;
/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED! // Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
framepars[frame8].pars[index] = val; framepars[frame8].pars[index] = val;
framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod[bindex] |= bmask;
framepars[frame8].mod32 |= bmask32; framepars[frame8].mod32 |= bmask32;
if (pars[npar].num & FRAMEPAIR_FORCE_PROC) { if (pars[npar].num & FRAMEPAIR_FORCE_PROC) {
framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters framepars[frame8].functions |= funcs2call[index]; //Mark which functions will be needed to process the parameters
} }
/// 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) {
MDF8(printk(": --- setting next frames")); MDF8(printk(": --- setting next frames"));
for (nframe = (frame8 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) { for (nframe = (frame8 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) {
D8(printk(" %d", nframe)); D8(printk(" %d", nframe));
framepars[nframe].pars[index] = val; framepars[nframe].pars[index] = val;
} }
frame8 = (frame8 - 1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does frame8 = (frame8 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
D8(printk("\n")); D8(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
// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { // for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here for (nframe = frame8; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame8 is modified here
framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince[bindex] |= bmask;
framepars[nframe].modsince32 |= bmask32; framepars[nframe].modsince32 |= bmask32;
} }
} }
} 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)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
return -ERR_FRAMEPARS_TOOEARLY; return -ERR_FRAMEPARS_TOOEARLY;
...@@ -1020,19 +1018,19 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa ...@@ -1020,19 +1018,19 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
return 0; return 0;
} }
///TODO: make some parameters readonly (prohibited from modification from the userland) //TODO: make some parameters readonly (prohibited from modification from the userland)
/// File operations: // File operations:
/// open, release - nop // open, release - nop
/// read - none // read - none
/// write -> setFrameParsAtomic (first 4 bytes - absolute frame number, next 4 bytes - latency, then each 8 bytes - index/value) // write -> setFrameParsAtomic (first 4 bytes - absolute frame number, next 4 bytes - latency, then each 8 bytes - index/value)
/// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters // can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
/// file pointer - absolute frame number // file pointer - absolute frame number
/// lseek (SEEK_SET, value) - set absolute frame number // lseek (SEEK_SET, value) - set absolute frame number
/// lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber), // lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
/// lseek (SEEK_CUR, 0) - (used by ftell()) also modifies file pointer - set it to thisFrameNumber, // lseek (SEEK_CUR, 0) - (used by ftell()) also modifies file pointer - set it to thisFrameNumber,
/// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer // lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
/// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to) // lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
/// mmap (should be used read only) // mmap (should be used read only)
static struct file_operations framepars_fops = { static struct file_operations framepars_fops = {
owner: THIS_MODULE, owner: THIS_MODULE,
...@@ -1122,24 +1120,24 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig) ...@@ -1122,24 +1120,24 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
file->f_pos = offset; file->f_pos = offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
if (offset == 0) return getThisFrameNumber(sensor_port); /// do not modify frame number if (offset == 0) return getThisFrameNumber(sensor_port); // do not modify frame number
file->f_pos = getThisFrameNumber(sensor_port) + offset; /// modifies frame number, but it is better to use absolute SEEK SET file->f_pos = getThisFrameNumber(sensor_port) + offset; // modifies frame number, but it is better to use absolute SEEK SET
break; break;
case SEEK_END: case SEEK_END:
if (offset <= 0) { if (offset <= 0) {
break; break;
} else if (offset >= LSEEK_FRAME_WAIT_REL) { } else if (offset >= LSEEK_FRAME_WAIT_REL) {
if (offset >= LSEEK_FRAME_WAIT_ABS) target_frame = offset - LSEEK_FRAME_WAIT_ABS; /// Wait for absolute frame number if (offset >= LSEEK_FRAME_WAIT_ABS) target_frame = offset - LSEEK_FRAME_WAIT_ABS; // Wait for absolute frame number
else target_frame = getThisFrameNumber(sensor_port) + offset - LSEEK_FRAME_WAIT_REL; else target_frame = getThisFrameNumber(sensor_port) + offset - LSEEK_FRAME_WAIT_REL;
/// Skip 0..255 frames // Skip 0..255 frames
// wait_event_interruptible (framepars_wait_queue, getThisFrameNumber()>=target_frame); // wait_event_interruptible (framepars_wait_queue, getThisFrameNumber()>=target_frame);
wait_event_interruptible(aframepars_wait_queue[sensor_port], getThisFrameNumber(sensor_port) >= target_frame); wait_event_interruptible(aframepars_wait_queue[sensor_port], getThisFrameNumber(sensor_port) >= target_frame);
// if (getThisFrameNumber()<target_frame) wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame); // if (getThisFrameNumber()<target_frame) wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame);
return getThisFrameNumber(sensor_port); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber() return getThisFrameNumber(sensor_port); // Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
} else { //! Other lseek commands } else { //! Other lseek commands
switch (offset & ~0x1f) { switch (offset & ~0x1f) {
case LSEEK_DAEMON_FRAME: /// wait the daemon enabled and a new frame interrupt (sensor frame sync) case LSEEK_DAEMON_FRAME: // wait the daemon enabled and a new frame interrupt (sensor frame sync)
wait_event_interruptible(aframepars_wait_queue[sensor_port], get_imageParamsThis(sensor_port, P_DAEMON_EN) & (1 << (offset & 0x1f))); wait_event_interruptible(aframepars_wait_queue[sensor_port], get_imageParamsThis(sensor_port, P_DAEMON_EN) & (1 << (offset & 0x1f)));
break; break;
default: default:
...@@ -1148,44 +1146,44 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig) ...@@ -1148,44 +1146,44 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
//X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) ); //X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) );
MDF2(printk("X313_GET_FPGA_TIME\n")); MDF2(printk("X313_GET_FPGA_TIME\n"));
break; break;
case LSEEK_SET_FPGA_TIME: /// better to use write, not lseek to set FPGA time case LSEEK_SET_FPGA_TIME: // better to use write, not lseek to set FPGA time
//X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) ); //X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
MDF2(printk("X313_SET_FPGA_TIME\n")); MDF2(printk("X313_SET_FPGA_TIME\n"));
break; break;
case LSEEK_FRAMEPARS_INIT: /// reset hardware sequencers, init framepars structure case LSEEK_FRAMEPARS_INIT: // reset hardware sequencers, init framepars structure
MDF2(printk("LSEEK_FRAMEPARS_INIT\n")); MDF2(printk("LSEEK_FRAMEPARS_INIT\n"));
initGlobalPars(sensor_port); /// reset all global parameters but the first 32 initGlobalPars(sensor_port); // reset all global parameters but the first 32
initSequencers(sensor_port); initSequencers(sensor_port);
break; break;
case LSEEK_FRAME_RESET: /// reset absolute frame number to avoid integer frame number overflow case LSEEK_FRAME_RESET: // reset absolute frame number to avoid integer frame number overflow
MDF2(printk("LSEEK_FRAME_RESET\n")); MDF2(printk("LSEEK_FRAME_RESET\n"));
resetFrameNumber(sensor_port); resetFrameNumber(sensor_port);
break; break;
case LSEEK_SENSORPROC: /// process modified parameters in frame 0 (to start sensor detection) case LSEEK_SENSORPROC: // process modified parameters in frame 0 (to start sensor detection)
MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n", framepars[0].functions)); MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n", framepars[0].functions));
processPars(sensor_port, sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8) processPars(sensor_port, sensorproc, 0, 8); //frame0, all 8 frames (maxAhead==8)
break; break;
case LSEEK_DMA_INIT: /// initialize ETRAX DMA (normally done in sensor_common.c at driver init case LSEEK_DMA_INIT: // initialize ETRAX DMA (normally done in sensor_common.c at driver init
MDF2(printk("LSEEK_DMA_INIT\n")); MDF2(printk("LSEEK_DMA_INIT\n"));
//x313_dma_init(); //x313_dma_init();
break; break;
case LSEEK_DMA_STOP: /// stop DMA case LSEEK_DMA_STOP: // stop DMA
MDF2(printk("LSEEK_DMA_STOP\n")); MDF2(printk("LSEEK_DMA_STOP\n"));
//x313_dma_stop(); /// //x313_dma_stop(); //
break; break;
case LSEEK_DMA_START: /// start DMA case LSEEK_DMA_START: // start DMA
MDF2(printk("LSEEK_DMA_START\n")); MDF2(printk("LSEEK_DMA_START\n"));
//x313_dma_start(); /// //x313_dma_start(); //
break; break;
case LSEEK_COMPRESSOR_RESET: /// reset compressor and buffer pointers case LSEEK_COMPRESSOR_RESET: // reset compressor and buffer pointers
MDF2(printk("LSEEK_COMPRESSOR_RESET\n")); MDF2(printk("LSEEK_COMPRESSOR_RESET\n"));
//reset_compressor(); //reset_compressor();
break; break;
case LSEEK_INTERRUPT_OFF: /// disable camera interrupts case LSEEK_INTERRUPT_OFF: // disable camera interrupts
MDF2(printk("LSEEK_INTERRUPT_OFF\n")); MDF2(printk("LSEEK_INTERRUPT_OFF\n"));
camera_interrupts(0); camera_interrupts(0);
break; break;
case LSEEK_INTERRUPT_ON: /// enable camera interrupts case LSEEK_INTERRUPT_ON: // enable camera interrupts
MDF2(printk("LSEEK_INTERRUPT_ON\n")); MDF2(printk("LSEEK_INTERRUPT_ON\n"));
camera_interrupts(1); camera_interrupts(1);
break; break;
...@@ -1211,25 +1209,25 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig) ...@@ -1211,25 +1209,25 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
*/ */
ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off) ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off)
{ {
struct frameparspair_t pars_static[256]; /// will be sufficient for most calls struct frameparspair_t pars_static[256]; // will be sufficient for most calls
struct frameparspair_t * pars = pars_static; struct frameparspair_t * pars = pars_static;
struct framepars_pd * privData = (struct framepars_pd*)file->private_data; struct framepars_pd * privData = (struct framepars_pd*)file->private_data;
int sensor_port = privData -> minor - CMOSCAM_MINOR_FRAMEPARS_CHN_0; int sensor_port = privData -> minor - CMOSCAM_MINOR_FRAMEPARS_CHN_0;
// struct framepars_t *framepars = aframepars[sensor_port]; // struct framepars_t *framepars = aframepars[sensor_port];
unsigned long frame = *off; /// ************* NOTE: Never use file->f_pos in write() and read() !!! unsigned long frame = *off; // ************* NOTE: Never use file->f_pos in write() and read() !!!
int latency = -1; int latency = -1;
int first = 0; int first = 0;
int last; int last;
int result; int result;
MDF1(printk(": file->f_pos=0x%x, *off=0x%x, count=0x%x\n", (int)file->f_pos, (int)*off, (int)count)); MDF1(printk(": file->f_pos=0x%x, *off=0x%x, count=0x%x\n", (int)file->f_pos, (int)*off, (int)count));
count &= ~7; /// sizeof (struct frameparspair_t)==8 count &= ~7; // sizeof (struct frameparspair_t)==8
switch (privData->minor) { switch (privData->minor) {
case CMOSCAM_MINOR_FRAMEPARS: case CMOSCAM_MINOR_FRAMEPARS:
if (count > sizeof(pars_static)) /// only allocate if static is not enough if (count > sizeof(pars_static)) // only allocate if static is not enough
pars = (struct frameparspair_t*)kmalloc(count, GFP_KERNEL); pars = (struct frameparspair_t*)kmalloc(count, GFP_KERNEL);
if (!pars) return -ENOMEM; if (!pars) return -ENOMEM;
count >>= 3; /// divide by sizeof(struct frameparspair_t); // 8 count >>= 3; // divide by sizeof(struct frameparspair_t); // 8
if (count) { if (count) {
if (copy_from_user((char*)pars, buf, count << 3)) { if (copy_from_user((char*)pars, buf, count << 3)) {
if (count > sizeof(pars_static)) kfree(pars); if (count > sizeof(pars_static)) kfree(pars);
...@@ -1247,10 +1245,10 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff ...@@ -1247,10 +1245,10 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
case FRAMEPARS_SETLATENCY: case FRAMEPARS_SETLATENCY:
latency = (pars[first].val & 0x80000000) ? -1 : pars[first].val; latency = (pars[first].val & 0x80000000) ? -1 : pars[first].val;
break; break;
case FRAMEPARS_SETFPGATIME: ///ignore value (should be already set in G_SECONDS, G_MICROSECONDS frame0) case FRAMEPARS_SETFPGATIME: //ignore value (should be already set in G_SECONDS, G_MICROSECONDS frame0)
//X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) ); //X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
break; break;
case FRAMEPARS_GETFPGATIME: ///ignore value, set frame 0 G_SECONDS, G_MICROSECONDS to FPGA registers case FRAMEPARS_GETFPGATIME: //ignore value, set frame 0 G_SECONDS, G_MICROSECONDS to FPGA registers
//X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) ); //X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
break; break;
default: default:
...@@ -1270,7 +1268,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff ...@@ -1270,7 +1268,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
} }
} }
if (count > sizeof(pars_static)) kfree(pars); if (count > sizeof(pars_static)) kfree(pars);
return count << 3; /// *sizeof(struct frameparspair_t); return count << 3; // *sizeof(struct frameparspair_t);
default: return -EINVAL; default: return -EINVAL;
} }
} }
...@@ -1318,8 +1316,8 @@ int framepars_init(struct platform_device *pdev) ...@@ -1318,8 +1316,8 @@ int framepars_init(struct platform_device *pdev)
for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) { for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
init_framepars_ptr(sensor_port); init_framepars_ptr(sensor_port);
initGlobalPars(sensor_port); /// sets default debug if enabled - not anymore. Add here? initGlobalPars(sensor_port); // sets default debug if enabled - not anymore. Add here?
initMultiPars(sensor_port); /// just clear - needs to be called again when sensor is recognized initMultiPars(sensor_port); // just clear - needs to be called again when sensor is recognized
} }
frameParsInitialized = 0; frameParsInitialized = 0;
res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops); res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops);
......
/** @file sensor_common.c /** @file sensor_common.h
* *
*/ */
......
...@@ -2,21 +2,18 @@ ...@@ -2,21 +2,18 @@
* @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>
* 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/>.
*******************************************************************************/ *******************************************************************************/
/****************** INCLUDE FILES SECTION ***********************************/
//#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>
...@@ -26,20 +23,15 @@ ...@@ -26,20 +23,15 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
//#include <linux/poll.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
//#include <linux/spinlock_types.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <asm/io.h> #include <asm/io.h>
//#include <asm/system.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <elphel/driver_numbers.h> #include <elphel/driver_numbers.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "x393.h" #include "x393.h"
#include "sensor_i2c.h" #include "sensor_i2c.h"
...@@ -67,27 +59,25 @@ struct x393_i2c_device_list { ...@@ -67,27 +59,25 @@ struct x393_i2c_device_list {
}; };
const char of_prop_name[] = "elphel393-sensor-i2c,i2c_devices"; const char of_prop_name[] = "elphel393-sensor-i2c,i2c_devices";
const char group_name[] = "i2c_classes"; const char group_name[] = "i2c_classes";
const int max_buf_len = 4096-256; // stop output when only 256 bytes are left in the caller's buffer const int max_buf_len = 4096-256; ///< stop output when only 256 bytes are left in the caller's buffer
const int max_i2c_classes = 256; const int max_i2c_classes = 256;
const int mclk_mhz = 200; // mclk frequency in MHz const int mclk_mhz = 200; ///< mclk frequency in MHz
//const int tenth_sec = max(2, HZ/10); // make it not less than 2 jiffies for some very slow clock //const int tenth_sec = max(2, HZ/10); // make it not less than 2 jiffies for some very slow clock
//const int tenth_sec = (HZ >=20) ? (HZ/10) : 2; // make it not less than 2 jiffies for some very slow clock //const int tenth_sec = (HZ >=20) ? (HZ/10) : 2; // make it not less than 2 jiffies for some very slow clock
const int tenth_sec = 2; const int tenth_sec = 2;
static LIST_HEAD(i2c_class_list); static LIST_HEAD(i2c_class_list);
// 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_groups[4];
static u32 free_i2c_pages [32]; static u32 free_i2c_pages [32];
static DEFINE_SPINLOCK(lock); static DEFINE_SPINLOCK(lock);
static u32 i2c_pages_shadow[1024]; // 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 /** Mark all i2c pages for each channel as free */
void i2c_page_alloc_init(void)
/* Mark all i2c pages for each channel as free */ {
void i2c_page_alloc_init(void){
int i; int i;
for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000; for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000;
for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff; for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff;
...@@ -95,8 +85,11 @@ void i2c_page_alloc_init(void){ ...@@ -95,8 +85,11 @@ void i2c_page_alloc_init(void){
for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1; for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1;
} }
/* Reserve i2c page (1 of 256 for a sensor port)*/ /** Reserve i2c page (1 of 256) for a sensor port
int i2c_page_alloc(int chn){ * @param chn sensor port number (0..3)
*/
int i2c_page_alloc(int chn)
{
int g, b; int g, b;
u32 * fb; u32 * fb;
spin_lock(&lock); spin_lock(&lock);
...@@ -116,8 +109,12 @@ int i2c_page_alloc(int chn){ ...@@ -116,8 +109,12 @@ int i2c_page_alloc(int chn){
} }
EXPORT_SYMBOL_GPL(i2c_page_alloc); EXPORT_SYMBOL_GPL(i2c_page_alloc);
/* Free i2c page */ /** Free i2c page
void i2c_page_free(int chn, int page){ * @param chn sensor port number (0..3)
* @param page i2c configuration page to release
*/
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);
...@@ -128,8 +125,11 @@ void i2c_page_free(int chn, int page){ ...@@ -128,8 +125,11 @@ void i2c_page_free(int chn, int page){
} }
EXPORT_SYMBOL_GPL(i2c_page_free); EXPORT_SYMBOL_GPL(i2c_page_free);
/* calculate value of SCLK 1/4 period delay from maximal SCL frequency*/ /** Calculate value of SCLK 1/4 period delay from maximal SCL frequency
int get_bit_delay(int khz){ * @param khz - maximal I2C clock frequency in KHz
* @return bit delay for 1/4 SCL period in mclk (now 200MHz) cycles*/
int get_bit_delay(int khz)
{
int dly; int dly;
if (!khz) if (!khz)
return 0; return 0;
...@@ -139,10 +139,11 @@ int get_bit_delay(int khz){ ...@@ -139,10 +139,11 @@ int get_bit_delay(int khz){
return dly; return dly;
} }
/* Set i2c table entry to raw data (will just overwrite tbl_mode = 2)*/ /** Set i2c table entry to raw data (will just overwrite tbl_mode = 2)*/
void set_xi2c_raw(int chn, void set_xi2c_raw(int chn, ///< Sensor port number
int page, // index in lookup table int page, ///< index in lookup table
u32 data) { // Bit delay - number of mclk periods in 1/4 of the SCL period u32 data) ///< Raw table data (bits 27:0), bits 29:28 will be set to 2
{
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;
...@@ -157,15 +158,15 @@ void set_xi2c_raw(int chn, ...@@ -157,15 +158,15 @@ void set_xi2c_raw(int chn,
} }
EXPORT_SYMBOL_GPL(set_xi2c_raw); EXPORT_SYMBOL_GPL(set_xi2c_raw);
/* /** Set i2c table entry for write operation using known devices.
* Set i2c table entry for write 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
*/ */
void set_xi2c_wrc( x393_i2c_device_t * dc, // device class void set_xi2c_wrc( 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
int rah){ // High byte of the i2c register address int rah) ///< High byte of the i2c register address
{
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;
...@@ -186,14 +187,14 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, // device class ...@@ -186,14 +187,14 @@ void set_xi2c_wrc( x393_i2c_device_t * dc, // device class
} }
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
*/ */
void set_xi2c_rdc(x393_i2c_device_t * dc, // device class 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
{
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;
...@@ -215,13 +216,14 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, // device class ...@@ -215,13 +216,14 @@ void set_xi2c_rdc(x393_i2c_device_t * dc, // device class
EXPORT_SYMBOL_GPL(set_xi2c_rdc); EXPORT_SYMBOL_GPL(set_xi2c_rdc);
/* Set i2c table entry for write operation */ /** Set i2c table entry for write operation */
void set_xi2c_wr(int chn, void set_xi2c_wr(int chn, ///< sensor port
int page, // index in lookup table int page, ///< index in lookup table
int sa7, // slave address (7 bit) int sa7, ///< slave address (7 bit)
int rah, // High byte of the i2c register address int rah, ///< High byte of the i2c register address
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
{
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;
...@@ -243,12 +245,13 @@ void set_xi2c_wr(int chn, ...@@ -243,12 +245,13 @@ void set_xi2c_wr(int chn,
EXPORT_SYMBOL_GPL(set_xi2c_wr); EXPORT_SYMBOL_GPL(set_xi2c_wr);
/* Set i2c table entry for read operation */ /** Set i2c table entry for read operation */
void set_xi2c_rd(int chn, void set_xi2c_rd(int chn, ///< sensor port
int page, // index in lookup table int page, ///< index in lookup table
int two_byte_addr, // Number of address bytes (0 - one byte, 1 - two bytes) int two_byte_addr, ///< Number of address bytes (0 - one byte, 1 - two bytes)
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
{
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;
...@@ -268,29 +271,31 @@ void set_xi2c_rd(int chn, ...@@ -268,29 +271,31 @@ void set_xi2c_rd(int chn,
} }
EXPORT_SYMBOL_GPL(set_xi2c_rd); EXPORT_SYMBOL_GPL(set_xi2c_rd);
/* /** @brief Write i2c command to the i2c command sequencer, block of 16 DWORD slots for absolute frame numbers
// Write i2c command to the i2c command sequencer * (modulo 16) and 15 slots for relative ones: 0 - ASAP, 1 next frame, 14 -14-th next.
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones * This command writes one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command.
// 0 - ASAP, 1 next frame, 14 -14-th next. * Length of data is determined by the page data already preset. Data is written MSB first, first data word starts
// Data written depends on context: * with (in bits 31:24) table index.
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent *
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last). * Data written depends on context:
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are *
// skipped. * 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words * after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be * If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// sent for such extra word, only the lower bytes are sent. * skipped.
// * If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed * bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if * sent for such extra word, only the lower bytes are sent.
// read address in the table is programmed to be a single-byte one *
*/ * 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
* in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
/* Write one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command */ * read address in the table is programmed to be a single-byte one. */
/* Length of data is determined by the page data already preset */ int write_xi2c_rel (int chn, ///< sensor port
int write_xi2c_rel (int chn, int offs, ///< relative frame number modulo 16
int offs, // 4 bits u32 * data) ///< data array. Length written is defined by the pre-configured table entry.
u32 * data){ ///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
{
x393_i2c_ctltbl_t tb_data; x393_i2c_ctltbl_t tb_data;
int len; int len;
int i; int i;
...@@ -310,9 +315,16 @@ int write_xi2c_rel (int chn, ...@@ -310,9 +315,16 @@ int write_xi2c_rel (int chn,
} }
EXPORT_SYMBOL_GPL(write_xi2c_rel); EXPORT_SYMBOL_GPL(write_xi2c_rel);
int write_xi2c_abs (int chn, /** Write one or multiple DWORDs to i2c absolute (modulo16) address.
int offs, // 4 bits * Length of data is determined by the page data already preset. Data is written MSB first, first data word starts
u32 * data){ * with (in bits 31:24) table index.
* @see write_xi2c_rel */
int write_xi2c_abs (int chn, ///< sensor port
int offs, ///< absolute frame number modulo 16
u32 * data) ///< data array. Length written is defined by the pre-configured table entry.
///< MSB (data is sent MSB first) of the first entry is index in the table.
///< @return 0 on success, negative error if table shadow is not initialized to data
{
x393_i2c_ctltbl_t tb_data; x393_i2c_ctltbl_t tb_data;
int len; int len;
int i; int i;
...@@ -332,35 +344,38 @@ int write_xi2c_abs (int chn, ...@@ -332,35 +344,38 @@ int write_xi2c_abs (int chn,
} }
EXPORT_SYMBOL_GPL(write_xi2c_abs); EXPORT_SYMBOL_GPL(write_xi2c_abs);
/* Write sensor 16 bit (or 8 bit as programmed in the table) data in immediate mode */ /** Write sensor 16 bit (or 8 bit as programmed in the table) data in immediate mode */
void write_xi2c_reg16 (int chn, void write_xi2c_reg16 (int chn, ///< sensor port
int page, // page (8 bits) int page, ///< index in the table (8 bits)
int addr, // low 8 bits int addr, ///< low byte of the register address (high is in the table), 8 bits
u32 data){ // 16 or 8-bit data (LSB aligned) u32 data) ///< 16 or 8-bit data (LSB aligned)
{
u32 dw = ((page & 0xff) << 24) | ((addr & 0xff) << 16) | (data & 0xffff); u32 dw = ((page & 0xff) << 24) | ((addr & 0xff) << 16) | (data & 0xffff);
x393_sensi2c_rel (dw, chn, 0); x393_sensi2c_rel (dw, chn, 0);
} }
EXPORT_SYMBOL_GPL(write_xi2c_reg16); EXPORT_SYMBOL_GPL(write_xi2c_reg16);
/* /** Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_xi2c_fifo)
* Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_xi2c_fifo)
* Use slave address from provided class structure. * Use slave address from provided class structure.
*/ */
void read_xi2c (x393_i2c_device_t * dc, // device class void read_xi2c (x393_i2c_device_t * dc, ///< device class
int chn, int chn, ///< sensor port
int page, // page (8 bits) int page, ///< Table index (8 bits)
int addr){ // 8/16 bit address int addr) ///< 8/16 bit register address
{
u32 dw = ((page & 0xff) << 24) | (dc -> slave7 << 17) | (addr & 0xffff); u32 dw = ((page & 0xff) << 24) | (dc -> slave7 << 17) | (addr & 0xffff);
x393_sensi2c_rel (dw, chn, 0); x393_sensi2c_rel (dw, chn, 0);
} }
EXPORT_SYMBOL_GPL(read_xi2c); EXPORT_SYMBOL_GPL(read_xi2c);
/* Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_xi2c_fifo)*/ /** Initiate sensor i2c read in immediate mode, specify 7-bit slave address
void read_xi2c_sa7 (int chn, * (data itself has to be read from FIFO with read_xi2c_fifo) */
int page, // page (8 bits) void read_xi2c_sa7 (int chn, ///< sensor port
int sa7, // 7-bit i2c slave address int page, ///< Table index (8 bits)
int addr){ // 8/16 bit address int sa7, ///< 7-bit i2c slave address
int addr) ///< 8/16 bit register address
{
u32 dw = ((page & 0xff) << 24) | (sa7 << 17) | (addr & 0xffff); u32 dw = ((page & 0xff) << 24) | (sa7 << 17) | (addr & 0xffff);
dev_dbg(sdev, "read_xi2c_sa7(%d,0x%x,0x%x,0x%x): 0x%08x\n",chn,page,sa7,addr,(int) dw); dev_dbg(sdev, "read_xi2c_sa7(%d,0x%x,0x%x,0x%x): 0x%08x\n",chn,page,sa7,addr,(int) dw);
x393_sensi2c_rel (dw, chn, 0); x393_sensi2c_rel (dw, chn, 0);
...@@ -368,9 +383,11 @@ void read_xi2c_sa7 (int chn, ...@@ -368,9 +383,11 @@ void read_xi2c_sa7 (int chn,
EXPORT_SYMBOL_GPL(read_xi2c_sa7); EXPORT_SYMBOL_GPL(read_xi2c_sa7);
/* Read next byte from the channel i2c FIFO. Return byte or -1 if no data available, -EIO - error */ /** 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){ int read_xi2c_fifo(int chn) ///< sensor port
///< @return byte or -1 if no data available, -EIO - error
{
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;
...@@ -405,12 +422,16 @@ int read_xi2c_fifo(int chn){ ...@@ -405,12 +422,16 @@ int read_xi2c_fifo(int chn){
} }
EXPORT_SYMBOL_GPL(read_xi2c_fifo); EXPORT_SYMBOL_GPL(read_xi2c_fifo);
/* Single-command i2c write/read register using pre-defined device classes */ /** Single-command i2c write register using pre-defined device classes.
int x393_xi2c_write_reg(const char * cname, // device class name * This command reserves and configures table entry, releases it in the end */
int chn, // sensor port number int x393_xi2c_write_reg(const char * cname, ///< device class name
int sa7_offs, // slave address (7-bit) offset from the class defined slave address int chn, ///< sensor port number
int reg_addr, // register address (width is defined by class) int sa7_offs, ///< slave address (7-bit) offset from the class defined slave address,
int data){ // data to write (width is defined by class) ///< used when multiple instances of the same class devices are present.
int reg_addr, ///< register address (width is defined by class)
int data) ///< data to write (width is defined by class)
///< @return 0 on success, < 0 - error
{
x393_i2c_device_t * dc; x393_i2c_device_t * dc;
x393_i2c_device_t ds; x393_i2c_device_t ds;
int page; int page;
...@@ -443,12 +464,17 @@ int x393_xi2c_write_reg(const char * cname, // device class name ...@@ -443,12 +464,17 @@ int x393_xi2c_write_reg(const char * cname, // device class name
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(x393_xi2c_write_reg); EXPORT_SYMBOL_GPL(x393_xi2c_write_reg);
int x393_xi2c_read_reg( const char * cname, // device class name
int chn, // sensor port number
int sa7_offs, // slave address (7-bit) offset from the class defined slave address
int reg_addr, // register address (width is defined by class)
int * datap){ // pointer to a data receiver (read data width is defined by class)
/** Single-command i2c read register using pre-defined device classes.
* This command reserves and configures table entry, initiates i2c read, waits and receives data, releases table entry in the end */
int x393_xi2c_read_reg( const char * cname, ///< device class name
int chn, ///< sensor port number
int sa7_offs, ///< slave address (7-bit) offset from the class defined slave address.
///< Offset is non-zero when multiple devices of the same class are present.
int reg_addr, ///< register address (width is defined by class)
int * datap) ///< pointer to a data receiver (read data width is defined by class)
///< @return 0 on success, < 0 - error
{
x393_i2c_device_t * dc; x393_i2c_device_t * dc;
int page, i, db=-1; int page, i, db=-1;
unsigned long timeout_end; unsigned long timeout_end;
...@@ -470,7 +496,6 @@ int x393_xi2c_read_reg( const char * cname, // device class name ...@@ -470,7 +496,6 @@ int x393_xi2c_read_reg( const char * cname, // device class name
dev_dbg(sdev, "got page= 0x%x\n",page); dev_dbg(sdev, "got page= 0x%x\n",page);
/* Set table entry for reading */ /* Set table entry for reading */
// ds.slave7 = dc->slave7 + sa7_offs;
set_xi2c_rdc(dc, // device class set_xi2c_rdc(dc, // device class
chn, // sensor port chn, // sensor port
page); // index in lookup table page); // index in lookup table
...@@ -489,7 +514,6 @@ int x393_xi2c_read_reg( const char * cname, // device class name ...@@ -489,7 +514,6 @@ int x393_xi2c_read_reg( const char * cname, // device class name
*datap = 0; *datap = 0;
dev_dbg(sdev, "Trying to get FIFO data for channel %d\n",chn); dev_dbg(sdev, "Trying to get FIFO data for channel %d\n",chn);
for (i = 0; i< dc->data_bytes; i++) { for (i = 0; i< dc->data_bytes; i++) {
// timeout_end = jiffies + 20*tenth_sec;
timeout_end = jiffies + tenth_sec; timeout_end = jiffies + tenth_sec;
while (jiffies < timeout_end){ while (jiffies < timeout_end){
db = read_xi2c_fifo(chn); db = read_xi2c_fifo(chn);
...@@ -513,7 +537,10 @@ int x393_xi2c_read_reg( const char * cname, // device class name ...@@ -513,7 +537,10 @@ int x393_xi2c_read_reg( const char * cname, // device class name
EXPORT_SYMBOL_GPL(x393_xi2c_read_reg); EXPORT_SYMBOL_GPL(x393_xi2c_read_reg);
/* Handling classes of i2c devices */ /* Handling classes of i2c devices */
struct x393_i2c_device_list * i2c_dev_get(const char * 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
///< @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;
list_for_each(p, &i2c_class_list) { list_for_each(p, &i2c_class_list) {
...@@ -525,7 +552,10 @@ struct x393_i2c_device_list * i2c_dev_get(const char * name){ ...@@ -525,7 +552,10 @@ struct x393_i2c_device_list * i2c_dev_get(const char * name){
} }
return NULL; return NULL;
} }
x393_i2c_device_t * xi2c_dev_get(const char * name){ /** Find device list entry by device class name */
x393_i2c_device_t * xi2c_dev_get(const char * name) ///< Device class name as string
///< @return i2c device or NULL (if not found)
{
struct x393_i2c_device_list * dl = i2c_dev_get(name); struct x393_i2c_device_list * dl = i2c_dev_get(name);
if (dl) if (dl)
return &dl->i2c_dev; return &dl->i2c_dev;
...@@ -534,15 +564,16 @@ x393_i2c_device_t * xi2c_dev_get(const char * name){ ...@@ -534,15 +564,16 @@ x393_i2c_device_t * xi2c_dev_get(const char * name){
} }
EXPORT_SYMBOL_GPL(xi2c_dev_get); EXPORT_SYMBOL_GPL(xi2c_dev_get);
/** Add new i2c device class, OK to provide existing name */
struct x393_i2c_device_list * i2c_dev_add(const char * name){ struct x393_i2c_device_list * i2c_dev_add(const char * name) ///< Device class name (<32 characters)
///< @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 */
/*Allocate new structure */ /*Allocate new structure */
dev_dbg(sdev,"allocating space for %s\n",name); dev_dbg(sdev,"allocating space for %s\n",name);
sp = (struct x393_i2c_device_list *) devm_kzalloc(sdev, sizeof(struct x393_i2c_device_list), GFP_KERNEL); sp = (struct x393_i2c_device_list *) devm_kzalloc(sdev, sizeof(struct x393_i2c_device_list), GFP_KERNEL);
dev_dbg(sdev,"Copying name\n"); dev_dbg(sdev,"Copying name\n");
// INIT_LIST_HEAD(&sp->list);
strncpy(sp->i2c_dev.name, name, sizeof(sp->i2c_dev.name)); strncpy(sp->i2c_dev.name, name, sizeof(sp->i2c_dev.name));
dev_dbg(sdev,"Done\n"); dev_dbg(sdev,"Done\n");
INIT_LIST_HEAD(&sp->list); INIT_LIST_HEAD(&sp->list);
...@@ -552,7 +583,10 @@ struct x393_i2c_device_list * i2c_dev_add(const char * name){ ...@@ -552,7 +583,10 @@ struct x393_i2c_device_list * i2c_dev_add(const char * name){
return sp; return sp;
} }
int i2c_dev_remove(const char * name){ /** Remove i2c device class by name */
int i2c_dev_remove(const char * name) ///< existing device class name
///< @return 0 if OK, -ENOENT if specified device class does not exist
{
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;
/* remove sysfs entry */ /* remove sysfs entry */
...@@ -565,17 +599,31 @@ int i2c_dev_remove(const char * name){ ...@@ -565,17 +599,31 @@ int i2c_dev_remove(const char * name){
/* =========================== sysfs functionality ============================== */ /* =========================== sysfs functionality ============================== */
/* 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){ static int get_channel_from_name(struct device_attribute *attr) ///< Linux kernel interface for exporting device attributes
///< @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);
return reg; return reg;
} }
static ssize_t i2c_member_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ /** Sysfs function - respond to attempt of write to read only i2c device class member record */
static ssize_t i2c_member_store(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{
dev_warn(dev,"i2c_member_store(): not implemented\n"); dev_warn(dev,"i2c_member_store(): not implemented\n");
return count; return count;
} }
static ssize_t i2c_member_show(struct device *dev, struct device_attribute *attr, char *buf){
/** Sysfs function - show i2c device class member record */
static ssize_t i2c_member_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
{
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);
if (!sp) if (!sp)
...@@ -587,7 +635,18 @@ static ssize_t i2c_member_show(struct device *dev, struct device_attribute *attr ...@@ -587,7 +635,18 @@ static ssize_t i2c_member_show(struct device *dev, struct device_attribute *attr
sp->i2c_dev.scl_khz); sp->i2c_dev.scl_khz);
} }
static ssize_t i2c_class_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) /**Sysfs function - add new i2c device class. Buffer data should contain the following data, separated by spaces:
* - name
* - slave addr (7 bit)
* - address width (bytes)
* - data width (bytes)
* - max SCL frequency (kHz)
*/
static ssize_t i2c_class_store(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
struct x393_i2c_device_list * dl; struct x393_i2c_device_list * dl;
char name[32]; char name[32];
...@@ -633,7 +692,11 @@ static ssize_t i2c_class_store(struct device *dev, struct device_attribute *attr ...@@ -633,7 +692,11 @@ static ssize_t i2c_class_store(struct device *dev, struct device_attribute *attr
return count; return count;
} }
static ssize_t i2c_class_show(struct device *dev, struct device_attribute *attr, char *buf) /** Sysfs function - show all i2c device classes */
static ssize_t i2c_class_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
{ {
struct list_head *p; struct list_head *p;
struct x393_i2c_device_list * sp; struct x393_i2c_device_list * sp;
...@@ -656,33 +719,43 @@ static ssize_t i2c_class_show(struct device *dev, struct device_attribute *attr, ...@@ -656,33 +719,43 @@ static ssize_t i2c_class_show(struct device *dev, struct device_attribute *attr,
} }
return buf-cp; return buf-cp;
} }
static ssize_t get_i2c_page_alloc(struct device *dev, struct device_attribute *attr, char *buf)
/** Sysfs function - allocate new page in i2c device table, output page number as a decimal value */
static ssize_t get_i2c_page_alloc(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENOMEM
{ {
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
int page; int page;
// if (sysfs_page[chn]>=0)
// return -EBUSY;
page= i2c_page_alloc(chn); page= i2c_page_alloc(chn);
if (page <0) if (page <0)
return -ENOMEM; return -ENOMEM;
sysfs_page[chn] = page; sysfs_page[chn] = page;
return sprintf(buf,"%d\n",page); return sprintf(buf,"%d\n",page);
} }
static ssize_t free_i2c_page(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
/** Sysfs function - release page in i2c device table, input buffer *buf should contain page number as decimal or hex number*/
static ssize_t free_i2c_page(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
int page; int page;
sscanf(buf, "%i", &page); sscanf(buf, "%i", &page);
page &= 0xff; page &= 0xff;
// if (sysfs_page[chn] >= 0)
// i2c_page_free(chn, page);
// sysfs_page[chn] = -1; // free
i2c_page_free(chn, page); i2c_page_free(chn, page);
return count; return count;
} }
/* Set/get page number for reading */ /** Sysfs function - set page in i2c device table to use for next reading, input buffer *buf should contain page number as decimal or hex number*/
static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t set_i2c_page_inuse(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
int page; int page;
...@@ -690,7 +763,13 @@ static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *a ...@@ -690,7 +763,13 @@ static ssize_t set_i2c_page_inuse(struct device *dev, struct device_attribute *a
sysfs_page[chn] = page & 0xff; sysfs_page[chn] = page & 0xff;
return count; return count;
} }
static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf)
/** Sysfs function - get page number in i2c device table that was set to use for next reading.
* Output buffer *buf provides page number as a decimal */
static ssize_t get_i2c_page_inuse(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
{ {
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]);
...@@ -698,8 +777,11 @@ static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *a ...@@ -698,8 +777,11 @@ static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *a
// Get i2c table data as raw data (hex) /** Sysfs function - get i2c table entry as raw value (as hex number), page number is the same as used for reading, @see set_i2c_page_inuse */
static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_tbl_raw(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
{ {
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
...@@ -709,7 +791,13 @@ static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr ...@@ -709,7 +791,13 @@ static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr
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)]);
} }
static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) /** Sysfs function - set i2c table entry as raw value. Buffer string *buf should contain space-separated
* page number and table data as decimal or hex (starting with 0x) numbers */
static ssize_t set_i2c_tbl_raw(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
int ni, page, data; int ni, page, data;
...@@ -724,8 +812,11 @@ static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr ...@@ -724,8 +812,11 @@ static ssize_t set_i2c_tbl_raw(struct device *dev, struct device_attribute *attr
return count; return count;
} }
// Get/parse i2c table (hex) /** Sysfs function - read and interpret i2c table entry, page number is the same as used for reading, @see set_i2c_page_inuse */
static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_tbl_human(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer, or -ENXIO
{ {
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) ;
...@@ -742,7 +833,20 @@ static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *at ...@@ -742,7 +833,20 @@ static ssize_t get_i2c_tbl_human(struct device *dev, struct device_attribute *at
} }
} }
static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) /** Sysfs function - set i2c table entry for i2c write commands. Buffer string *buf should contain the following
* space-separated items as decimal or hex (0x) values:
* - page,
* - slave address (7 bit),
*
* Optional parameters (device class data will be used if not specified):
* - high reg address byte,
* - bytes to write (1..10),
* - 1/4 scl period in mclk (5 ns for current 200 MHz) */
static ssize_t set_i2c_tbl_wr_human(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
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;
...@@ -791,7 +895,19 @@ static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute ...@@ -791,7 +895,19 @@ static ssize_t set_i2c_tbl_wr_human(struct device *dev, struct device_attribute
return count; return count;
} }
static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) /** Sysfs function - set i2c table entry for i2c read commands. Buffer string *buf should contain the following
* space-separated items as decimal or hex (0x) values:
* - page,
* - two byte addr (0 - 8bit,1 - 16 bit reg. addr),
*
* Optional parameters (device class data will be used if not specified):
* - number of bytes to read (1..8),
* - 1/4 scl period in mclk (5 ns for current 200 MHz) */
static ssize_t set_i2c_tbl_rd_human(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
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;
...@@ -834,7 +950,19 @@ static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute ...@@ -834,7 +950,19 @@ static ssize_t set_i2c_tbl_rd_human(struct device *dev, struct device_attribute
return count; return count;
} }
static ssize_t i2c_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) /** Sysfs function - i2c read/write register (read requires subsequent reading from the same node).
* Buffer should contain the following space-separated items as decimal or hex (0x) values:
* - device class name,
* - slave offset, non-zero when multiple instances of the class are present on the bus or the address is different from the base one
* - device register address,
*
* Additional parameter
* - data to write identifies write operation, if it is missing i2c read will be issued */
static ssize_t i2c_store(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
const char *buf, ///< 4K buffer with what was written
size_t count) ///< offset to the end of buffer data
///< @return new offset to the end of buffer data
{ {
int chn = get_channel_from_name(attr) ; int chn = get_channel_from_name(attr) ;
char cname[32]; char cname[32];
...@@ -870,18 +998,28 @@ static ssize_t i2c_store(struct device *dev, struct device_attribute *attr, cons ...@@ -870,18 +998,28 @@ static ssize_t i2c_store(struct device *dev, struct device_attribute *attr, cons
return count; return count;
} }
static ssize_t i2c_show(struct device *dev, struct device_attribute *attr, char *buf) // Get i2c read data from fifo
/** Sysfs function - i2c read previously acquired i2c data from i2c read fifo, output buffer *buf
* will contain decimal representation of the value.
* This command should be preceded by the i2c command, @see i2c_store how to start an i2c read command. */
static ssize_t i2c_show(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
{ {
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);
return sprintf(buf,"%d\n",i2c_read_data[chn]); return sprintf(buf,"%d\n",i2c_read_data[chn]);
} }
/** Sysfs function - output instructions text of how to communicate with i2c devices attached to the sensor ports.
// Get i2c read data from fifo * Output buffer *buf will contain multi-line instructions text */
static ssize_t get_i2c_help(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t get_i2c_help(struct device *dev, ///< Linux kernel basic device structure
struct device_attribute *attr, ///< Linux kernel interface for exporting device attributes
char *buf) ///< 4K buffer to receive response
///< @return offset to the end of the output data in the *buf buffer
{ {
return sprintf(buf,"Numeric suffix in 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"
"i2c_classes - directory with register i2c classes, when read provide sa7, address bytes, data bytes, SCL kHz\n" "i2c_classes - directory with register i2c classes, when read provide sa7, address bytes, data bytes, SCL kHz\n"
"alloc*: read - allocate and return page, write <page> (any data) - free page\n" "alloc*: read - allocate and return page, write <page> (any data) - free page\n"
...@@ -923,16 +1061,13 @@ static DEVICE_ATTR(tbl_rd0 , SYSFS_PERMISSIONS , get_i2 ...@@ -923,16 +1061,13 @@ static DEVICE_ATTR(tbl_rd0 , SYSFS_PERMISSIONS , get_i2
static DEVICE_ATTR(tbl_rd1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd1 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(tbl_rd2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd2 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
static DEVICE_ATTR(tbl_rd3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human); static DEVICE_ATTR(tbl_rd3 , SYSFS_PERMISSIONS , get_i2c_tbl_human, set_i2c_tbl_rd_human);
//static DEVICE_ATTR(i2c_rd0 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
//static DEVICE_ATTR(i2c_rd1 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
//static DEVICE_ATTR(i2c_rd2 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
//static DEVICE_ATTR(i2c_rd3 , SYSFS_PERMISSIONS , get_i2c_read, set_i2c_read);
static DEVICE_ATTR(i2c0 , SYSFS_PERMISSIONS , i2c_show, i2c_store); static DEVICE_ATTR(i2c0 , SYSFS_PERMISSIONS , i2c_show, i2c_store);
static DEVICE_ATTR(i2c1 , SYSFS_PERMISSIONS , i2c_show, i2c_store); static DEVICE_ATTR(i2c1 , SYSFS_PERMISSIONS , i2c_show, i2c_store);
static DEVICE_ATTR(i2c2 , SYSFS_PERMISSIONS , i2c_show, i2c_store); static DEVICE_ATTR(i2c2 , SYSFS_PERMISSIONS , i2c_show, i2c_store);
static DEVICE_ATTR(i2c3 , SYSFS_PERMISSIONS , i2c_show, i2c_store); static DEVICE_ATTR(i2c3 , SYSFS_PERMISSIONS , i2c_show, i2c_store);
static DEVICE_ATTR(help, SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_help, NULL); static DEVICE_ATTR(help, SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_help, NULL);
/** Contains entries for the root node (directory) of the sysfs representation for sensor-port i2c devices */
static struct attribute *root_dev_attrs[] = { static struct attribute *root_dev_attrs[] = {
&dev_attr_i2c_all.attr, &dev_attr_i2c_all.attr,
&dev_attr_alloc0.attr, &dev_attr_alloc0.attr,
...@@ -955,10 +1090,6 @@ static struct attribute *root_dev_attrs[] = { ...@@ -955,10 +1090,6 @@ static struct attribute *root_dev_attrs[] = {
&dev_attr_tbl_rd1.attr, &dev_attr_tbl_rd1.attr,
&dev_attr_tbl_rd2.attr, &dev_attr_tbl_rd2.attr,
&dev_attr_tbl_rd3.attr, &dev_attr_tbl_rd3.attr,
// &dev_attr_i2c_rd0.attr,
// &dev_attr_i2c_rd1.attr,
// &dev_attr_i2c_rd2.attr,
// &dev_attr_i2c_rd3.attr,
&dev_attr_i2c0.attr, &dev_attr_i2c0.attr,
&dev_attr_i2c1.attr, &dev_attr_i2c1.attr,
&dev_attr_i2c2.attr, &dev_attr_i2c2.attr,
...@@ -967,38 +1098,35 @@ static struct attribute *root_dev_attrs[] = { ...@@ -967,38 +1098,35 @@ static struct attribute *root_dev_attrs[] = {
NULL NULL
}; };
/** Attribute group for the root node (directory) of the sysfs representation for sensor-port i2c devices*/
static const struct attribute_group dev_attr_root_group = { static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs, .attrs = root_dev_attrs, ///< Array of the items in the root directory
.name = NULL, .name = NULL, ///< No name for the root node
}; };
static int make_group (struct device *dev, const char * name/*,
ssize_t (*show)(struct device *dev, struct device_attribute *attr, /** Add a named group (subdirectory) with the specified name*/
char *buf), static int make_group (struct device *dev, ///< Linux kernel basic device structure
ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char * name) ///< Group name
const char *buf, size_t count)*/) ///< @return 0 on success, or negative error.
{ {
int retval=-1; int retval=-1;
// int index;
struct attribute *pattrs[max_i2c_classes]; /* array of pointers to attibutes */ struct attribute *pattrs[max_i2c_classes]; /* array of pointers to attibutes */
// struct device_attribute *dev_attrs;
struct attribute_group *attr_group; struct attribute_group *attr_group;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL); attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM; if (!attr_group) return -ENOMEM;
// memset(attr_group, 0, sizeof(*attr_group));
pattrs[0] = NULL; pattrs[0] = NULL;
attr_group->name = name; attr_group->name = name;
attr_group->attrs =pattrs; attr_group->attrs =pattrs;
// dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj)); dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) { if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group); retval = sysfs_create_group(&dev->kobj, attr_group);
} }
return retval; return retval;
} }
static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) /** Register this driver to implement sysfs interface */
static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
{ {
int retval=0; int retval=0;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -1011,14 +1139,15 @@ static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) ...@@ -1011,14 +1139,15 @@ static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev)
} }
return retval; return retval;
} }
// =======================================
static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) /** Initialize this driver from the Device Tree.
* Configures some i2c device classes specified in the DT. */
static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
{ {
// const __be32 * config_data;
const char * config_string; const char * config_string;
struct x393_i2c_device_list * dl; struct x393_i2c_device_list * dl;
char name[32]; char name[32];
// int len,chn,pre_disabled,old_dis_por,rc,chn_bits
int rslt; int rslt;
int num_devs, nd, ni, sa7, num_addr, num_data, khz; int num_devs, nd, ni, sa7, num_addr, num_data, khz;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
...@@ -1072,8 +1201,9 @@ static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ...@@ -1072,8 +1201,9 @@ static void elphel393_sensor_i2c_init_of(struct platform_device *pdev)
pr_info("elphel393_sensor_i2c: registered %d i2c device classes\n", num_devs); pr_info("elphel393_sensor_i2c: registered %d i2c device classes\n", num_devs);
} }
/** Probe this driver, register it with sysfs and initialize from the Device Tree */
static int elphel393_sensor_i2c_probe(struct platform_device *pdev) static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
{ {
sdev =&pdev->dev; sdev =&pdev->dev;
dev_dbg(&pdev->dev,"Probing elphel393-sensor-i2c\n"); dev_dbg(&pdev->dev,"Probing elphel393-sensor-i2c\n");
...@@ -1089,27 +1219,30 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev) ...@@ -1089,27 +1219,30 @@ static int elphel393_sensor_i2c_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int elphel393_sensor_i2c_remove(struct platform_device *pdev) /** Remove device driver - does nothing, just pretends.*/
static int elphel393_sensor_i2c_remove(struct platform_device *pdev) ///< Platform device structure for this driver
///< @return 0 on success, or negative error.
{ {
dev_info(&pdev->dev,"Removing elphel393-sensor-i2c"); dev_info(&pdev->dev,"Removing elphel393-sensor-i2c");
return 0; return 0;
} }
/** Compatible records in Device Tree fro this driver */
static struct of_device_id elphel393_sensor_i2c_of_match[] = { static struct of_device_id elphel393_sensor_i2c_of_match[] = {
{ .compatible = "elphel,elphel393-sensor-i2c-1.00", }, { .compatible = "elphel,elphel393-sensor-i2c-1.00", }, ///< Compatibility data
{ /* end of table */} { /* end of table */}
}; };
MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match);
/** Platform driver description of this driver */
static struct platform_driver elphel393_sensor_i2c = { static struct platform_driver elphel393_sensor_i2c = {
.probe = elphel393_sensor_i2c_probe, .probe = elphel393_sensor_i2c_probe, ///< Function executed on probe operation
.remove = elphel393_sensor_i2c_remove, .remove = elphel393_sensor_i2c_remove, ///< Function executed on remove operation
.driver = { .driver = { ///< Driver specifications
.name = "elphel393-sensor-i2c", .name = "elphel393-sensor-i2c", ///< driver name
.owner = THIS_MODULE, .owner = THIS_MODULE, ///< Driver owner
.of_match_table = elphel393_sensor_i2c_of_match, .of_match_table = elphel393_sensor_i2c_of_match, ///< Device tree match data
.pm = NULL, /* power management */ .pm = NULL, ///< No power management supported in this driver
}, },
}; };
......
...@@ -15,16 +15,18 @@ ...@@ -15,16 +15,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/ *******************************************************************************/
// I2C device description to be used with i2c sequencer /** I2C device description to be used with i2c sequencer*/
typedef struct{ typedef struct{
char name[32]; char name[32]; ///< Device class name (up to 31 characters)
u8 slave7; // slave address (7-bit) u8 slave7; ///< Device class base slave address (7-bit). Instances may have it
u8 address_bytes; ///< with offset added.
u8 data_bytes; u8 address_bytes; ///< Number of address bytes (1/2, used for read operations)
int scl_khz; // maximal SCL frequency in KHz (currently limited by 200KHz slowest) u8 data_bytes; ///< Number of data bytes (1..10), for writes it includes register address bytes
int scl_khz; ///< maximal SCL frequency in KHz (currently limited by 200KHz slowest)
} x393_i2c_device_t; } x393_i2c_device_t;
/* Reserve i2c page (1 of 256 for a sensor port)*/ /** Reserve i2c page (1 of 256) for a sensor port
* @param chn sensor port number (0..3) */
int i2c_page_alloc(int chn); int i2c_page_alloc(int chn);
/* Free i2c page */ /* Free i2c page */
...@@ -61,24 +63,6 @@ void set_xi2c_rd(int chn, ...@@ -61,24 +63,6 @@ void set_xi2c_rd(int chn,
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
/*
// Write i2c command to the i2c command sequencer
// I2C command sequencer, block of 16 DWORD slots for absolute frame numbers (modulo 16) and 15 slots for relative ones
// 0 - ASAP, 1 next frame, 14 -14-th next.
// Data written depends on context:
// 1 - I2C register write: index page (MSB), 3 payload bytes. Payload bytes are used according to table and sent
// after the slave address and optional high address byte. Other bytes are sent in descending order (LSB- last).
// If less than 4 bytes are programmed in the table the high bytes (starting with the one from the table) are
// skipped.
// If more than 4 bytes are programmed in the table for the page (high byte), one or two next 32-bit words
// bypass the index table and all 4 bytes are considered payload ones. If less than 4 extra bytes are to be
// sent for such extra word, only the lower bytes are sent.
//
// 2 - I2C register read: index page, slave address (8-bit, with lower bit 0) and one or 2 address bytes (as programmed
// in the table. Slave address is always in byte 2 (bits 23:16), byte1 (high register address) is skipped if
// read address in the table is programmed to be a single-byte one
*/
/* Write one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command */ /* Write one or multiple DWORDs to i2c relative (modulo16) address. Use offs = 0 for immediate (ASAP) command */
/* Length of data is determined by the page data already preset */ /* Length of data is determined by the page data already preset */
int write_xi2c_rel (int chn, int write_xi2c_rel (int chn,
...@@ -94,10 +78,8 @@ void write_xi2c_reg16 (int chn, ...@@ -94,10 +78,8 @@ void write_xi2c_reg16 (int chn,
int addr, // low 8 bits int addr, // low 8 bits
u32 data); // 16 or 8-bit data (LSB aligned) u32 data); // 16 or 8-bit data (LSB aligned)
/* /* Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_xi2c_fifo)
* Initiate sensor i2c read in immediate mode (data itself has to be read from FIFO with read_xi2c_fifo) * Use slave address from provided class structure. */
* Use slave address from provided class structure.
*/
void read_xi2c (x393_i2c_device_t * dc, // device class void read_xi2c (x393_i2c_device_t * dc, // device class
int chn, int chn,
int page, // page (8 bits) int page, // page (8 bits)
...@@ -128,5 +110,3 @@ int x393_xi2c_read_reg( const char * cname, // device class name ...@@ -128,5 +110,3 @@ int x393_xi2c_read_reg( const char * cname, // device class name
int sa7_offs, // slave address (7-bit) offset from the class defined slave address int sa7_offs, // slave address (7-bit) offset from the class defined slave address
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)
This source diff could not be displayed because it is too large. You can view the blob instead.
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