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

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *! FILE NAME  : fpgaclocks353.c
00003 *! provides control of the FPGA clocks based on 3-pll generator
00004 *! Direct r/w of the CY22393 over the I2C interface (connected to PB.16 and PB.17 of the CPU)
00005 *! supports 3 PLLs connected to 3 outputs (clk0, clk1 and clk2)
00006 *! clk3 can be only turned on to Xtal frequency (12MHz) or off
00007 *! Input parameter specifies frequency in Hz, internally data is rounded to 100Hz
00008 *!
00009 *!
00010 *! Copyright (C) 2002-2006 Elphel, Inc.
00011 *! -----------------------------------------------------------------------------**
00012 *!
00013 *!  This program is free software: you can redistribute it and/or modify
00014 *!  it under the terms of the GNU General Public License as published by
00015 *!  the Free Software Foundation, either version 3 of the License, or
00016 *!  (at your option) any later version.
00017 *!
00018 *!  This program is distributed in the hope that it will be useful,
00019 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 *!  GNU General Public License for more details.
00022 *!
00023 *!  You should have received a copy of the GNU General Public License
00024 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025 *! -----------------------------------------------------------------------------**
00026 *!  $Log: fpgaclocks353.c,v $
00027 *!  Revision 1.1.1.1  2007/08/17 10:23:18  elphel
00028 *!  This is a fresh tree based on elphel353-2.10
00029 *!
00030 *!  Revision 1.7  2007/08/17 10:23:18  spectr_rain
00031 *!  switch to GPL3 license
00032 *!
00033 *!  Revision 1.6  2007/07/20 10:17:45  spectr_rain
00034 *!  *** empty log message ***
00035 *!
00036 *!  Revision 1.2  2007/06/28 02:23:49  elphel
00037 *!  removed initilaization to some frequencies during Linux booting (they are programmed in other places)
00038 *!
00039 *!  Revision 1.1.1.1  2007/02/23 10:11:48  elphel
00040 *!  initial import into CVS
00041 *!
00042 *!  Revision 1.2  2005/05/10 21:08:49  elphel
00043 *!  *** empty log message ***
00044 *!
00045 
00046 */
00047 
00048 /****************** INCLUDE FILES SECTION ***********************************/
00049 #include <linux/autoconf.h>
00050 
00051 #include <linux/module.h>
00052 #include <linux/sched.h>
00053 #include <linux/slab.h>
00054    #include <linux/ioport.h> // needed?
00055 #include <linux/errno.h>
00056 #include <linux/kernel.h>
00057 #include <linux/fs.h>
00058 #include <linux/string.h>
00059 //#include <linux/poll.h>
00060 #include <linux/init.h>
00061 
00062 //#include <linux/interrupt.h>
00063 //#include <linux/spinlock.h>
00064 
00065 
00066 //#include <asm/svinto.h> - obsolete
00067 
00068 // #include <asm/etraxgpio.h> // probably just for gpio driver
00069 #include <asm/arch/hwregs/reg_map.h>
00070 #include <asm/arch/hwregs/reg_rdwr.h>
00071 #include <asm/arch/hwregs/gio_defs.h>
00072 #include <asm/arch/hwregs/intr_vect_defs.h>
00073 #include <asm/arch/hwregs/pinmux_defs.h>
00074 
00075 
00076 #include <asm/io.h>
00077 #include <asm/system.h>
00078 #include <asm/irq.h>
00079 
00080 
00081 
00082 #include <asm/delay.h>
00083 #include <asm/uaccess.h>
00084 
00085 
00086 #include <asm/elphel/fpgaclocks.h>
00087 
00088 #include "fpgactrl.h" // extern fpga_state
00089 
00090 #define D(x)
00091 //#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
00092 //#define D(x) x
00093 #define D1(x)
00094 //#define D1(x) printk("%s:%d:",__FILE__,__LINE__);x
00095 
00096 #define D2(x)
00097 //#define D2(x) x
00098 
00099 #define D3(x)
00100 //#define D3(x) printk("%s:%d:",__FILE__,__LINE__);x
00101 
00102 // add to other drivers to use clock change function
00103 //extern int setClockFreq(int nclock, int freq) { // freq now in Hz
00104 
00105 //#define D5(x) printk("%s:%d:",__FILE__,__LINE__);x
00106 #define D5(x)
00107 
00108 
00109 //=========================
00110 #define FPGA_CLOCK_MAJOR 133  /* LOCAL/EXPERIMENTAL */
00111 #define FPGA_CLOCK_DRIVER_NAME "Elphel (R) model 353 system clocks (PLL frequency synth.) driver"
00112 #define FPGA_CLOCK_MAXMINOR 10
00113 #define FPGA_CLOCK_MINOR    2
00114 /* MINORS */
00115 #define FPGA_CLOCK_MINOR_I2C        2
00116 #define FPGA_CLOCK_MINOR_CLOCKS     3
00117 
00118 
00119 
00120 
00121 /****************** I2C DEFINITION SECTION *************************/
00122 #define XCLOCK_LOW_TIME            8
00123 #define XCLOCK_HIGH_TIME           8
00124 #define XSTART_CONDITION_HOLD_TIME 8
00125 #define XSTOP_CONDITION_HOLD_TIME  8
00126 #define XENABLE_OUTPUT             0x01
00127 #define XENABLE_INPUT              0x00
00128 #define XI2C_CLOCK_HIGH            1
00129 #define XI2C_CLOCK_LOW             0
00130 #define XI2C_DATA_HIGH             1
00131 #define XI2C_DATA_LOW              0
00132 /*
00133 port B:
00134  16 - I2C SDA
00135  17 - I2C SCL
00136 */
00137 
00138 #define xi2c_delay(usecs) udelay(usecs)
00139 
00140 static int clock_frequency[4]; // in Hz
00141 typedef struct {
00142   unsigned int p :   11; // p - 16..1600
00143   unsigned int q :   8;  // q - 0.. 255
00144   unsigned int dv:   7;  // dv - 1.. 127
00145   unsigned int corr: 3;  // 0/1/2/3/4
00146   unsigned int rslt:   3;  // 0 - OK, 1 - frequency low, 2 - frequency high, 3 - other
00147 } t_pll_params;
00148  
00149 
00150 int xi2c_diagnose(void);
00151 int   xi2c_start(void);
00152 void xi2c_stop(void);
00153 void xi2c_nostop(void);
00154 int xi2c_outbyte(unsigned char d);
00155 unsigned char xi2c_inbyte(void);
00156 void xi2c_sendack(void);
00157 int fi2c_writeData(unsigned char theSlave, unsigned char *theData, int size, int nostop);
00158 int fi2c_readData(unsigned char theSlave, unsigned char *theData, int size);
00159 
00160 int fi2c_ioctl(struct inode *inode, struct file *file,  unsigned int cmd, unsigned long arg);
00161 int calc_pll_params (unsigned int f, t_pll_params * pars); // f -in Hz
00162 
00163 int setCYField (int addr, int mask, int value);
00164 int setClockFreq(int nclock, int freq); // freq now in Hz
00165 
00166 // interface functions
00167 static const char fpga_clock_name[] = "fpga_clock_control";
00168 static int minors[FPGA_CLOCK_MAXMINOR+1]; // each minor can be opened only once
00169 static int     fpga_clock_open   (struct inode *inode, struct file *filp);
00170 static int     fpga_clock_release(struct inode *inode, struct file *filp);
00171 static int     fpga_clock_ioctl  (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
00172 static int __init fpga_clock_init(void);
00173 
00174 
00175 static struct file_operations fpga_clock_fops = {
00176   owner:    THIS_MODULE,
00177   open:     fpga_clock_open,
00178   release:  fpga_clock_release,
00179   ioctl:    fpga_clock_ioctl,
00180 };
00181 
00182 
00183 
00184 
00185 
00186 #define CY223933_SA 0xd2
00187 // in Hz
00188 #define CY22393_SCALE 100 // precision will be 100Hz
00189 #define CY22393_PLLMIN (100000000/CY22393_SCALE)
00190 #define CY22393_PLLMAX (400000000/CY22393_SCALE)
00191 #define CY22393_XTAL   ( 12000000/CY22393_SCALE)
00192 #define CY22393_OUTMAX (166000000/CY22393_SCALE)
00193 #define CY22393_PMIN 16
00194 #define CY22393_PMAX 1600
00195 
00196 
00197 int calc_pll_params (unsigned int f, t_pll_params * pars) { // f -in Hz
00198 //   t_pll_params pars;
00199    unsigned int f0= CY22393_XTAL;
00200    unsigned int f0_2= CY22393_XTAL/2;
00201    unsigned int fpmn= CY22393_XTAL * (CY22393_PMIN + 6);
00202    unsigned int fpmx= CY22393_XTAL * (CY22393_PMAX + 6);
00203    int divmn, divmx, err1,err, div,q,qmn,qmx,qmx1,fdv,p, e,fdvq;
00204    pars->rslt=3; // other error
00205    D(printk("f0=%d,f=%d, CY22393_OUTMAX=%d\r\n",f0,f,CY22393_OUTMAX));
00206    f/=CY22393_SCALE; // to fit into 32-bit calcualtions
00207    D(printk("f0=%d,f=%d, CY22393_OUTMAX=%d\r\n",f0,f,CY22393_OUTMAX));
00208    if (f>CY22393_OUTMAX) {
00209      pars->rslt=2;
00210      D(printk("f0=%d,f=%d, CY22393_OUTMAX=%d\r\n",f0,f,CY22393_OUTMAX));
00211      return pars->rslt;
00212    }
00213    if (f <=0 ) {
00214      pars->rslt=1;
00215      D(printk("f0=%d,f=%d, CY22393_OUTMAX=%d\r\n",f0,f,CY22393_OUTMAX));
00216      return pars->rslt;
00217    }
00218    divmx=CY22393_PLLMAX/f; if (divmx > 127) divmx=127; // could not be <1
00219    divmn=CY22393_PLLMIN/f; if (divmn < 1)   divmn=1;
00220    if (divmn >127) {
00221      pars->rslt=1;
00222      D(printk("f0=%d,f=%d, CY22393_OUTMAX=%d, divmn=%d\r\n",f0,f,CY22393_OUTMAX,divmn));
00223      return pars->rslt;
00224    }
00225    err1=f;
00226    qmx1=0;
00227    for (div=divmn;div<=divmx;div++) {
00228      err=err1*div;
00229      fdv=f*div;
00230      qmn=fpmn/fdv-2; if (qmn < 0) qmn=0;
00231      qmx=fpmx/fdv-2; if (qmx >255) qmx=255;
00232 // recalculate qmn to avoid same div*qmn as already tried with lover div
00233      D1(printk("div=%d,qmn=%d, qmx=%d\r\n",div,qmn,qmx));
00234      if (div==1) qmx1=qmx;
00235      else if ((qmn*div) < qmx1) qmn=qmx1/div;
00236      for (q=qmn+2;q<=qmx+2; q++) {
00237        fdvq=fdv*q;
00238        p= (fdvq+f0_2)/f0; // can p be out of range here?
00239        e= fdvq-f0*p; if (e<0) e=-e;
00240        if (e< (err*q)) { // better solution found
00241          pars->rslt=0;
00242          pars->p=p-6;
00243          pars->q=q-2;
00244          pars->dv=div;
00245          err1=e/q/div;
00246          err=err1*div;
00247          D1(printk("f=%d, div=%d, p=%d,q=%d, err1=%d\r\n", (f0*p)/q/div, div,p, q, err1));
00248          if (err1==0) {
00249            pars->corr=(pars->p<226)?0:((pars->p<621)?1:((pars->p<829)?2:((pars->p<1038)?3:4)));
00250            D1(printk("f=%d, div=%d, p=%d,q=%d, err1=%d, rslt=%d\r\n",
00251            (f0*(pars->p+6))/(pars->q+2)/pars->dv,
00252            pars->dv,
00253            (pars->p+6),
00254            (pars->q+2),
00255            err1,
00256            pars->rslt));
00257            return pars->rslt;
00258          }
00259        }
00260      }
00261    }
00262    D1(printk("f=%d, div=%d, p=%d,q=%d, err1=%d, rslt=%d\r\n",
00263            (f0*(pars->p+6))/(pars->q+2)/pars->dv,
00264            pars->dv,
00265            (pars->p+6),
00266            (pars->q+2),
00267            err1,
00268            pars->rslt));
00269    pars->corr=(pars->p<226)?0:((pars->p<621)?1:((pars->p<829)?2:((pars->p<1038)?3:4)));
00270    return pars->rslt;
00271 }
00272 
00273 
00274 
00275 
00276 
00277 
00278 int setCYField (int addr, int mask, int value);
00279 
00280 /* I2C functions */
00281 
00282 #if 0
00283 inline void xi2c_disable(void){
00284     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00285     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00286     pb_dout.data |=  0x20000;
00287     pb_oe.oe &= ~0x10000; //SDA - in 
00288     pb_oe.oe |=  0x20000; //SCL out
00289     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00290     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00291 D2(printk("x"));
00292  }; // *R_PORT_PB_SET=(portb_shadow  = 0x0203)
00293 inline void xi2c_dir_out(void){ // is it really needed (only in start)
00294     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00295     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00296     pb_dout.data |=  0x20000;
00297     pb_dout.data &= ~0x10000;
00298     pb_oe.oe     |=  0x30000; //SCL out, SDA out
00299     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00300     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00301 D2(printk(">"));
00302 }; // *R_PORT_PB_SET=(portb_shadow  = 0x0303)
00303 inline void xi2c_dir_in(void){
00304     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00305     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00306     pb_dout.data |=  0x20000;
00307     pb_dout.data &= ~0x10000;
00308     pb_oe.oe &= ~0x10000; //SDA - in 
00309     pb_oe.oe |=  0x20000; //SCL out
00310     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00311     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00312 D2(printk("<"));
00313 }; //  *R_PORT_PB_SET=(portb_shadow  = 0x0203)
00314 inline void xi2c_scl_0(void){
00315     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00316     pb_dout.data &= ~0x20000;
00317     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00318 D2(printk("\\"));
00319 }; //   *R_PORT_PB_SET=(portb_shadow &= 0x0301)
00320 inline void xi2c_scl_1(void){
00321     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00322     pb_dout.data |= 0x20000;
00323     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00324 D2(printk("/"));
00325 }; //   *R_PORT_PB_SET=(portb_shadow |= 0x0002)
00326 inline void xi2c_sda(int x){
00327 /*
00328     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00329     pb_dout.data &= ~0x10000;
00330     pb_dout.data |= x? 0x10000:0;
00331     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00332 */
00333 // add acceleration here ?
00334 
00335     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00336     if (x) pb_oe.oe     &= ~0x10000; //SDA disabled (1)
00337     else   pb_oe.oe     |= ~0x10000; //SDAenabled (0)
00338 
00339     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00340 
00341 D2(printk("%d",x?1:0));
00342 }; //  *R_PORT_PB_SET=(portb_shadow = (portb_shadow & 0x0002) | 0x0300 | ((x)? 1:0));
00343 inline int  xi2c_getbit(void){
00344 D2(printk("%c",(((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1?'H':'L'));
00345     return (((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1;
00346 }; //  (*R_PORT_PB_READ & 1)
00347 inline int  xi2c_getscl(void){
00348 D2(printk("%c",(((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1?'+':'-'));
00349     return (((REG_RD(gio, regi_gio, r_pb_din)).data) >> 17) & 1;
00350 }; //  ((*R_PORT_PB_READ >>1) & 1)
00351 
00352 
00353 #endif
00354 
00355 
00356 inline void xi2c_disable(void){ //initial condition, no fast pull up for data scl=1, sda=z (==1)
00357     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00358     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00359     pb_dout.data |=  0x30000;
00360     pb_oe.oe &=     ~0x10000; //SDA - in 
00361     pb_oe.oe |=      0x20000; //SCL out
00362     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00363     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00364 D2(printk("x"));
00365  };
00366 
00367 inline void xi2c_scl(int x){ // sst SCL line to x (oe supposed to be setup earlier)
00368     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00369     if (x) pb_dout.data |=  0x20000;
00370     else   pb_dout.data &= ~0x20000;
00371     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00372 D2(if (x) printk("/"); else printk("\\"));
00373  }
00374 
00375 inline void xi2c_sda (int x){ // sst SDA line to x (accelerate with active high)
00376     reg_gio_rw_pb_dout      pb_dout=REG_RD(gio, regi_gio, rw_pb_dout);  
00377     reg_gio_rw_pb_oe        pb_oe =   REG_RD(gio, regi_gio, rw_pb_oe);
00378     if (x) {
00379         pb_dout.data |=  0x10000; // SDA=1
00380         pb_oe.oe     |=  0x10000; // SDA out enable
00381         REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00382         REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00383         pb_oe.oe     &= ~0x10000; // SDA out disable
00384         D2(printk("1"));
00385 
00386     } else {
00387         pb_dout.data &= ~0x10000; // SDA=0
00388         pb_oe.oe     |=  0x10000; // SDA out enable
00389         REG_WR(gio, regi_gio, rw_pb_dout, pb_dout);
00390         REG_WR(gio, regi_gio, rw_pb_oe, pb_oe);
00391         D2(printk("0"));
00392     }
00393     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout); // just extra delay
00394     REG_WR(gio, regi_gio, rw_pb_dout, pb_dout); // just extra delay
00395     REG_WR(gio, regi_gio, rw_pb_oe, pb_oe); // now - disable active pullup for SDA line (when sda=1, nop if sda=0)
00396  }
00397 
00398 inline int  xi2c_getbit(void){
00399 D2(printk("%c",(((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1?'H':'L'));
00400     return (((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1;
00401 }; //  (*R_PORT_PB_READ & 1)
00402 inline int  xi2c_getscl(void){
00403 D2(printk("%c",(((REG_RD(gio, regi_gio, r_pb_din)).data)>>16) & 1?'+':'-'));
00404     return (((REG_RD(gio, regi_gio, r_pb_din)).data) >> 17) & 1;
00405 }; //  ((*R_PORT_PB_READ >>1) & 1)
00406 
00407 /*
00408 inline void xi2c_disable(void);
00409 inline void xi2c_scl(int x);
00410 inline void xi2c_sda (int x);
00411 inline int  xi2c_getbit(void);
00412 inline int  xi2c_getscl(void);
00413 */
00414 
00415 
00416 
00417 void initPortB(void) {
00418 // connect 2 lower bits of port B to GPIO, disconnect from IOP
00419     unsigned long tmp;
00420     reg_pinmux_rw_pb_iop    pinmux_b_iop;
00421     reg_pinmux_rw_pb_gio    pinmux_b_gio;
00422 
00423     pinmux_b_iop= REG_RD(pinmux, regi_pinmux, rw_pb_iop);
00424     tmp = REG_TYPE_CONV(unsigned long, reg_pinmux_rw_pb_iop, pinmux_b_iop);
00425     tmp &= ~0x030000;
00426     pinmux_b_iop = REG_TYPE_CONV(reg_pinmux_rw_pb_iop, unsigned long, tmp);
00427     REG_WR(pinmux, regi_pinmux, rw_pb_iop, pinmux_b_iop);
00428 
00429     pinmux_b_gio= REG_RD(pinmux, regi_pinmux, rw_pb_gio);
00430     tmp = REG_TYPE_CONV(unsigned long, reg_pinmux_rw_pb_gio, pinmux_b_gio);
00431     tmp |=  0x030000;
00432     pinmux_b_gio = REG_TYPE_CONV(reg_pinmux_rw_pb_gio, unsigned long, tmp);
00433     REG_WR(pinmux, regi_pinmux, rw_pb_gio, pinmux_b_gio);
00434     xi2c_disable();
00435 }
00436 
00437 /* diagnose i2c bus problems. Will always return non-zero
00438 Normally is called from xi2c_start, if it detects problem  */
00439 int xi2c_diagnose(void) {
00440    int error=0;
00441   D(printk("diagnose\r\n"));
00442 
00443    while (!error) {
00444       xi2c_disable();xi2c_sda (1);  // will force high SCL, SDA
00445       xi2c_delay(XCLOCK_HIGH_TIME);
00446       if (!xi2c_getbit) error |= ERR_I2C_SDA_ST0;
00447       if (!xi2c_getscl) error |= ERR_I2C_SCL_ST0;
00448       if (error) break;
00449       xi2c_scl (0);
00450       xi2c_sda (0);
00451       xi2c_delay(XCLOCK_LOW_TIME);
00452       if (!xi2c_getbit) error |= ERR_I2C_SDA_ST0;
00453       if (!xi2c_getscl) error |= ERR_I2C_SCL_ST0;
00454       if (error) break;
00455       xi2c_disable(); // first disables, then sets high
00456       xi2c_delay(XCLOCK_HIGH_TIME*2);
00457       if (!xi2c_getbit) error |= ERR_I2C_SDA_NOPULLUP;
00458       if (!xi2c_getscl) error |= ERR_I2C_SCL_NOPULLUP;
00459       if (error) break;
00460       xi2c_sda(0);   // scl will be left disabled (high)
00461       if (!xi2c_getscl) error |= ERR_I2C_SHORT;
00462       break;
00463    }
00464    if (!error) error =   ERR_I2C_NOTDETECTED;
00465    /* try start-stop to reset effects of playing with sda/scl lines */
00466    xi2c_disable();  // will force high SCL, SDA
00467    xi2c_sda (0);
00468    xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00469    xi2c_scl(0);
00470    xi2c_delay(XCLOCK_LOW_TIME*2);
00471    xi2c_scl(1);
00472    xi2c_delay(XCLOCK_HIGH_TIME*2);
00473    xi2c_sda (1);
00474    xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00475    xi2c_disable();
00476    return error;
00477 }
00478 
00479 /* generate i2c start condition and test bus */
00480 
00481 int   xi2c_start(void) {
00482 // int error=0;
00483    int i;
00484   D(for(i=0;i<300;i++) udelay(1000); printk("start:\r\n"); for(i=0;i<300;i++) udelay(1000));
00485    /* SCL=1 SDA=1 */
00486    xi2c_disable();  // will set high SCL, SDA
00487    xi2c_delay(XCLOCK_HIGH_TIME/2);
00488    /* if the periferial (?) driving sda low (after being interrupted)? - try to recover */
00489 //   xi2c_dir_in();
00490    xi2c_delay(XCLOCK_HIGH_TIME/2);
00491    if (!xi2c_getbit()) {
00492       for (i=0;(i<9) && !xi2c_getbit();i++) {
00493          xi2c_scl(0);
00494          xi2c_delay(XCLOCK_LOW_TIME);
00495          xi2c_scl(1);
00496          xi2c_delay(XCLOCK_HIGH_TIME);
00497       }
00498       if (!xi2c_getbit) return  xi2c_diagnose(); // did not help - really stuck
00499       /* it is breathing - try "START"-"STOP" */
00500       xi2c_sda (0);
00501       xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00502       xi2c_scl(0);
00503       xi2c_delay(XCLOCK_LOW_TIME*2);
00504       xi2c_scl(1);
00505       xi2c_delay(XCLOCK_HIGH_TIME*2);
00506       xi2c_sda (1);
00507       xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00508    }
00509    /* SCL=1 SDA=1 */
00510    xi2c_delay(XCLOCK_HIGH_TIME/2);
00511    if ((!xi2c_getbit()) || (!xi2c_getscl())) return  xi2c_diagnose();
00512    /* SCL=1 SDA=0 */
00513    xi2c_sda(0);
00514    xi2c_delay(XSTART_CONDITION_HOLD_TIME);
00515    if (( xi2c_getbit()) || (!xi2c_getscl())) return  xi2c_diagnose();
00516    /* SCL=0 SDA=0 */
00517    xi2c_scl(0);
00518    xi2c_delay(XCLOCK_LOW_TIME);
00519    if (( xi2c_getbit()) || ( xi2c_getscl())) return  xi2c_diagnose();
00520    return 0;
00521 }
00522 
00523 /* generate i2c stop condition */
00524 void xi2c_stop(void) {  // assumed to be enabled
00525    /* SCL=0 SDA=0  */
00526   D(int i;)
00527   D( for (i=0;i<300;i++) udelay(1000); printk("stop:\r\n"); for(i=0;i<300;i++) udelay(1000));
00528 
00529    xi2c_scl (0);
00530    xi2c_sda (0);
00531    xi2c_delay(XCLOCK_LOW_TIME*2);
00532    /* SCL=1 SDA=0 */
00533    xi2c_scl(1);
00534    xi2c_delay(XCLOCK_HIGH_TIME*2);
00535    /* SCL=1 SDA=1 */
00536    xi2c_sda (1);
00537    xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00538 //   xi2c_disable();  // both high with resistor pull-up
00539 }
00540 
00541 /* generate i2c "no-stop" condition before repeated start */
00542 void xi2c_nostop(void) {  // assumed to be enabled
00543    /* SCL=0 SDA=0  */
00544   D(int i;)
00545   D( for (i=0;i<300;i++) udelay(1000); printk("nostop:\r\n"); for(i=0;i<300;i++) udelay(1000));
00546 
00547    xi2c_scl (0);
00548    xi2c_sda (0);
00549    xi2c_delay(XCLOCK_LOW_TIME*2);
00550    /* SCL=0 SDA=1 */
00551    xi2c_sda (1);
00552    xi2c_delay(XCLOCK_HIGH_TIME*2);
00553    /* SCL=1 SDA=1 */
00554    xi2c_scl(1);
00555    xi2c_delay(XSTOP_CONDITION_HOLD_TIME);
00556    xi2c_disable();  // both high with resistor pull-up
00557 }
00558 
00559 
00560 
00561 
00562 /* write a byte to the i2c interface , return acknowledge */
00563 int xi2c_outbyte(unsigned char d) { 
00564    int i;
00565    unsigned char x=d;   // make it non-destructive
00566   D(printk("outbyte: byte=%x\r\n",  (int) x));
00567 
00568    for (i = 0; i < 8; i++) { // assumed to be with SCL=0;
00569       xi2c_sda (x & 0x80); // checks only on non-zero, so no need to '>>'
00570 //portb_shadow
00571 //  D(printk("%x ",  (int) portb_shadow));
00572 
00573       xi2c_delay(XCLOCK_LOW_TIME/2);
00574       xi2c_scl (1);
00575       xi2c_delay(XCLOCK_HIGH_TIME);
00576       xi2c_scl (0);
00577       xi2c_delay(XCLOCK_LOW_TIME/2);
00578       x <<= 1;
00579    }
00580   D(printk("  "));
00581 
00582    /* enable input    */
00583 //   xi2c_dir_in();
00584    xi2c_sda (1);
00585    xi2c_delay(XCLOCK_LOW_TIME/2);
00586    xi2c_scl (1);
00587    xi2c_delay(XCLOCK_HIGH_TIME);
00588    i= (1-xi2c_getbit());
00589    xi2c_scl (0);
00590    xi2c_delay(XCLOCK_LOW_TIME/2);
00591   D(printk("ACK=%x ", i));
00592 
00593 
00594    return i;
00595 }
00596 
00597 /* read a byte from the i2c interface */
00598 
00599 unsigned char xi2c_inbyte(void) { // assumed SCL=0, SDA=X
00600    unsigned char aBitByte = 0;
00601    int i;
00602    /* enable input */
00603   D(printk("inbyte: "));
00604 
00605 //   xi2c_dir_in();
00606    xi2c_sda (1);
00607    /* get bits  */
00608    for (i = 0; i < 8; i++) {
00609       xi2c_delay(XCLOCK_LOW_TIME/2);
00610       /* low clock period   */
00611       xi2c_scl (1);
00612       xi2c_delay(XCLOCK_HIGH_TIME);
00613       aBitByte = (aBitByte << 1) | xi2c_getbit();
00614       xi2c_scl (0);
00615       xi2c_delay(XCLOCK_LOW_TIME/2);
00616    }
00617   D(printk(" data=%x\r\n", aBitByte));
00618    return aBitByte;  // returns with SCL=0, SDA - OFF
00619 }
00620 
00621 /*#---------------------------------------------------------------------------
00622 *#
00623 *# FUNCTION NAME: I2C::sendAck
00624 *#
00625 *# DESCRIPTION  : Send ACK on received data
00626 *#
00627 *#--------------------------------------------------------------------------*/
00628 void xi2c_sendack(void) {
00629     D(printk("sendack\r\n"));
00630 
00631       xi2c_sda (0);
00632       xi2c_delay(XCLOCK_LOW_TIME/2);
00633       xi2c_scl (1);
00634       xi2c_delay(XCLOCK_HIGH_TIME);
00635       xi2c_scl (0);
00636       xi2c_delay(XCLOCK_LOW_TIME/2);
00637 }
00638 
00639 /*#---------------------------------------------------------------------------
00640 *#
00641 *# FUNCTION NAME: fi2c_writeData
00642 *#
00643 *# DESCRIPTION  : Writes a sequence of bytes to an I2C device
00644 *# removed retries, will add test-ready later as a separate function
00645 *# removed all "dummy stuff" - I never needed that
00646 *#
00647 *#--------------------------------------------------------------------------*/
00648 int fi2c_writeData(unsigned char theSlave, unsigned char *theData, int size, int nostop) {
00649    int i,error=0;
00650    /* we don't like to be interrupted  *** WHY??? ***     */
00651    D3(printk("i2c_writeData:  theSlave=%x data=%x %x size=%x\r\n", theSlave, theData[0], theData[1], size));
00652    D(printk("writeData: %x %x %x %x\r\n", theSlave, theData[0], theData[1], size));
00653 
00654    /* generate start condition, test bus */
00655    if ((error=xi2c_start())) return error;
00656    /* send slave address, wait for ack */
00657    if(!xi2c_outbyte(theSlave)) {
00658        xi2c_stop();
00659        return ERR_I2C_BSY; // device does not exist or not ready
00660    }
00661 // OK, now send theData verifying ACK goes after each byte
00662    for (i=0;i<size;i++) {
00663       if(!xi2c_outbyte(theData[i])) {
00664          xi2c_stop();
00665          return ERR_I2C_NACK; // device failure
00666       }
00667    }
00668    if (nostop) xi2c_nostop();
00669    else xi2c_stop();
00670    return 0;
00671 }
00672 
00673 
00674 
00675 
00676 /*#---------------------------------------------------------------------------
00677 *#
00678 *# FUNCTION NAME: i2c_readData
00679 *#
00680 *# DESCRIPTION  : Reads a data from the i2c device, returns 0- OK, else - error code
00681 *#
00682 *#--------------------------------------------------------------------------*/
00683 
00684 int fi2c_readData(unsigned char theSlave, unsigned char *theData, int size) {
00685    int i, error=0;
00686    if ((error=xi2c_start())) return error;
00687    /* send slave address, wait for ack */
00688    D3(printk("i2c_readData:  theSlave=%x size=%x\r\n", theSlave, size));
00689    D(printk("readData:  %x %x\r\n", theSlave, size));
00690 
00691    if(!xi2c_outbyte(theSlave)) {
00692        xi2c_stop();
00693        return ERR_I2C_BSY; // device does not exist or not ready
00694    }
00695    for (i=0;i<size;i++) {
00696       theData[i]=xi2c_inbyte();
00697       xi2c_sendack();
00698    }
00699     xi2c_stop();
00700     return 0;
00701    
00702 }
00703 
00704 
00705 
00706 
00707 
00708 
00709 // for now - single register read/write only
00710 int fi2c_ioctl(struct inode *inode, struct file *file,
00711      unsigned int cmd, unsigned long arg) {
00712 //     unsigned char data[2];
00713      unsigned char data[10]; // for test purposes
00714 
00715      int error=0;
00716    D3(printk("i2c_ioctl cmd= %x, arg= %x\n\r",cmd,(int) arg));
00717    D3(printk("i2c_ioctl:  ((int *)file->private_data)[0]= %x\n\r",((int *)file->private_data)[0]));
00718    if(_IOC_TYPE(cmd) !=FPGA_CLOCK_IOCTYPE) {
00719       return -EINVAL;
00720    }
00721 
00722    switch (_IOC_NR(cmd)) {
00723       case FPGA_CLOCK_I2C_WRITEREG:
00724 
00725          /* write to an i2c slave */
00726          D3(printk("i2cw slave=%d, reg=%d, value=%d\n", 
00727              (int) I2C_ARGSLAVE(arg),
00728              (int) I2C_ARGREG(arg),
00729              (int) I2C_ARGVALUE(arg)));
00730          data[0]=I2C_ARGREG(arg);
00731          data[1]=I2C_ARGVALUE(arg);
00732          return -fi2c_writeData(I2C_ARGSLAVE(arg) & 0xfe, &data[0], 2,0); // stop at the end
00733       case FPGA_CLOCK_I2C_READREG:
00734       {
00735          /* read from an i2c slave */
00736          D3(printk("i2cr slave=%d, reg=%d ", 
00737              (int) I2C_ARGSLAVE(arg),
00738              (int) I2C_ARGREG(arg)));
00739 
00740          data[0]=I2C_ARGREG(arg);
00741          error=fi2c_writeData(I2C_ARGSLAVE(arg) & 0xfe, &data[0], 1,1); // nostop at the end
00742          if (error) return -error;
00743 
00744 //         error=fi2c_readData(I2C_ARGSLAVE(arg) | 0x01, &data[1], 1);
00745          error=fi2c_readData(I2C_ARGSLAVE(arg) | 0x01, &data[1], 8); // just testing
00746          if (error) return -error;
00747          D3(printk("returned %d\n", data[1]));
00748 
00749          return data[1];
00750       }
00751       default:
00752          return -EINVAL;
00753 
00754    }
00755    return 0;
00756 }
00757 
00758 
00759 int setCYField (int addr, int mask, int value) {
00760     unsigned char data[2];
00761     int error;
00762     data[0]=addr;
00763     error=fi2c_writeData(CY223933_SA,       &data[0], 1, 1); // nostop
00764     if (error) return -error;
00765     error=fi2c_readData(CY223933_SA | 0x01, &data[1], 1);
00766     if (error) return -error;
00767     data[1]^=(data[1] ^ (unsigned long) value) & (unsigned long) mask;
00768     error=fi2c_writeData(CY223933_SA,       &data[0], 2, 0); // stop
00769     return error;
00770 }
00771 
00772 int getClockFreq(int nclock) {
00773   if ((nclock <0) || (nclock >3)) return -1; // bad clock number
00774   else return clock_frequency[nclock];
00775 }
00776 //TODO: add one more clock 
00777 int setClockFreq(int nclock, int freq) { // freq now in Hz
00778   t_pll_params  pll_params;
00779   int i,bp,bq,bdiv,pllc,fact;
00780   bp=0; bq=0; bdiv=0; pllc= 0; // just to make gcc happy
00781   fact=0;
00782   D5(printk("setClockFreq(%d,%d)\r\n",nclock,freq));
00783   if ((freq!=0) && (nclock!=3) ){
00784     if ( (i=calc_pll_params (freq, &pll_params)) !=0) {
00785       printk("bad frequency for clock %d - %d Hz, err=%d\n",nclock,freq,i);
00786       return -2;
00787     }
00788     fact=CY22393_SCALE*(CY22393_XTAL*(pll_params.p+6)/(pll_params.q+2)/pll_params.dv);
00789     bp=  pll_params.p;    // (freqtab[freq]>>20)&0x7ff;
00790     bq=  pll_params.q;    // (freqtab[freq]>>12)&0xff;
00791     bdiv=pll_params.dv;   // (freqtab[freq]>> 4)&0xff;
00792     pllc=pll_params.corr; // freqtab[freq]     &0x0f;
00793 
00794 //    printk ("fpgaclocks353.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);
00795   }
00796   switch (nclock) {
00797        case 0: {
00798           if (freq==0) {
00799             setCYField (0x16, 0x40, 0x00); // turn off pll3
00800             setCYField (0x09, 0x7f, 0x00); // turn off divider- A
00801             setCYField (0x08, 0x7f, 0x00); // turn off divider- A
00802           } else {
00803           setCYField (0x16, 0x7f, 0x40+(pllc<<3)+((bp & 1)<<2)+((bp & 0x600)>>9) );
00804           setCYField (0x15, 0xff, ((bp & 0x1fe)>>1) );
00805           setCYField (0x14, 0xff, bq );
00806           setCYField (0x09, 0x7f, bdiv); // set divider- A
00807           setCYField (0x08, 0x7f, bdiv); // set divider- A
00808           setCYField (0x0e, 0x03, 0x03); // set PLL3 as source for ClkA
00809           }
00810           break;
00811        }
00812        case 1: {
00813           if (freq==0) {
00814             setCYField (0x0b, 0x7f, 0x00); // turn off divider- B
00815             setCYField (0x0a, 0x7f, 0x00); // turn off divider- B
00816             for (i=0;i<24;i+=3) setCYField (0x42+i, 0x40, 0x00); // turn off pll1
00817           } else {
00818 // progam all variants
00819             for (i=0;i<24;i+=3) {
00820               setCYField (0x42+i, 0x7f, 0x40+(pllc<<3)+((bp & 1)<<2)+((bp & 0x600)>>9) );
00821               setCYField (0x41+i, 0xff, ((bp & 0x1fe)>>1) );
00822               setCYField (0x40+i, 0xff, bq );
00823             }
00824             setCYField (0x0b, 0x7f, bdiv); // set divider- B
00825             setCYField (0x0a, 0x7f, bdiv); // set divider- B
00826             setCYField (0x0e, 0x0c, 0x04); // set PLL1 as source for ClkB
00827           }
00828           break;
00829        }
00830        case 2: {
00831           if (freq==0) {
00832             setCYField (0x13, 0x40, 0x00); // turn off pll2
00833             setCYField (0x0d, 0x7f, 0x00); // turn off divider- D
00834           } else {
00835             setCYField (0x13, 0x7f, 0x40+(pllc<<3)+((bp & 1)<<2)+((bp & 0x600)>>9) );
00836             setCYField (0x12, 0xff, ((bp & 0x1fe)>>1) );
00837             setCYField (0x11, 0xff, bq );
00838             setCYField (0x0d, 0x7f, bdiv); // set divider- D
00839             setCYField (0x0e, 0xc0, 0x80); // set PLL2 as source for ClkD
00840           }
00841           break;
00842        }
00843 
00844        case 3: {
00845          if ((freq!=0) && (freq!=CY22393_SCALE*CY22393_XTAL)) {
00846             printk("Only frequency 0 (off) and %d Hz (xtal) are allowed for channel 3\r\n",CY22393_SCALE*CY22393_XTAL);
00847             return -2;
00848           } else {
00849 //  int setCYField (int devfd, int addr, int mask, int value) O_RDWR
00850             if (freq==0) {
00851               setCYField (0x0f, 0x04, 0x00); 
00852             } else {
00853               setCYField (0x0f, 0x04, 0x04); 
00854               fact= CY22393_SCALE*CY22393_XTAL;
00855             }
00856           }
00857           break;
00858        }
00859        default: return -1; // wrong clock number
00860   }
00861   D5(printk("nclock=%d fact=%d\n",nclock,fact));
00862   clock_frequency[nclock]=fact;
00863   return fact;
00864 }
00865 
00866 
00867 
00868 //==============================================================================================================
00869 
00870 //============================= driver interface =========================
00871 
00872 static int fpga_clock_open(struct inode *inode, struct file *filp) {
00873    int p;
00874    p = MINOR(inode->i_rdev);
00875    D(printk("fpga_clock_open: minor=%x\r\n",p) );
00876    D(printk("filp=%lx\r\n",(unsigned long)filp) );
00877    switch ( p ) {
00878      case FPGA_CLOCK_MINOR_I2C :
00879      case FPGA_CLOCK_MINOR_CLOCKS :
00880       {
00881          if (minors[p])  return -EACCES;
00882          break;
00883       }
00884      default: return -EINVAL;
00885    }
00886    minors[p]=p;
00887    filp->private_data = &minors[p];
00888    return 0;
00889 }
00890 
00891 static int fpga_clock_release(struct inode *inode, struct file *filp) {
00892    int p = MINOR(inode->i_rdev);
00893    D(printk("fpga_clock_release:  done\r\n"));
00894    minors[p]=0;
00895    return 0;
00896 }
00897 
00898 static int fpga_clock_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {// switch by minor
00899 
00900    int res=0;
00901    D(printk("fpga_clock_ioctl cmd= %x, arg= %x\n\r",cmd,(int) arg));
00902    D5(printk("fpga_clock_ioctl cmd= %x, arg= %x, _IOC_TYPE(cmd)=%x, nclock=%x\n\r",cmd,(int) arg, (int) _IOC_TYPE(cmd), (int) (_IOC_NR(cmd) & 7)));
00903 
00904      switch (((int *)filp->private_data)[0]) {
00905 
00906        case FPGA_CLOCK_MINOR_I2C : 
00907            {
00908              res=fi2c_ioctl (inode, filp, cmd, arg);
00909              return res;
00910            }
00911        case FPGA_CLOCK_MINOR_CLOCKS : 
00912            {
00913              if(_IOC_TYPE(cmd) ==FPGA_CLOCK_IOCTYPE_RD)   return getClockFreq(_IOC_NR(cmd) & 7);
00914              else if(_IOC_TYPE(cmd) !=FPGA_CLOCK_IOCTYPE) return -EINVAL;
00915              res=setClockFreq(_IOC_NR(cmd) & 7, arg); //clock number, value in Hz
00916              if (res<0) return -EINVAL;
00917              else return res; // actual frequency  
00918            }
00919      default:return -EINVAL;
00920      }
00921 }
00922 
00923 //
00924 
00925 static int __init fpga_clock_init(void) {
00926    int i,res;
00927    res = register_chrdev(FPGA_CLOCK_MAJOR, fpga_clock_name, &fpga_clock_fops);
00928    if(res < 0) {
00929      printk(KERN_ERR "fpga_clock_init: couldn't get a major number.\n");
00930      return res;
00931    }
00932    printk(FPGA_CLOCK_DRIVER_NAME"\r\n");
00933    for (i=0;i<=FPGA_CLOCK_MAXMINOR;i++) minors[i]=0;
00934    initPortB();
00935 // Will initialize clocks in initscript
00936 //   setClockFreq(0, 125000000);
00937 //   setClockFreq(1,  20000000);
00938    fpga_state |= 0x10000; //mask 0xf0000
00939    return 0;
00940 }
00941 
00942 
00943 
00944 /* this makes sure that fpga_init is called during boot */
00945 
00946 module_init(fpga_clock_init);
00947 MODULE_LICENSE("GPL");
00948 MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
00949 MODULE_DESCRIPTION(FPGA_CLOCK_DRIVER_NAME);
00950 

Generated on Thu Aug 7 16:19:00 2008 for elphel by  doxygen 1.5.1