Merge remote-tracking branches 'spi/topic/res', 'spi/topic/rockchip', 'spi/topic/sh', 'spi/topic/ti-qspi' and 'spi/topic/xilinx' into spi-next
This commit is contained in:
Коммит
c508709bcf
|
@ -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
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
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>;
|
||||
};
|
||||
|
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -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/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/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#define DRIVER_NAME "rockchip-spi"
|
||||
|
||||
|
@ -179,7 +173,7 @@ struct rockchip_spi {
|
|||
u8 tmode;
|
||||
u8 bpw;
|
||||
u8 n_bytes;
|
||||
u8 rsd_nsecs;
|
||||
u32 rsd_nsecs;
|
||||
unsigned len;
|
||||
u32 speed;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -55,7 +58,7 @@ struct ti_qspi {
|
|||
u32 cmd;
|
||||
u32 dc;
|
||||
|
||||
bool ctrl_mod;
|
||||
bool mmap_enabled;
|
||||
};
|
||||
|
||||
#define QSPI_PID (0x0)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -604,6 +604,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
|||
* SPI resource management while processing a SPI message
|
||||
*/
|
||||
|
||||
typedef void (*spi_res_release_t)(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
void *res);
|
||||
|
||||
/**
|
||||
* struct spi_res - spi resource management structure
|
||||
* @entry: list entry
|
||||
|
@ -613,9 +617,6 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
|||
* this is based on ideas from devres, but focused on life-cycle
|
||||
* management during spi_message processing
|
||||
*/
|
||||
typedef void (*spi_res_release_t)(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
void *res);
|
||||
struct spi_res {
|
||||
struct list_head entry;
|
||||
spi_res_release_t release;
|
||||
|
|
Загрузка…
Ссылка в новой задаче