Loading Documentation/devicetree/bindings/spi/spi-rockchip.txt +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ Required Properties: "rockchip,rk3066-spi" for rk3066. "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188. "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288. "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399. - reg: physical base address of the controller and length of memory mapped region. - interrupts: The interrupt number to the cpu. The interrupt specifier format Loading Documentation/devicetree/bindings/spi/spi-xilinx.txt 0 → 100644 +22 −0 Original line number Diff line number Diff line Xilinx SPI controller Device Tree Bindings ------------------------------------------------- Required properties: - compatible : Should be "xlnx,xps-spi-2.00.a" or "xlnx,xps-spi-2.00.b" - reg : Physical base address and size of SPI registers map. - interrupts : Property with a value describing the interrupt number. - interrupt-parent : Must be core interrupt controller Optional properties: - xlnx,num-ss-bits : Number of chip selects used. Example: axi_quad_spi@41e00000 { compatible = "xlnx,xps-spi-2.00.a"; interrupt-parent = <&intc>; interrupts = <0 31 1>; reg = <0x41e00000 0x10000>; xlnx,num-ss-bits = <0x1>; }; drivers/spi/Kconfig +3 −3 Original line number Diff line number Diff line Loading @@ -487,7 +487,7 @@ config SPI_RB4XX config SPI_RSPI tristate "Renesas RSPI/QSPI controller" depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help SPI driver for Renesas RSPI and QSPI blocks. Loading Loading @@ -537,7 +537,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK && HAS_DMA depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH and SH Mobile MSIOF blocks. Loading @@ -556,7 +556,7 @@ config SPI_SH_SCI config SPI_SH_HSPI tristate "SuperH HSPI controller" depends on ARCH_SHMOBILE || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH HSPI blocks. Loading drivers/spi/spi-rockchip.c +35 −21 Original line number Diff line number Diff line Loading @@ -13,20 +13,14 @@ * */ #include <linux/init.h> #include <linux/module.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/scatterlist.h> #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/io.h> #include <linux/dmaengine.h> #include <linux/scatterlist.h> #define DRIVER_NAME "rockchip-spi" Loading Loading @@ -179,7 +173,7 @@ struct rockchip_spi { u8 tmode; u8 bpw; u8 n_bytes; u8 rsd_nsecs; u32 rsd_nsecs; unsigned len; u32 speed; Loading @@ -192,8 +186,6 @@ struct rockchip_spi { /* protect state */ spinlock_t lock; struct completion xfer_completion; u32 use_dma; struct sg_table tx_sg; struct sg_table rx_sg; Loading Loading @@ -265,7 +257,10 @@ static inline u32 rx_max(struct rockchip_spi *rs) static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { u32 ser; struct rockchip_spi *rs = spi_master_get_devdata(spi->master); struct spi_master *master = spi->master; struct rockchip_spi *rs = spi_master_get_devdata(master); pm_runtime_get_sync(rs->dev); ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; Loading @@ -290,6 +285,8 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) ser &= ~(1 << spi->chip_select); writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); pm_runtime_put_sync(rs->dev); } static int rockchip_spi_prepare_message(struct spi_master *master, Loading Loading @@ -319,12 +316,12 @@ static void rockchip_spi_handle_err(struct spi_master *master, */ if (rs->use_dma) { if (rs->state & RXBUSY) { dmaengine_terminate_all(rs->dma_rx.ch); dmaengine_terminate_async(rs->dma_rx.ch); flush_fifo(rs); } if (rs->state & TXBUSY) dmaengine_terminate_all(rs->dma_tx.ch); dmaengine_terminate_async(rs->dma_tx.ch); } spin_unlock_irqrestore(&rs->lock, flags); Loading Loading @@ -433,7 +430,7 @@ static void rockchip_spi_dma_txcb(void *data) spin_unlock_irqrestore(&rs->lock, flags); } static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) { unsigned long flags; struct dma_slave_config rxconf, txconf; Loading @@ -456,6 +453,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rs->dma_rx.ch, rs->rx_sg.sgl, rs->rx_sg.nents, rs->dma_rx.direction, DMA_PREP_INTERRUPT); if (!rxdesc) return -EINVAL; rxdesc->callback = rockchip_spi_dma_rxcb; rxdesc->callback_param = rs; Loading @@ -473,6 +472,11 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rs->dma_tx.ch, rs->tx_sg.sgl, rs->tx_sg.nents, rs->dma_tx.direction, DMA_PREP_INTERRUPT); if (!txdesc) { if (rxdesc) dmaengine_terminate_sync(rs->dma_rx.ch); return -EINVAL; } txdesc->callback = rockchip_spi_dma_txcb; txdesc->callback_param = rs; Loading @@ -494,6 +498,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) dmaengine_submit(txdesc); dma_async_issue_pending(rs->dma_tx.ch); } return 0; } static void rockchip_spi_config(struct rockchip_spi *rs) Loading @@ -503,7 +509,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs) int rsd = 0; u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET) | (CR0_SSD_ONE << CR0_SSD_OFFSET); | (CR0_SSD_ONE << CR0_SSD_OFFSET) | (CR0_EM_BIG << CR0_EM_OFFSET); cr0 |= (rs->n_bytes << CR0_DFS_OFFSET); cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET); Loading Loading @@ -606,12 +613,12 @@ static int rockchip_spi_transfer_one( if (rs->use_dma) { if (rs->tmode == CR0_XFM_RO) { /* rx: dma must be prepared first */ rockchip_spi_prepare_dma(rs); ret = rockchip_spi_prepare_dma(rs); spi_enable_chip(rs, 1); } else { /* tx or tr: spi must be enabled first */ spi_enable_chip(rs, 1); rockchip_spi_prepare_dma(rs); ret = rockchip_spi_prepare_dma(rs); } } else { spi_enable_chip(rs, 1); Loading Loading @@ -717,8 +724,14 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->handle_err = rockchip_spi_handle_err; rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx"); if (!rs->dma_tx.ch) if (IS_ERR_OR_NULL(rs->dma_tx.ch)) { /* Check tx to see if we need defer probing driver */ if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; goto err_get_fifo_len; } dev_warn(rs->dev, "Failed to request TX DMA channel\n"); } rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx"); if (!rs->dma_rx.ch) { Loading Loading @@ -871,6 +884,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = { { .compatible = "rockchip,rk3066-spi", }, { .compatible = "rockchip,rk3188-spi", }, { .compatible = "rockchip,rk3288-spi", }, { .compatible = "rockchip,rk3399-spi", }, { }, }; MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); Loading drivers/spi/spi-ti-qspi.c +110 −29 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/spi/spi.h> Loading @@ -44,8 +46,9 @@ struct ti_qspi { struct spi_master *master; void __iomem *base; void __iomem *ctrl_base; void __iomem *mmap_base; struct regmap *ctrl_base; unsigned int ctrl_reg; struct clk *fclk; struct device *dev; Loading @@ -55,7 +58,7 @@ struct ti_qspi { u32 cmd; u32 dc; bool ctrl_mod; bool mmap_enabled; }; #define QSPI_PID (0x0) Loading @@ -65,11 +68,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG (0x4c) #define QSPI_SPI_DATA_REG (0x50) #define QSPI_SPI_SETUP0_REG (0x54) #define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG (0x64) #define QSPI_SPI_SETUP1_REG (0x58) #define QSPI_SPI_SETUP2_REG (0x5c) #define QSPI_SPI_SETUP3_REG (0x60) #define QSPI_SPI_DATA_REG_1 (0x68) #define QSPI_SPI_DATA_REG_2 (0x6c) #define QSPI_SPI_DATA_REG_3 (0x70) Loading Loading @@ -109,6 +109,17 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 #define MEM_CS_EN(n) ((n + 1) << 8) #define MEM_CS_MASK (7 << 8) #define MM_SWITCH 0x1 #define QSPI_SETUP_RD_NORMAL (0x0 << 12) #define QSPI_SETUP_RD_DUAL (0x1 << 12) #define QSPI_SETUP_RD_QUAD (0x3 << 12) #define QSPI_SETUP_ADDR_SHIFT 8 #define QSPI_SETUP_DUMMY_SHIFT 10 static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { Loading Loading @@ -366,6 +377,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } static void ti_qspi_enable_memory_map(struct spi_device *spi) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); if (qspi->ctrl_base) { regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, MEM_CS_EN(spi->chip_select), MEM_CS_MASK); } qspi->mmap_enabled = true; } static void ti_qspi_disable_memory_map(struct spi_device *spi) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); if (qspi->ctrl_base) regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, 0, MEM_CS_MASK); qspi->mmap_enabled = false; } static void ti_qspi_setup_mmap_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); u32 memval = msg->read_opcode; switch (msg->data_nbits) { case SPI_NBITS_QUAD: memval |= QSPI_SETUP_RD_QUAD; break; case SPI_NBITS_DUAL: memval |= QSPI_SETUP_RD_DUAL; break; default: memval |= QSPI_SETUP_RD_NORMAL; break; } memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); ti_qspi_write(qspi, memval, QSPI_SPI_SETUP_REG(spi->chip_select)); } static int ti_qspi_spi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); int ret = 0; mutex_lock(&qspi->list_lock); if (!qspi->mmap_enabled) ti_qspi_enable_memory_map(spi); ti_qspi_setup_mmap_read(spi, msg); memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); msg->retlen = msg->len; mutex_unlock(&qspi->list_lock); return ret; } static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_message *m) { Loading Loading @@ -398,6 +475,9 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, mutex_lock(&qspi->list_lock); if (qspi->mmap_enabled) ti_qspi_disable_memory_map(spi); list_for_each_entry(t, &m->transfers, transfer_list) { qspi->cmd |= QSPI_WLEN(t->bits_per_word); Loading Loading @@ -441,7 +521,7 @@ static int ti_qspi_probe(struct platform_device *pdev) { struct ti_qspi *qspi; struct spi_master *master; struct resource *r, *res_ctrl, *res_mmap; struct resource *r, *res_mmap; struct device_node *np = pdev->dev.of_node; u32 max_freq; int ret = 0, num_cs, irq; Loading Loading @@ -487,16 +567,6 @@ static int ti_qspi_probe(struct platform_device *pdev) } } res_ctrl = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_ctrlmod"); if (res_ctrl == NULL) { res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (res_ctrl == NULL) { dev_dbg(&pdev->dev, "control module resources not required\n"); } } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); Loading @@ -511,20 +581,31 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } if (res_ctrl) { qspi->ctrl_mod = true; qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); if (IS_ERR(qspi->ctrl_base)) { ret = PTR_ERR(qspi->ctrl_base); goto free_master; if (res_mmap) { qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); master->spi_flash_read = ti_qspi_spi_flash_read; if (IS_ERR(qspi->mmap_base)) { dev_err(&pdev->dev, "falling back to PIO mode\n"); master->spi_flash_read = NULL; } } qspi->mmap_enabled = false; if (res_mmap) { qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); if (IS_ERR(qspi->mmap_base)) { ret = PTR_ERR(qspi->mmap_base); goto free_master; if (of_property_read_bool(np, "syscon-chipselects")) { qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); if (IS_ERR(qspi->ctrl_base)) return PTR_ERR(qspi->ctrl_base); ret = of_property_read_u32_index(np, "syscon-chipselects", 1, &qspi->ctrl_reg); if (ret) { dev_err(&pdev->dev, "couldn't get ctrl_mod reg index\n"); return ret; } } Loading Loading
Documentation/devicetree/bindings/spi/spi-rockchip.txt +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ Required Properties: "rockchip,rk3066-spi" for rk3066. "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188. "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288. "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399. - reg: physical base address of the controller and length of memory mapped region. - interrupts: The interrupt number to the cpu. The interrupt specifier format Loading
Documentation/devicetree/bindings/spi/spi-xilinx.txt 0 → 100644 +22 −0 Original line number Diff line number Diff line Xilinx SPI controller Device Tree Bindings ------------------------------------------------- Required properties: - compatible : Should be "xlnx,xps-spi-2.00.a" or "xlnx,xps-spi-2.00.b" - reg : Physical base address and size of SPI registers map. - interrupts : Property with a value describing the interrupt number. - interrupt-parent : Must be core interrupt controller Optional properties: - xlnx,num-ss-bits : Number of chip selects used. Example: axi_quad_spi@41e00000 { compatible = "xlnx,xps-spi-2.00.a"; interrupt-parent = <&intc>; interrupts = <0 31 1>; reg = <0x41e00000 0x10000>; xlnx,num-ss-bits = <0x1>; };
drivers/spi/Kconfig +3 −3 Original line number Diff line number Diff line Loading @@ -487,7 +487,7 @@ config SPI_RB4XX config SPI_RSPI tristate "Renesas RSPI/QSPI controller" depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help SPI driver for Renesas RSPI and QSPI blocks. Loading Loading @@ -537,7 +537,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK && HAS_DMA depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH and SH Mobile MSIOF blocks. Loading @@ -556,7 +556,7 @@ config SPI_SH_SCI config SPI_SH_HSPI tristate "SuperH HSPI controller" depends on ARCH_SHMOBILE || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH HSPI blocks. Loading
drivers/spi/spi-rockchip.c +35 −21 Original line number Diff line number Diff line Loading @@ -13,20 +13,14 @@ * */ #include <linux/init.h> #include <linux/module.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/scatterlist.h> #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/io.h> #include <linux/dmaengine.h> #include <linux/scatterlist.h> #define DRIVER_NAME "rockchip-spi" Loading Loading @@ -179,7 +173,7 @@ struct rockchip_spi { u8 tmode; u8 bpw; u8 n_bytes; u8 rsd_nsecs; u32 rsd_nsecs; unsigned len; u32 speed; Loading @@ -192,8 +186,6 @@ struct rockchip_spi { /* protect state */ spinlock_t lock; struct completion xfer_completion; u32 use_dma; struct sg_table tx_sg; struct sg_table rx_sg; Loading Loading @@ -265,7 +257,10 @@ static inline u32 rx_max(struct rockchip_spi *rs) static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { u32 ser; struct rockchip_spi *rs = spi_master_get_devdata(spi->master); struct spi_master *master = spi->master; struct rockchip_spi *rs = spi_master_get_devdata(master); pm_runtime_get_sync(rs->dev); ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; Loading @@ -290,6 +285,8 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) ser &= ~(1 << spi->chip_select); writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); pm_runtime_put_sync(rs->dev); } static int rockchip_spi_prepare_message(struct spi_master *master, Loading Loading @@ -319,12 +316,12 @@ static void rockchip_spi_handle_err(struct spi_master *master, */ if (rs->use_dma) { if (rs->state & RXBUSY) { dmaengine_terminate_all(rs->dma_rx.ch); dmaengine_terminate_async(rs->dma_rx.ch); flush_fifo(rs); } if (rs->state & TXBUSY) dmaengine_terminate_all(rs->dma_tx.ch); dmaengine_terminate_async(rs->dma_tx.ch); } spin_unlock_irqrestore(&rs->lock, flags); Loading Loading @@ -433,7 +430,7 @@ static void rockchip_spi_dma_txcb(void *data) spin_unlock_irqrestore(&rs->lock, flags); } static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) { unsigned long flags; struct dma_slave_config rxconf, txconf; Loading @@ -456,6 +453,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rs->dma_rx.ch, rs->rx_sg.sgl, rs->rx_sg.nents, rs->dma_rx.direction, DMA_PREP_INTERRUPT); if (!rxdesc) return -EINVAL; rxdesc->callback = rockchip_spi_dma_rxcb; rxdesc->callback_param = rs; Loading @@ -473,6 +472,11 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rs->dma_tx.ch, rs->tx_sg.sgl, rs->tx_sg.nents, rs->dma_tx.direction, DMA_PREP_INTERRUPT); if (!txdesc) { if (rxdesc) dmaengine_terminate_sync(rs->dma_rx.ch); return -EINVAL; } txdesc->callback = rockchip_spi_dma_txcb; txdesc->callback_param = rs; Loading @@ -494,6 +498,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) dmaengine_submit(txdesc); dma_async_issue_pending(rs->dma_tx.ch); } return 0; } static void rockchip_spi_config(struct rockchip_spi *rs) Loading @@ -503,7 +509,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs) int rsd = 0; u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET) | (CR0_SSD_ONE << CR0_SSD_OFFSET); | (CR0_SSD_ONE << CR0_SSD_OFFSET) | (CR0_EM_BIG << CR0_EM_OFFSET); cr0 |= (rs->n_bytes << CR0_DFS_OFFSET); cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET); Loading Loading @@ -606,12 +613,12 @@ static int rockchip_spi_transfer_one( if (rs->use_dma) { if (rs->tmode == CR0_XFM_RO) { /* rx: dma must be prepared first */ rockchip_spi_prepare_dma(rs); ret = rockchip_spi_prepare_dma(rs); spi_enable_chip(rs, 1); } else { /* tx or tr: spi must be enabled first */ spi_enable_chip(rs, 1); rockchip_spi_prepare_dma(rs); ret = rockchip_spi_prepare_dma(rs); } } else { spi_enable_chip(rs, 1); Loading Loading @@ -717,8 +724,14 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->handle_err = rockchip_spi_handle_err; rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx"); if (!rs->dma_tx.ch) if (IS_ERR_OR_NULL(rs->dma_tx.ch)) { /* Check tx to see if we need defer probing driver */ if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; goto err_get_fifo_len; } dev_warn(rs->dev, "Failed to request TX DMA channel\n"); } rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx"); if (!rs->dma_rx.ch) { Loading Loading @@ -871,6 +884,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = { { .compatible = "rockchip,rk3066-spi", }, { .compatible = "rockchip,rk3188-spi", }, { .compatible = "rockchip,rk3288-spi", }, { .compatible = "rockchip,rk3399-spi", }, { }, }; MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); Loading
drivers/spi/spi-ti-qspi.c +110 −29 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/spi/spi.h> Loading @@ -44,8 +46,9 @@ struct ti_qspi { struct spi_master *master; void __iomem *base; void __iomem *ctrl_base; void __iomem *mmap_base; struct regmap *ctrl_base; unsigned int ctrl_reg; struct clk *fclk; struct device *dev; Loading @@ -55,7 +58,7 @@ struct ti_qspi { u32 cmd; u32 dc; bool ctrl_mod; bool mmap_enabled; }; #define QSPI_PID (0x0) Loading @@ -65,11 +68,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG (0x4c) #define QSPI_SPI_DATA_REG (0x50) #define QSPI_SPI_SETUP0_REG (0x54) #define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG (0x64) #define QSPI_SPI_SETUP1_REG (0x58) #define QSPI_SPI_SETUP2_REG (0x5c) #define QSPI_SPI_SETUP3_REG (0x60) #define QSPI_SPI_DATA_REG_1 (0x68) #define QSPI_SPI_DATA_REG_2 (0x6c) #define QSPI_SPI_DATA_REG_3 (0x70) Loading Loading @@ -109,6 +109,17 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 #define MEM_CS_EN(n) ((n + 1) << 8) #define MEM_CS_MASK (7 << 8) #define MM_SWITCH 0x1 #define QSPI_SETUP_RD_NORMAL (0x0 << 12) #define QSPI_SETUP_RD_DUAL (0x1 << 12) #define QSPI_SETUP_RD_QUAD (0x3 << 12) #define QSPI_SETUP_ADDR_SHIFT 8 #define QSPI_SETUP_DUMMY_SHIFT 10 static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { Loading Loading @@ -366,6 +377,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } static void ti_qspi_enable_memory_map(struct spi_device *spi) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); if (qspi->ctrl_base) { regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, MEM_CS_EN(spi->chip_select), MEM_CS_MASK); } qspi->mmap_enabled = true; } static void ti_qspi_disable_memory_map(struct spi_device *spi) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); if (qspi->ctrl_base) regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, 0, MEM_CS_MASK); qspi->mmap_enabled = false; } static void ti_qspi_setup_mmap_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); u32 memval = msg->read_opcode; switch (msg->data_nbits) { case SPI_NBITS_QUAD: memval |= QSPI_SETUP_RD_QUAD; break; case SPI_NBITS_DUAL: memval |= QSPI_SETUP_RD_DUAL; break; default: memval |= QSPI_SETUP_RD_NORMAL; break; } memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); ti_qspi_write(qspi, memval, QSPI_SPI_SETUP_REG(spi->chip_select)); } static int ti_qspi_spi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); int ret = 0; mutex_lock(&qspi->list_lock); if (!qspi->mmap_enabled) ti_qspi_enable_memory_map(spi); ti_qspi_setup_mmap_read(spi, msg); memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); msg->retlen = msg->len; mutex_unlock(&qspi->list_lock); return ret; } static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_message *m) { Loading Loading @@ -398,6 +475,9 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, mutex_lock(&qspi->list_lock); if (qspi->mmap_enabled) ti_qspi_disable_memory_map(spi); list_for_each_entry(t, &m->transfers, transfer_list) { qspi->cmd |= QSPI_WLEN(t->bits_per_word); Loading Loading @@ -441,7 +521,7 @@ static int ti_qspi_probe(struct platform_device *pdev) { struct ti_qspi *qspi; struct spi_master *master; struct resource *r, *res_ctrl, *res_mmap; struct resource *r, *res_mmap; struct device_node *np = pdev->dev.of_node; u32 max_freq; int ret = 0, num_cs, irq; Loading Loading @@ -487,16 +567,6 @@ static int ti_qspi_probe(struct platform_device *pdev) } } res_ctrl = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_ctrlmod"); if (res_ctrl == NULL) { res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (res_ctrl == NULL) { dev_dbg(&pdev->dev, "control module resources not required\n"); } } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); Loading @@ -511,20 +581,31 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } if (res_ctrl) { qspi->ctrl_mod = true; qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); if (IS_ERR(qspi->ctrl_base)) { ret = PTR_ERR(qspi->ctrl_base); goto free_master; if (res_mmap) { qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); master->spi_flash_read = ti_qspi_spi_flash_read; if (IS_ERR(qspi->mmap_base)) { dev_err(&pdev->dev, "falling back to PIO mode\n"); master->spi_flash_read = NULL; } } qspi->mmap_enabled = false; if (res_mmap) { qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); if (IS_ERR(qspi->mmap_base)) { ret = PTR_ERR(qspi->mmap_base); goto free_master; if (of_property_read_bool(np, "syscon-chipselects")) { qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); if (IS_ERR(qspi->ctrl_base)) return PTR_ERR(qspi->ctrl_base); ret = of_property_read_u32_index(np, "syscon-chipselects", 1, &qspi->ctrl_reg); if (ret) { dev_err(&pdev->dev, "couldn't get ctrl_mod reg index\n"); return ret; } } Loading