(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/omap_i2c.c

    1: /*
    2:  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
    3:  *
    4:  * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
    5:  *
    6:  * This program is free software; you can redistribute it and/or
    7:  * modify it under the terms of the GNU General Public License as
    8:  * published by the Free Software Foundation; either version 2 of
    9:  * the License, or (at your option) any later version.
   10:  *
   11:  * This program is distributed in the hope that it will be useful,
   12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:  * GNU General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU General Public License
   17:  * along with this program; if not, write to the Free Software
   18:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   19:  * MA 02111-1307 USA
   20:  */
   21: #include "hw.h"
   22: #include "i2c.h"
   23: #include "omap.h"
   24: 
   25: struct omap_i2c_s {
   26:     target_phys_addr_t base;
   27:     qemu_irq irq;
   28:     qemu_irq drq[2];
   29:     i2c_slave slave;
   30:     i2c_bus *bus;
   31: 
   32:     uint8_t mask;
   33:     uint16_t stat;
   34:     uint16_t dma;
   35:     uint16_t count;
   36:     int count_cur;
   37:     uint32_t fifo;
   38:     int rxlen;
   39:     int txlen;
   40:     uint16_t control;
   41:     uint16_t addr[2];
   42:     uint8_t divider;
   43:     uint8_t times[2];
   44:     uint16_t test;
   45: };
   46: 
   47: static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
   48: {
   49:     qemu_set_irq(s->irq, s->stat & s->mask);
   50:     if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
   51:         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
   52:     if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
   53:         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
   54: }
   55: 
   56: /* These are only stubs now.  */
   57: static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
   58: {
   59:     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
   60: 
   61:     if ((~s->control >> 15) & 1)                                /* I2C_EN */
   62:         return;
   63: 
   64:     switch (event) {
   65:     case I2C_START_SEND:
   66:     case I2C_START_RECV:
   67:         s->stat |= 1 << 9;                                      /* AAS */
   68:         break;
   69:     case I2C_FINISH:
   70:         s->stat |= 1 << 2;                                      /* ARDY */
   71:         break;
   72:     case I2C_NACK:
   73:         s->stat |= 1 << 1;                                      /* NACK */
   74:         break;
   75:     }
   76: 
   77:     omap_i2c_interrupts_update(s);
   78: }
   79: 
   80: static int omap_i2c_rx(i2c_slave *i2c)
   81: {
   82:     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
   83:     uint8_t ret = 0;
   84: 
   85:     if ((~s->control >> 15) & 1)                                /* I2C_EN */
   86:         return -1;
   87: 
   88:     if (s->txlen)
   89:         ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
   90:     else
   91:         s->stat |= 1 << 10;                                     /* XUDF */
   92:     s->stat |= 1 << 4;                                          /* XRDY */
   93: 
   94:     omap_i2c_interrupts_update(s);
   95:     return ret;
   96: }
   97: 
   98: static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
   99: {
  100:     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
  101: 
  102:     if ((~s->control >> 15) & 1)                                /* I2C_EN */
  103:         return 1;
  104: 
  105:     if (s->rxlen < 4)
  106:         s->fifo |= data << ((s->rxlen ++) << 3);
  107:     else
  108:         s->stat |= 1 << 11;                                     /* ROVR */
  109:     s->stat |= 1 << 3;                                          /* RRDY */
  110: 
  111:     omap_i2c_interrupts_update(s);
  112:     return 1;
  113: }
  114: 
  115: static void omap_i2c_fifo_run(struct omap_i2c_s *s)
  116: {
  117:     int ack = 1;
  118: 
  119:     if (!i2c_bus_busy(s->bus))
  120:         return;
  121: 
  122:     if ((s->control >> 2) & 1) {                                /* RM */
  123:         if ((s->control >> 1) & 1) {                            /* STP */
  124:             i2c_end_transfer(s->bus);
  125:             s->control &= ~(1 << 1);                            /* STP */
  126:             s->count_cur = s->count;
  127:         } else if ((s->control >> 9) & 1) {                     /* TRX */
  128:             while (ack && s->txlen)
  129:                 ack = (i2c_send(s->bus,
  130:                                         (s->fifo >> ((-- s->txlen) << 3)) &
  131:                                         0xff) >= 0);
  132:             s->stat |= 1 << 4;                                  /* XRDY */
  133:         } else {
  134:             while (s->rxlen < 4)
  135:                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  136:             s->stat |= 1 << 3;                                  /* RRDY */
  137:         }
  138:     } else {
  139:         if ((s->control >> 9) & 1) {                            /* TRX */
  140:             while (ack && s->count_cur && s->txlen) {
  141:                 ack = (i2c_send(s->bus,
  142:                                         (s->fifo >> ((-- s->txlen) << 3)) &
  143:                                         0xff) >= 0);
  144:                 s->count_cur --;
  145:             }
  146:             if (ack && s->count_cur)
  147:                 s->stat |= 1 << 4;                              /* XRDY */
  148:             if (!s->count_cur) {
  149:                 s->stat |= 1 << 2;                              /* ARDY */
  150:                 s->control &= ~(1 << 10);                       /* MST */
  151:             }
  152:         } else {
  153:             while (s->count_cur && s->rxlen < 4) {
  154:                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  155:                 s->count_cur --;
  156:             }
  157:             if (s->rxlen)
  158:                 s->stat |= 1 << 3;                              /* RRDY */
  159:         }
  160:         if (!s->count_cur) {
  161:             if ((s->control >> 1) & 1) {                        /* STP */
  162:                 i2c_end_transfer(s->bus);
  163:                 s->control &= ~(1 << 1);                        /* STP */
  164:                 s->count_cur = s->count;
  165:             } else {
  166:                 s->stat |= 1 << 2;                              /* ARDY */
  167:                 s->control &= ~(1 << 10);                       /* MST */
  168:             }
  169:         }
  170:     }
  171: 
  172:     s->stat |= (!ack) << 1;                                     /* NACK */
  173:     if (!ack)
  174:         s->control &= ~(1 << 1);                                /* STP */
  175: }
  176: 
  177: void omap_i2c_reset(struct omap_i2c_s *s)
  178: {
  179:     s->mask = 0;
  180:     s->stat = 0;
  181:     s->dma = 0;
  182:     s->count = 0;
  183:     s->count_cur = 0;
  184:     s->fifo = 0;
  185:     s->rxlen = 0;
  186:     s->txlen = 0;
  187:     s->control = 0;
  188:     s->addr[0] = 0;
  189:     s->addr[1] = 0;
  190:     s->divider = 0;
  191:     s->times[0] = 0;
  192:     s->times[1] = 0;
  193:     s->test = 0;
  194: }
  195: 
  196: static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
  197: {
  198:     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
  199:     int offset = addr & OMAP_MPUI_REG_MASK;
  200:     uint16_t ret;
  201: 
  202:     switch (offset) {
  203:     case 0x00:  /* I2C_REV */
  204:         /* TODO: set a value greater or equal to real hardware */
  205:         return 0x11;                                            /* REV */
  206: 
  207:     case 0x04:  /* I2C_IE */
  208:         return s->mask;
  209: 
  210:     case 0x08:  /* I2C_STAT */
  211:         return s->stat | (i2c_bus_busy(s->bus) << 12);
  212: 
  213:     case 0x0c:  /* I2C_IV */
  214:         ret = ffs(s->stat & s->mask);
  215:         if (ret)
  216:             s->stat ^= 1 << (ret - 1);
  217:         omap_i2c_interrupts_update(s);
  218:         return ret;
  219: 
  220:     case 0x14:  /* I2C_BUF */
  221:         return s->dma;
  222: 
  223:     case 0x18:  /* I2C_CNT */
  224:         return s->count_cur;                                    /* DCOUNT */
  225: 
  226:     case 0x1c:  /* I2C_DATA */
  227:         ret = 0;
  228:         if (s->control & (1 << 14)) {                           /* BE */
  229:             ret |= ((s->fifo >> 0) & 0xff) << 8;
  230:             ret |= ((s->fifo >> 8) & 0xff) << 0;
  231:         } else {
  232:             ret |= ((s->fifo >> 8) & 0xff) << 8;
  233:             ret |= ((s->fifo >> 0) & 0xff) << 0;
  234:         }
  235:         if (s->rxlen == 1) {
  236:             s->stat |= 1 << 15;                                 /* SBD */
  237:             s->rxlen = 0;
  238:         } else if (s->rxlen > 1) {
  239:             if (s->rxlen > 2)
  240:                 s->fifo >>= 16;
  241:             s->rxlen -= 2;
  242:         } else
  243:             /* XXX: remote access (qualifier) error - what's that?  */;
  244:         if (!s->rxlen) {
  245:             s->stat |= ~(1 << 3);                               /* RRDY */
  246:             if (((s->control >> 10) & 1) &&                     /* MST */
  247:                             ((~s->control >> 9) & 1)) {         /* TRX */
  248:                 s->stat |= 1 << 2;                              /* ARDY */
  249:                 s->control &= ~(1 << 10);                       /* MST */
  250:             }
  251:         }
  252:         s->stat &= ~(1 << 11);                                  /* ROVR */
  253:         omap_i2c_fifo_run(s);
  254:         omap_i2c_interrupts_update(s);
  255:         return ret;
  256: 
  257:     case 0x24:  /* I2C_CON */
  258:         return s->control;
  259: 
  260:     case 0x28:  /* I2C_OA */
  261:         return s->addr[0];
  262: 
  263:     case 0x2c:  /* I2C_SA */
  264:         return s->addr[1];
  265: 
  266:     case 0x30:  /* I2C_PSC */
  267:         return s->divider;
  268: 
  269:     case 0x34:  /* I2C_SCLL */
  270:         return s->times[0];
  271: 
  272:     case 0x38:  /* I2C_SCLH */
  273:         return s->times[1];
  274: 
  275:     case 0x3c:  /* I2C_SYSTEST */
  276:         if (s->test & (1 << 15)) {                              /* ST_EN */
  277:             s->test ^= 0xa;
  278:             return s->test;
  279:         } else
  280:             return s->test & ~0x300f;
  281:     }
  282: 
  283:     OMAP_BAD_REG(addr);
  284:     return 0;
  285: }
  286: 
  287: static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
  288:                 uint32_t value)
  289: {
  290:     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
  291:     int offset = addr & OMAP_MPUI_REG_MASK;
  292:     int nack;
  293: 
  294:     switch (offset) {
  295:     case 0x00:  /* I2C_REV */
  296:     case 0x08:  /* I2C_STAT */
  297:     case 0x0c:  /* I2C_IV */
  298:         OMAP_BAD_REG(addr);
  299:         return;
  300: 
  301:     case 0x04:  /* I2C_IE */
  302:         s->mask = value & 0x1f;
  303:         break;
  304: 
  305:     case 0x14:  /* I2C_BUF */
  306:         s->dma = value & 0x8080;
  307:         if (value & (1 << 15))                                  /* RDMA_EN */
  308:             s->mask &= ~(1 << 3);                               /* RRDY_IE */
  309:         if (value & (1 << 7))                                   /* XDMA_EN */
  310:             s->mask &= ~(1 << 4);                               /* XRDY_IE */
  311:         break;
  312: 
  313:     case 0x18:  /* I2C_CNT */
  314:         s->count = value;                                       /* DCOUNT */
  315:         break;
  316: 
  317:     case 0x1c:  /* I2C_DATA */
  318:         if (s->txlen > 2) {
  319:             /* XXX: remote access (qualifier) error - what's that?  */
  320:             break;
  321:         }
  322:         s->fifo <<= 16;
  323:         s->txlen += 2;
  324:         if (s->control & (1 << 14)) {                           /* BE */
  325:             s->fifo |= ((value >> 8) & 0xff) << 8;
  326:             s->fifo |= ((value >> 0) & 0xff) << 0;
  327:         } else {
  328:             s->fifo |= ((value >> 0) & 0xff) << 8;
  329:             s->fifo |= ((value >> 8) & 0xff) << 0;
  330:         }
  331:         s->stat &= ~(1 << 10);                                  /* XUDF */
  332:         if (s->txlen > 2)
  333:             s->stat &= ~(1 << 4);                               /* XRDY */
  334:         omap_i2c_fifo_run(s);
  335:         omap_i2c_interrupts_update(s);
  336:         break;
  337: 
  338:     case 0x24:  /* I2C_CON */
  339:         s->control = value & 0xcf07;
  340:         if (~value & (1 << 15)) {                               /* I2C_EN */
  341:             omap_i2c_reset(s);
  342:             break;
  343:         }
  344:         if (~value & (1 << 10)) {                               /* MST */
  345:             printf("%s: I^2C slave mode not supported\n", __FUNCTION__);
  346:             break;
  347:         }
  348:         if (value & (1 << 9)) {                                 /* XA */
  349:             printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);
  350:             break;
  351:         }
  352:         if (value & (1 << 0)) {                                 /* STT */
  353:             nack = !!i2c_start_transfer(s->bus, s->addr[1],     /* SA */
  354:                             (~value >> 9) & 1);                 /* TRX */
  355:             s->stat |= nack << 1;                               /* NACK */
  356:             s->control &= ~(1 << 0);                            /* STT */
  357:             if (nack)
  358:                 s->control &= ~(1 << 1);                        /* STP */
  359:             else
  360:                 omap_i2c_fifo_run(s);
  361:             omap_i2c_interrupts_update(s);
  362:         }
  363:         break;
  364: 
  365:     case 0x28:  /* I2C_OA */
  366:         s->addr[0] = value & 0x3ff;
  367:         i2c_set_slave_address(&s->slave, value & 0x7f);
  368:         break;
  369: 
  370:     case 0x2c:  /* I2C_SA */
  371:         s->addr[1] = value & 0x3ff;
  372:         break;
  373: 
  374:     case 0x30:  /* I2C_PSC */
  375:         s->divider = value;
  376:         break;
  377: 
  378:     case 0x34:  /* I2C_SCLL */
  379:         s->times[0] = value;
  380:         break;
  381: 
  382:     case 0x38:  /* I2C_SCLH */
  383:         s->times[1] = value;
  384:         break;
  385: 
  386:     case 0x3c:  /* I2C_SYSTEST */
  387:         s->test = value & 0xf00f;
  388:         if (value & (1 << 15))                                  /* ST_EN */
  389:             printf("%s: System Test not supported\n", __FUNCTION__);
  390:         break;
  391: 
  392:     default:
  393:         OMAP_BAD_REG(addr);
  394:         return;
  395:     }
  396: }
  397: 
  398: static CPUReadMemoryFunc *omap_i2c_readfn[] = {
  399:     omap_badwidth_read16,
  400:     omap_i2c_read,
  401:     omap_badwidth_read16,
  402: };
  403: 
  404: static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
  405:     omap_badwidth_write16,
  406:     omap_i2c_write,
  407:     omap_i2c_write,     /* TODO: Only the last fifo write can be 8 bit.  */
  408: };
  409: 
  410: struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
  411:                 qemu_irq irq, qemu_irq *dma, omap_clk clk)
  412: {
  413:     int iomemtype;
  414:     struct omap_i2c_s *s = (struct omap_i2c_s *)
  415:             qemu_mallocz(sizeof(struct omap_i2c_s));
  416: 
  417:     s->base = base;
  418:     s->irq = irq;
  419:     s->drq[0] = dma[0];
  420:     s->drq[1] = dma[1];
  421:     s->slave.event = omap_i2c_event;
  422:     s->slave.recv = omap_i2c_rx;
  423:     s->slave.send = omap_i2c_tx;
  424:     s->bus = i2c_init_bus();
  425:     omap_i2c_reset(s);
  426: 
  427:     iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
  428:                     omap_i2c_writefn, s);
  429:     cpu_register_physical_memory(s->base, 0x800, iomemtype);
  430: 
  431:     return s;
  432: }
  433: 
  434: i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
  435: {
  436:     return s->bus;
  437: }
Syntax (Markdown)