1 /* 2 * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com> 3 * 4 * Driver for McSPI controller on OMAP3. Based on davinci_spi.c 5 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 * Copyright (C) 2007 Atmel Corporation 8 * 9 * Parts taken from linux/drivers/spi/omap2_mcspi.c 10 * Copyright (C) 2005, 2006 Nokia Corporation 11 * 12 * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com> 13 * 14 * See file CREDITS for list of people who contributed to this 15 * project. 16 * 17 * This program is free software; you can redistribute it and/or 18 * modify it under the terms of the GNU General Public License as 19 * published by the Free Software Foundation; either version 2 of 20 * the License, or (at your option) any later version. 21 * 22 * This program is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * GNU General Public License for more details. 26 * 27 * You should have received a copy of the GNU General Public License 28 * along with this program; if not, write to the Free Software 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 30 * MA 02111-1307 USA 31 * 32 */ 33 34 #include <common.h> 35 #include <spi.h> 36 #include <malloc.h> 37 #include <asm/io.h> 38 #include "omap3_spi.h" 39 40 #define WORD_LEN 8 41 #define SPI_WAIT_TIMEOUT 3000000; 42 43 static void spi_reset(struct omap3_spi_slave *ds) 44 { 45 unsigned int tmp; 46 47 writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig); 48 do { 49 tmp = readl(&ds->regs->sysstatus); 50 } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); 51 52 writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | 53 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | 54 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, 55 &ds->regs->sysconfig); 56 57 writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable); 58 } 59 60 void spi_init() 61 { 62 /* do nothing */ 63 } 64 65 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 66 unsigned int max_hz, unsigned int mode) 67 { 68 struct omap3_spi_slave *ds; 69 70 ds = malloc(sizeof(struct omap3_spi_slave)); 71 if (!ds) { 72 printf("SPI error: malloc of SPI structure failed\n"); 73 return NULL; 74 } 75 76 /* 77 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules) 78 * with different number of chip selects (CS, channels): 79 * McSPI1 has 4 CS (bus 0, cs 0 - 3) 80 * McSPI2 has 2 CS (bus 1, cs 0 - 1) 81 * McSPI3 has 2 CS (bus 2, cs 0 - 1) 82 * McSPI4 has 1 CS (bus 3, cs 0) 83 */ 84 85 switch (bus) { 86 case 0: 87 ds->regs = (struct mcspi *)OMAP3_MCSPI1_BASE; 88 break; 89 case 1: 90 ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE; 91 break; 92 case 2: 93 ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE; 94 break; 95 case 3: 96 ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE; 97 break; 98 default: 99 printf("SPI error: unsupported bus %i. \ 100 Supported busses 0 - 3\n", bus); 101 return NULL; 102 } 103 ds->slave.bus = bus; 104 105 if (((bus == 0) && (cs > 3)) || 106 ((bus == 1) && (cs > 1)) || 107 ((bus == 2) && (cs > 1)) || 108 ((bus == 3) && (cs > 0))) { 109 printf("SPI error: unsupported chip select %i \ 110 on bus %i\n", cs, bus); 111 return NULL; 112 } 113 ds->slave.cs = cs; 114 115 if (max_hz > OMAP3_MCSPI_MAX_FREQ) { 116 printf("SPI error: unsupported frequency %i Hz. \ 117 Max frequency is 48 Mhz\n", max_hz); 118 return NULL; 119 } 120 ds->freq = max_hz; 121 122 if (mode > SPI_MODE_3) { 123 printf("SPI error: unsupported SPI mode %i\n", mode); 124 return NULL; 125 } 126 ds->mode = mode; 127 128 return &ds->slave; 129 } 130 131 void spi_free_slave(struct spi_slave *slave) 132 { 133 struct omap3_spi_slave *ds = to_omap3_spi(slave); 134 135 free(ds); 136 } 137 138 int spi_claim_bus(struct spi_slave *slave) 139 { 140 struct omap3_spi_slave *ds = to_omap3_spi(slave); 141 unsigned int conf, div = 0; 142 143 /* McSPI global module configuration */ 144 145 /* 146 * setup when switching from (reset default) slave mode 147 * to single-channel master mode 148 */ 149 spi_reset(ds); 150 conf = readl(&ds->regs->modulctrl); 151 conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); 152 conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; 153 writel(conf, &ds->regs->modulctrl); 154 155 /* McSPI individual channel configuration */ 156 157 /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ 158 if (ds->freq) { 159 while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) 160 > ds->freq) 161 div++; 162 } else 163 div = 0xC; 164 165 conf = readl(&ds->regs->channel[ds->slave.cs].chconf); 166 167 /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS 168 * REVISIT: this controller could support SPI_3WIRE mode. 169 */ 170 conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); 171 conf |= OMAP3_MCSPI_CHCONF_DPE0; 172 173 /* wordlength */ 174 conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; 175 conf |= (WORD_LEN - 1) << 7; 176 177 /* set chipselect polarity; manage with FORCE */ 178 if (!(ds->mode & SPI_CS_HIGH)) 179 conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ 180 else 181 conf &= ~OMAP3_MCSPI_CHCONF_EPOL; 182 183 /* set clock divisor */ 184 conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; 185 conf |= div << 2; 186 187 /* set SPI mode 0..3 */ 188 if (ds->mode & SPI_CPOL) 189 conf |= OMAP3_MCSPI_CHCONF_POL; 190 else 191 conf &= ~OMAP3_MCSPI_CHCONF_POL; 192 if (ds->mode & SPI_CPHA) 193 conf |= OMAP3_MCSPI_CHCONF_PHA; 194 else 195 conf &= ~OMAP3_MCSPI_CHCONF_PHA; 196 197 /* Transmit & receive mode */ 198 conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; 199 200 writel(conf, &ds->regs->channel[ds->slave.cs].chconf); 201 202 return 0; 203 } 204 205 void spi_release_bus(struct spi_slave *slave) 206 { 207 struct omap3_spi_slave *ds = to_omap3_spi(slave); 208 209 /* Reset the SPI hardware */ 210 spi_reset(ds); 211 } 212 213 int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, 214 unsigned long flags) 215 { 216 struct omap3_spi_slave *ds = to_omap3_spi(slave); 217 int i; 218 int timeout = SPI_WAIT_TIMEOUT; 219 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); 220 221 if (flags & SPI_XFER_BEGIN) 222 writel(OMAP3_MCSPI_CHCTRL_EN, 223 &ds->regs->channel[ds->slave.cs].chctrl); 224 225 chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; 226 chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; 227 chconf |= OMAP3_MCSPI_CHCONF_FORCE; 228 writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); 229 230 for (i = 0; i < len; i++) { 231 /* wait till TX register is empty (TXS == 1) */ 232 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & 233 OMAP3_MCSPI_CHSTAT_TXS)) { 234 if (--timeout <= 0) { 235 printf("SPI TXS timed out, status=0x%08x\n", 236 readl(&ds->regs->channel[ds->slave.cs].chstat)); 237 return -1; 238 } 239 } 240 /* Write the data */ 241 writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); 242 } 243 244 if (flags & SPI_XFER_END) { 245 /* wait to finish of transfer */ 246 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & 247 OMAP3_MCSPI_CHSTAT_EOT)); 248 249 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; 250 writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); 251 252 writel(0, &ds->regs->channel[ds->slave.cs].chctrl); 253 } 254 return 0; 255 } 256 257 int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, 258 unsigned long flags) 259 { 260 struct omap3_spi_slave *ds = to_omap3_spi(slave); 261 int i; 262 int timeout = SPI_WAIT_TIMEOUT; 263 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); 264 265 if (flags & SPI_XFER_BEGIN) 266 writel(OMAP3_MCSPI_CHCTRL_EN, 267 &ds->regs->channel[ds->slave.cs].chctrl); 268 269 chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; 270 chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; 271 chconf |= OMAP3_MCSPI_CHCONF_FORCE; 272 writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); 273 274 writel(0, &ds->regs->channel[ds->slave.cs].tx); 275 276 for (i = 0; i < len; i++) { 277 /* Wait till RX register contains data (RXS == 1) */ 278 while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & 279 OMAP3_MCSPI_CHSTAT_RXS)) { 280 if (--timeout <= 0) { 281 printf("SPI RXS timed out, status=0x%08x\n", 282 readl(&ds->regs->channel[ds->slave.cs].chstat)); 283 return -1; 284 } 285 } 286 /* Read the data */ 287 rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); 288 } 289 290 if (flags & SPI_XFER_END) { 291 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; 292 writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); 293 294 writel(0, &ds->regs->channel[ds->slave.cs].chctrl); 295 } 296 297 return 0; 298 } 299 300 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 301 const void *dout, void *din, unsigned long flags) 302 { 303 struct omap3_spi_slave *ds = to_omap3_spi(slave); 304 unsigned int len; 305 const u8 *txp = dout; 306 u8 *rxp = din; 307 int ret = -1; 308 309 if (bitlen % 8) 310 return -1; 311 312 len = bitlen / 8; 313 314 if (bitlen == 0) { /* only change CS */ 315 int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); 316 317 if (flags & SPI_XFER_BEGIN) { 318 writel(OMAP3_MCSPI_CHCTRL_EN, 319 &ds->regs->channel[ds->slave.cs].chctrl); 320 chconf |= OMAP3_MCSPI_CHCONF_FORCE; 321 writel(chconf, 322 &ds->regs->channel[ds->slave.cs].chconf); 323 } 324 if (flags & SPI_XFER_END) { 325 chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; 326 writel(chconf, 327 &ds->regs->channel[ds->slave.cs].chconf); 328 writel(0, &ds->regs->channel[ds->slave.cs].chctrl); 329 } 330 ret = 0; 331 } else { 332 if (dout != NULL) 333 ret = omap3_spi_write(slave, len, txp, flags); 334 335 if (din != NULL) 336 ret = omap3_spi_read(slave, len, rxp, flags); 337 } 338 return ret; 339 } 340 341 int spi_cs_is_valid(unsigned int bus, unsigned int cs) 342 { 343 return 1; 344 } 345 346 void spi_cs_activate(struct spi_slave *slave) 347 { 348 } 349 350 void spi_cs_deactivate(struct spi_slave *slave) 351 { 352 } 353