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