ssi_lm3s.c

Go to the documentation of this file.
00001 
00038 #include "cfg/compiler.h"
00039 #include "cfg/debug.h"
00040 
00041 #include <string.h> /* memset() */
00042 
00043 #include "ssi_lm3s.h"
00044 
00045 /* SSI clocking informations (CPSDVSR + SCR) */
00046 struct SSIClock
00047 {
00048     unsigned int cpsdvsr;
00049     unsigned int scr;
00050 };
00051 
00052 /*
00053  * Evaluate the SSI clock prescale (SSICPSR) and SSI serial clock rate (SCR).
00054  */
00055 INLINE struct SSIClock
00056 lm3s_ssiPrescale(unsigned int bitrate)
00057 {
00058     struct SSIClock ret;
00059 
00060     for (ret.cpsdvsr = 2, ret.scr = CPU_FREQ / bitrate / ret.cpsdvsr - 1;
00061             ret.scr > 255; ret.cpsdvsr += 2);
00062     ASSERT(ret.cpsdvsr < 255);
00063 
00064     return ret;
00065 }
00066 
00067 /*
00068  * Initialize the SSI interface.
00069  *
00070  * Return 0 in case of success, a negative value otherwise.
00071  */
00072 int lm3s_ssiOpen(uint32_t addr, uint32_t frame, int mode,
00073             int bitrate, uint32_t data_width)
00074 {
00075     struct SSIClock ssi_clock;
00076 
00077     ASSERT(addr == SSI0_BASE || addr == SSI1_BASE);
00078     /* Configure the SSI operating mode */
00079     switch (mode)
00080     {
00081         /* SSI Slave Mode Output Disable */
00082         case SSI_MODE_SLAVE_OD:
00083             HWREG(addr + SSI_O_CR1) = SSI_CR1_SOD;
00084             break;
00085         /* SSI Slave */
00086         case SSI_MODE_SLAVE:
00087             HWREG(addr + SSI_O_CR1) = SSI_CR1_MS;
00088             break;
00089         /* SSI Master */
00090         case SSI_MODE_MASTER:
00091             HWREG(addr + SSI_O_CR1) = 0;
00092             break;
00093         default:
00094             ASSERT(0);
00095             return -1;
00096     }
00097     /* Configure the peripheral clock and frame format */
00098     ssi_clock = lm3s_ssiPrescale(bitrate);
00099     HWREG(addr + SSI_O_CPSR) = ssi_clock.cpsdvsr;
00100     HWREG(addr + SSI_O_CR0) =
00101             (ssi_clock.scr << 8)        |
00102             ((frame & 3) << 6)      |
00103             (frame & SSI_CR0_FRF_M)     |
00104             (data_width - 1);
00105     /* Enable the SSI interface */
00106     HWREG(addr + SSI_O_CR1) |= SSI_CR1_SSE;
00107 
00108     return 0;
00109 }
00110 
00111 /*
00112  * Write data to the SSI bus.
00113  *
00114  * Return the number of bytes written to the bus.
00115  */
00116 static size_t lm3s_ssiWrite(struct KFile *fd, const void *buf, size_t size)
00117 {
00118     LM3SSSI *fds = LM3SSSI_CAST(fd);
00119     const char *p = (const char *)buf;
00120     uint32_t frame;
00121     size_t count = 0;
00122 
00123     while (count < size)
00124     {
00125         frame = p[count];
00126         if (fds->flags & LM3S_SSI_NONBLOCK)
00127         {
00128             if (!lm3s_ssiWriteFrameNonBlocking(fds->addr,
00129                                 frame))
00130                 break;
00131         }
00132         else
00133             lm3s_ssiWriteFrame(fds->addr, frame);
00134         count++;
00135     }
00136     return count;
00137 }
00138 
00139 /*
00140  * Read data from the SSI bus.
00141  *
00142  * Return the number of bytes read from the bus.
00143  */
00144 static size_t lm3s_ssiRead(struct KFile *fd, void *buf, size_t size)
00145 {
00146     LM3SSSI *fds = LM3SSSI_CAST(fd);
00147 
00148     uint8_t *p = (uint8_t *)buf;
00149     uint32_t frame;
00150     size_t count = 0;
00151 
00152     while (count < size)
00153     {
00154         if (fds->flags & LM3S_SSI_NONBLOCK)
00155         {
00156             if (!lm3s_ssiReadFrameNonBlocking(fds->addr, &frame))
00157                 break;
00158         }
00159         else
00160             lm3s_ssiReadFrame(fds->addr, &frame);
00161         *p++ = (uint8_t)frame;
00162         count++;
00163     }
00164     return count;
00165 }
00166 
00167 
00168 /* Wait for data in the TX FIFO being actually transmitted */
00169 static int lm3s_ssiFlush(struct KFile *fd)
00170 {
00171     LM3SSSI *fds = LM3SSSI_CAST(fd);
00172 
00173     while (!lm3s_ssiTxDone(fds->addr))
00174         cpu_relax();
00175     return 0;
00176 }
00177 
00178 /* Disable the SSI interface */
00179 static int lm3s_ssiClose(struct KFile *fd)
00180 {
00181     LM3SSSI *fds = LM3SSSI_CAST(fd);
00182 
00183     lm3s_ssiFlush(fd);
00184     HWREG(fds->addr + SSI_O_CR1) &= ~SSI_CR1_SSE;
00185     return 0;
00186 }
00187 
00191 void lm3s_ssiInit(struct LM3SSSI *fds, uint32_t addr, uint32_t frame, int mode,
00192             int bitrate, uint32_t data_width)
00193 {
00194     memset(fds, 0, sizeof(*fds));
00195     DB(fds->fd._type = KFT_LM3SSSI);
00196 
00197     /* TODO: only 8-bit frame size is supported */
00198     ASSERT(data_width == 8);
00199 
00200     fds->fd.write = lm3s_ssiWrite;
00201     fds->fd.read = lm3s_ssiRead;
00202     fds->fd.close = lm3s_ssiClose;
00203     fds->fd.flush = lm3s_ssiFlush;
00204 
00205     fds->addr = addr;
00206     lm3s_ssiOpen(addr, frame, mode, bitrate, data_width);
00207 }