xref: /rk3399_rockchip-uboot/drivers/spi/atcspi200_spi.c (revision 0d17c3df7fd4704b61815d11bd914866bbfb27d1)
16b239db4SRick Chen /*
2*ab1460f2SRick Chen  * Andestech ATCSPI200 SPI controller driver.
36b239db4SRick Chen  *
46b239db4SRick Chen  * Copyright 2017 Andes Technology, Inc.
56b239db4SRick Chen  * Author: Rick Chen (rick@andestech.com)
66b239db4SRick Chen  *
76b239db4SRick Chen  * SPDX-License-Identifier:	GPL-2.0+
86b239db4SRick Chen  */
96b239db4SRick Chen 
106b239db4SRick Chen #include <clk.h>
116b239db4SRick Chen #include <common.h>
126b239db4SRick Chen #include <malloc.h>
136b239db4SRick Chen #include <spi.h>
146b239db4SRick Chen #include <asm/io.h>
156b239db4SRick Chen #include <dm.h>
166b239db4SRick Chen 
176b239db4SRick Chen DECLARE_GLOBAL_DATA_PTR;
186b239db4SRick Chen 
196b239db4SRick Chen #define MAX_TRANSFER_LEN	512
206b239db4SRick Chen #define CHUNK_SIZE		1
216b239db4SRick Chen #define SPI_TIMEOUT		0x100000
226b239db4SRick Chen #define SPI0_BUS		0
236b239db4SRick Chen #define SPI1_BUS		1
246b239db4SRick Chen #define SPI0_BASE		0xf0b00000
256b239db4SRick Chen #define SPI1_BASE		0xf0f00000
266b239db4SRick Chen #define NSPI_MAX_CS_NUM		1
276b239db4SRick Chen 
28*ab1460f2SRick Chen struct atcspi200_spi_regs {
296b239db4SRick Chen 	u32	rev;
306b239db4SRick Chen 	u32	reserve1[3];
316b239db4SRick Chen 	u32	format;		/* 0x10 */
326b239db4SRick Chen #define DATA_LENGTH(x)	((x-1)<<8)
336b239db4SRick Chen 	u32	pio;
346b239db4SRick Chen 	u32	reserve2[2];
356b239db4SRick Chen 	u32	tctrl;		/* 0x20 */
366b239db4SRick Chen #define TRAMODE_OFFSET	24
376b239db4SRick Chen #define TRAMODE_MASK	(0x0F<<TRAMODE_OFFSET)
386b239db4SRick Chen #define TRAMODE_WR_SYNC	(0<<TRAMODE_OFFSET)
396b239db4SRick Chen #define TRAMODE_WO	(1<<TRAMODE_OFFSET)
406b239db4SRick Chen #define TRAMODE_RO	(2<<TRAMODE_OFFSET)
416b239db4SRick Chen #define TRAMODE_WR	(3<<TRAMODE_OFFSET)
426b239db4SRick Chen #define TRAMODE_RW	(4<<TRAMODE_OFFSET)
436b239db4SRick Chen #define TRAMODE_WDR	(5<<TRAMODE_OFFSET)
446b239db4SRick Chen #define TRAMODE_RDW	(6<<TRAMODE_OFFSET)
456b239db4SRick Chen #define TRAMODE_NONE	(7<<TRAMODE_OFFSET)
466b239db4SRick Chen #define TRAMODE_DW	(8<<TRAMODE_OFFSET)
476b239db4SRick Chen #define TRAMODE_DR	(9<<TRAMODE_OFFSET)
486b239db4SRick Chen #define WCNT_OFFSET	12
496b239db4SRick Chen #define WCNT_MASK	(0x1FF<<WCNT_OFFSET)
506b239db4SRick Chen #define RCNT_OFFSET	0
516b239db4SRick Chen #define RCNT_MASK	(0x1FF<<RCNT_OFFSET)
526b239db4SRick Chen 	u32	cmd;
536b239db4SRick Chen 	u32	addr;
546b239db4SRick Chen 	u32	data;
556b239db4SRick Chen 	u32	ctrl;		/* 0x30 */
566b239db4SRick Chen #define TXFTH_OFFSET	16
576b239db4SRick Chen #define RXFTH_OFFSET	8
586b239db4SRick Chen #define TXDMAEN		(1<<4)
596b239db4SRick Chen #define RXDMAEN		(1<<3)
606b239db4SRick Chen #define TXFRST		(1<<2)
616b239db4SRick Chen #define RXFRST		(1<<1)
626b239db4SRick Chen #define SPIRST		(1<<0)
636b239db4SRick Chen 	u32	status;
646b239db4SRick Chen #define TXFFL		(1<<23)
656b239db4SRick Chen #define TXEPTY		(1<<22)
666b239db4SRick Chen #define TXFVE_MASK	(0x1F<<16)
676b239db4SRick Chen #define RXFEM		(1<<14)
686b239db4SRick Chen #define RXFVE_OFFSET	(8)
696b239db4SRick Chen #define RXFVE_MASK	(0x1F<<RXFVE_OFFSET)
706b239db4SRick Chen #define SPIBSY		(1<<0)
716b239db4SRick Chen 	u32	inten;
726b239db4SRick Chen 	u32	intsta;
736b239db4SRick Chen 	u32	timing;		/* 0x40 */
746b239db4SRick Chen #define SCLK_DIV_MASK	0xFF
756b239db4SRick Chen };
766b239db4SRick Chen 
776b239db4SRick Chen struct nds_spi_slave {
78*ab1460f2SRick Chen 	volatile struct atcspi200_spi_regs *regs;
796b239db4SRick Chen 	int		to;
806b239db4SRick Chen 	unsigned int	freq;
816b239db4SRick Chen 	ulong		clock;
826b239db4SRick Chen 	unsigned int	mode;
836b239db4SRick Chen 	u8 		num_cs;
846b239db4SRick Chen 	unsigned int	mtiming;
856b239db4SRick Chen 	size_t		cmd_len;
866b239db4SRick Chen 	u8		cmd_buf[16];
876b239db4SRick Chen 	size_t		data_len;
886b239db4SRick Chen 	size_t		tran_len;
896b239db4SRick Chen 	u8		*din;
906b239db4SRick Chen 	u8		*dout;
916b239db4SRick Chen 	unsigned int    max_transfer_length;
926b239db4SRick Chen };
936b239db4SRick Chen 
__atcspi200_spi_set_speed(struct nds_spi_slave * ns)94*ab1460f2SRick Chen static int __atcspi200_spi_set_speed(struct nds_spi_slave *ns)
956b239db4SRick Chen {
966b239db4SRick Chen 	u32 tm;
976b239db4SRick Chen 	u8 div;
986b239db4SRick Chen 	tm = ns->regs->timing;
996b239db4SRick Chen 	tm &= ~SCLK_DIV_MASK;
1006b239db4SRick Chen 
1016b239db4SRick Chen 	if(ns->freq >= ns->clock)
1026b239db4SRick Chen 		div =0xff;
1036b239db4SRick Chen 	else{
1046b239db4SRick Chen 		for (div = 0; div < 0xff; div++) {
1056b239db4SRick Chen 			if (ns->freq >= ns->clock / (2 * (div + 1)))
1066b239db4SRick Chen 				break;
1076b239db4SRick Chen 		}
1086b239db4SRick Chen 	}
1096b239db4SRick Chen 
1106b239db4SRick Chen 	tm |= div;
1116b239db4SRick Chen 	ns->regs->timing = tm;
1126b239db4SRick Chen 
1136b239db4SRick Chen 	return 0;
1146b239db4SRick Chen 
1156b239db4SRick Chen }
1166b239db4SRick Chen 
__atcspi200_spi_claim_bus(struct nds_spi_slave * ns)117*ab1460f2SRick Chen static int __atcspi200_spi_claim_bus(struct nds_spi_slave *ns)
1186b239db4SRick Chen {
1196b239db4SRick Chen 		unsigned int format=0;
1206b239db4SRick Chen 		ns->regs->ctrl |= (TXFRST|RXFRST|SPIRST);
1216b239db4SRick Chen 		while((ns->regs->ctrl &(TXFRST|RXFRST|SPIRST))&&(ns->to--))
1226b239db4SRick Chen 			if(!ns->to)
1236b239db4SRick Chen 				return -EINVAL;
1246b239db4SRick Chen 
1256b239db4SRick Chen 		ns->cmd_len = 0;
1266b239db4SRick Chen 		format = ns->mode|DATA_LENGTH(8);
1276b239db4SRick Chen 		ns->regs->format = format;
128*ab1460f2SRick Chen 		__atcspi200_spi_set_speed(ns);
1296b239db4SRick Chen 
1306b239db4SRick Chen 		return 0;
1316b239db4SRick Chen }
1326b239db4SRick Chen 
__atcspi200_spi_release_bus(struct nds_spi_slave * ns)133*ab1460f2SRick Chen static int __atcspi200_spi_release_bus(struct nds_spi_slave *ns)
1346b239db4SRick Chen {
1356b239db4SRick Chen 	/* do nothing */
1366b239db4SRick Chen 	return 0;
1376b239db4SRick Chen }
1386b239db4SRick Chen 
__atcspi200_spi_start(struct nds_spi_slave * ns)139*ab1460f2SRick Chen static int __atcspi200_spi_start(struct nds_spi_slave *ns)
1406b239db4SRick Chen {
1416b239db4SRick Chen 	int i,olen=0;
1426b239db4SRick Chen 	int tc = ns->regs->tctrl;
1436b239db4SRick Chen 
1446b239db4SRick Chen 	tc &= ~(WCNT_MASK|RCNT_MASK|TRAMODE_MASK);
1456b239db4SRick Chen 	if ((ns->din)&&(ns->cmd_len))
1466b239db4SRick Chen 		tc |= TRAMODE_WR;
1476b239db4SRick Chen 	else if (ns->din)
1486b239db4SRick Chen 		tc |= TRAMODE_RO;
1496b239db4SRick Chen 	else
1506b239db4SRick Chen 		tc |= TRAMODE_WO;
1516b239db4SRick Chen 
1526b239db4SRick Chen 	if(ns->dout)
1536b239db4SRick Chen 		olen = ns->tran_len;
1546b239db4SRick Chen 	tc |= (ns->cmd_len+olen-1) << WCNT_OFFSET;
1556b239db4SRick Chen 
1566b239db4SRick Chen 	if(ns->din)
1576b239db4SRick Chen 		tc |= (ns->tran_len-1) << RCNT_OFFSET;
1586b239db4SRick Chen 
1596b239db4SRick Chen 	ns->regs->tctrl = tc;
1606b239db4SRick Chen 	ns->regs->cmd = 1;
1616b239db4SRick Chen 
1626b239db4SRick Chen 	for (i=0;i<ns->cmd_len;i++)
1636b239db4SRick Chen 		ns->regs->data = ns->cmd_buf[i];
1646b239db4SRick Chen 
1656b239db4SRick Chen 	return 0;
1666b239db4SRick Chen }
1676b239db4SRick Chen 
__atcspi200_spi_stop(struct nds_spi_slave * ns)168*ab1460f2SRick Chen static int __atcspi200_spi_stop(struct nds_spi_slave *ns)
1696b239db4SRick Chen {
1706b239db4SRick Chen 	ns->regs->timing = ns->mtiming;
1716b239db4SRick Chen 	while ((ns->regs->status & SPIBSY)&&(ns->to--))
1726b239db4SRick Chen 		if (!ns->to)
1736b239db4SRick Chen 			return -EINVAL;
1746b239db4SRick Chen 
1756b239db4SRick Chen 	return 0;
1766b239db4SRick Chen }
1776b239db4SRick Chen 
__nspi_espi_tx(struct nds_spi_slave * ns,const void * dout)1786b239db4SRick Chen static void __nspi_espi_tx(struct nds_spi_slave *ns, const void *dout)
1796b239db4SRick Chen {
1806b239db4SRick Chen 	ns->regs->data = *(u8 *)dout;
1816b239db4SRick Chen }
1826b239db4SRick Chen 
__nspi_espi_rx(struct nds_spi_slave * ns,void * din,unsigned int bytes)1836b239db4SRick Chen static int __nspi_espi_rx(struct nds_spi_slave *ns, void *din, unsigned int bytes)
1846b239db4SRick Chen {
1856b239db4SRick Chen 	*(u8 *)din = ns->regs->data;
1866b239db4SRick Chen 	return bytes;
1876b239db4SRick Chen }
1886b239db4SRick Chen 
1896b239db4SRick Chen 
__atcspi200_spi_xfer(struct nds_spi_slave * ns,unsigned int bitlen,const void * data_out,void * data_in,unsigned long flags)190*ab1460f2SRick Chen static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
1916b239db4SRick Chen 		unsigned int bitlen,  const void *data_out, void *data_in,
1926b239db4SRick Chen 		unsigned long flags)
1936b239db4SRick Chen {
1946b239db4SRick Chen 		unsigned int event, rx_bytes;
1956b239db4SRick Chen 		const void *dout = NULL;
1966b239db4SRick Chen 		void *din = NULL;
1976b239db4SRick Chen 		int num_blks, num_chunks, max_tran_len, tran_len;
1986b239db4SRick Chen 		int num_bytes;
1996b239db4SRick Chen 		u8 *cmd_buf = ns->cmd_buf;
2006b239db4SRick Chen 		size_t cmd_len = ns->cmd_len;
2016b239db4SRick Chen 		size_t data_len = bitlen / 8;
2026b239db4SRick Chen 		int rf_cnt;
2036b239db4SRick Chen 		int ret = 0;
2046b239db4SRick Chen 
2056b239db4SRick Chen 		max_tran_len = ns->max_transfer_length;
2066b239db4SRick Chen 		switch (flags) {
2076b239db4SRick Chen 		case SPI_XFER_BEGIN:
2086b239db4SRick Chen 			cmd_len = ns->cmd_len = data_len;
2096b239db4SRick Chen 			memcpy(cmd_buf, data_out, cmd_len);
2106b239db4SRick Chen 			return 0;
2116b239db4SRick Chen 
2126b239db4SRick Chen 		case 0:
2136b239db4SRick Chen 		case SPI_XFER_END:
2146b239db4SRick Chen 			if (bitlen == 0) {
2156b239db4SRick Chen 				return 0;
2166b239db4SRick Chen 			}
2176b239db4SRick Chen 			ns->data_len = data_len;
2186b239db4SRick Chen 			ns->din = (u8 *)data_in;
2196b239db4SRick Chen 			ns->dout = (u8 *)data_out;
2206b239db4SRick Chen 			break;
2216b239db4SRick Chen 
2226b239db4SRick Chen 		case SPI_XFER_BEGIN | SPI_XFER_END:
2236b239db4SRick Chen 			ns->data_len = 0;
2246b239db4SRick Chen 			ns->din = 0;
2256b239db4SRick Chen 			ns->dout = 0;
2266b239db4SRick Chen 			cmd_len = ns->cmd_len = data_len;
2276b239db4SRick Chen 			memcpy(cmd_buf, data_out, cmd_len);
2286b239db4SRick Chen 			data_out = 0;
2296b239db4SRick Chen 			data_len = 0;
230*ab1460f2SRick Chen 			__atcspi200_spi_start(ns);
2316b239db4SRick Chen 			break;
2326b239db4SRick Chen 		}
2336b239db4SRick Chen 		debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) data_len %u\n",
2346b239db4SRick Chen 		      *(uint *)data_out, data_out, *(uint *)data_in, data_in, data_len);
2356b239db4SRick Chen 		num_chunks = DIV_ROUND_UP(data_len, max_tran_len);
2366b239db4SRick Chen 		din = data_in;
2376b239db4SRick Chen 		dout = data_out;
2386b239db4SRick Chen 		while (num_chunks--) {
2396b239db4SRick Chen 			tran_len = min(data_len, (size_t)max_tran_len);
2406b239db4SRick Chen 			ns->tran_len = tran_len;
2416b239db4SRick Chen 			num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE);
2426b239db4SRick Chen 			num_bytes = (tran_len) % CHUNK_SIZE;
2436b239db4SRick Chen 			if(num_bytes == 0)
2446b239db4SRick Chen 				num_bytes = CHUNK_SIZE;
245*ab1460f2SRick Chen 			__atcspi200_spi_start(ns);
2466b239db4SRick Chen 
2476b239db4SRick Chen 			while (num_blks) {
2486b239db4SRick Chen 				event = in_le32(&ns->regs->status);
2496b239db4SRick Chen 				if ((event & TXEPTY) && (data_out)) {
2506b239db4SRick Chen 					__nspi_espi_tx(ns, dout);
2516b239db4SRick Chen 					num_blks -= CHUNK_SIZE;
2526b239db4SRick Chen 					dout += CHUNK_SIZE;
2536b239db4SRick Chen 				}
2546b239db4SRick Chen 
2556b239db4SRick Chen 				if ((event & RXFVE_MASK) && (data_in)) {
2566b239db4SRick Chen 					rf_cnt = ((event & RXFVE_MASK)>> RXFVE_OFFSET);
2576b239db4SRick Chen 					if (rf_cnt >= CHUNK_SIZE)
2586b239db4SRick Chen 						rx_bytes = CHUNK_SIZE;
2596b239db4SRick Chen 					else if (num_blks == 1 && rf_cnt == num_bytes)
2606b239db4SRick Chen 						rx_bytes = num_bytes;
2616b239db4SRick Chen 					else
2626b239db4SRick Chen 						continue;
2636b239db4SRick Chen 
2646b239db4SRick Chen 					if (__nspi_espi_rx(ns, din, rx_bytes) == rx_bytes) {
2656b239db4SRick Chen 						num_blks -= CHUNK_SIZE;
2666b239db4SRick Chen 						din = (unsigned char *)din + rx_bytes;
2676b239db4SRick Chen 					}
2686b239db4SRick Chen 				}
2696b239db4SRick Chen 			}
2706b239db4SRick Chen 
2716b239db4SRick Chen 			data_len -= tran_len;
2726b239db4SRick Chen 			if(data_len)
2736b239db4SRick Chen 			{
2746b239db4SRick Chen 				ns->cmd_buf[1] += ((tran_len>>16)&0xff);
2756b239db4SRick Chen 				ns->cmd_buf[2] += ((tran_len>>8)&0xff);
2766b239db4SRick Chen 				ns->cmd_buf[3] += ((tran_len)&0xff);
2776b239db4SRick Chen 				ns->data_len = data_len;
2786b239db4SRick Chen 			}
279*ab1460f2SRick Chen 			ret = __atcspi200_spi_stop(ns);
2806b239db4SRick Chen 		}
281*ab1460f2SRick Chen 		ret = __atcspi200_spi_stop(ns);
2826b239db4SRick Chen 
2836b239db4SRick Chen 		return ret;
2846b239db4SRick Chen }
2856b239db4SRick Chen 
atcspi200_spi_set_speed(struct udevice * bus,uint max_hz)286*ab1460f2SRick Chen static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz)
2876b239db4SRick Chen {
2886b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
2896b239db4SRick Chen 
2906b239db4SRick Chen 	debug("%s speed %u\n", __func__, max_hz);
2916b239db4SRick Chen 
2926b239db4SRick Chen 	ns->freq = max_hz;
293*ab1460f2SRick Chen 	__atcspi200_spi_set_speed(ns);
2946b239db4SRick Chen 
2956b239db4SRick Chen 	return 0;
2966b239db4SRick Chen }
2976b239db4SRick Chen 
atcspi200_spi_set_mode(struct udevice * bus,uint mode)298*ab1460f2SRick Chen static int atcspi200_spi_set_mode(struct udevice *bus, uint mode)
2996b239db4SRick Chen {
3006b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3016b239db4SRick Chen 
3026b239db4SRick Chen 	debug("%s mode %u\n", __func__, mode);
3036b239db4SRick Chen 	ns->mode = mode;
3046b239db4SRick Chen 
3056b239db4SRick Chen 	return 0;
3066b239db4SRick Chen }
3076b239db4SRick Chen 
atcspi200_spi_claim_bus(struct udevice * dev)308*ab1460f2SRick Chen static int atcspi200_spi_claim_bus(struct udevice *dev)
3096b239db4SRick Chen {
3106b239db4SRick Chen 	struct dm_spi_slave_platdata *slave_plat =
3116b239db4SRick Chen 		dev_get_parent_platdata(dev);
3126b239db4SRick Chen 	struct udevice *bus = dev->parent;
3136b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3146b239db4SRick Chen 
3156b239db4SRick Chen 	if (slave_plat->cs >= ns->num_cs) {
3166b239db4SRick Chen 		printf("Invalid SPI chipselect\n");
3176b239db4SRick Chen 		return -EINVAL;
3186b239db4SRick Chen 	}
3196b239db4SRick Chen 
320*ab1460f2SRick Chen 	return __atcspi200_spi_claim_bus(ns);
3216b239db4SRick Chen }
3226b239db4SRick Chen 
atcspi200_spi_release_bus(struct udevice * dev)323*ab1460f2SRick Chen static int atcspi200_spi_release_bus(struct udevice *dev)
3246b239db4SRick Chen {
3256b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(dev->parent);
3266b239db4SRick Chen 
327*ab1460f2SRick Chen 	return __atcspi200_spi_release_bus(ns);
3286b239db4SRick Chen }
3296b239db4SRick Chen 
atcspi200_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)330*ab1460f2SRick Chen static int atcspi200_spi_xfer(struct udevice *dev, unsigned int bitlen,
3316b239db4SRick Chen 			    const void *dout, void *din,
3326b239db4SRick Chen 			    unsigned long flags)
3336b239db4SRick Chen {
3346b239db4SRick Chen 	struct udevice *bus = dev->parent;
3356b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3366b239db4SRick Chen 
337*ab1460f2SRick Chen 	return __atcspi200_spi_xfer(ns, bitlen, dout, din, flags);
3386b239db4SRick Chen }
3396b239db4SRick Chen 
atcspi200_spi_get_clk(struct udevice * bus)340*ab1460f2SRick Chen static int atcspi200_spi_get_clk(struct udevice *bus)
3416b239db4SRick Chen {
3426b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3436b239db4SRick Chen 	struct clk clk;
3446b239db4SRick Chen 	ulong clk_rate;
3456b239db4SRick Chen 	int ret;
3466b239db4SRick Chen 
3476b239db4SRick Chen 	ret = clk_get_by_index(bus, 0, &clk);
3486b239db4SRick Chen 	if (ret)
3496b239db4SRick Chen 		return -EINVAL;
3506b239db4SRick Chen 
3516b239db4SRick Chen 	clk_rate = clk_get_rate(&clk);
3526b239db4SRick Chen 	if (!clk_rate)
3536b239db4SRick Chen 		return -EINVAL;
3546b239db4SRick Chen 
3556b239db4SRick Chen 	ns->clock = clk_rate;
3566b239db4SRick Chen 	clk_free(&clk);
3576b239db4SRick Chen 
3586b239db4SRick Chen 	return 0;
3596b239db4SRick Chen }
3606b239db4SRick Chen 
atcspi200_spi_probe(struct udevice * bus)361*ab1460f2SRick Chen static int atcspi200_spi_probe(struct udevice *bus)
3626b239db4SRick Chen {
3636b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3646b239db4SRick Chen 
3656b239db4SRick Chen 	ns->to = SPI_TIMEOUT;
3666b239db4SRick Chen 	ns->max_transfer_length = MAX_TRANSFER_LEN;
3676b239db4SRick Chen 	ns->mtiming = ns->regs->timing;
368*ab1460f2SRick Chen 	atcspi200_spi_get_clk(bus);
3696b239db4SRick Chen 
3706b239db4SRick Chen 	return 0;
3716b239db4SRick Chen }
3726b239db4SRick Chen 
atcspi200_ofdata_to_platadata(struct udevice * bus)373*ab1460f2SRick Chen static int atcspi200_ofdata_to_platadata(struct udevice *bus)
3746b239db4SRick Chen {
3756b239db4SRick Chen 	struct nds_spi_slave *ns = dev_get_priv(bus);
3766b239db4SRick Chen 	const void *blob = gd->fdt_blob;
3776b239db4SRick Chen 	int node = dev_of_offset(bus);
3786b239db4SRick Chen 
3796b239db4SRick Chen 	ns->regs = map_physmem(devfdt_get_addr(bus),
380*ab1460f2SRick Chen 				 sizeof(struct atcspi200_spi_regs),
3816b239db4SRick Chen 				 MAP_NOCACHE);
3826b239db4SRick Chen 	if (!ns->regs) {
3836b239db4SRick Chen 		printf("%s: could not map device address\n", __func__);
3846b239db4SRick Chen 		return -EINVAL;
3856b239db4SRick Chen 	}
3866b239db4SRick Chen 	ns->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
3876b239db4SRick Chen 
3886b239db4SRick Chen 	return 0;
3896b239db4SRick Chen }
3906b239db4SRick Chen 
391*ab1460f2SRick Chen static const struct dm_spi_ops atcspi200_spi_ops = {
392*ab1460f2SRick Chen 	.claim_bus	= atcspi200_spi_claim_bus,
393*ab1460f2SRick Chen 	.release_bus	= atcspi200_spi_release_bus,
394*ab1460f2SRick Chen 	.xfer		= atcspi200_spi_xfer,
395*ab1460f2SRick Chen 	.set_speed	= atcspi200_spi_set_speed,
396*ab1460f2SRick Chen 	.set_mode	= atcspi200_spi_set_mode,
3976b239db4SRick Chen };
3986b239db4SRick Chen 
399*ab1460f2SRick Chen static const struct udevice_id atcspi200_spi_ids[] = {
4006b239db4SRick Chen 	{ .compatible = "andestech,atcspi200" },
4016b239db4SRick Chen 	{ }
4026b239db4SRick Chen };
4036b239db4SRick Chen 
404*ab1460f2SRick Chen U_BOOT_DRIVER(atcspi200_spi) = {
405*ab1460f2SRick Chen 	.name = "atcspi200_spi",
4066b239db4SRick Chen 	.id = UCLASS_SPI,
407*ab1460f2SRick Chen 	.of_match = atcspi200_spi_ids,
408*ab1460f2SRick Chen 	.ops = &atcspi200_spi_ops,
409*ab1460f2SRick Chen 	.ofdata_to_platdata = atcspi200_ofdata_to_platadata,
4106b239db4SRick Chen 	.priv_auto_alloc_size = sizeof(struct nds_spi_slave),
411*ab1460f2SRick Chen 	.probe = atcspi200_spi_probe,
4126b239db4SRick Chen };
413