18ed58856SSekhar Nori /* 28ed58856SSekhar Nori * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ 38ed58856SSekhar Nori * 48ed58856SSekhar Nori * Driver for SPI controller on DaVinci. Based on atmel_spi.c 58ed58856SSekhar Nori * by Atmel Corporation 68ed58856SSekhar Nori * 78ed58856SSekhar Nori * Copyright (C) 2007 Atmel Corporation 88ed58856SSekhar Nori * 91a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 108ed58856SSekhar Nori */ 118ed58856SSekhar Nori #include <common.h> 128ed58856SSekhar Nori #include <spi.h> 138ed58856SSekhar Nori #include <malloc.h> 148ed58856SSekhar Nori #include <asm/io.h> 158ed58856SSekhar Nori #include <asm/arch/hardware.h> 168ed58856SSekhar Nori #include "davinci_spi.h" 178ed58856SSekhar Nori 188ed58856SSekhar Nori void spi_init() 198ed58856SSekhar Nori { 208ed58856SSekhar Nori /* do nothing */ 218ed58856SSekhar Nori } 228ed58856SSekhar Nori 238ed58856SSekhar Nori struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 248ed58856SSekhar Nori unsigned int max_hz, unsigned int mode) 258ed58856SSekhar Nori { 268ed58856SSekhar Nori struct davinci_spi_slave *ds; 278ed58856SSekhar Nori 288ed58856SSekhar Nori if (!spi_cs_is_valid(bus, cs)) 298ed58856SSekhar Nori return NULL; 308ed58856SSekhar Nori 31d3504feeSSimon Glass ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs); 328ed58856SSekhar Nori if (!ds) 338ed58856SSekhar Nori return NULL; 348ed58856SSekhar Nori 35*2bcdf84dSKaricheri, Muralidharan ds->slave.bus = bus; 36*2bcdf84dSKaricheri, Muralidharan ds->slave.cs = cs; 37*2bcdf84dSKaricheri, Muralidharan 38*2bcdf84dSKaricheri, Muralidharan switch (bus) { 39*2bcdf84dSKaricheri, Muralidharan case SPI0_BUS: 40*2bcdf84dSKaricheri, Muralidharan ds->regs = (struct davinci_spi_regs *)SPI0_BASE; 41*2bcdf84dSKaricheri, Muralidharan break; 42*2bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI1 43*2bcdf84dSKaricheri, Muralidharan case SPI1_BUS: 44*2bcdf84dSKaricheri, Muralidharan ds->regs = (struct davinci_spi_regs *)SPI0_BASE; 45*2bcdf84dSKaricheri, Muralidharan break; 46*2bcdf84dSKaricheri, Muralidharan #endif 47*2bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI2 48*2bcdf84dSKaricheri, Muralidharan case SPI2_BUS: 49*2bcdf84dSKaricheri, Muralidharan ds->regs = (struct davinci_spi_regs *)SPI2_BASE; 50*2bcdf84dSKaricheri, Muralidharan break; 51*2bcdf84dSKaricheri, Muralidharan #endif 52*2bcdf84dSKaricheri, Muralidharan default: /* Invalid bus number */ 53*2bcdf84dSKaricheri, Muralidharan return NULL; 54*2bcdf84dSKaricheri, Muralidharan } 55*2bcdf84dSKaricheri, Muralidharan 568ed58856SSekhar Nori ds->freq = max_hz; 578ed58856SSekhar Nori 588ed58856SSekhar Nori return &ds->slave; 598ed58856SSekhar Nori } 608ed58856SSekhar Nori 618ed58856SSekhar Nori void spi_free_slave(struct spi_slave *slave) 628ed58856SSekhar Nori { 638ed58856SSekhar Nori struct davinci_spi_slave *ds = to_davinci_spi(slave); 648ed58856SSekhar Nori 658ed58856SSekhar Nori free(ds); 668ed58856SSekhar Nori } 678ed58856SSekhar Nori 688ed58856SSekhar Nori int spi_claim_bus(struct spi_slave *slave) 698ed58856SSekhar Nori { 708ed58856SSekhar Nori struct davinci_spi_slave *ds = to_davinci_spi(slave); 7177436d66SNick Thompson unsigned int scalar; 728ed58856SSekhar Nori 738ed58856SSekhar Nori /* Enable the SPI hardware */ 748ed58856SSekhar Nori writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); 758ed58856SSekhar Nori udelay(1000); 768ed58856SSekhar Nori writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); 778ed58856SSekhar Nori 788ed58856SSekhar Nori /* Set master mode, powered up and not activated */ 798ed58856SSekhar Nori writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); 808ed58856SSekhar Nori 818ed58856SSekhar Nori /* CS, CLK, SIMO and SOMI are functional pins */ 82*2bcdf84dSKaricheri, Muralidharan writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK | 838ed58856SSekhar Nori SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); 848ed58856SSekhar Nori 858ed58856SSekhar Nori /* setup format */ 868ed58856SSekhar Nori scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; 878ed58856SSekhar Nori 888ed58856SSekhar Nori /* 898ed58856SSekhar Nori * Use following format: 908ed58856SSekhar Nori * character length = 8, 918ed58856SSekhar Nori * clock signal delayed by half clk cycle, 928ed58856SSekhar Nori * clock low in idle state - Mode 0, 938ed58856SSekhar Nori * MSB shifted out first 948ed58856SSekhar Nori */ 958ed58856SSekhar Nori writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | 968ed58856SSekhar Nori (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); 978ed58856SSekhar Nori 988ed58856SSekhar Nori /* 998ed58856SSekhar Nori * Including a minor delay. No science here. Should be good even with 1008ed58856SSekhar Nori * no delay 1018ed58856SSekhar Nori */ 1028ed58856SSekhar Nori writel((50 << SPI_C2TDELAY_SHIFT) | 1038ed58856SSekhar Nori (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); 1048ed58856SSekhar Nori 1058ed58856SSekhar Nori /* default chip select register */ 1068ed58856SSekhar Nori writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); 1078ed58856SSekhar Nori 1088ed58856SSekhar Nori /* no interrupts */ 1098ed58856SSekhar Nori writel(0, &ds->regs->int0); 1108ed58856SSekhar Nori writel(0, &ds->regs->lvl); 1118ed58856SSekhar Nori 1128ed58856SSekhar Nori /* enable SPI */ 11377436d66SNick Thompson writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); 1148ed58856SSekhar Nori 1158ed58856SSekhar Nori return 0; 1168ed58856SSekhar Nori } 1178ed58856SSekhar Nori 1188ed58856SSekhar Nori void spi_release_bus(struct spi_slave *slave) 1198ed58856SSekhar Nori { 1208ed58856SSekhar Nori struct davinci_spi_slave *ds = to_davinci_spi(slave); 1218ed58856SSekhar Nori 1228ed58856SSekhar Nori /* Disable the SPI hardware */ 1238ed58856SSekhar Nori writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); 1248ed58856SSekhar Nori } 1258ed58856SSekhar Nori 12677436d66SNick Thompson /* 12777436d66SNick Thompson * This functions needs to act like a macro to avoid pipeline reloads in the 12877436d66SNick Thompson * loops below. Use always_inline. This gains us about 160KiB/s and the bloat 12977436d66SNick Thompson * appears to be zero bytes (da830). 13077436d66SNick Thompson */ 13177436d66SNick Thompson __attribute__((always_inline)) 13277436d66SNick Thompson static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) 13377436d66SNick Thompson { 13477436d66SNick Thompson u32 buf_reg_val; 13577436d66SNick Thompson 13677436d66SNick Thompson /* send out data */ 13777436d66SNick Thompson writel(data, &ds->regs->dat1); 13877436d66SNick Thompson 13977436d66SNick Thompson /* wait for the data to clock in/out */ 14077436d66SNick Thompson while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK) 14177436d66SNick Thompson ; 14277436d66SNick Thompson 14377436d66SNick Thompson return buf_reg_val; 14477436d66SNick Thompson } 14577436d66SNick Thompson 14677436d66SNick Thompson static int davinci_spi_read(struct spi_slave *slave, unsigned int len, 14777436d66SNick Thompson u8 *rxp, unsigned long flags) 14877436d66SNick Thompson { 14977436d66SNick Thompson struct davinci_spi_slave *ds = to_davinci_spi(slave); 15077436d66SNick Thompson unsigned int data1_reg_val; 15177436d66SNick Thompson 15277436d66SNick Thompson /* enable CS hold, CS[n] and clear the data bits */ 15377436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | 15477436d66SNick Thompson (slave->cs << SPIDAT1_CSNR_SHIFT)); 15577436d66SNick Thompson 15677436d66SNick Thompson /* wait till TXFULL is deasserted */ 15777436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) 15877436d66SNick Thompson ; 15977436d66SNick Thompson 16077436d66SNick Thompson /* preload the TX buffer to avoid clock starvation */ 16177436d66SNick Thompson writel(data1_reg_val, &ds->regs->dat1); 16277436d66SNick Thompson 16377436d66SNick Thompson /* keep reading 1 byte until only 1 byte left */ 16477436d66SNick Thompson while ((len--) > 1) 16577436d66SNick Thompson *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val); 16677436d66SNick Thompson 16777436d66SNick Thompson /* clear CS hold when we reach the end */ 16877436d66SNick Thompson if (flags & SPI_XFER_END) 16977436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); 17077436d66SNick Thompson 17177436d66SNick Thompson /* read the last byte */ 17277436d66SNick Thompson *rxp = davinci_spi_xfer_data(ds, data1_reg_val); 17377436d66SNick Thompson 17477436d66SNick Thompson return 0; 17577436d66SNick Thompson } 17677436d66SNick Thompson 17777436d66SNick Thompson static int davinci_spi_write(struct spi_slave *slave, unsigned int len, 17877436d66SNick Thompson const u8 *txp, unsigned long flags) 17977436d66SNick Thompson { 18077436d66SNick Thompson struct davinci_spi_slave *ds = to_davinci_spi(slave); 18177436d66SNick Thompson unsigned int data1_reg_val; 18277436d66SNick Thompson 18377436d66SNick Thompson /* enable CS hold and clear the data bits */ 18477436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | 18577436d66SNick Thompson (slave->cs << SPIDAT1_CSNR_SHIFT)); 18677436d66SNick Thompson 18777436d66SNick Thompson /* wait till TXFULL is deasserted */ 18877436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) 18977436d66SNick Thompson ; 19077436d66SNick Thompson 19177436d66SNick Thompson /* preload the TX buffer to avoid clock starvation */ 19277436d66SNick Thompson if (len > 2) { 19377436d66SNick Thompson writel(data1_reg_val | *txp++, &ds->regs->dat1); 19477436d66SNick Thompson len--; 19577436d66SNick Thompson } 19677436d66SNick Thompson 19777436d66SNick Thompson /* keep writing 1 byte until only 1 byte left */ 19877436d66SNick Thompson while ((len--) > 1) 19977436d66SNick Thompson davinci_spi_xfer_data(ds, data1_reg_val | *txp++); 20077436d66SNick Thompson 20177436d66SNick Thompson /* clear CS hold when we reach the end */ 20277436d66SNick Thompson if (flags & SPI_XFER_END) 20377436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); 20477436d66SNick Thompson 20577436d66SNick Thompson /* write the last byte */ 20677436d66SNick Thompson davinci_spi_xfer_data(ds, data1_reg_val | *txp); 20777436d66SNick Thompson 20877436d66SNick Thompson return 0; 20977436d66SNick Thompson } 21077436d66SNick Thompson 21177436d66SNick Thompson #ifndef CONFIG_SPI_HALF_DUPLEX 21277436d66SNick Thompson static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, 21377436d66SNick Thompson u8 *rxp, const u8 *txp, unsigned long flags) 21477436d66SNick Thompson { 21577436d66SNick Thompson struct davinci_spi_slave *ds = to_davinci_spi(slave); 21677436d66SNick Thompson unsigned int data1_reg_val; 21777436d66SNick Thompson 21877436d66SNick Thompson /* enable CS hold and clear the data bits */ 21977436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | 22077436d66SNick Thompson (slave->cs << SPIDAT1_CSNR_SHIFT)); 22177436d66SNick Thompson 22277436d66SNick Thompson /* wait till TXFULL is deasserted */ 22377436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) 22477436d66SNick Thompson ; 22577436d66SNick Thompson 22677436d66SNick Thompson /* keep reading and writing 1 byte until only 1 byte left */ 22777436d66SNick Thompson while ((len--) > 1) 22877436d66SNick Thompson *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val | *txp++); 22977436d66SNick Thompson 23077436d66SNick Thompson /* clear CS hold when we reach the end */ 23177436d66SNick Thompson if (flags & SPI_XFER_END) 23277436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); 23377436d66SNick Thompson 23477436d66SNick Thompson /* read and write the last byte */ 23577436d66SNick Thompson *rxp = davinci_spi_xfer_data(ds, data1_reg_val | *txp); 23677436d66SNick Thompson 23777436d66SNick Thompson return 0; 23877436d66SNick Thompson } 23977436d66SNick Thompson #endif 24077436d66SNick Thompson 2418ed58856SSekhar Nori int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 2428ed58856SSekhar Nori const void *dout, void *din, unsigned long flags) 2438ed58856SSekhar Nori { 24477436d66SNick Thompson unsigned int len; 2458ed58856SSekhar Nori 2468ed58856SSekhar Nori if (bitlen == 0) 2478ed58856SSekhar Nori /* Finish any previously submitted transfers */ 2488ed58856SSekhar Nori goto out; 2498ed58856SSekhar Nori 2508ed58856SSekhar Nori /* 2518ed58856SSekhar Nori * It's not clear how non-8-bit-aligned transfers are supposed to be 2528ed58856SSekhar Nori * represented as a stream of bytes...this is a limitation of 2538ed58856SSekhar Nori * the current SPI interface - here we terminate on receiving such a 2548ed58856SSekhar Nori * transfer request. 2558ed58856SSekhar Nori */ 2568ed58856SSekhar Nori if (bitlen % 8) { 2578ed58856SSekhar Nori /* Errors always terminate an ongoing transfer */ 2588ed58856SSekhar Nori flags |= SPI_XFER_END; 2598ed58856SSekhar Nori goto out; 2608ed58856SSekhar Nori } 2618ed58856SSekhar Nori 2628ed58856SSekhar Nori len = bitlen / 8; 2638ed58856SSekhar Nori 26477436d66SNick Thompson if (!dout) 26577436d66SNick Thompson return davinci_spi_read(slave, len, din, flags); 26677436d66SNick Thompson else if (!din) 26777436d66SNick Thompson return davinci_spi_write(slave, len, dout, flags); 26877436d66SNick Thompson #ifndef CONFIG_SPI_HALF_DUPLEX 26977436d66SNick Thompson else 27077436d66SNick Thompson return davinci_spi_read_write(slave, len, din, dout, flags); 271dce6538fSNick Thompson #else 272dce6538fSNick Thompson printf("SPI full duplex transaction requested with " 273dce6538fSNick Thompson "CONFIG_SPI_HALF_DUPLEX defined.\n"); 274dce6538fSNick Thompson flags |= SPI_XFER_END; 27577436d66SNick Thompson #endif 2768ed58856SSekhar Nori 2778ed58856SSekhar Nori out: 2788ed58856SSekhar Nori if (flags & SPI_XFER_END) { 27977436d66SNick Thompson u8 dummy = 0; 28077436d66SNick Thompson davinci_spi_write(slave, 1, &dummy, flags); 2818ed58856SSekhar Nori } 2828ed58856SSekhar Nori return 0; 2838ed58856SSekhar Nori } 2848ed58856SSekhar Nori 2858ed58856SSekhar Nori int spi_cs_is_valid(unsigned int bus, unsigned int cs) 2868ed58856SSekhar Nori { 287*2bcdf84dSKaricheri, Muralidharan int ret = 0; 288*2bcdf84dSKaricheri, Muralidharan 289*2bcdf84dSKaricheri, Muralidharan switch (bus) { 290*2bcdf84dSKaricheri, Muralidharan case SPI0_BUS: 291*2bcdf84dSKaricheri, Muralidharan if (cs < SPI0_NUM_CS) 292*2bcdf84dSKaricheri, Muralidharan ret = 1; 293*2bcdf84dSKaricheri, Muralidharan break; 294*2bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI1 295*2bcdf84dSKaricheri, Muralidharan case SPI1_BUS: 296*2bcdf84dSKaricheri, Muralidharan if (cs < SPI1_NUM_CS) 297*2bcdf84dSKaricheri, Muralidharan ret = 1; 298*2bcdf84dSKaricheri, Muralidharan break; 299*2bcdf84dSKaricheri, Muralidharan #endif 300*2bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI2 301*2bcdf84dSKaricheri, Muralidharan case SPI2_BUS: 302*2bcdf84dSKaricheri, Muralidharan if (cs < SPI2_NUM_CS) 303*2bcdf84dSKaricheri, Muralidharan ret = 1; 304*2bcdf84dSKaricheri, Muralidharan break; 305*2bcdf84dSKaricheri, Muralidharan #endif 306*2bcdf84dSKaricheri, Muralidharan default: 307*2bcdf84dSKaricheri, Muralidharan /* Invalid bus number. Do nothing */ 308*2bcdf84dSKaricheri, Muralidharan break; 309*2bcdf84dSKaricheri, Muralidharan } 310*2bcdf84dSKaricheri, Muralidharan return ret; 3118ed58856SSekhar Nori } 3128ed58856SSekhar Nori 3138ed58856SSekhar Nori void spi_cs_activate(struct spi_slave *slave) 3148ed58856SSekhar Nori { 3158ed58856SSekhar Nori /* do nothing */ 3168ed58856SSekhar Nori } 3178ed58856SSekhar Nori 3188ed58856SSekhar Nori void spi_cs_deactivate(struct spi_slave *slave) 3198ed58856SSekhar Nori { 3208ed58856SSekhar Nori /* do nothing */ 3218ed58856SSekhar Nori } 322