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