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:
Mark Brown 2016-03-11 14:28:53 +07:00
Коммит c508709bcf
6 изменённых файлов: 176 добавлений и 57 удалений

Просмотреть файл

@ -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;