Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /*  $NetBSD: gti2c.c,v 1.2 2005/02/27 00:27:21 perry Exp $  */
0002 
0003 /*
0004  * Copyright (c) 2005 Brocade Communcations, inc.
0005  * All rights reserved.
0006  *
0007  * Written by Matt Thomas for Brocade Communcations, Inc.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  * 3. The name of Brocade Communications, Inc. may not be used to endorse
0018  *    or promote products derived from this software without specific prior
0019  *    written permission.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
0022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED.  IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
0031  * OF THE POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 /* Fixed many things + ported to RTEMS by Till Straumann, 2005 */
0035 
0036 #include <stdio.h>
0037 #include <rtems.h>
0038 #include <libcpu/io.h>
0039 #include <sys/errno.h>
0040 #include <rtems/bspIo.h>
0041 #include <rtems/score/sysstate.h>
0042 #include <bsp/irq.h>
0043 #include <rtems/libi2c.h>
0044 
0045 #include <sys/cdefs.h>
0046 
0047 #include <bsp/gtintrreg.h>
0048 #include <bsp/gti2creg.h>
0049 #include <bsp/gti2c_busdrv.h>
0050 
0051 #define ENABLE_IRQ_AT_PIC_HACK  /* workaround for a bad HW bug */
0052 #undef  DEBUG
0053 
0054 #ifndef BSP_IRQ_MIN_PRIO
0055 #define BSP_IRQ_MIN_PRIO 1
0056 #endif
0057 
0058 struct gti2c_softc {
0059     uint32_t    sc_gt;
0060     uint32_t    sc_cntl;
0061     int         sc_inited;
0062     rtems_id    sc_sync;
0063     int         sc_irqs; /* statistics */
0064 };
0065 
0066 #ifdef DEBUG
0067 #define STATIC
0068 #else
0069 #define STATIC static
0070 #endif
0071 
0072 typedef struct {
0073     rtems_libi2c_bus_t  bus_desc;   
0074     struct gti2c_softc  pvt;
0075 } gti2c_desc_rec, *gti2c_desc;
0076 
0077 STATIC rtems_status_code
0078 gt_i2c_init(rtems_libi2c_bus_t *bh);
0079 STATIC rtems_status_code
0080 gt_i2c_send_start(rtems_libi2c_bus_t *bh);
0081 STATIC rtems_status_code
0082 gt_i2c_send_stop(rtems_libi2c_bus_t *bh);
0083 STATIC rtems_status_code
0084 gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw);
0085 STATIC int
0086 gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
0087 STATIC int
0088 gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
0089 
0090 static rtems_libi2c_bus_ops_t myops = {
0091     init:           gt_i2c_init,
0092     send_start:     gt_i2c_send_start,
0093     send_stop:      gt_i2c_send_stop,
0094     send_addr:      gt_i2c_send_addr,
0095     read_bytes:     gt_i2c_read_bytes,
0096     write_bytes:    gt_i2c_write_bytes,
0097 };
0098 
0099 static gti2c_desc_rec my_bus_tbl = {
0100     {
0101         ops:    &myops,
0102         size:   sizeof(my_bus_tbl),
0103     },/* public fields */
0104     {
0105         sc_gt:      BSP_MV64x60_BASE,
0106         sc_cntl:    I2C_Control_TWSIEn,
0107         sc_inited:  0,
0108         sc_sync:    0
0109     } /* our private fields */
0110 };
0111 
0112 
0113 static inline uint32_t
0114 gt_read(uint32_t base, uint32_t off)
0115 {
0116     return in_le32((volatile uint32_t*)(base+off));
0117 }
0118 
0119 static inline void
0120 gt_write(uint32_t base, uint32_t off, uint32_t val)
0121 {
0122     out_le32((volatile uint32_t*)(base+off), val);
0123 }
0124 
0125 
0126 static inline void
0127 disable_irq(struct gti2c_softc *sc)
0128 {
0129 uint32_t v = gt_read(sc->sc_gt, I2C_REG_Control);
0130     gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn);
0131 }
0132 
0133 
0134 static rtems_status_code
0135 gt_i2c_wait(struct gti2c_softc *sc, uint32_t control, uint32_t desired_status)
0136 {
0137     uint32_t status;
0138     rtems_status_code rval;
0139 
0140     control |= I2C_Control_IntEn;
0141 
0142     gt_write(sc->sc_gt, I2C_REG_Control, control | sc->sc_cntl);
0143 
0144     if ( sc->sc_inited ) {
0145 
0146 #ifdef ENABLE_IRQ_AT_PIC_HACK
0147         BSP_enable_irq_at_pic(BSP_IRQ_I2C);
0148 #endif
0149 
0150         rval = rtems_semaphore_obtain(sc->sc_sync, RTEMS_WAIT, 100);
0151 
0152         if ( RTEMS_SUCCESSFUL != rval )
0153             return rval;
0154     } else {
0155         uint32_t then, now;
0156 
0157         /* run in polling mode - useful during init */
0158         if ( _System_state_Is_up(_System_state_Get()) ) {
0159             printk("WARNING: gti2c running in polled mode -- should initialize properly!\n");
0160         }
0161 
0162         asm volatile("mftb %0":"=r"(then));
0163 
0164         do {
0165             asm volatile("mftb %0":"=r"(now));
0166             /* poll timebase for .2 seconds assuming a bus clock of 100MHz */
0167             if ( now - then > (uint32_t)100000000/4/5 )
0168                 return RTEMS_TIMEOUT;
0169         } while ( ! (I2C_Control_IFlg & gt_read(sc->sc_gt, I2C_REG_Control)) );
0170     }
0171 
0172     status = gt_read(sc->sc_gt, I2C_REG_Status);
0173 
0174     if ( status != desired_status && (status!=I2C_Status_ReStarted || desired_status!=I2C_Status_Started) )
0175         return RTEMS_IO_ERROR;
0176 
0177     return RTEMS_SUCCESSFUL;
0178 }
0179 
0180 static void
0181 gt_i2c_intr(void *arg)
0182 {
0183 struct gti2c_softc * const sc = &my_bus_tbl.pvt;
0184     uint32_t v;
0185 
0186     v = gt_read(sc->sc_gt, I2C_REG_Control);
0187     if ((v & I2C_Control_IFlg) == 0) {
0188         printk("gt_i2c_intr: IRQ but IFlg not set??\n");
0189         return;
0190     }
0191     gt_write(sc->sc_gt, I2C_REG_Control, v & ~(I2C_Control_IntEn));
0192 #if 0
0193     gt_read(sc->sc_gt, I2C_REG_Control);
0194     asm volatile("sync");
0195 /* This is how bad it is: after turning off the IntEn bit, the line
0196  * still remains asserted! (shame on you.)
0197  *
0198  * The test below (on MVME6100; the MVME5500 has the same problem
0199  * but the main cause register address is different; substitute
0200  * 0xf100000c for 0xf1000c68 on a 5500).
0201  * 
0202  * The skew was 101 TB ticks or ~3us (bus freq 133MHz) which
0203  * really sucks.
0204  *
0205  * Therefore, we must disable the interrupt at the PIC 
0206  */
0207 {unsigned from,to;
0208     asm volatile("mftb %0":"=r"(from));
0209     while ( in_le32((volatile uint32_t*)0xf100000c) & 0x20 )
0210         ;
0211     asm volatile("mftb %0":"=r"(to));
0212     printk("I2C IRQ remained asserted for %i TB ticks!\n",to-from);
0213 }
0214 #endif
0215 #ifdef ENABLE_IRQ_AT_PIC_HACK
0216     BSP_disable_irq_at_pic(BSP_IRQ_I2C);
0217 #endif
0218 
0219     sc->sc_irqs++;
0220 
0221     rtems_semaphore_release(sc->sc_sync);
0222 }
0223 
0224 STATIC rtems_status_code
0225 gt_i2c_init(rtems_libi2c_bus_t *bh)
0226 {
0227 struct gti2c_softc * const  sc = &((gti2c_desc)bh)->pvt;
0228 unsigned                    m,n,N;
0229 
0230     disable_irq(sc);
0231 
0232     /* reset */
0233     gt_write(sc->sc_gt, I2C_REG_SoftReset, 0);
0234     gt_write(sc->sc_gt, I2C_REG_SlaveAddr, 0);
0235     gt_write(sc->sc_gt, I2C_REG_ExtSlaveAddr, 0);
0236 
0237     /* Set baud rate; I don't know the details
0238      * but have to assume that it has to fit into 7 bits
0239      * (as indicated by some experiment)
0240      */
0241     n = 0, N=1<<n;
0242     do {
0243         n++, N<<=1;
0244         /* increase 2^n until m becomes small enough */
0245         m = BSP_bus_frequency / 10 / 62500 / N;
0246     } while ( m > 16 );
0247 
0248     /* n is at least 1 */
0249     if ( n > 8 ) {
0250         n = 8; m = 16;  /* nothing else we can do */
0251     }
0252     if ( 0 == m )
0253         m = 1; /* nothing we can do */
0254 
0255     gt_write(sc->sc_gt, I2C_REG_BaudRate, I2C_BaudRate(m-1, n-1));
0256 
0257     if ( !sc->sc_inited ) { 
0258 
0259         if ( _System_state_Is_up(_System_state_Get()) ) {
0260             rtems_irq_connect_data ii = {
0261                 name:   BSP_IRQ_I2C,
0262                 hdl:    gt_i2c_intr,
0263                 on:     0,
0264                 off:    0,
0265                 isOn:   0
0266             };
0267             rtems_status_code err;
0268             /* synchronization semaphore */
0269             err = rtems_semaphore_create(
0270                     rtems_build_name('g','i','2','c'),
0271                     0, 
0272                     RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL,
0273                     0,
0274                     &sc->sc_sync);
0275             if ( err ) {
0276                 sc->sc_sync = 0;
0277                 return err;
0278             }
0279             if ( !BSP_install_rtems_irq_handler(&ii) ) {
0280                 fprintf(stderr,"Unable to install interrupt handler\n");
0281                 rtems_semaphore_delete(sc->sc_sync);
0282                 return RTEMS_INTERNAL_ERROR;
0283             }
0284             BSP_irq_set_priority(BSP_IRQ_I2C, BSP_IRQ_MIN_PRIO);
0285             sc->sc_inited = 1;
0286         } else {
0287         }
0288     } else {
0289         rtems_semaphore_flush(sc->sc_sync);
0290     }
0291     return RTEMS_SUCCESSFUL;
0292 }
0293 
0294 STATIC rtems_status_code
0295 gt_i2c_send_start(rtems_libi2c_bus_t *bh)
0296 {
0297 struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
0298 
0299     return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started);
0300 }
0301 
0302 STATIC rtems_status_code
0303 gt_i2c_send_stop(rtems_libi2c_bus_t *bh)
0304 {
0305 struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
0306 uint32_t    data;
0307 
0308     data = gt_read(sc->sc_gt, I2C_REG_Status);
0309     if ( I2C_Status_Started == data || I2C_Status_ReStarted == data ) {
0310         /* According to the spec, a void message (start - stop sequence)
0311          * is illegal and indeed, the chip plays bad tricks with us, i.e.,
0312          * sometimes it hangs the bus so that it remains idle forever.
0313          * so we have to address someone...
0314          */
0315         gt_i2c_send_addr(bh, /*just something... */ 8, 1);
0316         data = gt_read(sc->sc_gt, I2C_REG_Status);
0317     }
0318 
0319     if ( I2C_Status_AddrReadAck == data ) {
0320         /* Another thing: spec says that the master generates stop only after
0321          * not acknowledging the last byte. Again, the chip doesn't like
0322          * to be stopped in this condition - hence we just do it the favor
0323          * and read a single byte...
0324          */
0325         gt_i2c_read_bytes(bh, (unsigned char *)&data, 1);
0326     }
0327 
0328     gt_write(sc->sc_gt, I2C_REG_Control, I2C_Control_Stop | sc->sc_cntl);
0329 
0330     /* should we poll for idle? There seems to be in IRQ when this completes */
0331     return RTEMS_SUCCESSFUL;
0332 }
0333 
0334 STATIC rtems_status_code
0335 gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw)
0336 {
0337 struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
0338 uint32_t data, wanted_status;
0339 uint8_t read_mask = rw ? 1 : 0;
0340 rtems_status_code error;
0341 
0342     if (read_mask) {
0343         wanted_status = I2C_Status_AddrReadAck;
0344     } else {
0345         wanted_status = I2C_Status_AddrWriteAck;
0346     }
0347     /*
0348      * First byte contains whether this xfer is a read or write.
0349      */
0350     data = read_mask;
0351     if (addr > 0x7f) {
0352         /*
0353          * If this is a 10bit request, the first address byte is
0354          * 0b11110<b9><b8><r/w>.
0355          */
0356         data |= 0xf0 | ((addr & 0x300) >> 7);
0357         gt_write(sc->sc_gt, I2C_REG_Data, data);
0358         error = gt_i2c_wait(sc, 0, wanted_status);
0359         if (error)
0360             return error;
0361         /*
0362          * The first address byte has been sent, now to send
0363          * the second one.
0364          */
0365         if (read_mask) {
0366             wanted_status = I2C_Status_2ndAddrReadAck;
0367         } else {
0368             wanted_status = I2C_Status_2ndAddrWriteAck;
0369         }
0370         data = (uint8_t) addr;
0371     } else {
0372         data |= (addr << 1);
0373     }
0374 
0375     gt_write(sc->sc_gt, I2C_REG_Data, data);
0376     return gt_i2c_wait(sc, 0, wanted_status);
0377 }
0378 
0379 STATIC int
0380 gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
0381 {
0382 struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
0383 rtems_status_code error;
0384 register unsigned char *p=buf;
0385 
0386     while ( len-- > 0 ) {
0387         error = gt_i2c_wait(
0388                     sc,
0389                     len ? I2C_Control_ACK : 0,
0390                     len ? I2C_Status_MasterReadAck : I2C_Status_MasterReadNoAck);
0391         if ( error ) {
0392             return -error;
0393         }
0394         *p++ = gt_read(sc->sc_gt, I2C_REG_Data);
0395     }
0396 
0397     return p-buf;
0398 }
0399 
0400 STATIC int
0401 gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
0402 {
0403 struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
0404 int rval = 0;
0405 rtems_status_code error;
0406 
0407     while ( len-- > 0 ) {
0408         gt_write(sc->sc_gt, I2C_REG_Data, buf[rval]);
0409         error = gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck);
0410         if ( error ) {
0411             return -error;
0412         }
0413         rval++;
0414     }
0415 
0416     return rval;
0417 }
0418 
0419 rtems_libi2c_bus_t *gt64260_i2c_bus_descriptor = &my_bus_tbl.bus_desc;
0420 
0421 #ifdef DEBUG_MODULAR
0422 
0423 void
0424 _cexpModuleInitialize(void *arg)
0425 {
0426     gt_i2c_init(&gt64260_i2c_bus_descriptor->bus_desc);
0427 }
0428 
0429 int
0430 _cexpModuleFinalize(void * arg)
0431 {
0432 struct gti2c_softc * const sc = &gt64260_i2c_bus_descriptor->pvt;
0433 
0434     rtems_irq_connect_data ii = {
0435             name:   BSP_IRQ_I2C,
0436             hdl:    gt_i2c_intr,
0437             on:     noop,
0438             off:    noop,
0439             isOn:   inoop
0440     };
0441 
0442     rtems_semaphore_delete(sc->sc_sync);
0443 
0444     return !BSP_remove_rtems_irq_handler(&ii);
0445 }
0446 
0447 #endif