diff options
Diffstat (limited to 'drivers/spi/spi-s3c64xx.c')
| -rw-r--r-- | drivers/spi/spi-s3c64xx.c | 634 |
1 files changed, 383 insertions, 251 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 71d324ec9a70..aab36c779c06 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -3,23 +3,24 @@ // Copyright (c) 2009 Samsung Electronics Co., Ltd. // Jaswinder Singh <jassi.brar@samsung.com> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/bits.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_data/spi-s3c64xx.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> -#include <linux/of.h> -#include <linux/of_device.h> - -#include <linux/platform_data/spi-s3c64xx.h> +#include <linux/types.h> #define MAX_SPI_PORTS 12 -#define S3C64XX_SPI_QUIRK_POLL (1 << 0) #define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1) #define AUTOSUSPEND_TIMEOUT 2000 @@ -59,6 +60,8 @@ #define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17) #define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17) #define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17) +#define S3C64XX_SPI_MODE_RX_RDY_LVL GENMASK(16, 11) +#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT 11 #define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3) #define S3C64XX_SPI_MODE_RXDMA_ON (1<<2) #define S3C64XX_SPI_MODE_TXDMA_ON (1<<1) @@ -76,6 +79,9 @@ #define S3C64XX_SPI_INT_RX_FIFORDY_EN (1<<1) #define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0) +#define S3C64XX_SPI_ST_RX_FIFO_RDY_V2 GENMASK(23, 15) +#define S3C64XX_SPI_ST_TX_FIFO_RDY_V2 GENMASK(14, 6) +#define S3C64XX_SPI_ST_TX_FIFO_LVL_SHIFT 6 #define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5) #define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4) #define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3) @@ -106,17 +112,19 @@ #define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id]) #define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \ (1 << (i)->port_conf->tx_st_done)) ? 1 : 0) -#define TX_FIFO_LVL(v, i) (((v) >> 6) & FIFO_LVL_MASK(i)) -#define RX_FIFO_LVL(v, i) (((v) >> (i)->port_conf->rx_lvl_offset) & \ - FIFO_LVL_MASK(i)) +#define TX_FIFO_LVL(v, sdd) (((v) & (sdd)->tx_fifomask) >> \ + __ffs((sdd)->tx_fifomask)) +#define RX_FIFO_LVL(v, sdd) (((v) & (sdd)->rx_fifomask) >> \ + __ffs((sdd)->rx_fifomask)) +#define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1) #define S3C64XX_SPI_MAX_TRAILCNT 0x3ff #define S3C64XX_SPI_TRAILCNT_OFF 19 -#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT +#define S3C64XX_SPI_POLLING_SIZE 32 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) -#define is_polling(x) (x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL) +#define is_polling(x) (x->cntrlr_info->polling) #define RXBUSY (1<<2) #define TXBUSY (1<<3) @@ -129,8 +137,15 @@ struct s3c64xx_spi_dma_data { /** * struct s3c64xx_spi_port_config - SPI Controller hardware info - * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register. - * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter. + * @fifo_lvl_mask: [DEPRECATED] use @{rx, tx}_fifomask instead. + * @rx_lvl_offset: [DEPRECATED] use @{rx,tx}_fifomask instead. + * @fifo_depth: depth of the FIFOs. Used by compatibles where all the instances + * of the IP define the same FIFO depth. It has higher precedence + * than the FIFO depth specified via DT. + * @rx_fifomask: SPI_STATUS.RX_FIFO_LVL mask. Shifted mask defining the field's + * length and position. + * @tx_fifomask: SPI_STATUS.TX_FIFO_LVL mask. Shifted mask defining the field's + * length and position. * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter. * @clk_div: Internal clock divider * @quirks: Bitmask of known quirks @@ -139,6 +154,7 @@ struct s3c64xx_spi_dma_data { * prescaler unit. * @clk_ioclk: True if clock is present on this device * @has_loopback: True if loopback mode can be supported + * @use_32bit_io: True if the SoC allows only 32-bit register accesses. * * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but * differ in some aspects such as the size of the fifo and spi bus clock @@ -148,6 +164,9 @@ struct s3c64xx_spi_dma_data { struct s3c64xx_spi_port_config { int fifo_lvl_mask[MAX_SPI_PORTS]; int rx_lvl_offset; + unsigned int fifo_depth; + u32 rx_fifomask; + u32 tx_fifomask; int tx_st_done; int quirks; int clk_div; @@ -155,15 +174,16 @@ struct s3c64xx_spi_port_config { bool clk_from_cmu; bool clk_ioclk; bool has_loopback; + bool use_32bit_io; }; /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. * @src_clk: Pointer to the clock used to generate SPI signals. - * @ioclk: Pointer to the i/o clock between master and slave + * @ioclk: Pointer to the i/o clock between host and target * @pdev: Pointer to device's platform device data - * @master: Pointer to the SPI Protocol master. + * @host: Pointer to the SPI Protocol host. * @cntrlr_info: Platform specific data for the controller this driver manages. * @lock: Controller specific lock. * @state: Set of FLAGS to indicate status. @@ -175,8 +195,13 @@ struct s3c64xx_spi_port_config { * @cur_speed: Current clock speed * @rx_dma: Local receive DMA data (e.g. chan and direction) * @tx_dma: Local transmit DMA data (e.g. chan and direction) - * @port_conf: Local SPI port configuartion data - * @port_id: Port identification number + * @port_conf: Local SPI port configuration data + * @port_id: [DEPRECATED] use @{rx,tx}_fifomask instead. + * @fifo_depth: depth of the FIFO. + * @rx_fifomask: SPI_STATUS.RX_FIFO_LVL mask. Shifted mask defining the field's + * length and position. + * @tx_fifomask: SPI_STATUS.TX_FIFO_LVL mask. Shifted mask defining the field's + * length and position. */ struct s3c64xx_spi_driver_data { void __iomem *regs; @@ -184,7 +209,7 @@ struct s3c64xx_spi_driver_data { struct clk *src_clk; struct clk *ioclk; struct platform_device *pdev; - struct spi_master *master; + struct spi_controller *host; struct s3c64xx_spi_info *cntrlr_info; spinlock_t lock; unsigned long sfr_start; @@ -196,6 +221,9 @@ struct s3c64xx_spi_driver_data { struct s3c64xx_spi_dma_data tx_dma; const struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; + unsigned int fifo_depth; + u32 rx_fifomask; + u32 tx_fifomask; }; static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd) @@ -219,7 +247,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd) loops = msecs_to_loops(1); do { val = readl(regs + S3C64XX_SPI_STATUS); - } while (TX_FIFO_LVL(val, sdd) && loops--); + } while (TX_FIFO_LVL(val, sdd) && --loops); if (loops == 0) dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n"); @@ -232,7 +260,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd) readl(regs + S3C64XX_SPI_RX_DATA); else break; - } while (loops--); + } while (--loops); if (loops == 0) dev_warn(&sdd->pdev->dev, "Timed out flushing RX FIFO\n"); @@ -274,8 +302,8 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -static int prepare_dma(struct s3c64xx_spi_dma_data *dma, - struct sg_table *sgt) +static int s3c64xx_prepare_dma(struct s3c64xx_spi_dma_data *dma, + struct sg_table *sgt) { struct s3c64xx_spi_driver_data *sdd; struct dma_slave_config config; @@ -287,20 +315,20 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma, if (dma->direction == DMA_DEV_TO_MEM) { sdd = container_of((void *)dma, struct s3c64xx_spi_driver_data, rx_dma); - config.direction = dma->direction; config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA; config.src_addr_width = sdd->cur_bpw / 8; config.src_maxburst = 1; - dmaengine_slave_config(dma->ch, &config); } else { sdd = container_of((void *)dma, struct s3c64xx_spi_driver_data, tx_dma); - config.direction = dma->direction; config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA; config.dst_addr_width = sdd->cur_bpw / 8; config.dst_maxburst = 1; - dmaengine_slave_config(dma->ch, &config); } + config.direction = dma->direction; + ret = dmaengine_slave_config(dma->ch, &config); + if (ret) + return ret; desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents, dma->direction, DMA_PREP_INTERRUPT); @@ -317,7 +345,7 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma, ret = dma_submit_error(dma->cookie); if (ret) { dev_err(&sdd->pdev->dev, "DMA submission failed"); - return -EIO; + return ret; } dma_async_issue_pending(dma->ch); @@ -327,7 +355,7 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma, static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) { struct s3c64xx_spi_driver_data *sdd = - spi_master_get_devdata(spi->master); + spi_controller_get_devdata(spi->controller); if (sdd->cntrlr_info->no_cs) return; @@ -349,9 +377,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) } } -static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) +static int s3c64xx_spi_prepare_transfer(struct spi_controller *spi) { - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi); if (is_polling(sdd)) return 0; @@ -379,9 +407,9 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) return 0; } -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) +static int s3c64xx_spi_unprepare_transfer(struct spi_controller *spi) { - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi); if (is_polling(sdd)) return 0; @@ -397,18 +425,66 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) return 0; } -static bool s3c64xx_spi_can_dma(struct spi_master *master, +static bool s3c64xx_spi_can_dma(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *xfer) { - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); - if (sdd->rx_dma.ch && sdd->tx_dma.ch) { - return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; - } else { - return false; + if (sdd->rx_dma.ch && sdd->tx_dma.ch) + return xfer->len >= sdd->fifo_depth; + + return false; +} + +static void s3c64xx_iowrite8_32_rep(volatile void __iomem *addr, + const void *buffer, unsigned int count) +{ + if (count) { + const u8 *buf = buffer; + + do { + __raw_writel(*buf++, addr); + } while (--count); } +} + +static void s3c64xx_iowrite16_32_rep(volatile void __iomem *addr, + const void *buffer, unsigned int count) +{ + if (count) { + const u16 *buf = buffer; + do { + __raw_writel(*buf++, addr); + } while (--count); + } +} + +static void s3c64xx_iowrite_rep(const struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) +{ + void __iomem *addr = sdd->regs + S3C64XX_SPI_TX_DATA; + const void *buf = xfer->tx_buf; + unsigned int len = xfer->len; + + switch (sdd->cur_bpw) { + case 32: + iowrite32_rep(addr, buf, len / 4); + break; + case 16: + if (sdd->port_conf->use_32bit_io) + s3c64xx_iowrite16_32_rep(addr, buf, len / 2); + else + iowrite16_rep(addr, buf, len / 2); + break; + default: + if (sdd->port_conf->use_32bit_io) + s3c64xx_iowrite8_32_rep(addr, buf, len); + else + iowrite8_rep(addr, buf, len); + break; + } } static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd, @@ -442,22 +518,9 @@ static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - ret = prepare_dma(&sdd->tx_dma, &xfer->tx_sg); + ret = s3c64xx_prepare_dma(&sdd->tx_dma, &xfer->tx_sg); } else { - switch (sdd->cur_bpw) { - case 32: - iowrite32_rep(regs + S3C64XX_SPI_TX_DATA, - xfer->tx_buf, xfer->len / 4); - break; - case 16: - iowrite16_rep(regs + S3C64XX_SPI_TX_DATA, - xfer->tx_buf, xfer->len / 2); - break; - default: - iowrite8_rep(regs + S3C64XX_SPI_TX_DATA, - xfer->tx_buf, xfer->len); - break; - } + s3c64xx_iowrite_rep(sdd, xfer); } } @@ -474,7 +537,7 @@ static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - ret = prepare_dma(&sdd->rx_dma, &xfer->rx_sg); + ret = s3c64xx_prepare_dma(&sdd->rx_dma, &xfer->rx_sg); } } @@ -493,9 +556,7 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, void __iomem *regs = sdd->regs; unsigned long val = 1; u32 status; - - /* max fifo depth available */ - u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1; + u32 max_fifo = sdd->fifo_depth; if (timeout_ms) val = msecs_to_loops(timeout_ms); @@ -526,7 +587,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, /* * If the previous xfer was completed within timeout, then - * proceed further else return -EIO. + * proceed further else return -ETIMEDOUT. * DmaTx returns after simply writing data in the FIFO, * w/o waiting for real transmission on the bus to finish. * DmaRx returns only after Dma read data from FIFO which @@ -547,13 +608,13 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, /* If timed out while checking rx/tx status return error */ if (!val) - return -EIO; + return -ETIMEDOUT; return 0; } static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer) + struct spi_transfer *xfer, bool use_irq) { void __iomem *regs = sdd->regs; unsigned long val; @@ -562,11 +623,24 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, u32 cpy_len; u8 *buf; int ms; + unsigned long time_us; - /* millisecs to xfer 'len' bytes @ 'cur_speed' */ - ms = xfer->len * 8 * 1000 / sdd->cur_speed; + /* microsecs to xfer 'len' bytes @ 'cur_speed' */ + time_us = (xfer->len * 8 * 1000 * 1000) / sdd->cur_speed; + ms = (time_us / 1000); ms += 10; /* some tolerance */ + /* sleep during signal transfer time */ + status = readl(regs + S3C64XX_SPI_STATUS); + if (RX_FIFO_LVL(status, sdd) < xfer->len) + usleep_range(time_us / 2, time_us); + + if (use_irq) { + val = msecs_to_jiffies(ms); + if (!wait_for_completion_timeout(&sdd->xfer_completion, val)) + return -ETIMEDOUT; + } + val = msecs_to_loops(ms); do { status = readl(regs + S3C64XX_SPI_STATUS); @@ -589,7 +663,7 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, * For any size less than the fifo size the below code is * executed atleast once. */ - loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1); + loops = xfer->len / sdd->fifo_depth; buf = xfer->rx_buf; do { /* wait for data to be received in the fifo */ @@ -668,6 +742,8 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) if ((sdd->cur_mode & SPI_LOOP) && sdd->port_conf->has_loopback) val |= S3C64XX_SPI_MODE_SELF_LOOPBACK; + else + val &= ~S3C64XX_SPI_MODE_SELF_LOOPBACK; writel(val, regs + S3C64XX_SPI_MODE_CFG); @@ -695,10 +771,10 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) -static int s3c64xx_spi_prepare_message(struct spi_master *master, +static int s3c64xx_spi_prepare_message(struct spi_controller *host, struct spi_message *msg) { - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); struct spi_device *spi = msg->spi; struct s3c64xx_spi_csinfo *cs = spi->controller_data; @@ -719,20 +795,23 @@ static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi) return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX; } -static int s3c64xx_spi_transfer_one(struct spi_master *master, +static int s3c64xx_spi_transfer_one(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *xfer) { - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1; + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); + const unsigned int fifo_len = sdd->fifo_depth; const void *tx_buf = NULL; void *rx_buf = NULL; int target_len = 0, origin_len = 0; int use_dma = 0; + bool use_irq = false; int status; u32 speed; u8 bpw; unsigned long flags; + u32 rdy_lv; + u32 val; reinit_completion(&sdd->xfer_completion); @@ -749,21 +828,49 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, return status; } - if (!is_polling(sdd) && (xfer->len > fifo_len) && + if (!is_polling(sdd) && xfer->len >= fifo_len && sdd->rx_dma.ch && sdd->tx_dma.ch) { use_dma = 1; - - } else if (xfer->len > fifo_len) { + } else if (xfer->len >= fifo_len) { tx_buf = xfer->tx_buf; rx_buf = xfer->rx_buf; origin_len = xfer->len; - target_len = xfer->len; - if (xfer->len > fifo_len) - xfer->len = fifo_len; + xfer->len = fifo_len - 1; } do { + /* transfer size is greater than 32, change to IRQ mode */ + if (!use_dma && xfer->len > S3C64XX_SPI_POLLING_SIZE) + use_irq = true; + + if (use_irq) { + reinit_completion(&sdd->xfer_completion); + + rdy_lv = xfer->len; + /* Setup RDY_FIFO trigger Level + * RDY_LVL = + * fifo_lvl up to 64 byte -> N bytes + * 128 byte -> RDY_LVL * 2 bytes + * 256 byte -> RDY_LVL * 4 bytes + */ + if (fifo_len == 128) + rdy_lv /= 2; + else if (fifo_len == 256) + rdy_lv /= 4; + + val = readl(sdd->regs + S3C64XX_SPI_MODE_CFG); + val &= ~S3C64XX_SPI_MODE_RX_RDY_LVL; + val |= (rdy_lv << S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT); + writel(val, sdd->regs + S3C64XX_SPI_MODE_CFG); + + /* Enable FIFO_RDY_EN IRQ */ + val = readl(sdd->regs + S3C64XX_SPI_INT_EN); + writel((val | S3C64XX_SPI_INT_RX_FIFORDY_EN), + sdd->regs + S3C64XX_SPI_INT_EN); + + } + spin_lock_irqsave(&sdd->lock, flags); /* Pending only which is to be done */ @@ -785,7 +892,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, if (use_dma) status = s3c64xx_wait_for_dma(sdd, xfer); else - status = s3c64xx_wait_for_pio(sdd, xfer); + status = s3c64xx_wait_for_pio(sdd, xfer, use_irq); if (status) { dev_err(&spi->dev, @@ -824,8 +931,8 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, if (xfer->rx_buf) xfer->rx_buf += xfer->len; - if (target_len > fifo_len) - xfer->len = fifo_len; + if (target_len >= fifo_len) + xfer->len = fifo_len - 1; else xfer->len = target_len; } @@ -841,15 +948,15 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, return status; } -static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( +static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs; - struct device_node *slave_np, *data_np = NULL; + struct device_node *target_np; u32 fb_delay = 0; - slave_np = spi->dev.of_node; - if (!slave_np) { + target_np = spi->dev.of_node; + if (!target_np) { dev_err(&spi->dev, "device node not found\n"); return ERR_PTR(-EINVAL); } @@ -858,7 +965,8 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( if (!cs) return ERR_PTR(-ENOMEM); - data_np = of_get_child_by_name(slave_np, "controller-data"); + struct device_node *data_np __free(device_node) = + of_get_child_by_name(target_np, "controller-data"); if (!data_np) { dev_info(&spi->dev, "feedback delay set to default (0)\n"); return cs; @@ -866,7 +974,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); cs->fb_delay = fb_delay; - of_node_put(data_np); return cs; } @@ -883,15 +990,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi) int err; int div; - sdd = spi_master_get_devdata(spi->master); + sdd = spi_controller_get_devdata(spi->controller); if (spi->dev.of_node) { - cs = s3c64xx_get_slave_ctrldata(spi); + cs = s3c64xx_get_target_ctrldata(spi); spi->controller_data = cs; } /* NULL is fine, we just avoid using the FB delay (=0) */ if (IS_ERR(cs)) { - dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select); + dev_err(&spi->dev, "No CS for SPI(%d)\n", spi_get_chipselect(spi, 0)); return -ENODEV; } @@ -938,14 +1045,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } } - pm_runtime_mark_last_busy(&sdd->pdev->dev); pm_runtime_put_autosuspend(&sdd->pdev->dev); s3c64xx_spi_set_cs(spi, false); return 0; setup_exit: - pm_runtime_mark_last_busy(&sdd->pdev->dev); pm_runtime_put_autosuspend(&sdd->pdev->dev); /* setup() returns with device de-selected */ s3c64xx_spi_set_cs(spi, false); @@ -973,7 +1078,7 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) static irqreturn_t s3c64xx_spi_irq(int irq, void *data) { struct s3c64xx_spi_driver_data *sdd = data; - struct spi_master *spi = sdd->master; + struct spi_controller *spi = sdd->host; unsigned int val, clr = 0; val = readl(sdd->regs + S3C64XX_SPI_STATUS); @@ -995,6 +1100,14 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data) dev_err(&spi->dev, "TX underrun\n"); } + if (val & S3C64XX_SPI_ST_RX_FIFORDY) { + complete(&sdd->xfer_completion); + /* No pending clear irq, turn-off INT_EN_RX_FIFO_RDY */ + val = readl(sdd->regs + S3C64XX_SPI_INT_EN); + writel((val & ~S3C64XX_SPI_INT_RX_FIFORDY_EN), + sdd->regs + S3C64XX_SPI_INT_EN); + } + /* Clear the pending irq by setting and then clearing it */ writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR); writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR); @@ -1036,8 +1149,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd) val = readl(regs + S3C64XX_SPI_MODE_CFG); val &= ~S3C64XX_SPI_MODE_4BURST; - val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF); - val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF); + val |= (S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF); writel(val, regs + S3C64XX_SPI_MODE_CFG); s3c64xx_flush_fifo(sdd); @@ -1054,20 +1166,21 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) return ERR_PTR(-ENOMEM); if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) { - dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n"); + dev_dbg(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n"); sci->src_clk_nr = 0; } else { sci->src_clk_nr = temp; } if (of_property_read_u32(dev->of_node, "num-cs", &temp)) { - dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line\n"); + dev_dbg(dev, "number of chip select lines not specified, assuming 1 chip select line\n"); sci->num_cs = 1; } else { sci->num_cs = temp; } sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback"); + sci->polling = !of_property_present(dev->of_node, "dmas"); return sci; } @@ -1088,12 +1201,54 @@ static inline const struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( return (const struct s3c64xx_spi_port_config *)platform_get_device_id(pdev)->driver_data; } +static int s3c64xx_spi_set_port_id(struct platform_device *pdev, + struct s3c64xx_spi_driver_data *sdd) +{ + const struct s3c64xx_spi_port_config *port_conf = sdd->port_conf; + int ret; + + if (port_conf->rx_fifomask && port_conf->tx_fifomask) + return 0; + + if (pdev->dev.of_node) { + ret = of_alias_get_id(pdev->dev.of_node, "spi"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to get alias id\n"); + sdd->port_id = ret; + } else { + if (pdev->id < 0) + return dev_err_probe(&pdev->dev, -EINVAL, + "Negative platform ID is not allowed\n"); + sdd->port_id = pdev->id; + } + + return 0; +} + +static void s3c64xx_spi_set_fifomask(struct s3c64xx_spi_driver_data *sdd) +{ + const struct s3c64xx_spi_port_config *port_conf = sdd->port_conf; + + if (port_conf->rx_fifomask) + sdd->rx_fifomask = port_conf->rx_fifomask; + else + sdd->rx_fifomask = FIFO_LVL_MASK(sdd) << + port_conf->rx_lvl_offset; + + if (port_conf->tx_fifomask) + sdd->tx_fifomask = port_conf->tx_fifomask; + else + sdd->tx_fifomask = FIFO_LVL_MASK(sdd) << + S3C64XX_SPI_ST_TX_FIFO_LVL_SHIFT; +} + static int s3c64xx_spi_probe(struct platform_device *pdev) { struct resource *mem_res; struct s3c64xx_spi_driver_data *sdd; struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev); - struct spi_master *master; + struct spi_controller *host; int ret, irq; char clk_name[16]; @@ -1103,131 +1258,92 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) return PTR_ERR(sci); } - if (!sci) { - dev_err(&pdev->dev, "platform_data missing!\n"); - return -ENODEV; - } - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mem_res == NULL) { - dev_err(&pdev->dev, "Unable to get SPI MEM resource\n"); - return -ENXIO; - } + if (!sci) + return dev_err_probe(&pdev->dev, -ENODEV, + "Platform_data missing!\n"); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_warn(&pdev->dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } - master = spi_alloc_master(&pdev->dev, - sizeof(struct s3c64xx_spi_driver_data)); - if (master == NULL) { - dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*sdd)); + if (!host) return -ENOMEM; - } - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, host); - sdd = spi_master_get_devdata(master); + sdd = spi_controller_get_devdata(host); sdd->port_conf = s3c64xx_spi_get_port_config(pdev); - sdd->master = master; + sdd->host = host; sdd->cntrlr_info = sci; sdd->pdev = pdev; - sdd->sfr_start = mem_res->start; - if (pdev->dev.of_node) { - ret = of_alias_get_id(pdev->dev.of_node, "spi"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id, errno %d\n", - ret); - goto err_deref_master; - } - sdd->port_id = ret; - } else { - sdd->port_id = pdev->id; - } + + ret = s3c64xx_spi_set_port_id(pdev, sdd); + if (ret) + return ret; + + if (sdd->port_conf->fifo_depth) + sdd->fifo_depth = sdd->port_conf->fifo_depth; + else if (of_property_read_u32(pdev->dev.of_node, "fifo-depth", + &sdd->fifo_depth)) + sdd->fifo_depth = FIFO_DEPTH(sdd); + + s3c64xx_spi_set_fifomask(sdd); sdd->cur_bpw = 8; sdd->tx_dma.direction = DMA_MEM_TO_DEV; sdd->rx_dma.direction = DMA_DEV_TO_MEM; - master->dev.of_node = pdev->dev.of_node; - master->bus_num = sdd->port_id; - master->setup = s3c64xx_spi_setup; - master->cleanup = s3c64xx_spi_cleanup; - master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; - master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; - master->prepare_message = s3c64xx_spi_prepare_message; - master->transfer_one = s3c64xx_spi_transfer_one; - master->max_transfer_size = s3c64xx_spi_max_transfer_size; - master->num_chipselect = sci->num_cs; - master->use_gpio_descriptors = true; - master->dma_alignment = 8; - master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | - SPI_BPW_MASK(8); + host->dev.of_node = pdev->dev.of_node; + host->bus_num = -1; + host->setup = s3c64xx_spi_setup; + host->cleanup = s3c64xx_spi_cleanup; + host->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; + host->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; + host->prepare_message = s3c64xx_spi_prepare_message; + host->transfer_one = s3c64xx_spi_transfer_one; + host->max_transfer_size = s3c64xx_spi_max_transfer_size; + host->num_chipselect = sci->num_cs; + host->use_gpio_descriptors = true; + host->dma_alignment = 8; + host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; if (sdd->port_conf->has_loopback) - master->mode_bits |= SPI_LOOP; - master->auto_runtime_pm = true; + host->mode_bits |= SPI_LOOP; + host->auto_runtime_pm = true; if (!is_polling(sdd)) - master->can_dma = s3c64xx_spi_can_dma; + host->can_dma = s3c64xx_spi_can_dma; - sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); - if (IS_ERR(sdd->regs)) { - ret = PTR_ERR(sdd->regs); - goto err_deref_master; - } + sdd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res); + if (IS_ERR(sdd->regs)) + return PTR_ERR(sdd->regs); + sdd->sfr_start = mem_res->start; - if (sci->cfg_gpio && sci->cfg_gpio()) { - dev_err(&pdev->dev, "Unable to config gpio\n"); - ret = -EBUSY; - goto err_deref_master; - } + if (sci->cfg_gpio && sci->cfg_gpio()) + return dev_err_probe(&pdev->dev, -EBUSY, + "Unable to config gpio\n"); /* Setup clocks */ - sdd->clk = devm_clk_get(&pdev->dev, "spi"); - if (IS_ERR(sdd->clk)) { - dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n"); - ret = PTR_ERR(sdd->clk); - goto err_deref_master; - } - - ret = clk_prepare_enable(sdd->clk); - if (ret) { - dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n"); - goto err_deref_master; - } + sdd->clk = devm_clk_get_enabled(&pdev->dev, "spi"); + if (IS_ERR(sdd->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sdd->clk), + "Unable to acquire clock 'spi'\n"); sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr); - sdd->src_clk = devm_clk_get(&pdev->dev, clk_name); - if (IS_ERR(sdd->src_clk)) { - dev_err(&pdev->dev, - "Unable to acquire clock '%s'\n", clk_name); - ret = PTR_ERR(sdd->src_clk); - goto err_disable_clk; - } - - ret = clk_prepare_enable(sdd->src_clk); - if (ret) { - dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name); - goto err_disable_clk; - } + sdd->src_clk = devm_clk_get_enabled(&pdev->dev, clk_name); + if (IS_ERR(sdd->src_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sdd->src_clk), + "Unable to acquire clock '%s'\n", + clk_name); if (sdd->port_conf->clk_ioclk) { - sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk"); - if (IS_ERR(sdd->ioclk)) { - dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n"); - ret = PTR_ERR(sdd->ioclk); - goto err_disable_src_clk; - } - - ret = clk_prepare_enable(sdd->ioclk); - if (ret) { - dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n"); - goto err_disable_src_clk; - } + sdd->ioclk = devm_clk_get_enabled(&pdev->dev, "spi_ioclk"); + if (IS_ERR(sdd->ioclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sdd->ioclk), + "Unable to acquire 'ioclk'\n"); } pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); @@ -1236,7 +1352,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - /* Setup Deufult Mode */ + /* Setup Default Mode */ s3c64xx_spi_hwinit(sdd); spin_lock_init(&sdd->lock); @@ -1254,18 +1370,17 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, sdd->regs + S3C64XX_SPI_INT_EN); - ret = devm_spi_register_master(&pdev->dev, master); + ret = devm_spi_register_controller(&pdev->dev, host); if (ret != 0) { - dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret); + dev_err(&pdev->dev, "cannot register SPI host: %d\n", ret); goto err_pm_put; } - dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", - sdd->port_id, master->num_chipselect); + dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Targets attached\n", + host->bus_num, host->num_chipselect); dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n", - mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1); + mem_res, sdd->fifo_depth); - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; @@ -1275,21 +1390,13 @@ err_pm_put: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - clk_disable_unprepare(sdd->ioclk); -err_disable_src_clk: - clk_disable_unprepare(sdd->src_clk); -err_disable_clk: - clk_disable_unprepare(sdd->clk); -err_deref_master: - spi_master_put(master); - return ret; } -static int s3c64xx_spi_remove(struct platform_device *pdev) +static void s3c64xx_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct spi_controller *host = platform_get_drvdata(pdev); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); pm_runtime_get_sync(&pdev->dev); @@ -1300,26 +1407,19 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) dma_release_channel(sdd->tx_dma.ch); } - clk_disable_unprepare(sdd->ioclk); - - clk_disable_unprepare(sdd->src_clk); - - clk_disable_unprepare(sdd->clk); - pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP static int s3c64xx_spi_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); + int ret; - int ret = spi_master_suspend(master); + ret = spi_controller_suspend(host); if (ret) return ret; @@ -1334,8 +1434,8 @@ static int s3c64xx_spi_suspend(struct device *dev) static int s3c64xx_spi_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); struct s3c64xx_spi_info *sci = sdd->cntrlr_info; int ret; @@ -1346,15 +1446,15 @@ static int s3c64xx_spi_resume(struct device *dev) if (ret < 0) return ret; - return spi_master_resume(master); + return spi_controller_resume(host); } #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM static int s3c64xx_spi_runtime_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); clk_disable_unprepare(sdd->clk); clk_disable_unprepare(sdd->src_clk); @@ -1365,8 +1465,8 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev) static int s3c64xx_spi_runtime_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host); int ret; if (sdd->port_conf->clk_ioclk) { @@ -1406,23 +1506,19 @@ static const struct dev_pm_ops s3c64xx_spi_pm = { s3c64xx_spi_runtime_resume, NULL) }; -static const struct s3c64xx_spi_port_config s3c2443_spi_port_config = { - .fifo_lvl_mask = { 0x7f }, - .rx_lvl_offset = 13, - .tx_st_done = 21, - .clk_div = 2, - .high_speed = true, -}; - static const struct s3c64xx_spi_port_config s3c6410_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x7f, 0x7F }, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 13, .tx_st_done = 21, .clk_div = 2, }; static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x1ff, 0x7F }, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 2, @@ -1430,7 +1526,9 @@ static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = { }; static const struct s3c64xx_spi_port_config exynos4_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F }, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 2, @@ -1440,7 +1538,9 @@ static const struct s3c64xx_spi_port_config exynos4_spi_port_config = { }; static const struct s3c64xx_spi_port_config exynos7_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 2, @@ -1450,7 +1550,9 @@ static const struct s3c64xx_spi_port_config exynos7_spi_port_config = { }; static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff}, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 2, @@ -1460,9 +1562,23 @@ static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, }; +static const struct s3c64xx_spi_port_config exynos850_spi_port_config = { + .fifo_depth = 64, + .rx_fifomask = S3C64XX_SPI_ST_RX_FIFO_RDY_V2, + .tx_fifomask = S3C64XX_SPI_ST_TX_FIFO_RDY_V2, + .tx_st_done = 25, + .clk_div = 4, + .high_speed = true, + .clk_from_cmu = true, + .has_loopback = true, + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, +}; + static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x1ff, 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 4, @@ -1474,7 +1590,9 @@ static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = { }; static const struct s3c64xx_spi_port_config fsd_spi_port_config = { + /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */ .fifo_lvl_mask = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, + /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */ .rx_lvl_offset = 15, .tx_st_done = 25, .clk_div = 2, @@ -1484,41 +1602,55 @@ static const struct s3c64xx_spi_port_config fsd_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, }; +static const struct s3c64xx_spi_port_config gs101_spi_port_config = { + .fifo_depth = 64, + .rx_fifomask = S3C64XX_SPI_ST_RX_FIFO_RDY_V2, + .tx_fifomask = S3C64XX_SPI_ST_TX_FIFO_RDY_V2, + .tx_st_done = 25, + .clk_div = 4, + .high_speed = true, + .clk_from_cmu = true, + .has_loopback = true, + .use_32bit_io = true, + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, +}; + static const struct platform_device_id s3c64xx_spi_driver_ids[] = { { - .name = "s3c2443-spi", - .driver_data = (kernel_ulong_t)&s3c2443_spi_port_config, - }, { .name = "s3c6410-spi", .driver_data = (kernel_ulong_t)&s3c6410_spi_port_config, }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c64xx_spi_driver_ids); static const struct of_device_id s3c64xx_spi_dt_match[] = { - { .compatible = "samsung,s3c2443-spi", - .data = (void *)&s3c2443_spi_port_config, + { .compatible = "google,gs101-spi", + .data = &gs101_spi_port_config, }, { .compatible = "samsung,s3c6410-spi", - .data = (void *)&s3c6410_spi_port_config, + .data = &s3c6410_spi_port_config, }, { .compatible = "samsung,s5pv210-spi", - .data = (void *)&s5pv210_spi_port_config, + .data = &s5pv210_spi_port_config, }, { .compatible = "samsung,exynos4210-spi", - .data = (void *)&exynos4_spi_port_config, + .data = &exynos4_spi_port_config, }, { .compatible = "samsung,exynos7-spi", - .data = (void *)&exynos7_spi_port_config, + .data = &exynos7_spi_port_config, }, { .compatible = "samsung,exynos5433-spi", - .data = (void *)&exynos5433_spi_port_config, + .data = &exynos5433_spi_port_config, + }, + { .compatible = "samsung,exynos850-spi", + .data = &exynos850_spi_port_config, }, { .compatible = "samsung,exynosautov9-spi", - .data = (void *)&exynosautov9_spi_port_config, + .data = &exynosautov9_spi_port_config, }, { .compatible = "tesla,fsd-spi", - .data = (void *)&fsd_spi_port_config, + .data = &fsd_spi_port_config, }, { }, }; |
