16639562eSYoshihiro Shimoda /*
26639562eSYoshihiro Shimoda * SH SPI driver
36639562eSYoshihiro Shimoda *
4c1d4ad94SYoshihiro Shimoda * Copyright (C) 2011-2012 Renesas Solutions Corp.
56639562eSYoshihiro Shimoda *
6*5b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0
76639562eSYoshihiro Shimoda */
86639562eSYoshihiro Shimoda
96639562eSYoshihiro Shimoda #include <common.h>
1024b852a7SSimon Glass #include <console.h>
116639562eSYoshihiro Shimoda #include <malloc.h>
126639562eSYoshihiro Shimoda #include <spi.h>
136639562eSYoshihiro Shimoda #include <asm/io.h>
146639562eSYoshihiro Shimoda #include "sh_spi.h"
156639562eSYoshihiro Shimoda
sh_spi_write(unsigned long data,unsigned long * reg)166639562eSYoshihiro Shimoda static void sh_spi_write(unsigned long data, unsigned long *reg)
176639562eSYoshihiro Shimoda {
186639562eSYoshihiro Shimoda writel(data, reg);
196639562eSYoshihiro Shimoda }
206639562eSYoshihiro Shimoda
sh_spi_read(unsigned long * reg)216639562eSYoshihiro Shimoda static unsigned long sh_spi_read(unsigned long *reg)
226639562eSYoshihiro Shimoda {
236639562eSYoshihiro Shimoda return readl(reg);
246639562eSYoshihiro Shimoda }
256639562eSYoshihiro Shimoda
sh_spi_set_bit(unsigned long val,unsigned long * reg)266639562eSYoshihiro Shimoda static void sh_spi_set_bit(unsigned long val, unsigned long *reg)
276639562eSYoshihiro Shimoda {
286639562eSYoshihiro Shimoda unsigned long tmp;
296639562eSYoshihiro Shimoda
306639562eSYoshihiro Shimoda tmp = sh_spi_read(reg);
316639562eSYoshihiro Shimoda tmp |= val;
326639562eSYoshihiro Shimoda sh_spi_write(tmp, reg);
336639562eSYoshihiro Shimoda }
346639562eSYoshihiro Shimoda
sh_spi_clear_bit(unsigned long val,unsigned long * reg)356639562eSYoshihiro Shimoda static void sh_spi_clear_bit(unsigned long val, unsigned long *reg)
366639562eSYoshihiro Shimoda {
376639562eSYoshihiro Shimoda unsigned long tmp;
386639562eSYoshihiro Shimoda
396639562eSYoshihiro Shimoda tmp = sh_spi_read(reg);
406639562eSYoshihiro Shimoda tmp &= ~val;
416639562eSYoshihiro Shimoda sh_spi_write(tmp, reg);
426639562eSYoshihiro Shimoda }
436639562eSYoshihiro Shimoda
clear_fifo(struct sh_spi * ss)446639562eSYoshihiro Shimoda static void clear_fifo(struct sh_spi *ss)
456639562eSYoshihiro Shimoda {
466639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_RSTF, &ss->regs->cr2);
476639562eSYoshihiro Shimoda sh_spi_clear_bit(SH_SPI_RSTF, &ss->regs->cr2);
486639562eSYoshihiro Shimoda }
496639562eSYoshihiro Shimoda
recvbuf_wait(struct sh_spi * ss)506639562eSYoshihiro Shimoda static int recvbuf_wait(struct sh_spi *ss)
516639562eSYoshihiro Shimoda {
526639562eSYoshihiro Shimoda while (sh_spi_read(&ss->regs->cr1) & SH_SPI_RBE) {
536639562eSYoshihiro Shimoda if (ctrlc())
546639562eSYoshihiro Shimoda return 1;
556639562eSYoshihiro Shimoda udelay(10);
566639562eSYoshihiro Shimoda }
576639562eSYoshihiro Shimoda return 0;
586639562eSYoshihiro Shimoda }
596639562eSYoshihiro Shimoda
write_fifo_empty_wait(struct sh_spi * ss)606639562eSYoshihiro Shimoda static int write_fifo_empty_wait(struct sh_spi *ss)
616639562eSYoshihiro Shimoda {
626639562eSYoshihiro Shimoda while (!(sh_spi_read(&ss->regs->cr1) & SH_SPI_TBE)) {
636639562eSYoshihiro Shimoda if (ctrlc())
646639562eSYoshihiro Shimoda return 1;
656639562eSYoshihiro Shimoda udelay(10);
666639562eSYoshihiro Shimoda }
676639562eSYoshihiro Shimoda return 0;
686639562eSYoshihiro Shimoda }
696639562eSYoshihiro Shimoda
spi_init(void)706639562eSYoshihiro Shimoda void spi_init(void)
716639562eSYoshihiro Shimoda {
726639562eSYoshihiro Shimoda }
736639562eSYoshihiro Shimoda
sh_spi_set_cs(struct sh_spi * ss,unsigned int cs)74c1d4ad94SYoshihiro Shimoda static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs)
75c1d4ad94SYoshihiro Shimoda {
76c1d4ad94SYoshihiro Shimoda unsigned long val = 0;
77c1d4ad94SYoshihiro Shimoda
78c1d4ad94SYoshihiro Shimoda if (cs & 0x01)
79c1d4ad94SYoshihiro Shimoda val |= SH_SPI_SSS0;
80c1d4ad94SYoshihiro Shimoda if (cs & 0x02)
81c1d4ad94SYoshihiro Shimoda val |= SH_SPI_SSS1;
82c1d4ad94SYoshihiro Shimoda
83c1d4ad94SYoshihiro Shimoda sh_spi_clear_bit(SH_SPI_SSS0 | SH_SPI_SSS1, &ss->regs->cr4);
84c1d4ad94SYoshihiro Shimoda sh_spi_set_bit(val, &ss->regs->cr4);
85c1d4ad94SYoshihiro Shimoda }
86c1d4ad94SYoshihiro Shimoda
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)876639562eSYoshihiro Shimoda struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
886639562eSYoshihiro Shimoda unsigned int max_hz, unsigned int mode)
896639562eSYoshihiro Shimoda {
906639562eSYoshihiro Shimoda struct sh_spi *ss;
916639562eSYoshihiro Shimoda
926639562eSYoshihiro Shimoda if (!spi_cs_is_valid(bus, cs))
936639562eSYoshihiro Shimoda return NULL;
946639562eSYoshihiro Shimoda
95d3504feeSSimon Glass ss = spi_alloc_slave(struct sh_spi, bus, cs);
966639562eSYoshihiro Shimoda if (!ss)
976639562eSYoshihiro Shimoda return NULL;
986639562eSYoshihiro Shimoda
996639562eSYoshihiro Shimoda ss->regs = (struct sh_spi_regs *)CONFIG_SH_SPI_BASE;
1006639562eSYoshihiro Shimoda
1016639562eSYoshihiro Shimoda /* SPI sycle stop */
1026639562eSYoshihiro Shimoda sh_spi_write(0xfe, &ss->regs->cr1);
1036639562eSYoshihiro Shimoda /* CR1 init */
1046639562eSYoshihiro Shimoda sh_spi_write(0x00, &ss->regs->cr1);
1056639562eSYoshihiro Shimoda /* CR3 init */
1066639562eSYoshihiro Shimoda sh_spi_write(0x00, &ss->regs->cr3);
107c1d4ad94SYoshihiro Shimoda sh_spi_set_cs(ss, cs);
1086639562eSYoshihiro Shimoda
1096639562eSYoshihiro Shimoda clear_fifo(ss);
1106639562eSYoshihiro Shimoda
1116639562eSYoshihiro Shimoda /* 1/8 clock */
1126639562eSYoshihiro Shimoda sh_spi_write(sh_spi_read(&ss->regs->cr2) | 0x07, &ss->regs->cr2);
1136639562eSYoshihiro Shimoda udelay(10);
1146639562eSYoshihiro Shimoda
1156639562eSYoshihiro Shimoda return &ss->slave;
1166639562eSYoshihiro Shimoda }
1176639562eSYoshihiro Shimoda
spi_free_slave(struct spi_slave * slave)1186639562eSYoshihiro Shimoda void spi_free_slave(struct spi_slave *slave)
1196639562eSYoshihiro Shimoda {
1206639562eSYoshihiro Shimoda struct sh_spi *spi = to_sh_spi(slave);
1216639562eSYoshihiro Shimoda
1226639562eSYoshihiro Shimoda free(spi);
1236639562eSYoshihiro Shimoda }
1246639562eSYoshihiro Shimoda
spi_claim_bus(struct spi_slave * slave)1256639562eSYoshihiro Shimoda int spi_claim_bus(struct spi_slave *slave)
1266639562eSYoshihiro Shimoda {
1276639562eSYoshihiro Shimoda return 0;
1286639562eSYoshihiro Shimoda }
1296639562eSYoshihiro Shimoda
spi_release_bus(struct spi_slave * slave)1306639562eSYoshihiro Shimoda void spi_release_bus(struct spi_slave *slave)
1316639562eSYoshihiro Shimoda {
1326639562eSYoshihiro Shimoda struct sh_spi *ss = to_sh_spi(slave);
1336639562eSYoshihiro Shimoda
1346639562eSYoshihiro Shimoda sh_spi_write(sh_spi_read(&ss->regs->cr1) &
1356639562eSYoshihiro Shimoda ~(SH_SPI_SSA | SH_SPI_SSDB | SH_SPI_SSD), &ss->regs->cr1);
1366639562eSYoshihiro Shimoda }
1376639562eSYoshihiro Shimoda
sh_spi_send(struct sh_spi * ss,const unsigned char * tx_data,unsigned int len,unsigned long flags)1386639562eSYoshihiro Shimoda static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data,
1396639562eSYoshihiro Shimoda unsigned int len, unsigned long flags)
1406639562eSYoshihiro Shimoda {
1416639562eSYoshihiro Shimoda int i, cur_len, ret = 0;
1426639562eSYoshihiro Shimoda int remain = (int)len;
1436639562eSYoshihiro Shimoda
1446639562eSYoshihiro Shimoda if (len >= SH_SPI_FIFO_SIZE)
1456639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
1466639562eSYoshihiro Shimoda
1476639562eSYoshihiro Shimoda while (remain > 0) {
1486639562eSYoshihiro Shimoda cur_len = (remain < SH_SPI_FIFO_SIZE) ?
1496639562eSYoshihiro Shimoda remain : SH_SPI_FIFO_SIZE;
1506639562eSYoshihiro Shimoda for (i = 0; i < cur_len &&
1516639562eSYoshihiro Shimoda !(sh_spi_read(&ss->regs->cr4) & SH_SPI_WPABRT) &&
1526639562eSYoshihiro Shimoda !(sh_spi_read(&ss->regs->cr1) & SH_SPI_TBF);
1536639562eSYoshihiro Shimoda i++)
1546639562eSYoshihiro Shimoda sh_spi_write(tx_data[i], &ss->regs->tbr_rbr);
1556639562eSYoshihiro Shimoda
1566639562eSYoshihiro Shimoda cur_len = i;
1576639562eSYoshihiro Shimoda
1586639562eSYoshihiro Shimoda if (sh_spi_read(&ss->regs->cr4) & SH_SPI_WPABRT) {
1596639562eSYoshihiro Shimoda /* Abort the transaction */
1606639562eSYoshihiro Shimoda flags |= SPI_XFER_END;
1616639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_WPABRT, &ss->regs->cr4);
1626639562eSYoshihiro Shimoda ret = 1;
1636639562eSYoshihiro Shimoda break;
1646639562eSYoshihiro Shimoda }
1656639562eSYoshihiro Shimoda
1666639562eSYoshihiro Shimoda remain -= cur_len;
1676639562eSYoshihiro Shimoda tx_data += cur_len;
1686639562eSYoshihiro Shimoda
1696639562eSYoshihiro Shimoda if (remain > 0)
1706639562eSYoshihiro Shimoda write_fifo_empty_wait(ss);
1716639562eSYoshihiro Shimoda }
1726639562eSYoshihiro Shimoda
1736639562eSYoshihiro Shimoda if (flags & SPI_XFER_END) {
17412f00cafSAxel Lin sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
1756639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
1766639562eSYoshihiro Shimoda udelay(100);
1776639562eSYoshihiro Shimoda write_fifo_empty_wait(ss);
1786639562eSYoshihiro Shimoda }
1796639562eSYoshihiro Shimoda
1806639562eSYoshihiro Shimoda return ret;
1816639562eSYoshihiro Shimoda }
1826639562eSYoshihiro Shimoda
sh_spi_receive(struct sh_spi * ss,unsigned char * rx_data,unsigned int len,unsigned long flags)1836639562eSYoshihiro Shimoda static int sh_spi_receive(struct sh_spi *ss, unsigned char *rx_data,
1846639562eSYoshihiro Shimoda unsigned int len, unsigned long flags)
1856639562eSYoshihiro Shimoda {
1866639562eSYoshihiro Shimoda int i;
1876639562eSYoshihiro Shimoda
1886639562eSYoshihiro Shimoda if (len > SH_SPI_MAX_BYTE)
1896639562eSYoshihiro Shimoda sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3);
1906639562eSYoshihiro Shimoda else
1916639562eSYoshihiro Shimoda sh_spi_write(len, &ss->regs->cr3);
1926639562eSYoshihiro Shimoda
19312f00cafSAxel Lin sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
1946639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
1956639562eSYoshihiro Shimoda
1966639562eSYoshihiro Shimoda for (i = 0; i < len; i++) {
1976639562eSYoshihiro Shimoda if (recvbuf_wait(ss))
1986639562eSYoshihiro Shimoda return 0;
1996639562eSYoshihiro Shimoda
2006639562eSYoshihiro Shimoda rx_data[i] = (unsigned char)sh_spi_read(&ss->regs->tbr_rbr);
2016639562eSYoshihiro Shimoda }
2026639562eSYoshihiro Shimoda sh_spi_write(0, &ss->regs->cr3);
2036639562eSYoshihiro Shimoda
2046639562eSYoshihiro Shimoda return 0;
2056639562eSYoshihiro Shimoda }
2066639562eSYoshihiro Shimoda
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)2076639562eSYoshihiro Shimoda int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
2086639562eSYoshihiro Shimoda void *din, unsigned long flags)
2096639562eSYoshihiro Shimoda {
2106639562eSYoshihiro Shimoda struct sh_spi *ss = to_sh_spi(slave);
2116639562eSYoshihiro Shimoda const unsigned char *tx_data = dout;
2126639562eSYoshihiro Shimoda unsigned char *rx_data = din;
2136639562eSYoshihiro Shimoda unsigned int len = bitlen / 8;
2146639562eSYoshihiro Shimoda int ret = 0;
2156639562eSYoshihiro Shimoda
2166639562eSYoshihiro Shimoda if (flags & SPI_XFER_BEGIN)
2176639562eSYoshihiro Shimoda sh_spi_write(sh_spi_read(&ss->regs->cr1) & ~SH_SPI_SSA,
2186639562eSYoshihiro Shimoda &ss->regs->cr1);
2196639562eSYoshihiro Shimoda
2206639562eSYoshihiro Shimoda if (tx_data)
2216639562eSYoshihiro Shimoda ret = sh_spi_send(ss, tx_data, len, flags);
2226639562eSYoshihiro Shimoda
2236639562eSYoshihiro Shimoda if (ret == 0 && rx_data)
2246639562eSYoshihiro Shimoda ret = sh_spi_receive(ss, rx_data, len, flags);
2256639562eSYoshihiro Shimoda
2266639562eSYoshihiro Shimoda if (flags & SPI_XFER_END) {
2276639562eSYoshihiro Shimoda sh_spi_set_bit(SH_SPI_SSD, &ss->regs->cr1);
2286639562eSYoshihiro Shimoda udelay(100);
2296639562eSYoshihiro Shimoda
2306639562eSYoshihiro Shimoda sh_spi_clear_bit(SH_SPI_SSA | SH_SPI_SSDB | SH_SPI_SSD,
2316639562eSYoshihiro Shimoda &ss->regs->cr1);
2326639562eSYoshihiro Shimoda clear_fifo(ss);
2336639562eSYoshihiro Shimoda }
2346639562eSYoshihiro Shimoda
2356639562eSYoshihiro Shimoda return ret;
2366639562eSYoshihiro Shimoda }
2376639562eSYoshihiro Shimoda
spi_cs_is_valid(unsigned int bus,unsigned int cs)2386639562eSYoshihiro Shimoda int spi_cs_is_valid(unsigned int bus, unsigned int cs)
2396639562eSYoshihiro Shimoda {
240c1d4ad94SYoshihiro Shimoda if (!bus && cs < SH_SPI_NUM_CS)
2416639562eSYoshihiro Shimoda return 1;
2426639562eSYoshihiro Shimoda else
2436639562eSYoshihiro Shimoda return 0;
2446639562eSYoshihiro Shimoda }
2456639562eSYoshihiro Shimoda
spi_cs_activate(struct spi_slave * slave)2466639562eSYoshihiro Shimoda void spi_cs_activate(struct spi_slave *slave)
2476639562eSYoshihiro Shimoda {
2486639562eSYoshihiro Shimoda
2496639562eSYoshihiro Shimoda }
2506639562eSYoshihiro Shimoda
spi_cs_deactivate(struct spi_slave * slave)2516639562eSYoshihiro Shimoda void spi_cs_deactivate(struct spi_slave *slave)
2526639562eSYoshihiro Shimoda {
2536639562eSYoshihiro Shimoda
2546639562eSYoshihiro Shimoda }
255