xref: /rk3399_rockchip-uboot/drivers/spi/sh_spi.c (revision 5b8031ccb4ed6e84457d883198d77efc307085dc)
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