Main Page   Modules   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

/projects/cubeos/src_current/drivers/i2c/i2cd.c

Go to the documentation of this file.
00001 /*  src_experimental/drivers/i2c/i2cd.c
00002    CubeOS Version 0.4.90 experimental
00003    Copyright (C) 1999,2000 Holger Kenn
00004 
00005    CubeOS is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or any later version.
00009 
00010    CubeOS is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015  */
00016 #include <cubeos.h>
00017 #include <mc68332.h>
00018 #include <ivtab.h>
00019 #include <i2cd.h>
00020 #include <pcf8584.h>
00021 #include <stdio.h>
00022 
00030 struct i2c i2c[2];
00031 
00038 static void GenerateStop (struct i2c *p, unsigned char mess)
00039 {
00040         p->m_state = MASTER_IDLE;
00041         p->m_buff[p->m_tail]->status = mess;    /* still ptr of finished msg */
00042         p->m_buff[p->m_tail]->procBytes = p->m_dcnt;
00043         if (++p->m_tail >= MBUFLEN)
00044                 p->m_tail = 0;
00045         p->m_cnt--;
00046         ssem_signal (p->m_sem);
00047 
00048         /* check for further entries in output buffer */
00049 
00050         if (p->m_cnt == 0) {
00051                 p->mode = I2C_SLAVE_MODE;
00052         } else {
00053                 (p->m_state_handler) (p);
00054         }
00055 }
00056 
00062 void _I2C_master_handler (struct i2c *p)
00063 {
00064         struct i2c_device *dev;
00065         struct i2cmess *msg;
00066         unsigned long timeoutcnt;
00067         unsigned char dummy;
00068 
00069         dev = p->ioaddr;
00070         msg = p->m_buff[p->m_tail];
00071 
00072         switch (p->m_state) {
00073         case MASTER_IDLE:
00074                 timeoutcnt = I2C_TIMEOUT_VAL;
00075                 while (!(dev->control & BB) && timeoutcnt--);   /* wait until bus
00076                                                                    free */
00077                 if (timeoutcnt) {
00078                         p->m_dcnt = 0;
00079                         p->m_state = (msg->address & 1) ? MASTER_WAIT_ACK : MASTER_SEND;
00080                         dev->data = msg->address;
00081                         dev->control = PIN | ESO | ENI | STA | ACK;     /* generate
00082                                                                            start */
00083                 } else {
00084                         GenerateStop (p, I2C_TIME_OUT);
00085                 }
00086                 return;
00087         case MASTER_SEND:
00088                 if (dev->control & LAB) {       /* arbitration was lost */
00089                         p->mode = I2C_SLAVE_MODE;
00090                         (p->s_state_handler) (p);       /* check if addressed as slave */
00091                         p->mode = I2C_MASTER_MODE;
00092                         GenerateStop (p, I2C_ARBITRATION_LOST);         /* leave the bus */
00093                         return;
00094                 }
00095                 if (dev->control & LRB) {
00096                         dev->control = PIN | ESO | ENI | STO | ACK;
00097                         GenerateStop (p, I2C_NACK_ON_DATA);     /* last byte not
00098                                                                    ack'ed */
00099                 } else if (p->m_dcnt < msg->nrBytes)
00100                         dev->data = msg->buf[p->m_dcnt++];      /* send next byte */
00101                 else {
00102                         dev->control = PIN | ESO | ENI | STO | ACK;
00103                         GenerateStop (p, I2C_OK);       /* transfer ready */
00104                 }
00105                 break;
00106         case MASTER_WAIT_ACK:
00107                 if (dev->control & LAB) {       /* arbitration was lost */
00108                         p->mode = I2C_SLAVE_MODE;
00109                         (p->s_state_handler) (p);       /* check if addressed as slave */
00110                         p->mode = I2C_MASTER_MODE;
00111                         GenerateStop (p, I2C_ARBITRATION_LOST);         /* leave the bus */
00112                         return;
00113                 }
00114                 if (dev->control & LRB) {
00115                         dev->control = PIN | ESO | ENI | STO | ACK;
00116                         GenerateStop (p, I2C_NACK_ON_ADDRESS);
00117                 } else {
00118                         if (msg->nrBytes == 1) {
00119                                 p->m_state = MASTER_RECV_LAST;
00120                                 dev->control = ESO | ENI;
00121                         } else {
00122                                 p->m_state = MASTER_RECV;
00123                         }
00124                         dummy = dev->data;      /* start generation of clock pulses for the
00125                                                    first byte to read        */
00126                 }
00127                 break;
00128         case MASTER_RECV:
00129                 if (p->m_dcnt + 2 == msg->nrBytes) {
00130                         dev->control = ESO | ENI;       /* clear ACK */
00131                         p->m_state = MASTER_RECV_LAST;
00132                 }
00133                 msg->buf[p->m_dcnt++] = dev->data;
00134                 break;
00135         case MASTER_RECV_LAST:
00136                 dev->control = PIN | ESO | ENI | STO | ACK;
00137                 msg->buf[p->m_dcnt++] = dev->data;
00138                 GenerateStop (p, I2C_OK);       /* transfer ready */
00139                 break;
00140         default:                /* impossible, just to be sure */
00141                 GenerateStop (p, I2C_ERR);
00142                 break;
00143         }
00144 }
00145 
00146 
00152 void _I2C_slave_handler (struct i2c *p)
00153 {
00154         register struct i2c_device *dev;
00155 
00156         dev = p->ioaddr;
00157 
00158         switch (p->s_state) {
00159         case SLAVE_IDLE:
00160                 if (dev->control & AAS) {       /* addressed as slave ? */
00161                         if (dev->data & 1) {    /* slave transmitter */
00162                                 p->s_state = SLAVE_SEND;
00163                         } else {        /* slave receiver */
00164                                 if (p->s_icnt >= SBUFLEN) {
00165                                         p->s_status |= I2C_SLAVE_IBUF_OVERFLOW;
00166                                         dev->control = PIN | ESO | ENI;
00167                                         ssem_signal (p->s_isem);
00168                                 } else {
00169                                         p->s_state = SLAVE_RECV;
00170                                 }
00171                         }
00172                 } else {        /* clear interupt */
00173                         dev->control = PIN | ESO | ENI;
00174                 }
00175                 return;
00176         case SLAVE_SEND:
00177                 if (dev->control & LRB) {       /* no ack from master */
00178                         p->s_state = SLAVE_IDLE;
00179                         ssem_signal (p->s_osem);
00180                 }
00181                 if (p->s_ocnt == 0) {
00182                         dev->data = 0xff;
00183                         p->s_status |= I2C_SLAVE_OBUF_EMPTY;
00184                 } else {
00185                         dev->data = p->s_obuff[p->s_optr++];
00186                         p->s_ocnt--;
00187                 }
00188                 return;
00189         case SLAVE_RECV:
00190                 if (dev->control & STS) {       /* STOP detected */
00191                         p->s_state = SLAVE_IDLE;
00192                         dev->control = PIN | ESO | ENI | ACK;
00193                         ssem_signal (p->s_isem);
00194                 } else if (p->s_icnt == SBUFLEN) {
00195                         dev->control = PIN | ESO | ENI;         /* clear ACK */
00196                         p->s_state = SLAVE_IDLE;
00197                         ssem_signal (p->s_isem);
00198                 } else {
00199                         p->s_ibuff[p->s_iptr++] = dev->data;
00200                         p->s_icnt++;
00201                 }
00202                 return;
00203         default:
00204                 dev->control = PIN | ESO | ENI | ACK;   /* clear interrupt */
00205                 p->s_status |= I2C_SLAVE_ERR;
00206                 return;
00207         }
00208 }
00209 
00220 void I2C_inthandler (unsigned long minor)
00221 {
00222         struct i2c *p;
00223 
00224         p = &i2c[minor];
00225         if (p->mode == I2C_MASTER_MODE)
00226                 (p->m_state_handler) (p);       /* Master Mode */
00227         else
00228                 (p->s_state_handler) (p);       /* Slave Mode  */
00229 }
00230 
00237 int I2C_init (int which, unsigned long ioaddr)
00238 {
00239         register struct i2c *iptr;
00240         register struct i2c_device *chip;
00241         unsigned short v;
00242 
00243         printf("I2C init called\n");
00244         /* set up interrupt vector and interrupt dispatch table */
00245         if (which == I2CA) {
00246                 if (I2CA_BASE == 0)
00247                         return (-1);
00248 
00249 
00250                 _KERN_IVTab_setvector (I2CA_VECTORNUM, I2C_int_a);
00251 
00252 #ifdef I2C_INITCSA
00253                 if (I2C_INITCSA) {
00254                         writeshort (SIM_CSBAR4, ioaddr >> 8);   /* CS4: (2k) -- I2C-A */
00255                         writeshort (SIM_CSOR4, 0x7ffa);         /* ASYNC,H+L,R/W,DS,DSACK
00256                                                                    EXT,S+U SP */
00257                         v = readshort (SIM_CSPAR0);
00258                         v |= 0xc00;
00259                         v &= 0xfbff;
00260                         writeshort (SIM_CSPAR0, v);     /* enables CS4 as 8 bit port */
00261                 }
00262 #endif
00263                 iptr = &(i2c[0]);
00264         } else if (which == I2CB) {
00265                 if (I2CB_BASE == 0)
00266                         return (-1);
00267                 _KERN_IVTab_setvector (I2CB_VECTORNUM, I2C_int_b);
00268 
00269 #ifdef I2C_INITCSB
00270                 if (I2C_INITCSB) {
00271                         writeshort (SIM_CSBAR3, ioaddr >> 8);   /* CS3: (2k) -- I2C-B */
00272                         writeshort (SIM_CSOR3, 0x7ffa);         /* ASYNC,H+L,R/W,DS,DSACK
00273                                                                    EXT,S+U SP */
00274                         v = readshort (SIM_CSPAR0);
00275                         v |= 0x300;
00276                         v &= 0xfeff;
00277                         writeshort (SIM_CSPAR0, v);     /* enables CS3 as 8 bit port */
00278                 }
00279 #endif
00280                 iptr = &(i2c[1]);
00281         } else
00282                 return (-1);
00283 
00284         /* fill i2c control blk       */
00285         iptr->ioaddr = (struct i2c_device *) ioaddr;    /* chip address */
00286         iptr->mode = I2C_SLAVE_MODE;
00287         iptr->m_head = iptr->m_tail = 0;        /* empty input queue */
00288         /* iptr->m_isem = screate(0); */
00289         iptr->m_sem = MBUFLEN;
00290         iptr->m_cnt = 0;
00291         iptr->m_dcnt = 0;
00292         iptr->m_state_handler = &_I2C_master_handler;
00293         iptr->m_state = MASTER_IDLE;
00294 
00295         iptr->s_iptr = 0;
00296         iptr->s_isem = 0;
00297         iptr->s_icnt = 0;
00298         iptr->s_optr = 0;
00299         iptr->s_osem = 0;
00300         iptr->s_ocnt = 0;
00301         iptr->s_state_handler = &_I2C_slave_handler;
00302         iptr->s_state = SLAVE_IDLE;
00303         iptr->s_status = 0;
00304 
00305         /* set up the chip */
00306         chip = iptr->ioaddr;
00307         chip->control = 0x80;   /* software reset            */
00308         if (which == I2CA)
00309                 chip->data = I2CA_SLAVE_ADDR;   /* write own slave address   */
00310         else
00311                 chip->data = I2CB_SLAVE_ADDR;   /* write own slave address   */
00312         chip->control = 0xa0;   /* write clock register      */
00313         chip->data = I2C_SPEED;
00314         chip->control = PIN | ESO | ENI | ACK;  /* enable i2c bus interface  */
00315         return (0);
00316 }
00317 
00318 /************* Interface functions *******************/
00319 
00326 int I2C_Start_I2C_Transfer (unsigned char which, struct i2cmess *msg)
00327 {
00328         struct i2c *hdl;
00329         int timeout;
00330 
00331         if (which == I2CA)
00332                 hdl = &i2c[0];
00333         else
00334                 hdl = &i2c[1];
00335 
00336         if (!(hdl->ioaddr)) {
00337                 msg->status = I2C_NO_BUS;
00338                 return (-1);
00339         }
00340         /* insert message in queue    */
00341         msg->status = I2C_NOT_PROCESSED;
00342         ssem_wait (hdl->m_sem);
00343         hdl->m_buff[hdl->m_head++] = msg;
00344         ++hdl->m_cnt;
00345         if (hdl->m_head >= MBUFLEN)
00346                 hdl->m_head = 0;
00347 
00348         /* Start Transfer if necessary */
00349         if ((hdl->mode == I2C_SLAVE_MODE) && (hdl->s_state == SLAVE_IDLE)) {
00350                 hdl->mode = I2C_MASTER_MODE;
00351                 disable ();
00352                 (hdl->m_state_handler) (hdl);   /* handler returns here */
00353                 enable ();
00354         }
00355         timeout = 0;
00356         while ((msg->status == I2C_NOT_PROCESSED) && (++timeout < 1000000));
00357         if (timeout > 0)
00358                 return (-1);
00359 
00360         switch (msg->status) {
00361         case I2C_OK:
00362                 return (0);
00363                 break;
00364         case I2C_NACK_ON_DATA:
00365                 return (-1);
00366                 break;
00367         case I2C_NACK_ON_ADDRESS:
00368                 return (-1);
00369                 break;
00370         case I2C_ARBITRATION_LOST:
00371                 return (-1);
00372                 break;
00373         case I2C_TIME_OUT:
00374                 return (-1);
00375                 break;
00376         case I2C_ERR:
00377                 return (-1);
00378                 break;
00379         default:
00380                 return (-1);
00381                 break;
00382         }
00383 
00384 }
00385 
00392 int I2C_slprocess (unsigned char which, struct i2cmess *msg)
00393 {
00394         struct i2c *hdl;
00395         int i;
00396 
00397         if (which == I2CA)
00398                 hdl = &i2c[0];
00399         else
00400                 hdl = &i2c[1];
00401 
00402         if (!(hdl->ioaddr)) {
00403                 msg->status = I2C_NO_BUS;
00404                 return (-1);
00405         }
00406         /* insert message in queue    */
00407         msg->status = I2C_NOT_PROCESSED;
00408 
00409         if (msg->nrBytes != SBUFLEN)
00410                 return (-1);
00411 
00412         if (msg->address & 1) { /* read */
00413                 ssem_wait (hdl->s_isem);
00414                 disable ();
00415                 for (i = 0; i < hdl->s_icnt; i++)
00416                         msg->buf[i] = hdl->s_ibuff[i];
00417                 msg->procBytes = hdl->s_icnt;
00418                 hdl->s_icnt = 0;
00419                 hdl->s_iptr = 0;
00420                 if (hdl->s_status == 0)
00421                         msg->status = I2C_OK;
00422                 if (hdl->s_status & I2C_SLAVE_IBUF_OVERFLOW) {
00423                         msg->status = I2C_ERR;
00424                         hdl->s_status &= ~I2C_SLAVE_IBUF_OVERFLOW;
00425                 }
00426                 enable ();
00427         } else {                /* write */
00428                 disable ();
00429                 for (i = 0; i < SBUFLEN; i++)
00430                         hdl->s_obuff[i] = msg->buf[i];
00431                 hdl->s_ocnt = SBUFLEN;
00432                 hdl->s_optr = 0;
00433                 enable ();
00434                 ssem_wait (hdl->s_osem);
00435                 disable ();
00436                 msg->procBytes = hdl->s_ocnt;
00437                 hdl->s_ocnt = 0;
00438                 hdl->s_optr = 0;
00439                 if (hdl->s_status == 0)
00440                         msg->status = I2C_OK;
00441                 if (hdl->s_status & I2C_SLAVE_OBUF_EMPTY) {
00442                         msg->status = I2C_ERR;
00443                         hdl->s_status &= ~I2C_SLAVE_OBUF_EMPTY;
00444                 }
00445                 enable ();
00446         }
00447         return (0);
00448 }
00449 
00457 int I2C_process (unsigned char whichBus, unsigned char whichQueue, struct i2cmess *msg)
00458 {
00459         if (whichQueue == I2C_MASTER)
00460                 return I2C_Start_I2C_Transfer (whichBus, msg);
00461         else
00462                 return I2C_slprocess (whichBus, msg);
00463 }
00464 
00465 
00474 int I2C_messagestatus (struct i2cmess *msg)
00475 {
00476         switch (msg->status) {
00477         case I2C_OK:
00478                 return (0);
00479                 break;
00480         case I2C_NACK_ON_DATA:
00481                 printf ("I2C: transfer interupted\n");
00482                 return (-1);
00483                 break;
00484         case I2C_NACK_ON_ADDRESS:
00485                 printf ("I2C: device not present\n");
00486                 return (-1);
00487                 break;
00488         case I2C_ARBITRATION_LOST:
00489                 printf ("I2C: arbitration lost\n");
00490                 return (-1);
00491                 break;
00492         case I2C_TIME_OUT:
00493                 printf ("I2C: time-out\n\r");
00494                 return (-1);
00495                 break;
00496         case I2C_ERR:
00497                 printf ("I2C: master handler in strange state\n");
00498                 return (-1);
00499                 break;
00500         case I2C_NO_BUS:
00501                 printf ("I2C: there is no such bus\n");
00502                 return (-1);
00503                 break;
00504         default:
00505                 printf ("I2C: unknown status (%d)\n\r", msg->status);
00506                 return (-1);
00507                 break;
00508         }
00509 
00510 }
00511 
00517 int I2C_scanbus (unsigned char bus)
00518 {
00519 
00520         struct i2cmess msg;
00521         unsigned char buf[10];
00522         int i, j;
00523         int count = 0;
00524         int ret;
00525 
00526         for (i = 0; i < 127; i++) {
00527 
00528                 msg.address = i << 1;
00529                 msg.nrBytes = 1;
00530                 msg.buf = buf;
00531                 for (j = 0; j < 10; j++)
00532                         buf[j] = 0;
00533 
00534                 ret = I2C_process (bus, I2C_MASTER, &msg);
00535 
00536                 switch (msg.status) {
00537                 case I2C_OK:
00538                         printf ("found device at adress 0x%x \n", msg.address);
00539                         count++;
00540                         break;
00541                 case I2C_TIME_OUT:
00542                 case I2C_NACK_ON_ADDRESS:
00543                 case I2C_NACK_ON_DATA:
00544                         printf (".");
00545                         fflush (stdout);
00546                         break;
00547                 case I2C_NO_BUS:
00548                         I2C_messagestatus (&msg);
00549                         return (-1);
00550                         break;
00551                 default:
00552                         I2C_messagestatus (&msg);
00553                 }
00554 
00555         }
00556         return (count);
00557 }

Generated on Thu Feb 20 15:38:43 2003 for cubeOS by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002