BeRTOS
|
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 }