xref: /openbmc/u-boot/drivers/spi/atcspi200_spi.c (revision 8ada17dde84954e36d8bc6ff62a6956686eb0ec4)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
241bbb8b3SRick Chen /*
36720e4aeSRick Chen  * Andestech ATCSPI200 SPI controller driver.
441bbb8b3SRick Chen  *
541bbb8b3SRick Chen  * Copyright 2017 Andes Technology, Inc.
641bbb8b3SRick Chen  * Author: Rick Chen (rick@andestech.com)
741bbb8b3SRick Chen  */
841bbb8b3SRick Chen 
941bbb8b3SRick Chen #include <clk.h>
1041bbb8b3SRick Chen #include <common.h>
1141bbb8b3SRick Chen #include <malloc.h>
1241bbb8b3SRick Chen #include <spi.h>
1341bbb8b3SRick Chen #include <asm/io.h>
1441bbb8b3SRick Chen #include <dm.h>
1541bbb8b3SRick Chen 
1641bbb8b3SRick Chen DECLARE_GLOBAL_DATA_PTR;
1741bbb8b3SRick Chen 
1841bbb8b3SRick Chen #define MAX_TRANSFER_LEN	512
1941bbb8b3SRick Chen #define CHUNK_SIZE		1
2041bbb8b3SRick Chen #define SPI_TIMEOUT		0x100000
2141bbb8b3SRick Chen #define SPI0_BUS		0
2241bbb8b3SRick Chen #define SPI1_BUS		1
2341bbb8b3SRick Chen #define SPI0_BASE		0xf0b00000
2441bbb8b3SRick Chen #define SPI1_BASE		0xf0f00000
2541bbb8b3SRick Chen #define NSPI_MAX_CS_NUM		1
2641bbb8b3SRick Chen 
276720e4aeSRick Chen struct atcspi200_spi_regs {
2841bbb8b3SRick Chen 	u32	rev;
2941bbb8b3SRick Chen 	u32	reserve1[3];
3041bbb8b3SRick Chen 	u32	format;		/* 0x10 */
3141bbb8b3SRick Chen #define DATA_LENGTH(x)	((x-1)<<8)
3241bbb8b3SRick Chen 	u32	pio;
3341bbb8b3SRick Chen 	u32	reserve2[2];
3441bbb8b3SRick Chen 	u32	tctrl;		/* 0x20 */
3541bbb8b3SRick Chen #define TRAMODE_OFFSET	24
3641bbb8b3SRick Chen #define TRAMODE_MASK	(0x0F<<TRAMODE_OFFSET)
3741bbb8b3SRick Chen #define TRAMODE_WR_SYNC	(0<<TRAMODE_OFFSET)
3841bbb8b3SRick Chen #define TRAMODE_WO	(1<<TRAMODE_OFFSET)
3941bbb8b3SRick Chen #define TRAMODE_RO	(2<<TRAMODE_OFFSET)
4041bbb8b3SRick Chen #define TRAMODE_WR	(3<<TRAMODE_OFFSET)
4141bbb8b3SRick Chen #define TRAMODE_RW	(4<<TRAMODE_OFFSET)
4241bbb8b3SRick Chen #define TRAMODE_WDR	(5<<TRAMODE_OFFSET)
4341bbb8b3SRick Chen #define TRAMODE_RDW	(6<<TRAMODE_OFFSET)
4441bbb8b3SRick Chen #define TRAMODE_NONE	(7<<TRAMODE_OFFSET)
4541bbb8b3SRick Chen #define TRAMODE_DW	(8<<TRAMODE_OFFSET)
4641bbb8b3SRick Chen #define TRAMODE_DR	(9<<TRAMODE_OFFSET)
4741bbb8b3SRick Chen #define WCNT_OFFSET	12
4841bbb8b3SRick Chen #define WCNT_MASK	(0x1FF<<WCNT_OFFSET)
4941bbb8b3SRick Chen #define RCNT_OFFSET	0
5041bbb8b3SRick Chen #define RCNT_MASK	(0x1FF<<RCNT_OFFSET)
5141bbb8b3SRick Chen 	u32	cmd;
5241bbb8b3SRick Chen 	u32	addr;
5341bbb8b3SRick Chen 	u32	data;
5441bbb8b3SRick Chen 	u32	ctrl;		/* 0x30 */
5541bbb8b3SRick Chen #define TXFTH_OFFSET	16
5641bbb8b3SRick Chen #define RXFTH_OFFSET	8
5741bbb8b3SRick Chen #define TXDMAEN		(1<<4)
5841bbb8b3SRick Chen #define RXDMAEN		(1<<3)
5941bbb8b3SRick Chen #define TXFRST		(1<<2)
6041bbb8b3SRick Chen #define RXFRST		(1<<1)
6141bbb8b3SRick Chen #define SPIRST		(1<<0)
6241bbb8b3SRick Chen 	u32	status;
6341bbb8b3SRick Chen #define TXFFL		(1<<23)
6441bbb8b3SRick Chen #define TXEPTY		(1<<22)
6541bbb8b3SRick Chen #define TXFVE_MASK	(0x1F<<16)
6641bbb8b3SRick Chen #define RXFEM		(1<<14)
6741bbb8b3SRick Chen #define RXFVE_OFFSET	(8)
6841bbb8b3SRick Chen #define RXFVE_MASK	(0x1F<<RXFVE_OFFSET)
6941bbb8b3SRick Chen #define SPIBSY		(1<<0)
7041bbb8b3SRick Chen 	u32	inten;
7141bbb8b3SRick Chen 	u32	intsta;
7241bbb8b3SRick Chen 	u32	timing;		/* 0x40 */
7341bbb8b3SRick Chen #define SCLK_DIV_MASK	0xFF
7441bbb8b3SRick Chen };
7541bbb8b3SRick Chen 
7641bbb8b3SRick Chen struct nds_spi_slave {
776720e4aeSRick Chen 	volatile struct atcspi200_spi_regs *regs;
7841bbb8b3SRick Chen 	int		to;
7941bbb8b3SRick Chen 	unsigned int	freq;
8041bbb8b3SRick Chen 	ulong		clock;
8141bbb8b3SRick Chen 	unsigned int	mode;
8241bbb8b3SRick Chen 	u8 		num_cs;
8341bbb8b3SRick Chen 	unsigned int	mtiming;
8441bbb8b3SRick Chen 	size_t		cmd_len;
8541bbb8b3SRick Chen 	u8		cmd_buf[16];
8641bbb8b3SRick Chen 	size_t		data_len;
8741bbb8b3SRick Chen 	size_t		tran_len;
8841bbb8b3SRick Chen 	u8		*din;
8941bbb8b3SRick Chen 	u8		*dout;
9041bbb8b3SRick Chen 	unsigned int    max_transfer_length;
9141bbb8b3SRick Chen };
9241bbb8b3SRick Chen 
__atcspi200_spi_set_speed(struct nds_spi_slave * ns)936720e4aeSRick Chen static int __atcspi200_spi_set_speed(struct nds_spi_slave *ns)
9441bbb8b3SRick Chen {
9541bbb8b3SRick Chen 	u32 tm;
9641bbb8b3SRick Chen 	u8 div;
9741bbb8b3SRick Chen 	tm = ns->regs->timing;
9841bbb8b3SRick Chen 	tm &= ~SCLK_DIV_MASK;
9941bbb8b3SRick Chen 
10041bbb8b3SRick Chen 	if(ns->freq >= ns->clock)
10141bbb8b3SRick Chen 		div =0xff;
10241bbb8b3SRick Chen 	else{
10341bbb8b3SRick Chen 		for (div = 0; div < 0xff; div++) {
10441bbb8b3SRick Chen 			if (ns->freq >= ns->clock / (2 * (div + 1)))
10541bbb8b3SRick Chen 				break;
10641bbb8b3SRick Chen 		}
10741bbb8b3SRick Chen 	}
10841bbb8b3SRick Chen 
10941bbb8b3SRick Chen 	tm |= div;
11041bbb8b3SRick Chen 	ns->regs->timing = tm;
11141bbb8b3SRick Chen 
11241bbb8b3SRick Chen 	return 0;
11341bbb8b3SRick Chen 
11441bbb8b3SRick Chen }
11541bbb8b3SRick Chen 
__atcspi200_spi_claim_bus(struct nds_spi_slave * ns)1166720e4aeSRick Chen static int __atcspi200_spi_claim_bus(struct nds_spi_slave *ns)
11741bbb8b3SRick Chen {
11841bbb8b3SRick Chen 		unsigned int format=0;
11941bbb8b3SRick Chen 		ns->regs->ctrl |= (TXFRST|RXFRST|SPIRST);
12041bbb8b3SRick Chen 		while((ns->regs->ctrl &(TXFRST|RXFRST|SPIRST))&&(ns->to--))
12141bbb8b3SRick Chen 			if(!ns->to)
12241bbb8b3SRick Chen 				return -EINVAL;
12341bbb8b3SRick Chen 
12441bbb8b3SRick Chen 		ns->cmd_len = 0;
12541bbb8b3SRick Chen 		format = ns->mode|DATA_LENGTH(8);
12641bbb8b3SRick Chen 		ns->regs->format = format;
1276720e4aeSRick Chen 		__atcspi200_spi_set_speed(ns);
12841bbb8b3SRick Chen 
12941bbb8b3SRick Chen 		return 0;
13041bbb8b3SRick Chen }
13141bbb8b3SRick Chen 
__atcspi200_spi_release_bus(struct nds_spi_slave * ns)1326720e4aeSRick Chen static int __atcspi200_spi_release_bus(struct nds_spi_slave *ns)
13341bbb8b3SRick Chen {
13441bbb8b3SRick Chen 	/* do nothing */
13541bbb8b3SRick Chen 	return 0;
13641bbb8b3SRick Chen }
13741bbb8b3SRick Chen 
__atcspi200_spi_start(struct nds_spi_slave * ns)1386720e4aeSRick Chen static int __atcspi200_spi_start(struct nds_spi_slave *ns)
13941bbb8b3SRick Chen {
14041bbb8b3SRick Chen 	int i,olen=0;
14141bbb8b3SRick Chen 	int tc = ns->regs->tctrl;
14241bbb8b3SRick Chen 
14341bbb8b3SRick Chen 	tc &= ~(WCNT_MASK|RCNT_MASK|TRAMODE_MASK);
14441bbb8b3SRick Chen 	if ((ns->din)&&(ns->cmd_len))
14541bbb8b3SRick Chen 		tc |= TRAMODE_WR;
14641bbb8b3SRick Chen 	else if (ns->din)
14741bbb8b3SRick Chen 		tc |= TRAMODE_RO;
14841bbb8b3SRick Chen 	else
14941bbb8b3SRick Chen 		tc |= TRAMODE_WO;
15041bbb8b3SRick Chen 
15141bbb8b3SRick Chen 	if(ns->dout)
15241bbb8b3SRick Chen 		olen = ns->tran_len;
15341bbb8b3SRick Chen 	tc |= (ns->cmd_len+olen-1) << WCNT_OFFSET;
15441bbb8b3SRick Chen 
15541bbb8b3SRick Chen 	if(ns->din)
15641bbb8b3SRick Chen 		tc |= (ns->tran_len-1) << RCNT_OFFSET;
15741bbb8b3SRick Chen 
15841bbb8b3SRick Chen 	ns->regs->tctrl = tc;
15941bbb8b3SRick Chen 	ns->regs->cmd = 1;
16041bbb8b3SRick Chen 
16141bbb8b3SRick Chen 	for (i=0;i<ns->cmd_len;i++)
16241bbb8b3SRick Chen 		ns->regs->data = ns->cmd_buf[i];
16341bbb8b3SRick Chen 
16441bbb8b3SRick Chen 	return 0;
16541bbb8b3SRick Chen }
16641bbb8b3SRick Chen 
__atcspi200_spi_stop(struct nds_spi_slave * ns)1676720e4aeSRick Chen static int __atcspi200_spi_stop(struct nds_spi_slave *ns)
16841bbb8b3SRick Chen {
16941bbb8b3SRick Chen 	ns->regs->timing = ns->mtiming;
17041bbb8b3SRick Chen 	while ((ns->regs->status & SPIBSY)&&(ns->to--))
17141bbb8b3SRick Chen 		if (!ns->to)
17241bbb8b3SRick Chen 			return -EINVAL;
17341bbb8b3SRick Chen 
17441bbb8b3SRick Chen 	return 0;
17541bbb8b3SRick Chen }
17641bbb8b3SRick Chen 
__nspi_espi_tx(struct nds_spi_slave * ns,const void * dout)17741bbb8b3SRick Chen static void __nspi_espi_tx(struct nds_spi_slave *ns, const void *dout)
17841bbb8b3SRick Chen {
17941bbb8b3SRick Chen 	ns->regs->data = *(u8 *)dout;
18041bbb8b3SRick Chen }
18141bbb8b3SRick Chen 
__nspi_espi_rx(struct nds_spi_slave * ns,void * din,unsigned int bytes)18241bbb8b3SRick Chen static int __nspi_espi_rx(struct nds_spi_slave *ns, void *din, unsigned int bytes)
18341bbb8b3SRick Chen {
18441bbb8b3SRick Chen 	*(u8 *)din = ns->regs->data;
18541bbb8b3SRick Chen 	return bytes;
18641bbb8b3SRick Chen }
18741bbb8b3SRick Chen 
18841bbb8b3SRick Chen 
__atcspi200_spi_xfer(struct nds_spi_slave * ns,unsigned int bitlen,const void * data_out,void * data_in,unsigned long flags)1896720e4aeSRick Chen static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
19041bbb8b3SRick Chen 		unsigned int bitlen,  const void *data_out, void *data_in,
19141bbb8b3SRick Chen 		unsigned long flags)
19241bbb8b3SRick Chen {
19341bbb8b3SRick Chen 		unsigned int event, rx_bytes;
19441bbb8b3SRick Chen 		const void *dout = NULL;
19541bbb8b3SRick Chen 		void *din = NULL;
19641bbb8b3SRick Chen 		int num_blks, num_chunks, max_tran_len, tran_len;
19741bbb8b3SRick Chen 		int num_bytes;
19841bbb8b3SRick Chen 		u8 *cmd_buf = ns->cmd_buf;
19941bbb8b3SRick Chen 		size_t cmd_len = ns->cmd_len;
200*6083cf38SRick Chen 		unsigned long data_len = bitlen / 8;
20141bbb8b3SRick Chen 		int rf_cnt;
20241bbb8b3SRick Chen 		int ret = 0;
20341bbb8b3SRick Chen 
20441bbb8b3SRick Chen 		max_tran_len = ns->max_transfer_length;
20541bbb8b3SRick Chen 		switch (flags) {
20641bbb8b3SRick Chen 		case SPI_XFER_BEGIN:
20741bbb8b3SRick Chen 			cmd_len = ns->cmd_len = data_len;
20841bbb8b3SRick Chen 			memcpy(cmd_buf, data_out, cmd_len);
20941bbb8b3SRick Chen 			return 0;
21041bbb8b3SRick Chen 
21141bbb8b3SRick Chen 		case 0:
21241bbb8b3SRick Chen 		case SPI_XFER_END:
21341bbb8b3SRick Chen 			if (bitlen == 0) {
21441bbb8b3SRick Chen 				return 0;
21541bbb8b3SRick Chen 			}
21641bbb8b3SRick Chen 			ns->data_len = data_len;
21741bbb8b3SRick Chen 			ns->din = (u8 *)data_in;
21841bbb8b3SRick Chen 			ns->dout = (u8 *)data_out;
21941bbb8b3SRick Chen 			break;
22041bbb8b3SRick Chen 
22141bbb8b3SRick Chen 		case SPI_XFER_BEGIN | SPI_XFER_END:
22241bbb8b3SRick Chen 			ns->data_len = 0;
22341bbb8b3SRick Chen 			ns->din = 0;
22441bbb8b3SRick Chen 			ns->dout = 0;
22541bbb8b3SRick Chen 			cmd_len = ns->cmd_len = data_len;
22641bbb8b3SRick Chen 			memcpy(cmd_buf, data_out, cmd_len);
22741bbb8b3SRick Chen 			data_out = 0;
22841bbb8b3SRick Chen 			data_len = 0;
2296720e4aeSRick Chen 			__atcspi200_spi_start(ns);
23041bbb8b3SRick Chen 			break;
23141bbb8b3SRick Chen 		}
2328fad5e0bSHeinrich Schuchardt 		if (data_out)
233*6083cf38SRick Chen 			debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) data_len %lu\n",
2348fad5e0bSHeinrich Schuchardt 			      *(uint *)data_out, data_out, *(uint *)data_in,
2358fad5e0bSHeinrich Schuchardt 			      data_in, data_len);
23641bbb8b3SRick Chen 		num_chunks = DIV_ROUND_UP(data_len, max_tran_len);
23741bbb8b3SRick Chen 		din = data_in;
23841bbb8b3SRick Chen 		dout = data_out;
23941bbb8b3SRick Chen 		while (num_chunks--) {
240*6083cf38SRick Chen 			tran_len = min((size_t)data_len, (size_t)max_tran_len);
24141bbb8b3SRick Chen 			ns->tran_len = tran_len;
24241bbb8b3SRick Chen 			num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE);
24341bbb8b3SRick Chen 			num_bytes = (tran_len) % CHUNK_SIZE;
24441bbb8b3SRick Chen 			if(num_bytes == 0)
24541bbb8b3SRick Chen 				num_bytes = CHUNK_SIZE;
2466720e4aeSRick Chen 			__atcspi200_spi_start(ns);
24741bbb8b3SRick Chen 
24841bbb8b3SRick Chen 			while (num_blks) {
24941bbb8b3SRick Chen 				event = in_le32(&ns->regs->status);
25041bbb8b3SRick Chen 				if ((event & TXEPTY) && (data_out)) {
25141bbb8b3SRick Chen 					__nspi_espi_tx(ns, dout);
25241bbb8b3SRick Chen 					num_blks -= CHUNK_SIZE;
25341bbb8b3SRick Chen 					dout += CHUNK_SIZE;
25441bbb8b3SRick Chen 				}
25541bbb8b3SRick Chen 
25641bbb8b3SRick Chen 				if ((event & RXFVE_MASK) && (data_in)) {
25741bbb8b3SRick Chen 					rf_cnt = ((event & RXFVE_MASK)>> RXFVE_OFFSET);
25841bbb8b3SRick Chen 					if (rf_cnt >= CHUNK_SIZE)
25941bbb8b3SRick Chen 						rx_bytes = CHUNK_SIZE;
26041bbb8b3SRick Chen 					else if (num_blks == 1 && rf_cnt == num_bytes)
26141bbb8b3SRick Chen 						rx_bytes = num_bytes;
26241bbb8b3SRick Chen 					else
26341bbb8b3SRick Chen 						continue;
26441bbb8b3SRick Chen 
26541bbb8b3SRick Chen 					if (__nspi_espi_rx(ns, din, rx_bytes) == rx_bytes) {
26641bbb8b3SRick Chen 						num_blks -= CHUNK_SIZE;
26741bbb8b3SRick Chen 						din = (unsigned char *)din + rx_bytes;
26841bbb8b3SRick Chen 					}
26941bbb8b3SRick Chen 				}
27041bbb8b3SRick Chen 			}
27141bbb8b3SRick Chen 
27241bbb8b3SRick Chen 			data_len -= tran_len;
27341bbb8b3SRick Chen 			if(data_len)
27441bbb8b3SRick Chen 			{
27541bbb8b3SRick Chen 				ns->cmd_buf[1] += ((tran_len>>16)&0xff);
27641bbb8b3SRick Chen 				ns->cmd_buf[2] += ((tran_len>>8)&0xff);
27741bbb8b3SRick Chen 				ns->cmd_buf[3] += ((tran_len)&0xff);
27841bbb8b3SRick Chen 				ns->data_len = data_len;
27941bbb8b3SRick Chen 			}
2806720e4aeSRick Chen 			ret = __atcspi200_spi_stop(ns);
28141bbb8b3SRick Chen 		}
2826720e4aeSRick Chen 		ret = __atcspi200_spi_stop(ns);
28341bbb8b3SRick Chen 
28441bbb8b3SRick Chen 		return ret;
28541bbb8b3SRick Chen }
28641bbb8b3SRick Chen 
atcspi200_spi_set_speed(struct udevice * bus,uint max_hz)2876720e4aeSRick Chen static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz)
28841bbb8b3SRick Chen {
28941bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
29041bbb8b3SRick Chen 
29141bbb8b3SRick Chen 	debug("%s speed %u\n", __func__, max_hz);
29241bbb8b3SRick Chen 
29341bbb8b3SRick Chen 	ns->freq = max_hz;
2946720e4aeSRick Chen 	__atcspi200_spi_set_speed(ns);
29541bbb8b3SRick Chen 
29641bbb8b3SRick Chen 	return 0;
29741bbb8b3SRick Chen }
29841bbb8b3SRick Chen 
atcspi200_spi_set_mode(struct udevice * bus,uint mode)2996720e4aeSRick Chen static int atcspi200_spi_set_mode(struct udevice *bus, uint mode)
30041bbb8b3SRick Chen {
30141bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
30241bbb8b3SRick Chen 
30341bbb8b3SRick Chen 	debug("%s mode %u\n", __func__, mode);
30441bbb8b3SRick Chen 	ns->mode = mode;
30541bbb8b3SRick Chen 
30641bbb8b3SRick Chen 	return 0;
30741bbb8b3SRick Chen }
30841bbb8b3SRick Chen 
atcspi200_spi_claim_bus(struct udevice * dev)3096720e4aeSRick Chen static int atcspi200_spi_claim_bus(struct udevice *dev)
31041bbb8b3SRick Chen {
31141bbb8b3SRick Chen 	struct dm_spi_slave_platdata *slave_plat =
31241bbb8b3SRick Chen 		dev_get_parent_platdata(dev);
31341bbb8b3SRick Chen 	struct udevice *bus = dev->parent;
31441bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
31541bbb8b3SRick Chen 
31641bbb8b3SRick Chen 	if (slave_plat->cs >= ns->num_cs) {
31741bbb8b3SRick Chen 		printf("Invalid SPI chipselect\n");
31841bbb8b3SRick Chen 		return -EINVAL;
31941bbb8b3SRick Chen 	}
32041bbb8b3SRick Chen 
3216720e4aeSRick Chen 	return __atcspi200_spi_claim_bus(ns);
32241bbb8b3SRick Chen }
32341bbb8b3SRick Chen 
atcspi200_spi_release_bus(struct udevice * dev)3246720e4aeSRick Chen static int atcspi200_spi_release_bus(struct udevice *dev)
32541bbb8b3SRick Chen {
32641bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(dev->parent);
32741bbb8b3SRick Chen 
3286720e4aeSRick Chen 	return __atcspi200_spi_release_bus(ns);
32941bbb8b3SRick Chen }
33041bbb8b3SRick Chen 
atcspi200_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)3316720e4aeSRick Chen static int atcspi200_spi_xfer(struct udevice *dev, unsigned int bitlen,
33241bbb8b3SRick Chen 			    const void *dout, void *din,
33341bbb8b3SRick Chen 			    unsigned long flags)
33441bbb8b3SRick Chen {
33541bbb8b3SRick Chen 	struct udevice *bus = dev->parent;
33641bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
33741bbb8b3SRick Chen 
3386720e4aeSRick Chen 	return __atcspi200_spi_xfer(ns, bitlen, dout, din, flags);
33941bbb8b3SRick Chen }
34041bbb8b3SRick Chen 
atcspi200_spi_get_clk(struct udevice * bus)3416720e4aeSRick Chen static int atcspi200_spi_get_clk(struct udevice *bus)
34241bbb8b3SRick Chen {
34341bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
34441bbb8b3SRick Chen 	struct clk clk;
34541bbb8b3SRick Chen 	ulong clk_rate;
34641bbb8b3SRick Chen 	int ret;
34741bbb8b3SRick Chen 
34841bbb8b3SRick Chen 	ret = clk_get_by_index(bus, 0, &clk);
34941bbb8b3SRick Chen 	if (ret)
35041bbb8b3SRick Chen 		return -EINVAL;
35141bbb8b3SRick Chen 
35241bbb8b3SRick Chen 	clk_rate = clk_get_rate(&clk);
35341bbb8b3SRick Chen 	if (!clk_rate)
35441bbb8b3SRick Chen 		return -EINVAL;
35541bbb8b3SRick Chen 
35641bbb8b3SRick Chen 	ns->clock = clk_rate;
35741bbb8b3SRick Chen 	clk_free(&clk);
35841bbb8b3SRick Chen 
35941bbb8b3SRick Chen 	return 0;
36041bbb8b3SRick Chen }
36141bbb8b3SRick Chen 
atcspi200_spi_probe(struct udevice * bus)3626720e4aeSRick Chen static int atcspi200_spi_probe(struct udevice *bus)
36341bbb8b3SRick Chen {
36441bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
36541bbb8b3SRick Chen 
36641bbb8b3SRick Chen 	ns->to = SPI_TIMEOUT;
36741bbb8b3SRick Chen 	ns->max_transfer_length = MAX_TRANSFER_LEN;
36841bbb8b3SRick Chen 	ns->mtiming = ns->regs->timing;
3696720e4aeSRick Chen 	atcspi200_spi_get_clk(bus);
37041bbb8b3SRick Chen 
37141bbb8b3SRick Chen 	return 0;
37241bbb8b3SRick Chen }
37341bbb8b3SRick Chen 
atcspi200_ofdata_to_platadata(struct udevice * bus)3746720e4aeSRick Chen static int atcspi200_ofdata_to_platadata(struct udevice *bus)
37541bbb8b3SRick Chen {
37641bbb8b3SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
37741bbb8b3SRick Chen 	const void *blob = gd->fdt_blob;
37841bbb8b3SRick Chen 	int node = dev_of_offset(bus);
37941bbb8b3SRick Chen 
38041bbb8b3SRick Chen 	ns->regs = map_physmem(devfdt_get_addr(bus),
3816720e4aeSRick Chen 				 sizeof(struct atcspi200_spi_regs),
38241bbb8b3SRick Chen 				 MAP_NOCACHE);
38341bbb8b3SRick Chen 	if (!ns->regs) {
38441bbb8b3SRick Chen 		printf("%s: could not map device address\n", __func__);
38541bbb8b3SRick Chen 		return -EINVAL;
38641bbb8b3SRick Chen 	}
38741bbb8b3SRick Chen 	ns->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
38841bbb8b3SRick Chen 
38941bbb8b3SRick Chen 	return 0;
39041bbb8b3SRick Chen }
39141bbb8b3SRick Chen 
3926720e4aeSRick Chen static const struct dm_spi_ops atcspi200_spi_ops = {
3936720e4aeSRick Chen 	.claim_bus	= atcspi200_spi_claim_bus,
3946720e4aeSRick Chen 	.release_bus	= atcspi200_spi_release_bus,
3956720e4aeSRick Chen 	.xfer		= atcspi200_spi_xfer,
3966720e4aeSRick Chen 	.set_speed	= atcspi200_spi_set_speed,
3976720e4aeSRick Chen 	.set_mode	= atcspi200_spi_set_mode,
39841bbb8b3SRick Chen };
39941bbb8b3SRick Chen 
4006720e4aeSRick Chen static const struct udevice_id atcspi200_spi_ids[] = {
40141bbb8b3SRick Chen 	{ .compatible = "andestech,atcspi200" },
40241bbb8b3SRick Chen 	{ }
40341bbb8b3SRick Chen };
40441bbb8b3SRick Chen 
4056720e4aeSRick Chen U_BOOT_DRIVER(atcspi200_spi) = {
4066720e4aeSRick Chen 	.name = "atcspi200_spi",
40741bbb8b3SRick Chen 	.id = UCLASS_SPI,
4086720e4aeSRick Chen 	.of_match = atcspi200_spi_ids,
4096720e4aeSRick Chen 	.ops = &atcspi200_spi_ops,
4106720e4aeSRick Chen 	.ofdata_to_platdata = atcspi200_ofdata_to_platadata,
41141bbb8b3SRick Chen 	.priv_auto_alloc_size = sizeof(struct nds_spi_slave),
4126720e4aeSRick Chen 	.probe = atcspi200_spi_probe,
41341bbb8b3SRick Chen };
414