os/linux-2.6-tag--devboard-R2_10-4/arch/cris/arch-v32/drivers/elphel/fpgaconfi2c.c

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 fpgaconfi2c.c
00003 */
00004 
00005 /****************** INCLUDE FILES SECTION ***********************************/
00006 
00007 #include <linux/module.h>
00008 #include <linux/sched.h>
00009 #include <linux/slab.h>
00010 #include <linux/errno.h>
00011 #include <linux/kernel.h>
00012 #include <linux/fs.h>
00013 #include <linux/string.h>
00014 #include <linux/init.h>
00015 #include <linux/autoconf.h>
00016 
00017 #include <asm/system.h>
00018 #include <asm/svinto.h>
00019 #include <asm/io.h>
00020 
00021 #include <asm/irq.h>
00022 
00023 
00024 
00025 #include <asm/delay.h>
00026 #include <asm/uaccess.h>
00027 #include <asm/fpgaconfa.h>
00028 
00029 #include "fpgaconf.h"
00030 #include "fpgaconfi2c.h"
00031 
00032 #define D(x)
00033 
00034 /****************** I2C DEFINITION SECTION *************************/
00035 #define XCLOCK_LOW_TIME            8
00036 #define XCLOCK_HIGH_TIME           8
00037 #define XSTART_CONDITION_HOLD_TIME 8
00038 #define XSTOP_CONDITION_HOLD_TIME  8
00039 #define XENABLE_OUTPUT             0x01
00040 #define XENABLE_INPUT              0x00
00041 #define XI2C_CLOCK_HIGH            1
00042 #define XI2C_CLOCK_LOW             0
00043 #define XI2C_DATA_HIGH             1
00044 #define XI2C_DATA_LOW              0
00045 /*
00046 port A:
00047  0 - TDO  (in)
00048  1 - TDI  (out)
00049  2 - TMS  (out)
00050  3 - TCK  (out)
00051  4 - INIT (i/o)
00052  5 - DONE (in)
00053  6 - NU
00054  7 - PGM  (out)
00055 
00056 port B:
00057  0 - I2C SDA
00058  1 - I2C SCL
00059  2-7 - NU
00060 */
00061 /* use the kernel delay routine */
00062 
00063 #define xi2c_delay(usecs) udelay(usecs)
00064 
00065 int xi2c_diagnose(void);
00066 int     xi2c_start(void);
00067 void xi2c_stop(void);
00068 int xi2c_outbyte(unsigned char d);
00069 unsigned char xi2c_inbyte(void);
00070 
00071 void xi2c_sendack(void);
00072 int setCYField (int addr, int mask, int value);
00073 
00074 
00075 static unsigned long portb_shadow=0x0000fe03;  // only i2c uses port B
00076 void initPortB(void) {
00077   *R_PORT_PB_SET=portb_shadow;
00078 }
00079 
00080 /* I2C functions */
00081 
00082 #define  xi2c_disable *R_PORT_PB_SET=(portb_shadow  = 0x0203)
00083 #define  xi2c_dir_out *R_PORT_PB_SET=(portb_shadow  = 0x0303)
00084 #define  xi2c_dir_in  *R_PORT_PB_SET=(portb_shadow  = 0x0203)
00085 #define  xi2c_scl_0   *R_PORT_PB_SET=(portb_shadow &= 0x0301)
00086 #define  xi2c_scl_1   *R_PORT_PB_SET=(portb_shadow |= 0x0002)
00087 #define  xi2c_sda(x)  *R_PORT_PB_SET=(portb_shadow = (portb_shadow & 0x0002) | 0x0300 | ((x)? 1:0));
00088 #define  xi2c_getbit  (*R_PORT_PB_READ & 1)
00089 #define  xi2c_getscl  ((*R_PORT_PB_READ >>1) & 1)
00090 
00091 /* diagnose i2c bus problems. Will always return non-zero
00092 Normally is called from xi2c_start, if it detects problem  */
00093 int xi2c_diagnose(void) {
00094         int error=0;
00095   D(printk("xi2c_diagnose\r\n"));
00096 
00097         while (!error) {
00098                 xi2c_dir_out;   // will force high SCL, SDA
00099                 xi2c_delay(XCLOCK_HIGH_TIME);
00100                 if (!xi2c_getbit) error |= ERR_I2C_SDA_ST0;
00101                 if (!xi2c_getscl) error |= ERR_I2C_SCL_ST0;
00102                 if (error) break;
00103                 xi2c_scl_0;
00104                 xi2c_sda (0);
00105                 xi2c_delay(XCLOCK_LOW_TIME);
00106                 if (!xi2c_getbit) error |= ERR_I2C_SDA_ST0;
00107                 if (!xi2c_getscl) error |= ERR_I2C_SCL_ST0;
00108                 if (error) break;
00109                 xi2c_disable; // first disables, then sets high
00110                 xi2c_delay(XCLOCK_HIGH_TIME*2);
00111                 if (!xi2c_getbit) error |= ERR_I2C_SDA_NOPULLUP;
00112                 if (!xi2c_getscl) error |= ERR_I2C_SCL_NOPULLUP;
00113                 if (error) break;
00114                 xi2c_sda(0);    // scl will be left disabled (high)
00115                 if (!xi2c_getscl) error |= ERR_I2C_SHORT;
00116                 break;
00117         }
00118         if (!error) error =      ERR_I2C_NOTDETECTED;
00119         /* try start-stop to reset effects of playing with sda/scl lines */
00120         xi2c_dir_out;   // will force high SCL, SDA
00121         xi2c_sda (0);
00122         xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00123         xi2c_scl_0;
00124         xi2c_delay(XCLOCK_LOW_TIME*2);
00125         xi2c_scl_1;
00126         xi2c_delay(XCLOCK_HIGH_TIME*2);
00127         xi2c_sda (1);
00128         xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00129         xi2c_disable;
00130 
00131         return error;
00132 }
00133 
00134 /* generate i2c start condition and test bus */
00135 
00136 int     xi2c_start(void) {
00137 //      int error=0;
00138         int i;
00139   D(printk("xi2c_start:\r\n"));
00140         /* SCL=1 SDA=1 */
00141         xi2c_dir_out;   // will set high SCL, SDA
00142         xi2c_delay(XCLOCK_HIGH_TIME/2);
00143         /* if the periferial (?) driving sda low (after being interrupted)? - try to recover */
00144         xi2c_dir_in;
00145         xi2c_delay(XCLOCK_HIGH_TIME/2);
00146         if (!xi2c_getbit) {
00147                 for (i=0;(i<9) && !xi2c_getbit;i++) {
00148                         xi2c_scl_0;
00149                         xi2c_delay(XCLOCK_LOW_TIME);
00150                         xi2c_scl_1;
00151                         xi2c_delay(XCLOCK_HIGH_TIME);
00152                 }
00153                 if (!xi2c_getbit) return  xi2c_diagnose(); // did not help - really stuck
00154                 /* it is breathing - try "START"-"STOP" */
00155                 xi2c_sda (0);
00156                 xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00157                 xi2c_scl_0;
00158                 xi2c_delay(XCLOCK_LOW_TIME*2);
00159                 xi2c_scl_1;
00160                 xi2c_delay(XCLOCK_HIGH_TIME*2);
00161                 xi2c_sda (1);
00162                 xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00163         }
00164         /* SCL=1 SDA=1 */
00165         xi2c_dir_out;   // will set high SCL, SDA
00166         xi2c_delay(XCLOCK_HIGH_TIME/2);
00167 
00168         if ((!xi2c_getbit) || (!xi2c_getscl)) return  xi2c_diagnose();
00169         /* SCL=1 SDA=0 */
00170         xi2c_sda(0);
00171         xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00172         if (( xi2c_getbit) || (!xi2c_getscl)) return  xi2c_diagnose();
00173         /* SCL=0 SDA=0 */
00174         xi2c_scl_0;
00175         xi2c_delay(XCLOCK_LOW_TIME);
00176         if (( xi2c_getbit) || ( xi2c_getscl)) return  xi2c_diagnose();
00177         return 0;
00178 }
00179 
00180 /* generate i2c stop condition */
00181 void xi2c_stop(void) {  // assumed to be enabled
00182         /* SCL=0 SDA=0  */
00183   D(printk("xi2c_stop\r\n"));
00184 
00185         xi2c_scl_0;
00186         xi2c_sda (0);
00187         xi2c_delay(XCLOCK_LOW_TIME*2);
00188         /* SCL=1 SDA=0 */
00189         xi2c_scl_1;
00190         xi2c_delay(XCLOCK_HIGH_TIME*2);
00191         /* SCL=1 SDA=1 */
00192         xi2c_sda (1);
00193         xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00194         xi2c_disable;   // both high with resistor pull-up
00195 }
00196 
00197 /* write a byte to the i2c interface , return acknowledge */
00198 int xi2c_outbyte(unsigned char d) { 
00199         int i;
00200         unsigned char x=d;      // make it non-destructive
00201   D(printk("xi2c_outbyte: byte=%x\r\n",  (int) x));
00202 
00203         for (i = 0; i < 8; i++) { // assumed to be with SCL=0;
00204                 xi2c_sda (x & 0x80);    // checks only on non-zero, so no need to '>>'
00205 //portb_shadow
00206   D(printk("%x ",  (int) portb_shadow));
00207 
00208                 xi2c_delay(XCLOCK_LOW_TIME/2);
00209                 xi2c_scl_1;
00210                 xi2c_delay(XCLOCK_HIGH_TIME);
00211                 xi2c_scl_0;
00212                 xi2c_delay(XCLOCK_LOW_TIME/2);
00213                 x <<= 1;
00214         }
00215   D(printk("\r\n"));
00216 
00217         /* enable input  */
00218         xi2c_dir_in;
00219         xi2c_delay(XCLOCK_LOW_TIME/2);
00220         xi2c_scl_1;
00221         xi2c_delay(XCLOCK_HIGH_TIME);
00222         i= (1-xi2c_getbit);
00223         xi2c_scl_0;
00224         xi2c_delay(XCLOCK_LOW_TIME/2);
00225   D(printk("xi2c_outbyte:  ACK=%x\r\n", i));
00226 
00227 
00228         return i;
00229 }
00230 
00231 /* read a byte from the i2c interface */
00232 
00233 unsigned char xi2c_inbyte(void) { // assumed SCL=0, SDA=X
00234         unsigned char aBitByte = 0;
00235         int i;
00236         /* enable input */
00237   D(printk("xi2c_inbyte\r\n"));
00238 
00239         xi2c_dir_in;
00240         /* get bits      */
00241         for (i = 0; i < 8; i++) {
00242                 xi2c_delay(XCLOCK_LOW_TIME/2);
00243                 /* low clock period      */
00244                 xi2c_scl_1;
00245                 xi2c_delay(XCLOCK_HIGH_TIME);
00246                 aBitByte = (aBitByte << 1) | xi2c_getbit;
00247                 xi2c_scl_0;
00248                 xi2c_delay(XCLOCK_LOW_TIME/2);
00249         }
00250   D(printk("xi2c_inbyte:  data=%x\r\n", aBitByte));
00251         return aBitByte;        // returns with SCL=0, SDA - OFF
00252 }
00253 
00254 /*#---------------------------------------------------------------------------
00255 *#
00256 *# FUNCTION NAME: I2C::sendAck
00257 *#
00258 *# DESCRIPTION  : Send ACK on received data
00259 *#
00260 *#--------------------------------------------------------------------------*/
00261 void xi2c_sendack(void) {
00262          D(printk("xi2c_sendack\r\n"));
00263 
00264                 xi2c_sda (0);
00265                 xi2c_delay(XCLOCK_LOW_TIME/2);
00266                 xi2c_scl_1;
00267                 xi2c_delay(XCLOCK_HIGH_TIME);
00268                 xi2c_scl_0;
00269                 xi2c_delay(XCLOCK_LOW_TIME/2);
00270 }
00271 
00272 /*#---------------------------------------------------------------------------
00273 *#
00274 *# FUNCTION NAME: fi2c_writeData
00275 *#
00276 *# DESCRIPTION  : Writes a sequence of bytes to an I2C device
00277 *# removed retries, will add test-ready later as a separate function
00278 *# removed all "dummy stuff" - I never needed that
00279 *#
00280 *#--------------------------------------------------------------------------*/
00281 int fi2c_writeData(unsigned char theSlave, unsigned char *theData, int size) {
00282         int i,error=0;
00283         /* we don't like to be interrupted      *** WHY??? ***   */
00284    D(printk("i2c_writeData:  theSlave=%x data=%x %x size=%x\r\n", theSlave, theData[0], theData[1], size));
00285 
00286         /* generate start condition, test bus */
00287         if ((error=xi2c_start())) return error;
00288         /* send slave address, wait for ack */
00289         if(!xi2c_outbyte(theSlave)) {
00290                  xi2c_stop();
00291                  return ERR_I2C_BSY;    // device does not exist or not ready
00292         }
00293 // OK, now send theData verifying ACK goes after each byte
00294         for (i=0;i<size;i++) {
00295                 if(!xi2c_outbyte(theData[i])) {
00296                         xi2c_stop();
00297                         return ERR_I2C_NACK;    // device failure
00298                 }
00299         }
00300         xi2c_stop();
00301         return 0;
00302 }
00303 
00304 /*#---------------------------------------------------------------------------
00305 *#
00306 *# FUNCTION NAME: i2c_readData
00307 *#
00308 *# DESCRIPTION  : Reads a data from the i2c device, returns 0- OK, else - error code
00309 *#
00310 *#--------------------------------------------------------------------------*/
00311 
00312 int fi2c_readData(unsigned char theSlave, unsigned char *theData, int size) {
00313         int i, error=0;
00314         if ((error=xi2c_start())) return error;
00315         /* send slave address, wait for ack */
00316    D(printk("i2c_readData:  theSlave=%x size=%x\r\n", theSlave, size));
00317 
00318         if(!xi2c_outbyte(theSlave)) {
00319                  xi2c_stop();
00320                  return ERR_I2C_BSY;    // device does not exist or not ready
00321         }
00322         for (i=0;i<size;i++) {
00323                 theData[i]=xi2c_inbyte();
00324                 xi2c_sendack();
00325         }
00326          xi2c_stop();
00327          return 0;
00328         
00329 }
00330 
00331 
00332 /* Main device API. ioctl's to write or read to/from i2c registers.  */
00333 // for now - single register read/write only
00334 int fi2c_ioctl(struct inode *inode, struct file *file,
00335           unsigned int cmd, unsigned long arg) {
00336           unsigned char data[2];
00337 //          unsigned long flags;
00338 
00339           int error=0;
00340    D(printk("i2c_ioctl cmd= %x, arg= %x\n\r",cmd,(int) arg));
00341    D(printk("i2c_ioctl:  ((int *)file->private_data)[0]= %x\n\r",((int *)file->private_data)[0]));
00342         if(_IOC_TYPE(cmd) != FPGACONF_IOCTYPE) {
00343                 return -EINVAL;
00344         }
00345 
00346         switch (_IOC_NR(cmd)) {
00347                 case I2C_WRITEREG:
00348 
00349                         /* write to an i2c slave */
00350                         D(printk("i2cw slave=%d, reg=%d, value=%d\n", 
00351                                  (int) I2C_ARGSLAVE(arg),
00352                                  (int) I2C_ARGREG(arg),
00353                                  (int) I2C_ARGVALUE(arg)));
00354                         data[0]=I2C_ARGREG(arg);
00355                         data[1]=I2C_ARGVALUE(arg);
00356                         return -fi2c_writeData(I2C_ARGSLAVE(arg) & 0xfe, &data[0], 2);
00357                 case I2C_READREG:
00358                 {
00359                         /* read from an i2c slave */
00360                         D(printk("i2cr slave=%d, reg=%d ", 
00361                                  (int) I2C_ARGSLAVE(arg),
00362                                  (int) I2C_ARGREG(arg)));
00363 
00364                         data[0]=I2C_ARGREG(arg);
00365                         error=fi2c_writeData(I2C_ARGSLAVE(arg) & 0xfe, &data[0], 1);
00366                         if (error) return -error;
00367 
00368                         error=fi2c_readData(I2C_ARGSLAVE(arg) | 0x01, &data[1], 1);
00369                         if (error) return -error;
00370                         D(printk("returned %d\n", data[1]));
00371 
00372                         return data[1];
00373                 }
00374                 default:
00375                         return -EINVAL;
00376 
00377         }
00378         
00379         return 0;
00380 }
00381 //int fi2c_writeData(unsigned char theSlave, unsigned char *theData, int size);
00382 
00383 //int fi2c_readData(unsigned char theSlave, unsigned char *theData, int size);
00384 #define CY223933_SA 0xd2
00385 
00386 int setCYField (int addr, int mask, int value) {
00387     unsigned char data[2];
00388     int error;
00389     data[0]=addr;
00390     error=fi2c_writeData(CY223933_SA,       &data[0], 1);
00391     if (error) return -error;
00392     error=fi2c_readData(CY223933_SA | 0x01, &data[1], 1);
00393     if (error) return -error;
00394     data[1]^=(data[1] ^ (unsigned long) value) & (unsigned long) mask;
00395     error=fi2c_writeData(CY223933_SA,       &data[0], 2);
00396     return error;
00397 }
00398 
00399 // sets clock to 1-127MHz for clock 0/1
00400 int setClockFreq(int nclock, int freq) {
00401   int i,bp,bq,bdiv,pllc;
00402   const int freqtab[]=
00403   {     0x0, 0x1303640, 0x1303320, 0x2d08220, 0x1303190, 0x1303140, 0x2d08110, 0x24060f0,
00404   0x14030d0, 0x15030c0, 0x13030a0, 0x10020a0, 0x1503090, 0x1403080, 0x1603080, 0x2406070,
00405   0x1603070, 0x2d08060, 0x1503060, 0x3308060, 0x1303050, 0x2406050, 0x1002050, 0x1102050,
00406   0x1202050, 0x1303040, 0x1403040, 0x1503040, 0x1603040, 0x1703040, 0x1202040, 0x1903040,
00407   0x1a03040, 0x1b03040, 0x2d08030, 0x2406030, 0x1503030, 0x6912030, 0x3308030, 0x6f12030,
00408   0x1202030, 0x7512030, 0x3908030, 0x7b12030, 0x1b03030, 0x1502030, 0x3f08030, 0x8712030,
00409   0x1e03030, 0x8d12030, 0x1303020, 0x2d08020, 0x1403020, 0x2f08020, 0x1503020, 0x1002020,
00410   0x1603020, 0x3308020, 0x1703020, 0x3508020, 0x1202020, 0x3708020, 0x1903020, 0x3908020,
00411   0x1a03020, 0x1402020, 0x1b03020, 0x3d08020, 0x1c03020, 0x3f08020, 0x1602020, 0x4108020,
00412   0x1e03020, 0x4308020, 0x1f03020, 0x1802020, 0x2003020, 0x4708020, 0x2103020, 0x4908020,
00413   0x1201020, 0x4b08020, 0x2303020, 0x4d08020, 0x2403020, 0x1c02020, 0x2503020, 0x5108020,
00414   0x2603020, 0x5308020, 0x1501020, 0x5508020, 0x2803020, 0x5708020, 0x2903020, 0x2002020,
00415   0x2a03020, 0x5b08020, 0x2b03020, 0x5d08020, 0x1303010, 0x5f12010, 0x2d08010, 0x6112010,
00416   0x1403010, 0x2406010, 0x2f08010, 0x6512010, 0x1503010, 0x6712010, 0x1002010, 0x6912010,
00417   0x1603010, 0x6b12010, 0x3308010, 0x1102010, 0x1703010, 0x6f12010, 0x3508010, 0x7112010,
00418   0x1202010, 0x7312010, 0x3708010, 0x7512010, 0x1903010, 0x1302010, 0x3908010, 0x7912010};
00419   if ((freq<0) || (freq>127)) {printk("bad frequency for clock %d - %d MHz\n",nclock,freq);return -2;}
00420 //          n=((bp<<20)+(bq<<12)+(bdiv<<4)+pllc);
00421           bp=  (freqtab[freq]>>20)&0x7ff;
00422           bq=  (freqtab[freq]>>12)&0xff;
00423           bdiv=(freqtab[freq]>> 4)&0xff;
00424           pllc= freqtab[freq]     &0x0f;
00425   printk ("fpgaconfi2c.c::setClockFreq(clock=%d, freq=%d) bp=0x%x, bq=0x%x, bdiv=0x%x, pllc=0x%x\r\n", nclock, freq,bp,bq,bdiv,pllc);
00426   switch (nclock) {
00427        case 0: {
00428           if (freq==0) {
00429             setCYField (0x16, 0x40, 0x00); // turn off pll3
00430             setCYField (0x09, 0x7f, 0x00); // turn off divider- A
00431             setCYField (0x08, 0x7f, 0x00); // turn off divider- A
00432             return 0;
00433           }
00434           setCYField (0x16, 0x7f, 0x40+(pllc<<3)+((bp & 1)<<2)+((bp & 0x600)>>9) );
00435           setCYField (0x15, 0xff, ((bp & 0x1fe)>>1) );
00436           setCYField (0x14, 0xff, bq );
00437           setCYField (0x09, 0x7f, bdiv); // set divider- A
00438           setCYField (0x08, 0x7f, bdiv); // set divider- A
00439           setCYField (0x0e, 0x03, 0x03); // set PLL3 as source for ClkA
00440           return 0;
00441        }
00442        case 1: {
00443           if (freq==0) {
00444             setCYField (0x0b, 0x7f, 0x00); // turn off divider- B
00445             setCYField (0x0a, 0x7f, 0x00); // turn off divider- B
00446             for (i=0;i<24;i+=3) setCYField (0x42+i, 0x40, 0x00); // turn off pll1
00447             return 0;
00448           }
00449 // progam all variants
00450           for (i=0;i<24;i+=3) {
00451             setCYField (0x42+i, 0x7f, 0x40+(pllc<<3)+((bp & 1)<<2)+((bp & 0x600)>>9) );
00452             setCYField (0x41+i, 0xff, ((bp & 0x1fe)>>1) );
00453             setCYField (0x40+i, 0xff, bq );
00454           }
00455           setCYField (0x0b, 0x7f, bdiv); // set divider- B
00456           setCYField (0x0a, 0x7f, bdiv); // set divider- B
00457           setCYField (0x0e, 0x0c, 0x04); // set PLL1 as source for ClkB
00458           return 0;
00459        }
00460    default: return -1; // wrong clock number
00461   }
00462 }
00463 

Generated on Fri Nov 28 00:06:23 2008 for elphel by  doxygen 1.5.1