1c1cd6cb6SAndy Yan /* 2c1cd6cb6SAndy Yan * sfc driver for rockchip 3c1cd6cb6SAndy Yan * 4c1cd6cb6SAndy Yan * (C) Copyright 2008-2016 Rockchip Electronics 5c1cd6cb6SAndy Yan * Yifeng.zhao, Software Engineering, <zhao0116@gmail.com>. 6c1cd6cb6SAndy Yan * 7c1cd6cb6SAndy Yan * SPDX-License-Identifier: GPL-2.0+ 8c1cd6cb6SAndy Yan */ 9c1cd6cb6SAndy Yan 10c1cd6cb6SAndy Yan #include <common.h> 11c1cd6cb6SAndy Yan #include <clk.h> 12c1cd6cb6SAndy Yan #include <dm.h> 13c1cd6cb6SAndy Yan #include <dt-structs.h> 14c1cd6cb6SAndy Yan #include <errno.h> 15c1cd6cb6SAndy Yan #include <spi.h> 16c1cd6cb6SAndy Yan #include <linux/errno.h> 17c1cd6cb6SAndy Yan #include <asm/io.h> 18c1cd6cb6SAndy Yan #include <asm/arch/clock.h> 19c1cd6cb6SAndy Yan #include <asm/arch/periph.h> 20c1cd6cb6SAndy Yan #include <dm/pinctrl.h> 21c1cd6cb6SAndy Yan #include "rockchip_sfc.h" 22c1cd6cb6SAndy Yan 23c1cd6cb6SAndy Yan DECLARE_GLOBAL_DATA_PTR; 24c1cd6cb6SAndy Yan 25c1cd6cb6SAndy Yan enum rockchip_sfc_if_type { 26c1cd6cb6SAndy Yan IF_TYPE_STD, 27c1cd6cb6SAndy Yan IF_TYPE_DUAL, 28c1cd6cb6SAndy Yan IF_TYPE_QUAD, 29c1cd6cb6SAndy Yan }; 30c1cd6cb6SAndy Yan 31c1cd6cb6SAndy Yan struct rockchip_sfc_platdata { 32c1cd6cb6SAndy Yan s32 frequency; 33c1cd6cb6SAndy Yan fdt_addr_t base; 34c1cd6cb6SAndy Yan }; 35c1cd6cb6SAndy Yan 36c1cd6cb6SAndy Yan struct rockchip_sfc { 37c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regbase; 38c1cd6cb6SAndy Yan struct clk clk; 39c1cd6cb6SAndy Yan unsigned int max_freq; 40c1cd6cb6SAndy Yan unsigned int mode; 41c1cd6cb6SAndy Yan unsigned int speed_hz; 42c1cd6cb6SAndy Yan u32 cmd; 43c1cd6cb6SAndy Yan u32 addr; 44c1cd6cb6SAndy Yan }; 45c1cd6cb6SAndy Yan 46c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) 47c1cd6cb6SAndy Yan { 48c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 49c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 50c1cd6cb6SAndy Yan const void *blob = gd->fdt_blob; 51c1cd6cb6SAndy Yan int node = dev_of_offset(bus); 52c1cd6cb6SAndy Yan int subnode; 53c1cd6cb6SAndy Yan int ret; 54c1cd6cb6SAndy Yan 55c1cd6cb6SAndy Yan plat->base = devfdt_get_addr(bus); 56c1cd6cb6SAndy Yan 57c1cd6cb6SAndy Yan ret = clk_get_by_index(bus, 0, &sfc->clk); 58c1cd6cb6SAndy Yan if (ret < 0) { 59c1cd6cb6SAndy Yan debug("Could not get clock for %s: %d\n", bus->name, ret); 60c1cd6cb6SAndy Yan return ret; 61c1cd6cb6SAndy Yan } 62c1cd6cb6SAndy Yan 63c1cd6cb6SAndy Yan subnode = fdt_first_subnode(blob, node); 64c1cd6cb6SAndy Yan if (subnode < 0) { 65c1cd6cb6SAndy Yan debug("Error: subnode with SPI flash config missing!\n"); 66c1cd6cb6SAndy Yan return -ENODEV; 67c1cd6cb6SAndy Yan } 68c1cd6cb6SAndy Yan 69c1cd6cb6SAndy Yan plat->frequency = fdtdec_get_int(blob, subnode, "spi-max-frequency", 70c1cd6cb6SAndy Yan 100000000); 71c1cd6cb6SAndy Yan 72c1cd6cb6SAndy Yan return 0; 73c1cd6cb6SAndy Yan } 74c1cd6cb6SAndy Yan 75c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus) 76c1cd6cb6SAndy Yan { 77c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 78c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 79c1cd6cb6SAndy Yan int ret; 80c1cd6cb6SAndy Yan 81c1cd6cb6SAndy Yan sfc->regbase = (struct rockchip_sfc_reg *)plat->base; 82c1cd6cb6SAndy Yan 83c1cd6cb6SAndy Yan sfc->max_freq = plat->frequency; 84c1cd6cb6SAndy Yan 85c1cd6cb6SAndy Yan ret = clk_set_rate(&sfc->clk, sfc->max_freq); 86c1cd6cb6SAndy Yan if (ret < 0) { 87c1cd6cb6SAndy Yan debug("%s: Failed to set clock: %d\n", __func__, ret); 88c1cd6cb6SAndy Yan return ret; 89c1cd6cb6SAndy Yan } 90c1cd6cb6SAndy Yan 91c1cd6cb6SAndy Yan return 0; 92c1cd6cb6SAndy Yan } 93c1cd6cb6SAndy Yan 94c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc) 95c1cd6cb6SAndy Yan { 96c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 97c1cd6cb6SAndy Yan int tbase = get_timer(0); 98c1cd6cb6SAndy Yan u32 rcvr; 99c1cd6cb6SAndy Yan int ret = 0; 100c1cd6cb6SAndy Yan 101c1cd6cb6SAndy Yan writel(SFC_RESET, ®s->rcvr); 102c1cd6cb6SAndy Yan do { 103c1cd6cb6SAndy Yan rcvr = readl(®s->rcvr); 104c1cd6cb6SAndy Yan if (get_timer(tbase) > 1000) { 105c1cd6cb6SAndy Yan debug("sfc reset timeout\n"); 106c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 107c1cd6cb6SAndy Yan break; 108c1cd6cb6SAndy Yan } 109c1cd6cb6SAndy Yan udelay(1); 110c1cd6cb6SAndy Yan } while (rcvr); 111c1cd6cb6SAndy Yan 112c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 113c1cd6cb6SAndy Yan 114c1cd6cb6SAndy Yan debug("sfc reset\n"); 115c1cd6cb6SAndy Yan 116c1cd6cb6SAndy Yan return ret; 117c1cd6cb6SAndy Yan } 118c1cd6cb6SAndy Yan 119c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc) 120c1cd6cb6SAndy Yan { 121c1cd6cb6SAndy Yan int type = IF_TYPE_STD; 122c1cd6cb6SAndy Yan 123c1cd6cb6SAndy Yan if (sfc->cmd & SFC_WR) { 124c1cd6cb6SAndy Yan if (sfc->mode & SPI_TX_QUAD) 125c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 126c1cd6cb6SAndy Yan else if (sfc->mode & SPI_TX_DUAL) 127c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 128c1cd6cb6SAndy Yan else 129c1cd6cb6SAndy Yan type = IF_TYPE_STD; 130c1cd6cb6SAndy Yan } else { 131c1cd6cb6SAndy Yan if (sfc->mode & SPI_RX_QUAD) 132c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 133c1cd6cb6SAndy Yan else if (sfc->mode & SPI_RX_DUAL) 134c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 135c1cd6cb6SAndy Yan else 136c1cd6cb6SAndy Yan type = IF_TYPE_STD; 137c1cd6cb6SAndy Yan } 138c1cd6cb6SAndy Yan 139c1cd6cb6SAndy Yan return type; 140c1cd6cb6SAndy Yan } 141c1cd6cb6SAndy Yan 142c1cd6cb6SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc) 143c1cd6cb6SAndy Yan { 144c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 145c1cd6cb6SAndy Yan u32 val = 0x02; 146c1cd6cb6SAndy Yan u32 fsr = readl(®s->fsr); 147c1cd6cb6SAndy Yan u32 sr = readl(®s->sr); 148c1cd6cb6SAndy Yan u8 data_width = IF_TYPE_STD; 149c1cd6cb6SAndy Yan 150c1cd6cb6SAndy Yan if (!(fsr & SFC_TX_EMPTY) || !(fsr & SFC_RX_EMPTY) || (sr & SFC_BUSY)) 151c1cd6cb6SAndy Yan rockchip_sfc_reset(sfc); 152c1cd6cb6SAndy Yan 153c1cd6cb6SAndy Yan if (sfc->cmd & SFC_ADDR_XBITS) 154c1cd6cb6SAndy Yan data_width = rockchip_sfc_get_if_type(sfc); 155c1cd6cb6SAndy Yan 156c1cd6cb6SAndy Yan val |= (data_width << SFC_DATA_WIDTH_SHIFT); 157c1cd6cb6SAndy Yan 158c1cd6cb6SAndy Yan writel(val, ®s->ctrl); 159c1cd6cb6SAndy Yan writel(sfc->cmd, ®s->cmd); 160c1cd6cb6SAndy Yan if (sfc->cmd & SFC_ADDR_XBITS) 161c1cd6cb6SAndy Yan writel(sfc->addr, ®s->addr); 162c1cd6cb6SAndy Yan } 163c1cd6cb6SAndy Yan 164c1cd6cb6SAndy Yan static int rockchip_sfc_do_dma_xfer(struct rockchip_sfc *sfc, u32 *buffer) 165c1cd6cb6SAndy Yan { 166c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 167c1cd6cb6SAndy Yan int timeout = 1000; 168c1cd6cb6SAndy Yan int ret = 0; 169c1cd6cb6SAndy Yan int risr; 170c1cd6cb6SAndy Yan unsigned long tbase; 171c1cd6cb6SAndy Yan 172c1cd6cb6SAndy Yan rockchip_sfc_setup_xfer(sfc); 173c1cd6cb6SAndy Yan 174c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 175c1cd6cb6SAndy Yan writel((u32)buffer, ®s->dmaaddr); 176c1cd6cb6SAndy Yan writel(SFC_DMA_START, ®s->dmatr); 177c1cd6cb6SAndy Yan 178c1cd6cb6SAndy Yan tbase = get_timer(0); 179c1cd6cb6SAndy Yan do { 180c1cd6cb6SAndy Yan udelay(1); 181c1cd6cb6SAndy Yan risr = readl(®s->risr); 182c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) { 183c1cd6cb6SAndy Yan debug("dma timeout\n"); 184c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 185c1cd6cb6SAndy Yan break; 186c1cd6cb6SAndy Yan } 187c1cd6cb6SAndy Yan } while (!(risr & TRANS_FINISH_INT)); 188c1cd6cb6SAndy Yan 189c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 190c1cd6cb6SAndy Yan 191c1cd6cb6SAndy Yan return ret; 192c1cd6cb6SAndy Yan } 193c1cd6cb6SAndy Yan 194c1cd6cb6SAndy Yan static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len) 195c1cd6cb6SAndy Yan { 196c1cd6cb6SAndy Yan u32 trb; 197c1cd6cb6SAndy Yan u32 *p32_data = buf; 198c1cd6cb6SAndy Yan int ret = 0; 199c1cd6cb6SAndy Yan 200c1cd6cb6SAndy Yan while (len) { 201c1cd6cb6SAndy Yan trb = min(len, (u32)SFC_MAX_TRB); 202*6bf64646SAndy Yan sfc->cmd &= ~SFC_TRB_MASK; 203c1cd6cb6SAndy Yan sfc->cmd |= (trb << SFC_TRB_SHIFT); 204c1cd6cb6SAndy Yan ret = rockchip_sfc_do_dma_xfer(sfc, p32_data); 205c1cd6cb6SAndy Yan if (ret < 0) 206c1cd6cb6SAndy Yan break; 207c1cd6cb6SAndy Yan len -= trb; 208c1cd6cb6SAndy Yan sfc->addr += trb; 209c1cd6cb6SAndy Yan p32_data += (trb >> 2); 210c1cd6cb6SAndy Yan } 211c1cd6cb6SAndy Yan 212c1cd6cb6SAndy Yan return ret; 213c1cd6cb6SAndy Yan } 214c1cd6cb6SAndy Yan 215c1cd6cb6SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr, 216c1cd6cb6SAndy Yan u32 timeout) 217c1cd6cb6SAndy Yan { 218c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 219c1cd6cb6SAndy Yan unsigned long tbase = get_timer(0); 220c1cd6cb6SAndy Yan u8 level; 221c1cd6cb6SAndy Yan u32 fsr; 222c1cd6cb6SAndy Yan 223c1cd6cb6SAndy Yan do { 224c1cd6cb6SAndy Yan fsr = readl(®s->fsr); 225c1cd6cb6SAndy Yan if (wr) 226c1cd6cb6SAndy Yan level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT; 227c1cd6cb6SAndy Yan else 228c1cd6cb6SAndy Yan level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT; 229c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) 230c1cd6cb6SAndy Yan return -ETIMEDOUT; 231c1cd6cb6SAndy Yan udelay(1); 232c1cd6cb6SAndy Yan } while (!level); 233c1cd6cb6SAndy Yan 234c1cd6cb6SAndy Yan return level; 235c1cd6cb6SAndy Yan } 236c1cd6cb6SAndy Yan 237c1cd6cb6SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 *buf, u32 len) 238c1cd6cb6SAndy Yan { 239c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 240c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 241c1cd6cb6SAndy Yan u32 words = len >> 2; 242c1cd6cb6SAndy Yan u32 tx_level = 0; 243c1cd6cb6SAndy Yan u32 val = 0; 244c1cd6cb6SAndy Yan u8 count; 245c1cd6cb6SAndy Yan 246c1cd6cb6SAndy Yan while (words) { 247c1cd6cb6SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, 1, 1000); 248c1cd6cb6SAndy Yan if (tx_level <= 0) 249c1cd6cb6SAndy Yan return tx_level; 250c1cd6cb6SAndy Yan count = min(words, tx_level); 251c1cd6cb6SAndy Yan writesl(®s->data, buf, count); 252c1cd6cb6SAndy Yan buf += count; 253c1cd6cb6SAndy Yan words -= count; 254c1cd6cb6SAndy Yan } 255c1cd6cb6SAndy Yan 256c1cd6cb6SAndy Yan /* handle the last none word aligned bytes */ 257c1cd6cb6SAndy Yan if (bytes) { 258c1cd6cb6SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, 1, 1000); 259c1cd6cb6SAndy Yan if (tx_level <= 0) 260c1cd6cb6SAndy Yan return tx_level; 261c1cd6cb6SAndy Yan memcpy(&val, buf, bytes); 262c1cd6cb6SAndy Yan writel(val, ®s->data); 263c1cd6cb6SAndy Yan } 264c1cd6cb6SAndy Yan 265c1cd6cb6SAndy Yan return 0; 266c1cd6cb6SAndy Yan } 267c1cd6cb6SAndy Yan 268c1cd6cb6SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 *buf, u32 len) 269c1cd6cb6SAndy Yan { 270c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 271c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 272c1cd6cb6SAndy Yan u32 words = len >> 2; 273c1cd6cb6SAndy Yan u32 rx_level = 0; 274c1cd6cb6SAndy Yan u32 count; 275c1cd6cb6SAndy Yan u32 val; 276c1cd6cb6SAndy Yan 277c1cd6cb6SAndy Yan while (words) { 278c1cd6cb6SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, 0, 1000); 279c1cd6cb6SAndy Yan if (rx_level <= 0) 280c1cd6cb6SAndy Yan return rx_level; 281c1cd6cb6SAndy Yan count = min(words, rx_level); 282c1cd6cb6SAndy Yan readsl(®s->data, buf, count); 283c1cd6cb6SAndy Yan buf += count; 284c1cd6cb6SAndy Yan words -= count; 285c1cd6cb6SAndy Yan } 286c1cd6cb6SAndy Yan 287c1cd6cb6SAndy Yan /* handle the last none word aligned bytes */ 288c1cd6cb6SAndy Yan if (bytes) { 289c1cd6cb6SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, 0, 1000); 290c1cd6cb6SAndy Yan if (rx_level <= 0) 291c1cd6cb6SAndy Yan return rx_level; 292c1cd6cb6SAndy Yan val = readl(®s->data); 293c1cd6cb6SAndy Yan memcpy(buf, &val, bytes); 294c1cd6cb6SAndy Yan } 295c1cd6cb6SAndy Yan 296c1cd6cb6SAndy Yan return 0; 297c1cd6cb6SAndy Yan } 298c1cd6cb6SAndy Yan 299c1cd6cb6SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len) 300c1cd6cb6SAndy Yan { 301c1cd6cb6SAndy Yan int ret = 0; 302c1cd6cb6SAndy Yan int rw = sfc->cmd & SFC_WR; 303c1cd6cb6SAndy Yan 304*6bf64646SAndy Yan sfc->cmd &= ~SFC_TRB_MASK; 305c1cd6cb6SAndy Yan sfc->cmd |= (len << SFC_TRB_SHIFT); 306c1cd6cb6SAndy Yan rockchip_sfc_setup_xfer(sfc); 307c1cd6cb6SAndy Yan if (len) { 308c1cd6cb6SAndy Yan if (rw) 309c1cd6cb6SAndy Yan ret = rockchip_sfc_write(sfc, buf, len); 310c1cd6cb6SAndy Yan else 311c1cd6cb6SAndy Yan ret = rockchip_sfc_read(sfc, buf, len); 312c1cd6cb6SAndy Yan } 313c1cd6cb6SAndy Yan 314c1cd6cb6SAndy Yan return ret; 315c1cd6cb6SAndy Yan } 316c1cd6cb6SAndy Yan 317c1cd6cb6SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len) 318c1cd6cb6SAndy Yan { 319c1cd6cb6SAndy Yan int ret = 0; 320*6bf64646SAndy Yan u32 bytes = len & 0x3; 321*6bf64646SAndy Yan u32 dma_trans; 322c1cd6cb6SAndy Yan 323*6bf64646SAndy Yan if (len >= SFC_MAX_TRB) { 324*6bf64646SAndy Yan dma_trans = len - bytes; 325*6bf64646SAndy Yan } else { 326*6bf64646SAndy Yan dma_trans = 0; 327*6bf64646SAndy Yan bytes = len; 328*6bf64646SAndy Yan } 329*6bf64646SAndy Yan 330*6bf64646SAndy Yan if (dma_trans) { 331*6bf64646SAndy Yan ret = rockchip_sfc_dma_xfer(sfc, buf, dma_trans); 332*6bf64646SAndy Yan buf += (dma_trans >> 2); 333*6bf64646SAndy Yan } 334*6bf64646SAndy Yan 335*6bf64646SAndy Yan /* 336*6bf64646SAndy Yan * transfer the last non 4 bytes anligned byte by pio mode 337*6bf64646SAndy Yan * there are also some commands like WREN(0x06) that execute 338*6bf64646SAndy Yan * whth no data, we also need to handle it here. 339*6bf64646SAndy Yan */ 340*6bf64646SAndy Yan if (bytes || (!bytes && !dma_trans)) 341*6bf64646SAndy Yan ret = rockchip_sfc_pio_xfer(sfc, buf, bytes); 342c1cd6cb6SAndy Yan 343c1cd6cb6SAndy Yan return ret; 344c1cd6cb6SAndy Yan } 345c1cd6cb6SAndy Yan 346c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen, 347c1cd6cb6SAndy Yan const void *dout, void *din, unsigned long flags) 348c1cd6cb6SAndy Yan { 349c1cd6cb6SAndy Yan struct udevice *bus = dev->parent; 350c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 351c1cd6cb6SAndy Yan int len = bitlen >> 3; 352c1cd6cb6SAndy Yan u8 *pcmd = (u8 *)dout; 353c1cd6cb6SAndy Yan int ret = 0; 354c1cd6cb6SAndy Yan 355c1cd6cb6SAndy Yan if (flags & SPI_XFER_BEGIN) { 356c1cd6cb6SAndy Yan sfc->cmd = pcmd[0]; 357c1cd6cb6SAndy Yan if (len >= 4) { 358c1cd6cb6SAndy Yan sfc->cmd |= SFC_ADDR_24BITS | (((len - 4) * 8) << 8); 359c1cd6cb6SAndy Yan sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 360c1cd6cb6SAndy Yan } 361c1cd6cb6SAndy Yan } 362c1cd6cb6SAndy Yan 363c1cd6cb6SAndy Yan if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) 364c1cd6cb6SAndy Yan len = 0; 365c1cd6cb6SAndy Yan 366c1cd6cb6SAndy Yan if (flags & SPI_XFER_END) { 367*6bf64646SAndy Yan if (dout) 368c1cd6cb6SAndy Yan sfc->cmd |= SFC_WR; 369c1cd6cb6SAndy Yan 370c1cd6cb6SAndy Yan if (din) 371c1cd6cb6SAndy Yan ret = rockchip_sfc_do_xfer(sfc, (u32 *)din, len); 372c1cd6cb6SAndy Yan else if (dout) 373c1cd6cb6SAndy Yan ret = rockchip_sfc_do_xfer(sfc, (u32 *)dout, len); 374c1cd6cb6SAndy Yan } 375c1cd6cb6SAndy Yan 376c1cd6cb6SAndy Yan return ret; 377c1cd6cb6SAndy Yan } 378c1cd6cb6SAndy Yan 379c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) 380c1cd6cb6SAndy Yan { 381c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 382c1cd6cb6SAndy Yan 383c1cd6cb6SAndy Yan if (speed > sfc->max_freq) 384c1cd6cb6SAndy Yan speed = sfc->max_freq; 385c1cd6cb6SAndy Yan 386c1cd6cb6SAndy Yan sfc->speed_hz = speed; 387c1cd6cb6SAndy Yan 388c1cd6cb6SAndy Yan return 0; 389c1cd6cb6SAndy Yan } 390c1cd6cb6SAndy Yan 391c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode) 392c1cd6cb6SAndy Yan { 393c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 394c1cd6cb6SAndy Yan 395c1cd6cb6SAndy Yan sfc->mode = mode; 396c1cd6cb6SAndy Yan 397c1cd6cb6SAndy Yan return 0; 398c1cd6cb6SAndy Yan } 399c1cd6cb6SAndy Yan 400c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = { 401c1cd6cb6SAndy Yan .xfer = rockchip_sfc_xfer, 402c1cd6cb6SAndy Yan .set_speed = rockchip_sfc_set_speed, 403c1cd6cb6SAndy Yan .set_mode = rockchip_sfc_set_mode, 404c1cd6cb6SAndy Yan }; 405c1cd6cb6SAndy Yan 406c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = { 407c1cd6cb6SAndy Yan { .compatible = "rockchip,sfc" }, 408c1cd6cb6SAndy Yan { } 409c1cd6cb6SAndy Yan }; 410c1cd6cb6SAndy Yan 411c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = { 412c1cd6cb6SAndy Yan .name = "rockchip_sfc", 413c1cd6cb6SAndy Yan .id = UCLASS_SPI, 414c1cd6cb6SAndy Yan .of_match = rockchip_sfc_ids, 415c1cd6cb6SAndy Yan .ops = &rockchip_sfc_ops, 416c1cd6cb6SAndy Yan .ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata, 417c1cd6cb6SAndy Yan .platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata), 418c1cd6cb6SAndy Yan .priv_auto_alloc_size = sizeof(struct rockchip_sfc), 419c1cd6cb6SAndy Yan .probe = rockchip_sfc_probe, 420c1cd6cb6SAndy Yan }; 421