CV1800B: Added CVITEK-SPIF driver.
Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
parent
636e87e455
commit
a63830773f
|
@ -34,6 +34,31 @@
|
|||
i2c1_pins: i2c1 {
|
||||
pinmux = <PINMUX(PAD_MIPIRX0N, IIC1_SCL)>, <PINMUX(PAD_MIPIRX1P, IIC1_SDA)>;
|
||||
};
|
||||
|
||||
spif_pins: spif {
|
||||
pinmux = <PINMUX(SPINOR_SCK, SPINOR_SCK)>, <PINMUX(SPINOR_MOSI, SPINOR_MOSI)>,
|
||||
<PINMUX(SPINOR_MISO, SPINOR_MISO)>, <PINMUX(SPINOR_CS_X, SPINOR_CS_X)>,
|
||||
<PINMUX(SPINOR_HOLD_X, SPINOR_HOLD_X)>, <PINMUX(SPINOR_WP_X, SPINOR_WP_X)>;
|
||||
};
|
||||
};
|
||||
|
||||
&spif {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pinctrl-0 = <&spif_pins>;
|
||||
pinctrl-names = "default";
|
||||
spi-max-frequency = <30000000>;
|
||||
status = "okay";
|
||||
|
||||
nor-flash@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "jedec,spi-nor";
|
||||
reg=<0>;
|
||||
spi-tx-bus-width = <4>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <30000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
|
|
|
@ -45,6 +45,13 @@
|
|||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
hsp_clk: hs-peri-clock {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "hsp_clk";
|
||||
clock-frequency = <150000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
apb_clk: apb-clk-clock {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "apb_clk";
|
||||
|
@ -81,6 +88,14 @@
|
|||
pins = <75>;
|
||||
};
|
||||
|
||||
spif: spi@10000000 {
|
||||
compatible = "cvitek,cv1800b-spif", "cvitek,cvitek-spif";
|
||||
reg = <0x0 0x10000000 0x0 0x10000000>;
|
||||
interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&hsp_clk>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart0: serial@04140000 {
|
||||
compatible = "cvitek,cv1800b-uart", "snps,dw-apb-uart";
|
||||
reg = <0x0 0x04140000 0x0 0x1000>;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <dt-bindings/pinctrl/cv1800b-pinctrl.h>
|
||||
#include <mapmem.h>
|
||||
|
@ -34,7 +35,7 @@ static int cv1800b_pc_get_pins_count(struct udevice *dev)
|
|||
{
|
||||
struct cv1800b_pc_priv *priv = dev_get_priv(dev);
|
||||
|
||||
debug("%s: pin count: %d", __func__, priv->num_pins);
|
||||
dev_dbg(dev, "pin count: %d", priv->num_pins);
|
||||
|
||||
return priv->num_pins;
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ static int cv1800b_pc_pinmux_set(struct udevice *dev, u32 pinmux_group)
|
|||
|
||||
priv->pinmux->ctrl[pin] = (priv->pinmux->ctrl[pin] & ~(CV1800B_PC_FUNC)) | func;
|
||||
|
||||
debug("%s: pin %d, func: %d\n", __func__, pin, func);
|
||||
dev_dbg(dev, "pin %d, func: %d\n", pin, func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ static int cv1800b_pc_probe(struct udevice *dev)
|
|||
if(dev_read_u32(dev, "pins", &priv->num_pins) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
debug("%s: pinctrl@%p, %d pins\n", __func__, priv->pinmux, priv->num_pins);
|
||||
dev_dbg(dev, "pinctrl@%p, %d pins\n", priv->pinmux, priv->num_pins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -168,6 +168,12 @@ config CF_SPI
|
|||
Enable the ColdFire SPI driver. This driver can be used on
|
||||
some m68k SoCs.
|
||||
|
||||
config CVITEK_SPIF
|
||||
bool "Cvitek SPIF controller driver"
|
||||
help
|
||||
Enable the Cvitek SPIF controller driver, which (almost always)
|
||||
connects to an SPI NOR flash device.
|
||||
|
||||
config DAVINCI_SPI
|
||||
bool "Davinci & Keystone SPI driver"
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE
|
||||
|
|
|
@ -30,6 +30,7 @@ obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o
|
|||
obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o
|
||||
obj-$(CONFIG_CF_SPI) += cf_spi.o
|
||||
obj-$(CONFIG_CORTINA_SFLASH) += ca_sflash.o
|
||||
obj-$(CONFIG_CVITEK_SPIF) += cvitek-spif.o
|
||||
obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
|
||||
obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
|
||||
obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
|
||||
|
|
499
drivers/spi/cvitek-spif.c
Normal file
499
drivers/spi/cvitek-spif.c
Normal file
|
@ -0,0 +1,499 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2023 Yilin Sun <imi415@imi.moe>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <spi.h>
|
||||
#include <spi-mem.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#define CVI_SPIF_BUS_WIDTH_1 0x00
|
||||
#define CVI_SPIF_BUS_WIDTH_2 0x01
|
||||
#define CVI_SPIF_BUS_WIDTH_4 0x02
|
||||
|
||||
#define CVI_SPIF_FIFO_DEPTH 8U
|
||||
|
||||
/**
|
||||
* SPIF SPI_CTRL register
|
||||
*
|
||||
*/
|
||||
#define CVI_SPIF_SPI_CTRL_SCK_DIV_SHIFT 0
|
||||
#define CVI_SPIF_SPI_CTRL_SCK_DIV_MASK GENMASK(10, 0) /* Clock divider, assume F/(x+1) */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_CPHA_SHIFT 12
|
||||
#define CVI_SPIF_SPI_CTRL_CPHA_MASK BIT(12) /* Clock phase */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_CPOL_SHIFT 13
|
||||
#define CVI_SPIF_SPI_CTRL_CPOL_MASK BIT(13) /* Clock polarity */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_HOLD_OL_MASK BIT(14) /* HOLD output low?*/
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_WP_OL_MASK BIT(15) /* WP output low? */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_FRAME_LEN_MASK BIT(16) /* Frame length */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_LSB_FIRST_MASK BIT(20) /* LSB first SPI */
|
||||
|
||||
#define CVI_SPIF_SPI_CTRL_SRST_MASK BIT(21) /* Software Reset? */
|
||||
|
||||
|
||||
/**
|
||||
* SPIF CE_CTRL register
|
||||
*
|
||||
*/
|
||||
#define CVI_SPIF_CE_CTRL_CEMANUAL_MASK BIT(0) /* Manual CE control value */
|
||||
|
||||
#define CVI_SPIF_CE_CTRL_CEMANUAL_EN_MASK BIT(1) /* Manual CE control enable */
|
||||
|
||||
|
||||
/**
|
||||
* SPIF DLY_CTRL register
|
||||
*
|
||||
*/
|
||||
|
||||
#define CVI_SPIF_DLY_CTRL_CET_MASK GENMASK(9, 8)
|
||||
#define CVI_SPIF_DLY_CTRL_NEG_SAMPLE_MASK BIT(14)
|
||||
|
||||
/**
|
||||
* SPIF DMMR register
|
||||
*
|
||||
*/
|
||||
#define CVI_SPIF_DMMR_EN_MASK BIT(0) /* Direct memory-mapped mode enable */
|
||||
|
||||
/**
|
||||
* SPIF TRANS_CSR register
|
||||
*
|
||||
*/
|
||||
#define CVI_SPIF_TRANS_CSR_MODE_SHIFT 0
|
||||
#define CVI_SPIF_TRANS_CSR_MODE_MASK GENMASK(1, 0) /* Mode, 01: Read, 10: Write */
|
||||
#define CVI_SPIF_TRANS_CSR_MODE(x) \
|
||||
((x << CVI_SPIF_TRANS_CSR_MODE_SHIFT) & CVI_SPIF_TRANS_CSR_MODE_MASK)
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_CONT_READ_MASK BIT(2) /* Continous mode read? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_FAST_MODE_MASK BIT(3) /* Fast mode (which)? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_BUS_WIDTH_SHIFT 4
|
||||
#define CVI_SPIF_TRANS_CSR_BUS_WIDTH_MASK GENMASK(5, 4) /* Bus width, 2^x bits */
|
||||
#define CVI_SPIF_TRANS_CSR_BUS_WIDTH(x) \
|
||||
((x << CVI_SPIF_TRANS_CSR_BUS_WIDTH_SHIFT) & CVI_SPIF_TRANS_CSR_BUS_WIDTH_MASK)
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_DMA_EN_MASK BIT(6) /* DMA request enable? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_MISO_LVL_MASK BIT(7) /* Read MISO level? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_ADDR_BYTES_MASK GENMASK(10, 8) /* Address bytes? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_WITH_CMD_MASK BIT(11) /* ??? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL_SHIFT 12
|
||||
#define CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL_MASK GENMASK(13, 12) /* FIFO (IRQ?) trigger level, 2^x bytes */
|
||||
#define CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL(x) \
|
||||
((x << CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL_SHIFT) & CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL_MASK)
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_GO_BUSY_MASK BIT(15) /* Write 1 to GO? Self-cleared bit? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_DUMMY_MASK GENMASK(19, 16) /* Dummy count? */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_4B_ADDR_MASK BIT(20) /* 4 bytes address */
|
||||
|
||||
#define CVI_SPIF_TRANS_CSR_4B_CMD_MASK BIT(21) /* 4 bytes command */
|
||||
|
||||
/**
|
||||
* SPIF INT_STS register
|
||||
*
|
||||
*/
|
||||
#define CVI_SPIF_INT_STS_TRANS_DONE_MASK BIT(0)
|
||||
|
||||
#define CVI_SPIF_INT_STS_RD_FIFO_MASK BIT(2)
|
||||
|
||||
/*
|
||||
* Note: All registers are mapped into the XIP space:
|
||||
* Read access:
|
||||
* - If DMMR_EN = 1: Memory contents
|
||||
* - If DMMR_EN = 0: Register contents
|
||||
* Write access: Register contents (DMMR_EN ignored)
|
||||
*
|
||||
*/
|
||||
struct cvitek_spif_regs {
|
||||
u32 spi_ctrl; /* Offset: 0x00 */
|
||||
u32 ce_ctrl; /* Offset: 0x04 */
|
||||
u32 dly_ctrl; /* Offset: 0x08 */
|
||||
u32 dmmr; /* Offset: 0x0C */
|
||||
u32 trans_csr; /* Offset: 0x10 */
|
||||
u32 trans_num; /* Offset: 0x14 */
|
||||
u32 ff_port; /* Offset: 0x18 */
|
||||
u32 reserved0; /* Offset: 0x1C */
|
||||
u32 ff_pt; /* Offset: 0x20 */
|
||||
u32 reserved1; /* Offset: 0x24 */
|
||||
u32 int_sts; /* Offset: 0x28 */
|
||||
u32 int_en; /* Offset: 0x2C */
|
||||
};
|
||||
|
||||
struct cvitek_spif_xfer {
|
||||
u8 width; /* Bus width, 0: 1bit, 1: 2bits, 2: 4bits */
|
||||
union {
|
||||
u8 *in;
|
||||
const u8 *out;
|
||||
} data;
|
||||
u32 length; /* Length in bytes */
|
||||
};
|
||||
|
||||
struct cvitek_spif_priv {
|
||||
struct cvitek_spif_regs *regs;
|
||||
u32 clk_rate;
|
||||
unsigned int cs;
|
||||
};
|
||||
|
||||
static int cvitek_spif_claim_bus(struct udevice *dev)
|
||||
{
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(dev->parent);
|
||||
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
|
||||
|
||||
priv->cs = slave_plat->cs;
|
||||
|
||||
if(priv->cs > 0)
|
||||
return -ENODEV;
|
||||
|
||||
clrbits_le32(&priv->regs->ce_ctrl, CVI_SPIF_CE_CTRL_CEMANUAL_EN_MASK);
|
||||
|
||||
dev_dbg(dev, "claim_bus cs: %d\n", priv->cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_release_bus(struct udevice *dev)
|
||||
{
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(dev->parent);
|
||||
|
||||
clrbits_le32(&priv->regs->ce_ctrl, CVI_SPIF_CE_CTRL_CEMANUAL_EN_MASK);
|
||||
|
||||
dev_dbg(dev, "release_bus cs: %d\n", priv->cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_set_speed(struct udevice *bus, uint speed)
|
||||
{
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(bus);
|
||||
|
||||
u8 div_val = DIV_ROUND_UP(priv->clk_rate, speed) - 1;
|
||||
u32 dly_ctrl = CVI_SPIF_DLY_CTRL_CET_MASK;
|
||||
|
||||
clrsetbits_le32(&priv->regs->spi_ctrl,
|
||||
CVI_SPIF_SPI_CTRL_SCK_DIV_MASK,
|
||||
(div_val << CVI_SPIF_SPI_CTRL_SCK_DIV_SHIFT));
|
||||
|
||||
if(speed > 30000000)
|
||||
dly_ctrl |= CVI_SPIF_DLY_CTRL_NEG_SAMPLE_MASK;
|
||||
|
||||
|
||||
writel(dly_ctrl, &priv->regs->dly_ctrl);
|
||||
|
||||
dev_dbg(bus, "set_speed to %dHz, div: %d\n", speed, div_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_set_mode(struct udevice *bus, uint mode)
|
||||
{
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(bus);
|
||||
u32 mode_mask = 0U;
|
||||
|
||||
if(mode & SPI_CPHA)
|
||||
mode_mask |= CVI_SPIF_SPI_CTRL_CPHA_MASK;
|
||||
|
||||
if(mode & SPI_CPOL)
|
||||
mode_mask |= CVI_SPIF_SPI_CTRL_CPOL_MASK;
|
||||
|
||||
clrsetbits_le32(&priv->regs->spi_ctrl,
|
||||
(CVI_SPIF_SPI_CTRL_CPOL_MASK | CVI_SPIF_SPI_CTRL_CPHA_MASK),
|
||||
mode_mask);
|
||||
|
||||
dev_dbg(bus, "set_mode to %d\n", mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_read(struct cvitek_spif_priv *priv, struct cvitek_spif_xfer *xfer)
|
||||
{
|
||||
u32 trans_ctrl;
|
||||
u32 i;
|
||||
u8 width;
|
||||
|
||||
switch(xfer->width)
|
||||
{
|
||||
case 1:
|
||||
width = CVI_SPIF_BUS_WIDTH_1;
|
||||
break;
|
||||
case 2:
|
||||
width = CVI_SPIF_BUS_WIDTH_2;
|
||||
break;
|
||||
case 4:
|
||||
width = CVI_SPIF_BUS_WIDTH_4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL(3);
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_BUS_WIDTH(width);
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_MODE(1); /* RX mode */
|
||||
|
||||
/* Set up transfer mode */
|
||||
writel(trans_ctrl, &priv->regs->trans_csr);
|
||||
|
||||
/* Write transfer length in bytes */
|
||||
writel(xfer->length, &priv->regs->trans_num);
|
||||
|
||||
/* Reset FIFO pointer */
|
||||
writel(0U, &priv->regs->ff_pt);
|
||||
|
||||
/* Start transfer */
|
||||
setbits_le32(&priv->regs->trans_csr, CVI_SPIF_TRANS_CSR_GO_BUSY_MASK);
|
||||
|
||||
for(i = 0; i < xfer->length; i++)
|
||||
{
|
||||
/* Wait for FIFO not empty */
|
||||
while((readl(&priv->regs->ff_pt) & 0x0F) == 0U)
|
||||
;
|
||||
|
||||
xfer->data.in[i] = readb(&priv->regs->ff_port);
|
||||
}
|
||||
|
||||
|
||||
while((readl(&priv->regs->int_sts) & CVI_SPIF_INT_STS_TRANS_DONE_MASK) == 0U)
|
||||
;
|
||||
|
||||
/* Clear interrupt status */
|
||||
writeb(0U, &priv->regs->int_sts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_write(struct cvitek_spif_priv *priv, struct cvitek_spif_xfer *xfer)
|
||||
{
|
||||
u32 trans_ctrl;
|
||||
u32 i;
|
||||
u8 width;
|
||||
|
||||
switch(xfer->width)
|
||||
{
|
||||
case 1:
|
||||
width = CVI_SPIF_BUS_WIDTH_1;
|
||||
break;
|
||||
case 2:
|
||||
width = CVI_SPIF_BUS_WIDTH_2;
|
||||
break;
|
||||
case 4:
|
||||
width = CVI_SPIF_BUS_WIDTH_4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_FIFO_TRIG_LVL(3);
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_BUS_WIDTH(width);
|
||||
trans_ctrl |= CVI_SPIF_TRANS_CSR_MODE(2); /* TX mode */
|
||||
|
||||
/* Set up transfer mode */
|
||||
writel(trans_ctrl, &priv->regs->trans_csr);
|
||||
|
||||
/* Write transfer length in bytes */
|
||||
writel(xfer->length, &priv->regs->trans_num);
|
||||
|
||||
/* Reset FIFO pointer */
|
||||
writel(0U, &priv->regs->ff_pt);
|
||||
|
||||
/* Start transfer */
|
||||
setbits_le32(&priv->regs->trans_csr, CVI_SPIF_TRANS_CSR_GO_BUSY_MASK);
|
||||
|
||||
for(i = 0; i < xfer->length; i++)
|
||||
{
|
||||
/* Wait for FIFO not full */
|
||||
while((readl(&priv->regs->ff_pt) & 0x0F) >= CVI_SPIF_FIFO_DEPTH)
|
||||
;
|
||||
|
||||
writeb(xfer->data.out[i], &priv->regs->ff_port);
|
||||
}
|
||||
|
||||
|
||||
while((readl(&priv->regs->int_sts) & CVI_SPIF_INT_STS_TRANS_DONE_MASK) == 0U)
|
||||
;
|
||||
|
||||
/* Clear interrupt status */
|
||||
writeb(0U, &priv->regs->int_sts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
|
||||
{
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(slave->dev->parent);
|
||||
struct cvitek_spif_xfer xfer;
|
||||
u8 buf[4];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Use manual CE control mode */
|
||||
writel((CVI_SPIF_CE_CTRL_CEMANUAL_MASK | CVI_SPIF_CE_CTRL_CEMANUAL_EN_MASK), &priv->regs->ce_ctrl);
|
||||
|
||||
|
||||
clrbits_le32(&priv->regs->ce_ctrl, CVI_SPIF_CE_CTRL_CEMANUAL_MASK);
|
||||
if(op->cmd.nbytes)
|
||||
{
|
||||
|
||||
if(op->cmd.nbytes == 1U)
|
||||
buf[0] = op->cmd.opcode & 0xFFU;
|
||||
else
|
||||
{
|
||||
buf[0] = (op->cmd.opcode >> 8U) & 0xFFU;
|
||||
buf[1] = op->cmd.opcode & 0xFFU;
|
||||
}
|
||||
|
||||
xfer.data.out = buf;
|
||||
xfer.length = op->cmd.nbytes;
|
||||
xfer.width = op->cmd.buswidth;
|
||||
|
||||
ret = cvitek_spif_write(priv, &xfer);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(op->addr.nbytes)
|
||||
{
|
||||
if(op->addr.nbytes == 3U)
|
||||
{
|
||||
buf[0] = (op->addr.val >> 16U) & 0xFFU;
|
||||
buf[1] = (op->addr.val >> 8U) & 0xFFU;
|
||||
buf[2] = op->addr.val & 0xFFU;
|
||||
}
|
||||
else if(op->addr.nbytes == 4U)
|
||||
{
|
||||
buf[0] = (op->addr.val >> 24U) & 0xFFU;
|
||||
buf[1] = (op->addr.val >> 16U) & 0xFFU;
|
||||
buf[2] = (op->addr.val >> 8U) & 0xFFU;
|
||||
buf[3] = op->addr.val & 0xFFU;
|
||||
}
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
xfer.data.out = buf;
|
||||
xfer.length = op->addr.nbytes;
|
||||
xfer.width = op->addr.buswidth;
|
||||
|
||||
ret = cvitek_spif_write(priv, &xfer);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(op->dummy.nbytes)
|
||||
{
|
||||
xfer.data.in = buf;
|
||||
xfer.length = 1;
|
||||
xfer.width = op->dummy.buswidth;
|
||||
|
||||
for(i = 0; i < op->dummy.nbytes; i++)
|
||||
{
|
||||
ret = cvitek_spif_write(priv, &xfer);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if(op->data.nbytes && (op->data.dir != SPI_MEM_NO_DATA))
|
||||
{
|
||||
xfer.length = op->data.nbytes;
|
||||
xfer.width = op->data.buswidth;
|
||||
|
||||
if(op->data.dir == SPI_MEM_DATA_IN)
|
||||
{
|
||||
xfer.data.in = op->data.buf.in;
|
||||
ret = cvitek_spif_read(priv, &xfer);
|
||||
}
|
||||
|
||||
if(op->data.dir == SPI_MEM_DATA_OUT)
|
||||
{
|
||||
xfer.data.out = op->data.buf.out;
|
||||
ret = cvitek_spif_write(priv, &xfer);
|
||||
}
|
||||
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
setbits_le32(&priv->regs->ce_ctrl, CVI_SPIF_CE_CTRL_CEMANUAL_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvitek_spif_probe(struct udevice *bus)
|
||||
{
|
||||
int ret;
|
||||
struct clk clk;
|
||||
struct cvitek_spif_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->regs = dev_read_addr_ptr(bus);
|
||||
if(!priv->regs)
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_get_by_index(bus, 0, &clk);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if(ret)
|
||||
{
|
||||
dev_err(bus, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->clk_rate = clk_get_rate(&clk);
|
||||
if(!priv->clk_rate)
|
||||
{
|
||||
dev_err(bus, "failed to get clock rate\n");
|
||||
clk_disable(&clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable direct memory-mapped mode */
|
||||
writeb(0U, &priv->regs->dmmr);
|
||||
|
||||
dev_dbg(bus, "cvitek-spi probed on addr %p\r\n", priv->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_controller_mem_ops cvitek_spif_mem_ops = {
|
||||
.exec_op = cvitek_spif_exec_op,
|
||||
};
|
||||
|
||||
static const struct dm_spi_ops cvitek_spif_ops = {
|
||||
.claim_bus = cvitek_spif_claim_bus,
|
||||
.release_bus = cvitek_spif_release_bus,
|
||||
.set_speed = cvitek_spif_set_speed,
|
||||
.set_mode = cvitek_spif_set_mode,
|
||||
.mem_ops = &cvitek_spif_mem_ops,
|
||||
};
|
||||
|
||||
static const struct udevice_id cvitek_spif_ids[] = {
|
||||
{ .compatible = "cvitek,cvitek-spif" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cvitek_spif) = {
|
||||
.name = "cvitek_spif",
|
||||
.id = UCLASS_SPI,
|
||||
.of_match = cvitek_spif_ids,
|
||||
.ops = &cvitek_spif_ops,
|
||||
.priv_auto = sizeof(struct cvitek_spif_priv),
|
||||
.probe = cvitek_spif_probe,
|
||||
};
|
Loading…
Reference in New Issue
Block a user