This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
+++++config SPI_AU1550
+++++ tristate "Au1550/Au1200/Au1300 SPI Controller"
+++++ depends on MIPS_ALCHEMY
+++++ select SPI_BITBANG
+++++ help
+++++ If you say yes to this option, support will be included for the
+++++ PSC SPI controller found on Au1550, Au1200 and Au1300 series.
+++++
+++++config SPI_AXI_SPI_ENGINE
+++++ tristate "Analog Devices AXI SPI Engine controller"
+++++ depends on HAS_IOMEM
+++++ help
+++++ This enables support for the Analog Devices AXI SPI Engine SPI controller.
+++++ It is part of the SPI Engine framework that is used in some Analog Devices
+++++ reference designs for FPGAs.
+++++
config SPI_BCM2835
tristate "BCM2835 SPI controller"
depends on GPIOLIB
depends on ARCH_BCM2835 || COMPILE_TEST
----- depends on GPIOLIB
help
This selects a driver for the Broadcom BCM2835 SPI master.
config SPI_BCM2835AUX
tristate "BCM2835 SPI auxiliary controller"
----- depends on ARCH_BCM2835 || COMPILE_TEST
----- depends on GPIOLIB
+++++ depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI aux master.
help
Enable support for a SPI bus via the Blackfin SPORT peripheral.
-----config SPI_AU1550
----- tristate "Au1550/Au1200/Au1300 SPI Controller"
----- depends on MIPS_ALCHEMY
----- select SPI_BITBANG
----- help
----- If you say yes to this option, support will be included for the
----- PSC SPI controller found on Au1550, Au1200 and Au1300 series.
-----
config SPI_BCM53XX
tristate "Broadcom BCM53xx SPI controller"
depends on ARCH_BCM_5301X
help
SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+++++config SPI_DESIGNWARE
+++++ tristate "DesignWare SPI controller core support"
+++++ help
+++++ general driver for SPI controller core from DesignWare
+++++
+++++config SPI_DW_PCI
+++++ tristate "PCI interface driver for DW SPI core"
+++++ depends on SPI_DESIGNWARE && PCI
+++++
+++++config SPI_DW_MID_DMA
+++++ bool "DMA support for DW SPI controller on Intel MID platform"
+++++ depends on SPI_DW_PCI && DW_DMAC_PCI
+++++
+++++config SPI_DW_MMIO
+++++ tristate "Memory-mapped io interface driver for DW SPI core"
+++++ depends on SPI_DESIGNWARE
+++++
config SPI_DLN2
tristate "Diolan DLN-2 USB SPI adapter"
depends on MFD_DLN2
which interfaces to an LM70 temperature sensor using
a parallel port.
+++++config SPI_LP8841_RTC
+++++ tristate "ICP DAS LP-8841 SPI Controller for RTC"
+++++ depends on MACH_PXA27X_DT || COMPILE_TEST
+++++ help
+++++ This driver provides an SPI master device to drive Maxim
+++++ DS-1302 real time clock.
+++++
+++++ Say N here unless you plan to run the kernel on an ICP DAS
+++++ LP-8x4x industrial computer.
+++++
config SPI_MPC52xx
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
depends on PPC_MPC52xx
say Y or M here.If you are not sure, say N.
SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
+++++config SPI_NUC900
+++++ tristate "Nuvoton NUC900 series SPI"
+++++ depends on ARCH_W90X900
+++++ select SPI_BITBANG
+++++ help
+++++ SPI driver for Nuvoton NUC900 series ARM SoCs
+++++
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
depends on GPIOLIB || COMPILE_TEST
help
This selects a driver for the PPC4xx SPI Controller.
-----config SPI_PXA2XX_DMA
----- def_bool y
----- depends on SPI_PXA2XX
-----
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || PCI || ACPI)
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.
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.
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.
help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
-----config SPI_NUC900
----- tristate "Nuvoton NUC900 series SPI"
----- depends on ARCH_W90X900
----- select SPI_BITBANG
----- help
----- SPI driver for Nuvoton NUC900 series ARM SoCs
-----
#
# Add new SPI master controllers in alphabetical order above this line
#
-----config SPI_DESIGNWARE
----- tristate "DesignWare SPI controller core support"
----- help
----- general driver for SPI controller core from DesignWare
-----
-----config SPI_DW_PCI
----- tristate "PCI interface driver for DW SPI core"
----- depends on SPI_DESIGNWARE && PCI
-----
-----config SPI_DW_MID_DMA
----- bool "DMA support for DW SPI controller on Intel MID platform"
----- depends on SPI_DW_PCI && DW_DMAC_PCI
-----
-----config SPI_DW_MMIO
----- tristate "Memory-mapped io interface driver for DW SPI core"
----- depends on SPI_DESIGNWARE
-----
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
*
*/
-- ---#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"
u8 tmode;
u8 bpw;
u8 n_bytes;
-- --- u8 rsd_nsecs;
++ +++ u32 rsd_nsecs;
unsigned len;
u32 speed;
/* protect state */
spinlock_t lock;
-- --- struct completion xfer_completion;
-- ---
u32 use_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
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;
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,
*/
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);
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;
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;
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;
dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch);
}
++ +++
++ +++ return 0;
}
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);
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);
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) {
return 0;
err_register_master:
+++++ pm_runtime_disable(&pdev->dev);
if (rs->dma_tx.ch)
dma_release_channel(rs->dma_tx.ch);
if (rs->dma_rx.ch)
if (rs->dma_rx.ch)
dma_release_channel(rs->dma_rx.ch);
+++++ spi_master_put(master);
+++++
return 0;
}
{ .compatible = "rockchip,rk3066-spi", },
{ .compatible = "rockchip,rk3188-spi", },
{ .compatible = "rockchip,rk3288-spi", },
++ +++ { .compatible = "rockchip,rk3399-spi", },
{ },
};
MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
struct dma_chan;
struct spi_master;
struct spi_transfer;
+++ +struct spi_flash_read_message;
/*
* INTERFACES between SPI master-side drivers and SPI infrastructure.
*
* @transfer_bytes_histo:
* transfer bytes histogramm
+++++ *
+++++ * @transfers_split_maxsize:
+++++ * number of transfers that have been split because of
+++++ * maxsize limit
*/
struct spi_statistics {
spinlock_t lock; /* lock for the whole structure */
#define SPI_STATISTICS_HISTO_SIZE 17
unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];
+++++
+++++ unsigned long transfers_split_maxsize;
};
void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
* @min_speed_hz: Lowest supported transfer speed
* @max_speed_hz: Highest supported transfer speed
* @flags: other constraints relevant to this driver
+++++ * @max_transfer_size: function that returns the max transfer size for
+++++ * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
* @bus_lock_spinlock: spinlock for SPI bus locking
* @bus_lock_mutex: mutex for SPI bus locking
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
* @handle_err: the subsystem calls the driver to handle an error that occurs
* in the generic implementation of transfer_one_message().
* @unprepare_message: undo any work done by prepare_message().
+++ + * @spi_flash_read: to support spi-controller hardwares that provide
+++ + * accelerated interface to read from flash devices.
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
* number. Any individual value may be -ENOENT for CS lines that
* are not GPIOs (driven by the SPI controller itself).
* @dma_rx: DMA receive channel
* @dummy_rx: dummy receive buffer for full-duplex devices
* @dummy_tx: dummy transmit buffer for full-duplex devices
+++++ * @fw_translate_cs: If the boot firmware uses different numbering scheme
+++++ * what Linux expects, this optional hook can be used to translate
+++++ * between the two.
*
* Each SPI master controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals
struct spi_message *message);
int (*unprepare_message)(struct spi_master *master,
struct spi_message *message);
+++ + int (*spi_flash_read)(struct spi_device *spi,
+++ + struct spi_flash_read_message *msg);
/*
* These hooks are for drivers that use a generic implementation
/* dummy data for full duplex devices */
void *dummy_rx;
void *dummy_tx;
+++++
+++++ int (*fw_translate_cs)(struct spi_master *master, unsigned cs);
};
static inline void *spi_master_get_devdata(struct spi_master *master)
extern struct spi_master *spi_busnum_to_master(u16 busnum);
- typedef void (*spi_res_release_t)(struct spi_master *master,
- struct spi_message *msg,
- void *res);
++++/*
++++ * 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
++++ * @release: release code called prior to freeing this resource
++++ * @data: extra data allocated for the specific use-case
++++ *
++++ * this is based on ideas from devres, but focused on life-cycle
++++ * management during spi_message processing
++++ */
++++struct spi_res {
++++ struct list_head entry;
++++ spi_res_release_t release;
++++ unsigned long long data[]; /* guarantee ull alignment */
++++};
++++
++++extern void *spi_res_alloc(struct spi_device *spi,
++++ spi_res_release_t release,
++++ size_t size, gfp_t gfp);
++++extern void spi_res_add(struct spi_message *message, void *res);
++++extern void spi_res_free(void *res);
++++
++++extern void spi_res_release(struct spi_master *master,
++++ struct spi_message *message);
++++
/*---------------------------------------------------------------------------*/
/*
* @status: zero for success, else negative errno
* @queue: for use by whichever driver currently owns the message
* @state: for use by whichever driver currently owns the message
++++ * @resources: for resource management when the spi message is processed
*
* A @spi_message is used to execute an atomic sequence of data transfers,
* each represented by a struct spi_transfer. The sequence is "atomic"
*/
struct list_head queue;
void *state;
++++
++++ /* list of spi_res reources when the spi message is processed */
++++ struct list_head resources;
};
static inline void spi_message_init_no_memset(struct spi_message *m)
{
INIT_LIST_HEAD(&m->transfers);
++++ INIT_LIST_HEAD(&m->resources);
}
static inline void spi_message_init(struct spi_message *m)
/*---------------------------------------------------------------------------*/
+++++/* SPI transfer replacement methods which make use of spi_res */
+++++
+++++struct spi_replaced_transfers;
+++++typedef void (*spi_replaced_release_t)(struct spi_master *master,
+++++ struct spi_message *msg,
+++++ struct spi_replaced_transfers *res);
+++++/**
+++++ * struct spi_replaced_transfers - structure describing the spi_transfer
+++++ * replacements that have occurred
+++++ * so that they can get reverted
+++++ * @release: some extra release code to get executed prior to
+++++ * relasing this structure
+++++ * @extradata: pointer to some extra data if requested or NULL
+++++ * @replaced_transfers: transfers that have been replaced and which need
+++++ * to get restored
+++++ * @replaced_after: the transfer after which the @replaced_transfers
+++++ * are to get re-inserted
+++++ * @inserted: number of transfers inserted
+++++ * @inserted_transfers: array of spi_transfers of array-size @inserted,
+++++ * that have been replacing replaced_transfers
+++++ *
+++++ * note: that @extradata will point to @inserted_transfers[@inserted]
+++++ * if some extra allocation is requested, so alignment will be the same
+++++ * as for spi_transfers
+++++ */
+++++struct spi_replaced_transfers {
+++++ spi_replaced_release_t release;
+++++ void *extradata;
+++++ struct list_head replaced_transfers;
+++++ struct list_head *replaced_after;
+++++ size_t inserted;
+++++ struct spi_transfer inserted_transfers[];
+++++};
+++++
+++++extern struct spi_replaced_transfers *spi_replace_transfers(
+++++ struct spi_message *msg,
+++++ struct spi_transfer *xfer_first,
+++++ size_t remove,
+++++ size_t insert,
+++++ spi_replaced_release_t release,
+++++ size_t extradatasize,
+++++ gfp_t gfp);
+++++
+++++/*---------------------------------------------------------------------------*/
+++++
+++++/* SPI transfer transformation methods */
+++++
+++++extern int spi_split_transfers_maxsize(struct spi_master *master,
+++++ struct spi_message *msg,
+++++ size_t maxsize,
+++++ gfp_t gfp);
+++++
+++++/*---------------------------------------------------------------------------*/
+++++
/* All these synchronous SPI transfer routines are utilities layered
* over the core async transfer primitive. Here, "synchronous" means
* they will sleep uninterruptibly until the async transfer completes.
return be16_to_cpu(result);
}
+++ +/**
+++ + * struct spi_flash_read_message - flash specific information for
+++ + * spi-masters that provide accelerated flash read interfaces
+++ + * @buf: buffer to read data
+++ + * @from: offset within the flash from where data is to be read
+++ + * @len: length of data to be read
+++ + * @retlen: actual length of data read
+++ + * @read_opcode: read_opcode to be used to communicate with flash
+++ + * @addr_width: number of address bytes
+++ + * @dummy_bytes: number of dummy bytes
+++ + * @opcode_nbits: number of lines to send opcode
+++ + * @addr_nbits: number of lines to send address
+++ + * @data_nbits: number of lines for data
+++ + */
+++ +struct spi_flash_read_message {
+++ + void *buf;
+++ + loff_t from;
+++ + size_t len;
+++ + size_t retlen;
+++ + u8 read_opcode;
+++ + u8 addr_width;
+++ + u8 dummy_bytes;
+++ + u8 opcode_nbits;
+++ + u8 addr_nbits;
+++ + u8 data_nbits;
+++ +};
+++ +
+++ +/* SPI core interface for flash read support */
+++ +static inline bool spi_flash_read_supported(struct spi_device *spi)
+++ +{
+++ + return spi->master->spi_flash_read ? true : false;
+++ +}
+++ +
+++ +int spi_flash_read(struct spi_device *spi,
+++ + struct spi_flash_read_message *msg);
+++ +
/*---------------------------------------------------------------------------*/
/*