diff --git a/src/drivers/elphel/Makefile b/src/drivers/elphel/Makefile index 32257061ec8d69537d3a4a9eec32515f0ebafb09..586b0486429383343f2f43f5b347d64dce97943d 100644 --- a/src/drivers/elphel/Makefile +++ b/src/drivers/elphel/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ELPHEL393) += elphel393-pwr.o obj-$(CONFIG_ELPHEL393) += elphel393-mem.o obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel393-mem.o obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o - +obj-$(CONFIG_ELPHEL393) += x393.o +obj-$(CONFIG_ELPHEL393) += sensor_i2c.o fpgajtag-y := fpgajtag353.o x393.o obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o \ No newline at end of file diff --git a/src/drivers/elphel/fpgajtag353.c b/src/drivers/elphel/fpgajtag353.c index 94822c7f5089568913f0bd45291a8f94cc793d14..548acd708337c3d9f20dc565805d11c11dd60b22 100644 --- a/src/drivers/elphel/fpgajtag353.c +++ b/src/drivers/elphel/fpgajtag353.c @@ -223,8 +223,8 @@ static struct file_operations fpga_jtag_fops = { //static int sens_num = 0; // internal functions -loff_t fjtag_bitsize (int minor); -loff_t fjtag_bytesize (int minor); +//loff_t fjtag_bitsize (int minor); +//loff_t fjtag_bytesize (int minor); int JTAG_channel(int minor); void initPortC(void); void set_pgm_mode (int chn, int en); @@ -484,7 +484,7 @@ static int fpga_jtag_release(struct inode *inode, struct file *filp) { case FPGA_AJTAG_BOUNDARY_MINOR : // "dirty"? Send to JTAG if (JTAG_channels[chn].wp >0) { - D(printk("fpga_jtag_release(), JTAG_channels[%d].wp = 0x%x",chn,JTAG_channels[chn].wp)); +// D(printk("fpga_jtag_release(), JTAG_channels[%d].wp = 0x%x",chn,JTAG_channels[chn].wp)); JTAG_EXTEST (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsw); // size in bits } JTAG_resetChannel (chn); @@ -544,7 +544,7 @@ static ssize_t fpga_jtag_write(struct file * file, const char * buf, size_t coun if (*off > size) return -EFAULT; if ((*off + count) > size) count= (size - *off); if (*off < JTAG_channels[chn].wp) { - D(printk("fpga_jtag_write(), JTAG_channels[%d].wp = 0x%x",chn, JTAG_channels[chn].wp)); +// D(printk("fpga_jtag_write(), JTAG_channels[%d].wp = 0x%x",chn, JTAG_channels[chn].wp)); JTAG_EXTEST (chn, JTAG_channels[chn].dbuf, JTAG_channels[chn].bitsw); // writing "before" causes EXTEST to fill in boundary scan register JTAG_channels[chn].wdirty=0; } @@ -560,7 +560,7 @@ static ssize_t fpga_jtag_write(struct file * file, const char * buf, size_t coun default: return -EINVAL; } dev_dbg(NULL, "fpga_jtag_write end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size); - D(printk("fpga_jtag_write end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size)); + //D(printk("fpga_jtag_write end: p=%x,chn=%x, buf address=%lx count=%lx *offs=%lx, wp=%lx,size=0x%x\r\n", p, chn, (long) buf, (long) count, (long) *off, (long)JTAG_channels[chn].wp, (int) size)); return count; } @@ -756,11 +756,34 @@ inline x393_status_sens_io_t wait_sensio_status(int chn, u32 seq_num) // reducin return stat; } +inline u32 read_tdo(int sens_num) +{ + x393_status_sens_io_t stat; + x393_status_ctrl_t stat_ctrl; + int i; + stat_ctrl.d32 = 0; + stat = x393_sensio_status(sens_num); + stat_ctrl.seq_num = stat.seq_num + 1; + stat_ctrl.mode = 1; + set_x393_sensio_status_cntrl(stat_ctrl, sens_num); + for (i = 0; i < 10; i++) { + stat = x393_sensio_status(sens_num & 3); // sens_num); + if (likely(stat.seq_num == stat_ctrl.seq_num)) { + return stat.xfpgatdo; + } + } + dev_err(NULL,"read_tdo(%d): failed to get expected seq_num in 10 cycles, expected = 0x%x, got 0x%x\n",sens_num,stat_ctrl.seq_num, stat.seq_num); + return stat.xfpgatdo; +} + + + + // set FPGA in programming/JTAG mode (only for sensor board) // NOP for the main board FPGA configuration void set_pgm_mode (int chn, int en) { u32 seq_num; - x393_sensio_jpag_t data; + x393_sensio_jtag_t data; dev_dbg(NULL, "set_pgm_mode (%d,%d)\n",chn,en); switch (chn >> 2) { @@ -768,16 +791,15 @@ void set_pgm_mode (int chn, int en) { //port_csp0_addr[X313_WA_SENSFPGA] = (en ? (3 << SFPGA_PGMEN_BIT): (SFPGA_RD_SENSPGMPIN | (2 << SFPGA_PGMEN_BIT))) | (2 << SFPGA_TCK_BIT); // turn off TCK (if not turned off already) /* ? SFPGA_RD_SENSPGMPIN */ + data.d32 = 0; data.pgmen = (en) ? 1 : 0; data.pgmen_set = 1; data.tck = 0; data.tck_set = 1; /* check status register */ -// seq_num = prep_sensio_status(sens_num); x393_sensio_jtag(data, chn & 3); // sens_num); /* wait for status register update */ -// wait_sensio_status(sens_num, seq_num); -// x393_sensio_jtag(data, sens_num); + wait_sensio_status(chn & 3, prep_sensio_status(chn & 3)) ; // Not needed here break; } udelay (2); @@ -785,7 +807,7 @@ void set_pgm_mode (int chn, int en) { void set_pgm (int chn, int pgmon) { u32 seq_num; - x393_sensio_jpag_t data; + x393_sensio_jtag_t data; dev_dbg(NULL, "set_pgm (%d,%d)\n",chn,pgmon); switch (chn >> 2) { @@ -800,9 +822,7 @@ void set_pgm (int chn, int pgmon) { //port_csp0_addr[X313_WA_SENSFPGA] = (2 | (pgmon & 1)) << SFPGA_PROG_BIT; data.prog= pgmon & 1; data.prog_set = 1; -// seq_num = prep_sensio_status(sens_num); x393_sensio_jtag(data, chn >> 2); // sens_num); -// wait_sensio_status(sens_num, seq_num); break; case JTAG_AUX_FPGA: break; @@ -812,9 +832,8 @@ void set_pgm (int chn, int pgmon) { int read_done (int chn) { - u32 seq_num; x393_status_sens_io_t stat; - x393_sensio_jpag_t data; + x393_sensio_jtag_t data; switch (chn >> 2) { #ifdef TEST_DISABLE_CODE @@ -825,9 +844,8 @@ int read_done (int chn) { //port_csp0_addr[X313_WA_SENSFPGA] = SFPGA_RD_DONE; //udelay (1); //return (port_csp0_addr[X313__RA__SENSFPGA] >> SFPGA_RD_BIT) & 1 ; - seq_num = prep_sensio_status(chn & 3) ; // sens_num); -// stat = x393_sensio_status(chn & 3) ; // sens_num); - stat = wait_sensio_status(chn & 3, seq_num) ; // sens_num); + + stat = wait_sensio_status(chn & 3, prep_sensio_status(chn & 3)) ; return stat.xfpgadone; case JTAG_AUX_FPGA: return 0; @@ -838,7 +856,7 @@ int read_done (int chn) { // send 1..8 bits through JTAG int jtag_send (int chn, int tms, int len, int d) { int sens_num = chn & 3; - x393_sensio_jpag_t data; + x393_sensio_jtag_t data; x393_status_sens_io_t stat; u32 seq_num; int i; //,m; @@ -882,11 +900,12 @@ int jtag_send (int chn, int tms, int len, int d) { } port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 #endif /* TEST_DISABLE_CODE */ + data.d32 = 0; data.tck_set = 1; data.tms_set = 1; data.tdi_set = 1; - printk("jtag_send(0x%x, 0x%x, 0x%x, 0x%x)\n", chn, tms,len,d); + dev_dbg(NULL, "jtag_send(0x%x, 0x%x, 0x%x, 0x%x)\n", chn, tms,len,d); for ( ; i > 0; i--) { /* TCK = 0 - just a delay; is it really needed? */ data.tck = 0; @@ -897,31 +916,20 @@ int jtag_send (int chn, int tms, int len, int d) { x393_sensio_jtag(data, sens_num); /* repeat writel - just a delay; is it really needed? */ - x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); +// x393_sensio_jtag(data, sens_num); /* read TDO before TCK pulse */ - seq_num = prep_sensio_status(sens_num); - stat = wait_sensio_status(sens_num, seq_num); // get TDO (only where we need to wait status for here) - - // DEBUG: repeating read - seq_num = prep_sensio_status(sens_num); - stat = wait_sensio_status(sens_num, seq_num); // get TDO (only where we need to wait status for here) - - printk(" %08x", stat.d32); - - r = (r << 1) + (stat.xfpgatdo & 1); + r = (r << 1) + read_tdo(sens_num); // may to need to read twice to increase delay? data.tck = 1; x393_sensio_jtag(data, sens_num); // keep other signals, set TCK == 1 - x393_sensio_jtag(data, sens_num); // repeat if delay will be needed to increase length of the TCK signal +// x393_sensio_jtag(data, sens_num); // repeat if delay will be needed to increase length of the TCK signal data.tck = 0; - x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); +// x393_sensio_jtag(data, sens_num); } - printk(" ---> %02x\n", r); + x393_sensio_jtag(data, sens_num); + dev_dbg(NULL, " ---> %02x\n", r); break; case JTAG_AUX_FPGA: @@ -948,9 +956,9 @@ int jtag_write_bits (int chn, int i,j; int r=0; int d,d0; - u32 seq_num; +// u32 seq_num; x393_status_sens_io_t stat; - x393_sensio_jpag_t data; + x393_sensio_jtag_t data; dev_dbg(NULL, "jtag_write_bits(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\r\n", (int) chn, (int) buf, len, check, last); @@ -1030,51 +1038,36 @@ int jtag_write_bits (int chn, port_csp0_addr[X313_WA_SENSFPGA] = (2 << SFPGA_TCK_BIT); // TCK=0 #endif /* TEST_DISABLE_CODE */ // Can be done once + data.d32 = 0; data.tck_set = 1; data.tms_set = 1; data.tdi_set = 1; for (i = 0; len > 0; i++) { d0 = (d = buf[i]); - printk("jtag_write_bits(), i=0x%x ", i); - + dev_dbg(NULL,"jtag_write_bits(), i=0x%x ", i); for (j = 0; j < 8; j++) { - /* TCK = 0 - just a delay; is it really needed? */ - data.tck = 0; if (len > 0) { - if (len == 1 && last) data.tms = 1; - else data.tms = 0; - + data.tms = (len == 1 && last)? 1:0 ; data.tdi = ((d <<= 1) >> 8) & 1; data.tck = 0; x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); // repeat writel() if needed for delay - x393_sensio_jtag(data, sens_num); // repeat writel() if needed for delay - x393_sensio_jtag(data, sens_num); // repeat writel() if needed for delay - - seq_num = prep_sensio_status(sens_num); - stat = wait_sensio_status(sens_num, seq_num); - - seq_num = prep_sensio_status(sens_num); - stat = wait_sensio_status(sens_num, seq_num); - printk(" %d: %08x", j, stat.d32); - - r = (r << 1) + (stat.xfpgatdo & 1); - +// x393_sensio_jtag(data, sens_num); // repeat writel() if needed for delay + r = (r << 1) + read_tdo(sens_num); data.tck = 1; x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); // remove if no delay is needed +// x393_sensio_jtag(data, sens_num); // remove if no delay is needed data.tck = 0; x393_sensio_jtag(data, sens_num); - x393_sensio_jtag(data, sens_num); +// x393_sensio_jtag(data, sens_num); } else { r <<= 1; } len--; } buf[i] = r; - printk(" ===> %02x\n", r); + dev_dbg(NULL," ===> %02x\n", r); if (check && ((r ^ (prev[1]>>24)) & 0xff)) { return -((r & 0xff) | ((i+1) << 8)); //readback mismatch } @@ -1241,6 +1234,7 @@ int JTAG_resetChannel (int chn) { jtag_send(chn, 1, 5, 0 ); // set Test-Logic-Reset state // disable programmimg mode (nop for the 10353 FPGA) set_pgm_mode(chn, 0); // only for sensor FPGA + return 0; } // int JTAG_resetChannel (int chn) int JTAG_readID (int chn, unsigned char * buf) { @@ -1319,7 +1313,7 @@ int i; // only in debug #ifdef JTAG_DISABLE_IRQ unsigned long flags; #endif -D(printk("JTAG_CAPTURE(): buf=%p\n",buf)); +dev_dbg(NULL,"JTAG_CAPTURE(): buf=%p\n",buf); //*************************** NOW DISABLE INTERRUPS FOR THE WHOLE JTAG SEQUENCE *********************** #ifdef JTAG_DISABLE_IRQ local_irq_save(flags); @@ -1374,8 +1368,8 @@ int i; // only in debug local_irq_save(flags); //local_irq_disable(); #endif -D(printk("EXTEST: buf=%p, len=0x%x\n",buf,len)); -D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); ); +//D(printk("EXTEST: buf=%p, len=0x%x\n",buf,len)); +//D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); ); // jtag_send(chn, 1, 5, 0 ); //step 1 - set Test-Logic-Reset state // jtag_send(chn, 0, 1, 0 ); //step 2 - set Run-Test-Idle state @@ -1395,7 +1389,7 @@ D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if #ifdef JTAG_DISABLE_IRQ local_irq_restore(flags); #endif - D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); ); +// D(printk ("\n"); for (i=0; i<((len+7)>>3) ;i++) {printk("%3x ",(int) buf[i]); if ((i & 0xf) == 0xf) printk ("\n");}printk ("\n"); ); return 0; } //int JTAG_EXTEST (int chn, unsigned char * buf, int len) @@ -1430,6 +1424,6 @@ module_exit(fpga_jtag_exit); module_init(fpga_jtag_init); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Andrey Filippov ."); +MODULE_AUTHOR("Andrey Filippov "); MODULE_DESCRIPTION(FPGA_JTAG_DRIVER_NAME); diff --git a/src/drivers/elphel/sensor_i2c.c b/src/drivers/elphel/sensor_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..04c57bc102dc629aef017d5c448a9edb4da645d3 --- /dev/null +++ b/src/drivers/elphel/sensor_i2c.c @@ -0,0 +1,453 @@ +/******************************************************************************* +* FILE NAME : sensor_i2c.c +* DESCRIPTION: Interface to FPGA-based i2c sequencer for sensor ports +* Copyright 2016 (C) Elphel, Inc. +* -----------------------------------------------------------------------------* +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*******************************************************************************/ +/****************** INCLUDE FILES SECTION ***********************************/ + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +#include +//#include + +#include +//#include +#include + +#include +#include + +#include "x393.h" +#include "sensor_i2c.h" + +//------------------ + +#include +#include + +#include +#include +#include +#include +#include + +#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */ +#define SYSFS_READONLY 0444 +#define SYSFS_WRITEONLY 0222 + +#define DRV_NAME "elphel_sensor_i2c" + +//------------------ + + +// Number of channels is hard-wired to 4 +static u32 free_i2c_groups[4]; +static u32 free_i2c_pages [32]; +static DEFINE_SPINLOCK(lock); +static u32 i2c_pages_shadow[1024]; // Mostly for debugging to analyze i2c pages allocation +static int sysfs_page[4]; // when positive - page locked for exclusive access +/* Mark all i2c pages for each channel as free */ +void i2c_page_alloc_init(void){ + int i; + for (i = 0; i < sizeof(free_i2c_groups)/sizeof(free_i2c_groups[0]); i++) free_i2c_groups[i] = 0xff000000; + for (i = 0; i < sizeof(free_i2c_pages)/ sizeof(free_i2c_pages[0]); i++) free_i2c_pages[i] = 0xffffffff; + for (i = 0; i < sizeof(i2c_pages_shadow)/sizeof(i2c_pages_shadow[0]); i++) i2c_pages_shadow[i] = 0; + for (i = 0; i < sizeof(sysfs_page)/sizeof(sysfs_page[0]); i++) sysfs_page[i] = -1; + +} + +/* Reserve i2c page (1 of 256 for a sensor port)*/ +int i2c_page_alloc(int chn){ + int g, b; + u32 * fb; + spin_lock(&lock); + g = __builtin_clz(free_i2c_groups[chn]); + if (unlikely(g > 7)) { + spin_unlock(&lock); + return -ENOMEM; // no free i2c pages left + } + fb = free_i2c_pages + ((chn << 3) + g); + b = __builtin_clz(*fb); + *fb &= ~ (1 << (31-b)); + if (unlikely(*fb == 0)){ + free_i2c_groups[chn] &= ~(1 << (31 - g)); + } + spin_unlock(&lock); + return (g << 5) + b; +} + +/* Free i2c page */ +void i2c_page_free(int chn, int page){ + int g = page >> 5; + int b = page & 0x1f; + u32 * fb = free_i2c_pages + ((chn << 3) + g); + spin_lock(&lock); + free_i2c_groups[chn] |= 1 << (31 - g); + *fb |= 1 << (31-b); + spin_unlock(&lock); +} +/* Set i2c table entry to raw data (will just overwrite tbl_mode = 2)*/ +void set_sensor_i2c_raw(int chn, + int page, // index in lookup table + u32 data) { // Bit delay - number of mclk periods in 1/4 of the SCL period + x393_i2c_ctltbl_t tb_data, tb_addr; + tb_addr.d32 = 0; + tb_addr.tbl_mode = 3; + tb_data.d32 = data; + tb_data.tbl_mode = 2; // + /* Table address and data should not interleave with others */ + spin_lock(&lock); + x393_sensi2c_ctrl (tb_addr, chn); + x393_sensi2c_ctrl (tb_data, chn); + spin_unlock(&lock); + i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; +} + +/* Set i2c table entry for write operation */ +void set_sensor_i2c_wr(int chn, + int page, // index in lookup table + int sa, // slave address (7 bit) + int rah, // High byte of the i2c register address + 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 + x393_i2c_ctltbl_t tb_data, tb_addr; + tb_addr.d32 = 0; + tb_addr.tbl_mode = 3; + tb_data.d32 = 0; + tb_data.rah = rah; + tb_data.rnw = 0; + tb_data.sa = sa; + tb_data.nbwr = num_bytes; + tb_data.dly = bit_delay; + tb_data.tbl_mode = 2; + /* Table address and data should not interleave with others */ + spin_lock(&lock); + x393_sensi2c_ctrl (tb_addr, chn); + x393_sensi2c_ctrl (tb_data, chn); + spin_unlock(&lock); + i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; +} + +/* Set i2c table entry for read operation */ +void set_sensor_i2c_rd(int chn, + int page, // index in lookup table + 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 bit_delay) { // Bit delay - number of mclk periods in 1/4 of the SCL period + x393_i2c_ctltbl_t tb_data, tb_addr; + tb_addr.d32 = 0; + tb_addr.tbl_mode = 3; + tb_data.d32 = 0; + tb_data.rnw = 1; + tb_data.nabrd = two_byte_addr; + tb_data.nbrd = num_bytes; + tb_data.dly = bit_delay; + tb_data.tbl_mode = 2; + /* Table address and data should not interleave with others */ + spin_lock(&lock); + x393_sensi2c_ctrl (tb_addr, chn); + x393_sensi2c_ctrl (tb_data, chn); + spin_unlock(&lock); + i2c_pages_shadow[(chn << 8) + page] =tb_data.d32; +} + +/* +// 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 */ +/* Length of data is determined by the page data already preset */ +int write_sensor_i2c_rel (int chn, + int offs, // 4 bits + u32 * data){ + x393_i2c_ctltbl_t tb_data; + int len; + int i; + tb_data.d32 = i2c_pages_shadow[(chn <<8) + (data[0] >> 24)]; + if (tb_data.tbl_mode !=2) return -1; + len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3 + if (len > 1) { + spin_lock(&lock); + for (i = 0; i > 24)]; + if (tb_data.tbl_mode !=2) return -1; + len = (tb_data.rnw )? 1:((tb_data.nbwr + 5) >> 2); // read mode - always 1 DWORD, write - 1..3 + if (len > 1) { + spin_lock(&lock); + for (i = 0; i attr.name + (strlen(attr->attr.name)-1), "%du", ®); + return reg; +} + +static ssize_t get_i2c_page_alloc(struct device *dev, struct device_attribute *attr, char *buf) +{ + int chn = get_channel_from_name(attr) ; + int page; + if (sysfs_page[chn]>=0) + return -EBUSY; + page= i2c_page_alloc(chn); + if (page <0) + return -ENOMEM; + sysfs_page[chn] = 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) +{ + int chn = get_channel_from_name(attr) ; + int page; + sscanf(buf, "%i", &page); + page &= 0xff; + if (sysfs_page[chn] >= 0) + i2c_page_free(chn, page); + sysfs_page[chn] = -1; // free + return count; +} + +static ssize_t get_i2c_page_inuse(struct device *dev, struct device_attribute *attr, char *buf) +{ + int chn = get_channel_from_name(attr) ; + return sprintf(buf,"%d\n",sysfs_page[chn]); +} +// Get i2c table data as raw data (hex) +static ssize_t get_i2c_tbl_raw(struct device *dev, struct device_attribute *attr, char *buf) +{ + int chn = get_channel_from_name(attr) ; + int page = sysfs_page[chn]; // currently selected page for sysfs reads + if (page < 0) + return -ENXIO; /* No such device or address */ + + return sprintf(buf,"%0x08x\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) +{ + int chn = get_channel_from_name(attr) ; + int page, data; + sscanf(buf, "%i %i", &page, &data); + page &= 0xff; + set_sensor_i2c_raw(chn, + page, // index in lookup table + (u32) data); // Bit delay - number of mclk periods in 1/4 of the SCL period + return count; +} + +// Sysfs top + +static DEVICE_ATTR(alloc0 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); +static DEVICE_ATTR(alloc1 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); +static DEVICE_ATTR(alloc2 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); +static DEVICE_ATTR(alloc3 , SYSFS_PERMISSIONS & SYSFS_READONLY, get_i2c_page_alloc , NULL); +static DEVICE_ATTR(page_in_use0 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); +static DEVICE_ATTR(page_in_use1 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); +static DEVICE_ATTR(page_in_use2 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); +static DEVICE_ATTR(page_in_use3 , SYSFS_PERMISSIONS , get_i2c_page_inuse, free_i2c_page); +static DEVICE_ATTR(tbl_raw0 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); +static DEVICE_ATTR(tbl_raw1 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); +static DEVICE_ATTR(tbl_raw2 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); +static DEVICE_ATTR(tbl_raw3 , SYSFS_PERMISSIONS , get_i2c_tbl_raw, set_i2c_tbl_raw); + +static struct attribute *root_dev_attrs[] = { + &dev_attr_alloc0.attr, + &dev_attr_alloc1.attr, + &dev_attr_alloc2.attr, + &dev_attr_alloc3.attr, + &dev_attr_page_in_use0.attr, + &dev_attr_page_in_use1.attr, + &dev_attr_page_in_use2.attr, + &dev_attr_page_in_use3.attr, + &dev_attr_tbl_raw0.attr, + &dev_attr_tbl_raw1.attr, + &dev_attr_tbl_raw2.attr, + &dev_attr_tbl_raw3.attr, + NULL +}; + +static const struct attribute_group dev_attr_root_group = { + .attrs = root_dev_attrs, + .name = NULL, +}; + +static int elphel393_sens_i2c_sysfs_register(struct platform_device *pdev) +{ + int retval=0; + struct device *dev = &pdev->dev; + if (&dev->kobj) { + if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval; + } + return retval; +} + + +// ======================================= +static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) +{ + const __be32 * config_data; + const char * config_string; + char str[40]; + int len,chn,pre_disabled,old_dis_por,rc,chn_bits; + struct device_node *node = pdev->dev.of_node; +// struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev); +// struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev); + + if (node) { + /*TODO: Configure some i2c devices here (slaves, formats, speeds) to be used by names*/ + } + dev_info(&pdev->dev,"elphel393_sensor_i2c configuration done\n"); +} + + +static int elphel393_sensor_i2c_probe(struct platform_device *pdev) +{ + /* + struct gpio_chip *chip; +// struct device * ltc3489_dev; + int i,rc; + int base[2]; + struct i2c_client *ltc3589_client; + struct elphel393_pwr_data_t *clientdata = NULL; + */ + dev_info(&pdev->dev,"Probing elphel393-sensor-i2c\n"); + i2c_page_alloc_init(); +#if 0 + clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL); +#endif + elphel393_sensor_i2c_init_of(pdev); + elphel393_sens_i2c_sysfs_register(pdev); + return 0; +} + +static int elphel393_sensor_i2c_remove(struct platform_device *pdev) +{ + dev_info(&pdev->dev,"Removing elphel393-sensor-i2c"); + return 0; +} + +static struct of_device_id elphel393_sensor_i2c_of_match[] = { + { .compatible = "elphel,elphel393-sensor-i2c-1.00", }, + { /* end of table */} +}; + +MODULE_DEVICE_TABLE(of, elphel393_sensor_i2c_of_match); + +static struct platform_driver elphel393_pwr = { + .probe = elphel393_sensor_i2c_probe, + .remove = elphel393_sensor_i2c_remove, + .driver = { + .name = "elphel393-sensor-i2c", + .owner = THIS_MODULE, + .of_match_table = elphel393_sensor_i2c_of_match, + .pm = NULL, /* power management */ + }, +}; + +module_platform_driver(elphel393_pwr); + +MODULE_AUTHOR("Andrey Filippov "); +MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c"); +MODULE_LICENSE("GPL"); diff --git a/src/drivers/elphel/sensor_i2c.h b/src/drivers/elphel/sensor_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..45e95f035ab54046af7277c86087a1cdc3023b7c --- /dev/null +++ b/src/drivers/elphel/sensor_i2c.h @@ -0,0 +1,89 @@ +/******************************************************************************* +* FILE NAME : sensor_i2c.h +* DESCRIPTION: Interface to FPGA-based i2c sequencer for sensor ports +* Copyright 2016 (C) Elphel, Inc. +* -----------------------------------------------------------------------------* +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*******************************************************************************/ + +/* Reserve i2c page (1 of 256 for a sensor port)*/ +int i2c_page_alloc(int chn); + +/* Free i2c page */ +void i2c_page_free(int chn, int page); + +/* Set i2c table entry to raw data (will just overwrite tbl_mode = 2) */ +void set_sensor_i2c_raw(int chn, + int page, // index in lookup table + u32 data); // Bit delay - number of mclk periods in 1/4 of the SCL period + +/* Set i2c table entry for write operation */ +void set_sensor_i2c_wr(int chn, + int page, // index in lookup table + int sa, // slave address (7 bit) + int rah, // High byte of the i2c register address + 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 + +/* Set i2c table entry for read operation */ +void set_sensor_i2c_rd(int chn, + int page, // index in lookup table + 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 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 */ +/* Length of data is determined by the page data already preset */ +int write_sensor_i2c_rel (int chn, + int offs, // 4 bits + u32 * data); + +/* Same to absolute (modulo16) address */ +int write_sensor_i2c_abs (int chn, + int offs, // 4 bits + u32 * data); + +/* Write sensor 16 bit (or 8 bit as programmed in the table) data in immediate mode */ +void write_sensor_reg16 (int chn, + int page, // page (8 bits) + int addr, // low 8 bits + 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_sensor_i2c_fifo)*/ +void read_sensor_i2c (int chn, + int page, // page (8 bits) + int sa7, // 7-bit i2c slave address + int addr); // 8/16 bit address + +/* Read next byte from the channel i2c FIFO. Return byte or -1 if no data available */ +/* Sensor channel status should be in auto update mode (3) */ +int read_sensor_i2c_fifo(int chn); diff --git a/src/drivers/elphel/x393.c b/src/drivers/elphel/x393.c index 79d3f2f25c5d0cafb0b5a2f277781ff3e1d0358c..92453c8dfe149701ef45dac8dc7932f0dd75760a 100644 --- a/src/drivers/elphel/x393.c +++ b/src/drivers/elphel/x393.c @@ -1,6 +1,6 @@ /******************************************************************************* * File: x393.c - * Date: 2016-03-29 + * Date: 2016-04-06 * Author: auto-generated file, see x393_export_c.py * Description: Functions definitions to access x393 hardware registers *******************************************************************************/ @@ -174,7 +174,7 @@ void x393_sens_sync_late (x393_sens_sync void x393_sensio_ctrl (x393_sensio_ctl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1020 + 0x100 * sens_num));} // Configure sensor I/O port void set_x393_sensio_status_cntrl (x393_status_ctrl_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1024 + 0x100 * sens_num));} // Set status control for SENSIO module x393_status_ctrl_t get_x393_sensio_status_cntrl (int sens_num) { x393_status_ctrl_t d; d.d32 = readl(mmio_ptr + (0x1024 + 0x100 * sens_num)); return d; } -void x393_sensio_jtag (x393_sensio_jpag_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1028 + 0x100 * sens_num));} // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS) +void x393_sensio_jtag (x393_sensio_jtag_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1028 + 0x100 * sens_num));} // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS) void set_x393_sensio_width (x393_sensio_width_t d, int sens_num){writel(d.d32, mmio_ptr + (0x102c + 0x100 * sens_num));} // Set sensor line in pixels (0 - use line sync from the sensor) x393_sensio_width_t get_x393_sensio_width (int sens_num) { x393_sensio_width_t d; d.d32 = readl(mmio_ptr + (0x102c + 0x100 * sens_num)); return d; } void set_x393_sensio_tim0 (x393_sensio_tim0_t d, int sens_num){writel(d.d32, mmio_ptr + (0x1030 + 0x100 * sens_num));} // Sensor port i/o timing configuration, register 0 diff --git a/src/drivers/elphel/x393.h b/src/drivers/elphel/x393.h index 228157a598ed1b6251eed05cfc226af0768dede7..ae79da0402b0561cb3b07d75a197704d254eb910 100644 --- a/src/drivers/elphel/x393.h +++ b/src/drivers/elphel/x393.h @@ -1,11 +1,10 @@ /******************************************************************************* * File: x393.h - * Date: 2016-03-29 + * Date: 2016-04-06 * Author: auto-generated file, see x393_export_c.py * Description: Constants definitions and functions declarations to access x393 hardware registers *******************************************************************************/ -//#include "elphel/x393_types.h" #include "x393_types.h" //#include "elphel/x393_defs.h // alternative variant" @@ -174,7 +173,7 @@ void x393_sens_sync_late (x393_sens_sync void x393_sensio_ctrl (x393_sensio_ctl_t d, int sens_num); // Configure sensor I/O port void set_x393_sensio_status_cntrl (x393_status_ctrl_t d, int sens_num); // Set status control for SENSIO module x393_status_ctrl_t get_x393_sensio_status_cntrl (int sens_num); -void x393_sensio_jtag (x393_sensio_jpag_t d, int sens_num); // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS) +void x393_sensio_jtag (x393_sensio_jtag_t d, int sens_num); // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS) void set_x393_sensio_width (x393_sensio_width_t d, int sens_num); // Set sensor line in pixels (0 - use line sync from the sensor) x393_sensio_width_t get_x393_sensio_width (int sens_num); void set_x393_sensio_tim0 (x393_sensio_tim0_t d, int sens_num); // Sensor port i/o timing configuration, register 0 @@ -299,7 +298,6 @@ x393_status_sens_io_t x393_sensio_status (int sens_num); #define X393_CMPRS_CBIT_CMODE_MONO1 0x0000000b // Mono JPEG (not yet implemented) #define X393_CMPRS_CBIT_CMODE_MONO4 0x0000000e // Mono, 4 blocks (2x2 macroblocks) #define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 -#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 #define X393_CMPRS_CBIT_FRAMES_SINGLE 0x00000000 // Use single-frame buffer #define X393_CMPRS_CBIT_FRAMES_MULTI 0x00000001 // Use multi-frame buffer diff --git a/src/drivers/elphel/x393_defs.h b/src/drivers/elphel/x393_defs.h index 64b77be562b97d571c6aa683d6a77865529d2c61..9ad0d47b1b9916ed6f0378638c69cb1699af00cd 100644 --- a/src/drivers/elphel/x393_defs.h +++ b/src/drivers/elphel/x393_defs.h @@ -1,6 +1,6 @@ /******************************************************************************* * File: x393_defs.h - * Date: 2016-03-29 + * Date: 2016-04-06 * Author: auto-generated file, see x393_export_c.py * Description: Constants and hardware addresses definitions to access x393 hardware registers *******************************************************************************/ @@ -136,7 +136,7 @@ #define X393_SENS_SYNC_LATE(sens_num) (0x4000101c + 0x100 * (sens_num)) // Configure frame sync delay, sens_num = 0..3, data type: x393_sens_sync_late_t (wo) #define X393_SENSIO_CTRL(sens_num) (0x40001020 + 0x100 * (sens_num)) // Configure sensor I/O port, sens_num = 0..3, data type: x393_sensio_ctl_t (wo) #define X393_SENSIO_STATUS_CNTRL(sens_num) (0x40001024 + 0x100 * (sens_num)) // Set status control for SENSIO module, sens_num = 0..3, data type: x393_status_ctrl_t (rw) -#define X393_SENSIO_JTAG(sens_num) (0x40001028 + 0x100 * (sens_num)) // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), sens_num = 0..3, data type: x393_sensio_jpag_t (wo) +#define X393_SENSIO_JTAG(sens_num) (0x40001028 + 0x100 * (sens_num)) // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), sens_num = 0..3, data type: x393_sensio_jtag_t (wo) #define X393_SENSIO_WIDTH(sens_num) (0x4000102c + 0x100 * (sens_num)) // Set sensor line in pixels (0 - use line sync from the sensor), sens_num = 0..3, data type: x393_sensio_width_t (rw) #define X393_SENSIO_TIM0(sens_num) (0x40001030 + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 0, sens_num = 0..3, data type: x393_sensio_tim0_t (rw) #define X393_SENSIO_TIM1(sens_num) (0x40001034 + 0x100 * (sens_num)) // Sensor port i/o timing configuration, register 1, sens_num = 0..3, data type: x393_sensio_tim1_t (rw) @@ -240,7 +240,6 @@ #define X393_CMPRS_CBIT_CMODE_MONO1 0x0000000b // Mono JPEG (not yet implemented) #define X393_CMPRS_CBIT_CMODE_MONO4 0x0000000e // Mono, 4 blocks (2x2 macroblocks) #define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 -#define X393_CMPRS_CBIT_CMODE_JPEG18 0x00000000 // Color 4:2:0 #define X393_CMPRS_CBIT_FRAMES_SINGLE 0x00000000 // Use single-frame buffer #define X393_CMPRS_CBIT_FRAMES_MULTI 0x00000001 // Use multi-frame buffer diff --git a/src/drivers/elphel/x393_map.h b/src/drivers/elphel/x393_map.h index 9e4583fc4213091f9373e80251dfd4f8886bdf60..f10e53f03df66f3a541f49db54b5c7f7486ad326 100644 --- a/src/drivers/elphel/x393_map.h +++ b/src/drivers/elphel/x393_map.h @@ -1,6 +1,6 @@ /******************************************************************************* * File: x393_map.h - * Date: 2016-03-29 + * Date: 2016-04-06 * Author: auto-generated file, see x393_export_c.py * Description: Sorted hardware addresses map *******************************************************************************/ @@ -189,7 +189,7 @@ #define X393_SENS_SYNC_LATE__0 0x4000101c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo) #define X393_SENSIO_CTRL__0 0x40001020 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo) #define X393_SENSIO_STATUS_CNTRL__0 0x40001024 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw) -#define X393_SENSIO_JTAG__0 0x40001028 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jpag_t (wo) +#define X393_SENSIO_JTAG__0 0x40001028 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo) #define X393_SENSIO_WIDTH__0 0x4000102c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw) #define X393_SENSIO_TIM0__0 0x40001030 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw) #define X393_SENSIO_TIM1__0 0x40001034 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw) @@ -252,7 +252,7 @@ #define X393_SENS_SYNC_LATE__1 0x4000111c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo) #define X393_SENSIO_CTRL__1 0x40001120 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo) #define X393_SENSIO_STATUS_CNTRL__1 0x40001124 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw) -#define X393_SENSIO_JTAG__1 0x40001128 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jpag_t (wo) +#define X393_SENSIO_JTAG__1 0x40001128 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo) #define X393_SENSIO_WIDTH__1 0x4000112c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw) #define X393_SENSIO_TIM0__1 0x40001130 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw) #define X393_SENSIO_TIM1__1 0x40001134 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw) @@ -315,7 +315,7 @@ #define X393_SENS_SYNC_LATE__2 0x4000121c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo) #define X393_SENSIO_CTRL__2 0x40001220 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo) #define X393_SENSIO_STATUS_CNTRL__2 0x40001224 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw) -#define X393_SENSIO_JTAG__2 0x40001228 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jpag_t (wo) +#define X393_SENSIO_JTAG__2 0x40001228 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo) #define X393_SENSIO_WIDTH__2 0x4000122c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw) #define X393_SENSIO_TIM0__2 0x40001230 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw) #define X393_SENSIO_TIM1__2 0x40001234 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw) @@ -378,7 +378,7 @@ #define X393_SENS_SYNC_LATE__3 0x4000131c // Configure frame sync delay, data type: x393_sens_sync_late_t (wo) #define X393_SENSIO_CTRL__3 0x40001320 // Configure sensor I/O port, data type: x393_sensio_ctl_t (wo) #define X393_SENSIO_STATUS_CNTRL__3 0x40001324 // Set status control for SENSIO module, data type: x393_status_ctrl_t (rw) -#define X393_SENSIO_JTAG__3 0x40001328 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jpag_t (wo) +#define X393_SENSIO_JTAG__3 0x40001328 // Programming interface for multiplexer FPGA (with X393_SENSIO_STATUS), data type: x393_sensio_jtag_t (wo) #define X393_SENSIO_WIDTH__3 0x4000132c // Set sensor line in pixels (0 - use line sync from the sensor), data type: x393_sensio_width_t (rw) #define X393_SENSIO_TIM0__3 0x40001330 // Sensor port i/o timing configuration, register 0, data type: x393_sensio_tim0_t (rw) #define X393_SENSIO_TIM1__3 0x40001334 // Sensor port i/o timing configuration, register 1, data type: x393_sensio_tim1_t (rw) diff --git a/src/drivers/elphel/x393_types.h b/src/drivers/elphel/x393_types.h index 3bb19c1b1d6730e1469558874b7c08672a485789..38fd8421149db28602b96bdd5f82f05cfbaf6c74 100644 --- a/src/drivers/elphel/x393_types.h +++ b/src/drivers/elphel/x393_types.h @@ -1,6 +1,6 @@ /******************************************************************************* * File: x393_types.h - * Date: 2016-03-29 + * Date: 2016-04-06 * Author: auto-generated file, see x393_export_c.py * Description: typedef definitions for the x393 hardware registers *******************************************************************************/ @@ -310,7 +310,7 @@ typedef union { struct { u32 i2c_fifo_dout: 8; // [ 7: 0] (0) I2c byte read from the device through FIFO u32 i2c_fifo_nempty: 1; // [ 8] (0) I2C read FIFO has data - u32 i2c_fifo_cntrl: 1; // [ 9] (0) I2C FIFO byte counter (odd/even bytes) + u32 i2c_fifo_lsb: 1; // [ 9] (0) I2C FIFO byte counter (odd/even bytes) u32 busy: 1; // [ 10] (0) I2C sequencer busy u32 alive_fs: 1; // [ 11] (0) Sensor generated frame sync since last status update u32 frame_num: 4; // [15:12] (0) I2C sequencer frame number @@ -382,7 +382,7 @@ typedef union { typedef union { struct { - u32 tbl_addr: 8; // [ 7: 0] (0) Address/length in 64-bit words (<<3 to get byte address + u32 tbl_addr: 8; // [ 7: 0] (0) Address/length in 64-bit words (<<3 to get byte address) u32 :20; u32 tbl_mode: 2; // [29:28] (3) Should be 3 to select table address write mode u32 : 2; @@ -411,7 +411,9 @@ typedef union { u32 sda_release: 1; // [ 1] (0) Release SDA early if next bit ==1 (valid with drive_ctl) u32 drive_ctl: 1; // [ 2] (0) 0 - nop, 1 - set sda_release and sda_drive_high u32 next_fifo_rd: 1; // [ 3] (0) Advance I2C read FIFO pointer - u32 : 8; + u32 soft_scl: 2; // [ 5: 4] (0) Control SCL pin (when stopped): 0 - nop, 1 - low, 2 - high (driven), 3 - float + u32 soft_sda: 2; // [ 7: 6] (0) Control SDA pin (when stopped): 0 - nop, 1 - low, 2 - high (driven), 3 - float + u32 : 4; u32 cmd_run: 2; // [13:12] (0) Sequencer run/stop control: 0,1 - nop, 2 - stop, 3 - run u32 reset: 1; // [ 14] (0) Sequencer reset all FIFO (takes 16 clock pulses), also - stops i2c until run command u32 :13; @@ -664,7 +666,7 @@ typedef union { struct { u32 d32:32; // [31: 0] (0) cast to u32 }; -} x393_sensio_jpag_t; +} x393_sensio_jtag_t; // Sensor i/o timing register 0 (different meanings for different sensor types)