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