gonzui


Format: Advanced Search

tkernel_2/driver/tef_em1d/clk/src/em1d512_iic.cbare sourcepermlink (0.02 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   11:  *
   12:  *----------------------------------------------------------------------
   13:  */
   14: 
   15: /*
   16:         em1d512_iic.c   RTC/Audio CODEC access (IIC) (EM1-D512)
   17:  *
   18:  */
   19: 
   20: #include "clkdrv.h"
   21: #include <tk/util.h>
   22: #include <device/em1d512_iic.h>
   23: 
   24: #ifdef  DEBUG
   25: #define DP(x)   printf x
   26: #else
   27: #define DP(x)   /* do nothing */
   28: #endif
   29: 
   30: #define IICMAX          2
   31: LOCAL   FastLock  IICLock[IICMAX];
   32: LOCAL   ID                IICTskID[IICMAX];
   33: LOCAL   const UW  IICBase[IICMAX] = {0x50040000, 0x50030000};
   34: LOCAL   const UW  IICVec[IICMAX] = {IV_IRQ(33), IV_IRQ(39)};
   35: 
   36: #define IIC_IIC(x)      (IICBase[x] + 0x0000)
   37: #define IIC_IICC(x)     (IICBase[x] + 0x0008)
   38: #define IIC_SVA(x)      (IICBase[x] + 0x000c)
   39: #define IIC_IICCL(x)    (IICBase[x] + 0x0010)
   40: #define IIC_IICSE(x)    (IICBase[x] + 0x001c)
   41: #define IIC_IICF(x)     (IICBase[x] + 0x0028)
   42: 
   43: #define IICC_IICE       (1 << 7)
   44: #define IICC_LREL       (1 << 6)
   45: #define IICC_WREL       (1 << 5)
   46: #define IICC_SPIE       (1 << 4)
   47: #define IICC_WTIM       (1 << 3)
   48: #define IICC_ACKE       (1 << 2)
   49: #define IICC_STT        (1 << 1)
   50: #define IICC_SPT        (1 << 0)
   51: 
   52: #define IICCL_CLD       (1 << 5)
   53: #define IICCL_DAD       (1 << 4)
   54: #define IICCL_SMC       (1 << 3)
   55: #define IICCL_DFC       (1 << 2)
   56: 
   57: #define IICSE_MSTS      (1 << 15)
   58: #define IICSE_ALD       (1 << 14)
   59: #define IICSE_EXC       (1 << 13)
   60: #define IICSE_COI       (1 << 12)
   61: #define IICSE_TRC       (1 << 11)
   62: #define IICSE_ACKD      (1 << 10)
   63: #define IICSE_STD       (1 << 9)
   64: #define IICSE_SPD       (1 << 8)
   65: 
   66: #define IICF_STCF       (1 << 7)
   67: #define IICF_IICBSY     (1 << 6)
   68: #define IICF_STCEN      (1 << 1)
   69: #define IICF_IICRSV     (1 << 0)
   70: 
   71: #define TIMEOUT         1000000        // microsec
   72: 
   73: /* wait for register status */
   74: LOCAL   ER        wait_state(UW addr, UW mask, UW value)
   75: {
   76:         W      i;
   77: 
   78:         for (i = TIMEOUT; i > 0; i--) {
   79:                 WaitUsec(1);
   80:                 if ((in_w(addr) & mask) == value) break;
   81:         }
   82: 
   83:         return i ? E_OK : E_TMOUT;
   84: }
   85: 
   86: /* interrupt handler */
   87: LOCAL   void      iic_inthdr(INTVEC vec)
   88: {
   89:         W      i;
   90: 
   91:         for (i = 0; i < IICMAX; i++) {
   92:                 if (vec == IICVec[i]) {
   93:                         tk_wup_tsk(IICTskID[i]);
   94:                         break;
   95:                 }
   96:         }
   97: 
   98:         ClearInt(vec);
   99:         return;
  100: }
  101: 
  102: /* wait for interrupt */
  103: LOCAL   ER        wait_int(void)
  104: {
  105:         return tk_slp_tsk(TIMEOUT / 1000);
  106: }
  107: 
  108: /* start/restart */
  109: LOCAL   ER        send_start(W ch, UH addr)
  110: {
  111:         ER     er;
  112:         UW     sts;
  113: 
  114:         /* generate start condition */
  115:         out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) & ~IICC_ACKE);
  116:         out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) |  IICC_STT);
  117: 
  118:         /* wait for acquiring master status */
  119:         er = wait_state(IIC_IICSE(ch), IICSE_MSTS, IICSE_MSTS);
  120:         if (er < E_OK) {
  121:                 DP(("send_start: wait_state %d\n", er));
  122:                 goto fin0;
  123:         }
  124: 
  125:         /* sending slave address / transmission mode */
  126:         out_w(IIC_IIC(ch), addr & 0xff);
  127:         er = wait_int();
  128:         if (er < E_OK) {
  129:                 DP(("send_start: wait_int %d\n", er));
  130:                 goto fin0;
  131:         }
  132: 
  133:         /* error check */
  134:         sts = in_w(IIC_IICSE(ch));
  135:         if ((sts & IICSE_ALD) || !(sts & IICSE_ACKD)) {
  136:                 DP(("send_start: IICSE %#x\n", sts));
  137:                 er = E_IO;
  138:                 goto fin0;
  139:         }
  140: 
  141:         er = E_OK;
  142: fin0:
  143:         return er;
  144: }
  145: 
  146: /* stop */
  147: LOCAL   ER        send_stop(W ch)
  148: {
  149:         ER     er;
  150: 
  151:         /* generate stop condition */
  152:         out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) | IICC_SPT);
  153: 
  154:         /* wait for sending stop */
  155:         er = wait_state(IIC_IICSE(ch), IICSE_SPD, IICSE_SPD);
  156:         if (er < E_OK) {
  157:                 DP(("send_stop: wait_state %d\n", er));
  158:         }
  159: 
  160:         return er;
  161: }
  162: 
  163: /* sending data */
  164: LOCAL   ER        send_data(W ch, UH data)
  165: {
  166:         ER     er;
  167:         UW     sts;
  168: 
  169:         /* sending data */
  170:         out_w(IIC_IIC(ch), data & 0xff);
  171:         er = wait_int();
  172:         if (er < E_OK) {
  173:                 DP(("send_data: wait_int %d\n", er));
  174:                 goto fin0;
  175:         }
  176: 
  177:         /* checking NAK */
  178:         sts = in_w(IIC_IICSE(ch));
  179:         if (!(sts & IICSE_ACKD)) {
  180:                 DP(("send_data: IICSE %#x\n", sts));
  181:                 er = E_IO;
  182:                 goto fin0;
  183:         }
  184: 
  185:         er = E_OK;
  186: fin0:
  187:         return er;
  188: }
  189: 
  190: /* receiving data */
  191: LOCAL   ER        recv_data(W ch, UH *cmddata)
  192: {
  193:         ER     er;
  194:         W      cmd = *cmddata;
  195: 
  196:         /* On the initial data receive, switch to receive mode */
  197:         if (cmd & IIC_TOPDATA) {
  198:                 out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) & ~IICC_WTIM);
  199:                 out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) |  IICC_ACKE);
  200:         }
  201: 
  202:         /* initiate data receive */
  203:         out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) | IICC_WREL);
  204:         er = wait_int();
  205:         if (er < E_OK) {
  206:                 DP(("recv_data: wait_int %d\n", er));
  207:                 goto fin0;
  208:         }
  209: 
  210:         /* read data */
  211:         *cmddata = (cmd & 0xff00) | (in_w(IIC_IIC(ch)) & 0xff);
  212:         er = E_OK;
  213: fin0:
  214:         /* epilog processing invoked after an error or the last byte is read */
  215:         if ((cmd & IIC_LASTDATA) || er < E_OK) {
  216:                 out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) |  IICC_WTIM);
  217:                 out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) & ~IICC_ACKE);
  218:                 out_w(IIC_IICC(ch), in_w(IIC_IICC(ch)) | IICC_WREL);
  219:                 wait_int();
  220:         }
  221: 
  222:         return er;
  223: }
  224: 
  225: /* IIC transmission processing */
  226: EXPORT  ER       IICXfer(W ch, UH *cmddata, W words)
  227: {
  228:         ER     er;
  229: 
  230:         /* check channel number */
  231:         if (ch < 0 || ch > 1) {
  232:                 er = E_PAR;
  233:                 goto fin0;
  234:         }
  235: 
  236:         Lock(&IICLock[ch]);
  237:         IICTskID[ch] = tk_get_tid();
  238: 
  239:         /* initialization */
  240:         out_w(IIC_IICC(ch), 0);                                // halt entire operation
  241:         out_w(IIC_IICCL(ch), IICCL_SMC | IICCL_DFC);   // high-speed mode + filter
  242:         out_w(IIC_IICF(ch), IICF_STCEN | IICF_IICRSV); // force transmission
  243:         out_w(IIC_IICC(ch), IICC_IICE | IICC_WTIM);    // IIC operation, 9 bits mode
  244:         tk_can_wup(TSK_SELF);
  245: 
  246:         /* wait for bus free (since there is one master, the bus should be free, but just in case.) */
  247:         wait_state(IIC_IICF(ch), IICF_IICBSY, 0);
  248: 
  249:         /* process according to the instruction */
  250:         for (; words > 0; words--) {
  251:                 if (*cmddata & IIC_START) {
  252:                         er = send_start(ch, *cmddata);
  253: 
  254:                 } else if (*cmddata & IIC_STOP) {
  255:                         er = send_stop(ch);
  256: 
  257:                 } else if (*cmddata & IIC_SEND) {
  258:                         er = send_data(ch, *cmddata);
  259: 
  260:                 } else if (*cmddata & IIC_RECV) {
  261:                         er = recv_data(ch, cmddata);
  262: 
  263:                 } else {
  264:                         er = E_OK;   /* do nothing */
  265: 
  266:                 }
  267: 
  268:                 /* transmit stop condition upon encountering an error */
  269:                 if (er < E_OK) {
  270:                         send_stop(ch);
  271:                         goto fin1;
  272:                 }
  273: 
  274:                 cmddata++;
  275:         }
  276: 
  277:         er = E_OK;
  278: fin1:
  279:         out_w(IIC_IICC(ch), 0);        // halt entire operation
  280:         Unlock(&IICLock[ch]);
  281: fin0:
  282:         return er;
  283: }
  284: 
  285: /* IICdriver prolog ends */
  286: EXPORT  ER       IICup(W ch, BOOL start)
  287: {
  288: #define IICTag  "IIC_"
  289: 
  290:         ER     er;
  291:         T_DINT dint;
  292: 
  293:         /* check channel number */
  294:         if (ch < 0 || ch > 1) {
  295:                 er = E_PAR;
  296:                 goto fin0;
  297:         }
  298: 
  299:         /* epilog processing */
  300:         if (!start) {
  301:                 er = E_OK;
  302:                 goto fin2;
  303:         }
  304: 
  305:         /* creating a lock for exclusive control */
  306:         er = CreateLock(&IICLock[ch], IICTag);
  307:         if (er < E_OK) {
  308:                 DP(("IICup: CreateLock %d\n", er));
  309:                 goto fin0;
  310:         }
  311: 
  312:         /* register interrupt handler */
  313:         dint.intatr = TA_HLNG;
  314:         dint.inthdr = iic_inthdr;
  315:         er = tk_def_int(IICVec[ch], &dint);
  316:         if (er < E_OK) {
  317:                 DP(("IICup: tk_def_int %d\n", er));
  318:                 goto fin1;
  319:         }
  320: 
  321:         /* clear interrupt and permit it again */
  322:         SetIntMode(IICVec[ch], IM_ENA);
  323:         ClearInt(IICVec[ch]);
  324:         EnableInt(IICVec[ch]);
  325: 
  326:         er = E_OK;
  327:         goto fin0;
  328: 
  329: fin2:
  330:         DisableInt(IICVec[ch]);
  331:         ClearInt(IICVec[ch]);
  332:         SetIntMode(IICVec[ch], IM_DIS);
  333:         tk_def_int(IICVec[ch], NULL);
  334: fin1:
  335:         DeleteLock(&IICLock[ch]);
  336: fin0:
  337:         return er;
  338: }