From a3cfea0448905581c4dfc087342f5142793bcb66 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 28 Jul 2016 16:19:47 +0000 Subject: spi: pic32-sqi: use list_move_tail and list_move Using list_move_tail() and list_move() to simplify the code. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-pic32-sqi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index c41abddab318..bd1c6b53283f 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -253,15 +253,13 @@ static struct ring_desc *ring_desc_get(struct pic32_sqi *sqi) return NULL; rdesc = list_first_entry(&sqi->bd_list_free, struct ring_desc, list); - list_del(&rdesc->list); - list_add_tail(&rdesc->list, &sqi->bd_list_used); + list_move_tail(&rdesc->list, &sqi->bd_list_used); return rdesc; } static void ring_desc_put(struct pic32_sqi *sqi, struct ring_desc *rdesc) { - list_del(&rdesc->list); - list_add(&rdesc->list, &sqi->bd_list_free); + list_move(&rdesc->list, &sqi->bd_list_free); } static int pic32_sqi_one_transfer(struct pic32_sqi *sqi, -- cgit v1.2.3 From 7347a6c7af8d9b5edf587678e80c7e5bc24ec2d5 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 19 Aug 2016 16:03:20 +0200 Subject: spi: octeon: Add ThunderX driver Add ThunderX SPI driver using the shared part from the Octeon driver. The main difference of the ThunderX driver is that it is a PCI device so probing is different. The system clock settings can be specified in device tree. Signed-off-by: Jan Glauber Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 7 +++ drivers/spi/Makefile | 2 + drivers/spi/spi-cavium-thunderx.c | 118 ++++++++++++++++++++++++++++++++++++++ drivers/spi/spi-cavium.h | 3 + 4 files changed, 130 insertions(+) create mode 100644 drivers/spi/spi-cavium-thunderx.c (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d6fb8d4b7786..8108971af601 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -631,6 +631,13 @@ config SPI_TEGRA20_SLINK help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. +config SPI_THUNDERX + tristate "Cavium ThunderX SPI controller" + depends on PCI && 64BIT && (ARM64 || COMPILE_TEST) + help + SPI host driver for the hardware found on Cavium ThunderX + SOCs. + config SPI_TOPCLIFF_PCH tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" depends on PCI && (X86_32 || MIPS || COMPILE_TEST) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 185367ef6576..133364b069e6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -91,6 +91,8 @@ obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o +spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o +obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c new file mode 100644 index 000000000000..eff2a130ef0c --- /dev/null +++ b/drivers/spi/spi-cavium-thunderx.c @@ -0,0 +1,118 @@ +/* + * Cavium ThunderX SPI driver. + * + * Copyright (C) 2016 Cavium Inc. + * Authors: Jan Glauber + */ + +#include +#include +#include + +#include "spi-cavium.h" + +#define DRV_NAME "spi-thunderx" + +#define SYS_FREQ_DEFAULT 700000000 /* 700 Mhz */ + +static int thunderx_spi_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct spi_master *master; + struct octeon_spi *p; + int ret; + + master = spi_alloc_master(dev, sizeof(struct octeon_spi)); + if (!master) + return -ENOMEM; + + p = spi_master_get_devdata(master); + + ret = pcim_enable_device(pdev); + if (ret) + goto error; + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret) + goto error; + + p->register_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!p->register_base) { + ret = -EINVAL; + goto error; + } + + p->regs.config = 0x1000; + p->regs.status = 0x1008; + p->regs.tx = 0x1010; + p->regs.data = 0x1080; + + p->clk = devm_clk_get(dev, NULL); + if (IS_ERR(p->clk)) { + ret = PTR_ERR(p->clk); + goto error; + } + + ret = clk_prepare_enable(p->clk); + if (ret) + goto error; + + p->sys_freq = clk_get_rate(p->clk); + if (!p->sys_freq) + p->sys_freq = SYS_FREQ_DEFAULT; + dev_info(dev, "Set system clock to %u\n", p->sys_freq); + + master->num_chipselect = 4; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | + SPI_LSB_FIRST | SPI_3WIRE; + master->transfer_one_message = octeon_spi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; + master->dev.of_node = pdev->dev.of_node; + + pci_set_drvdata(pdev, master); + + ret = devm_spi_register_master(dev, master); + if (ret) + goto error; + + return 0; + +error: + spi_master_put(master); + return ret; +} + +static void thunderx_spi_remove(struct pci_dev *pdev) +{ + struct spi_master *master = pci_get_drvdata(pdev); + struct octeon_spi *p; + + p = spi_master_get_devdata(master); + if (!p) + return; + + /* Put everything in a known state. */ + writeq(0, p->register_base + OCTEON_SPI_CFG(p)); +} + +static const struct pci_device_id thunderx_spi_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa00b) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, thunderx_spi_pci_id_table); + +static struct pci_driver thunderx_spi_driver = { + .name = DRV_NAME, + .id_table = thunderx_spi_pci_id_table, + .probe = thunderx_spi_probe, + .remove = thunderx_spi_remove, +}; + +module_pci_driver(thunderx_spi_driver); + +MODULE_DESCRIPTION("Cavium, Inc. ThunderX SPI bus driver"); +MODULE_AUTHOR("Jan Glauber"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-cavium.h b/drivers/spi/spi-cavium.h index 88c5f36e7ea7..1f91d61b745b 100644 --- a/drivers/spi/spi-cavium.h +++ b/drivers/spi/spi-cavium.h @@ -1,6 +1,8 @@ #ifndef __SPI_CAVIUM_H #define __SPI_CAVIUM_H +#include + #define OCTEON_SPI_MAX_BYTES 9 #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 @@ -17,6 +19,7 @@ struct octeon_spi { u64 cs_enax; int sys_freq; struct octeon_spi_regs regs; + struct clk *clk; }; #define OCTEON_SPI_CFG(x) (x->regs.config) -- cgit v1.2.3 From 568852b7002414c81084f07c7e39e897229d3b6f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Aug 2016 15:03:48 +0000 Subject: spi: spi-cavium-thunderx: Add missing clk_disable_unprepare() Add the missing clk_disable_unprepare() before return in the probe error handling case and remove. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-cavium-thunderx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c index eff2a130ef0c..877937706240 100644 --- a/drivers/spi/spi-cavium-thunderx.c +++ b/drivers/spi/spi-cavium-thunderx.c @@ -80,6 +80,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, return 0; error: + clk_disable_unprepare(p->clk); spi_master_put(master); return ret; } @@ -93,6 +94,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev) if (!p) return; + clk_disable_unprepare(p->clk); /* Put everything in a known state. */ writeq(0, p->register_base + OCTEON_SPI_CFG(p)); } -- cgit v1.2.3 From 9d04d8bc4c18765f6a1f7b632fffe47b4578fb26 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 25 Aug 2016 13:33:28 +0100 Subject: spi: qup: skip clk_disable_unprepare if the device is already runtime suspended If the spi device is already runtime suspended, if spi_qup_suspend is executed during suspend-to-idle or suspend-to-ram it will result in the a splat from unpreparing a non-prepared clock. This patch fixes the issue by executing clk_disable_unprepare conditionally in spi_qup_suspend. [Reworded commit message to remove irrelevant backtrace -- broonie] Signed-off-by: Sudeep Holla Tested-by: Andy Gross Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index c338ef1136f6..a047e9882da8 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -982,8 +982,10 @@ static int spi_qup_suspend(struct device *device) if (ret) return ret; - clk_disable_unprepare(controller->cclk); - clk_disable_unprepare(controller->iclk); + if (!pm_runtime_suspended(device)) { + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + } return 0; } -- cgit v1.2.3 From bffc967e93c771805739a4cc4c7849a749a7b0a6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 7 Sep 2016 17:04:05 +0300 Subject: spi: pxa2xx: Do not needlessly initialize stack variables All of these variables are unconditionally set before their use. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 2 +- drivers/spi/spi-pxa2xx.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index db3ae1dd829e..80c8e27a2f73 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -146,7 +146,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) { struct dma_async_tx_descriptor *tx_desc, *rx_desc; - int err = 0; + int err; tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV); if (!tx_desc) { diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 87150a1049bd..0e0d445f4028 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -934,13 +934,13 @@ static void pump_transfers(unsigned long data) { struct driver_data *drv_data = (struct driver_data *)data; struct spi_master *master = drv_data->master; - struct spi_message *message = NULL; - struct spi_transfer *transfer = NULL; - struct spi_transfer *previous = NULL; - struct chip_data *chip = NULL; - u32 clk_div = 0; - u8 bits = 0; - u32 speed = 0; + struct spi_message *message; + struct spi_transfer *transfer; + struct spi_transfer *previous; + struct chip_data *chip; + u32 clk_div; + u8 bits; + u32 speed; u32 cr0; u32 cr1; u32 dma_thresh = drv_data->cur_chip->dma_threshold; @@ -1213,7 +1213,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, static int setup(struct spi_device *spi) { - struct pxa2xx_spi_chip *chip_info = NULL; + struct pxa2xx_spi_chip *chip_info; struct chip_data *chip; const struct lpss_config *config; struct driver_data *drv_data = spi_master_get_devdata(spi->master); @@ -1742,7 +1742,7 @@ static int pxa2xx_spi_suspend(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); struct ssp_device *ssp = drv_data->ssp; - int status = 0; + int status; status = spi_master_suspend(drv_data->master); if (status != 0) @@ -1759,7 +1759,7 @@ static int pxa2xx_spi_resume(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); struct ssp_device *ssp = drv_data->ssp; - int status = 0; + int status; /* Enable the SSP clock */ if (!pm_runtime_suspended(dev)) -- cgit v1.2.3 From 4fc0caac065dbf300238997c7d2c212a2b120099 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 7 Sep 2016 17:04:06 +0300 Subject: spi: pxa2xx: Remove pointer to current SPI message from driver data There is no need to carry pointer to current SPI message in driver data because cur_msg in struct spi_master holds it already when driver is using the message queueing infrastructure from the SPI core. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 2 +- drivers/spi/spi-pxa2xx.c | 25 +++++++++++-------------- drivers/spi/spi-pxa2xx.h | 1 - 3 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 80c8e27a2f73..38efac33da47 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -23,7 +23,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, bool error) { - struct spi_message *msg = drv_data->cur_msg; + struct spi_message *msg = drv_data->master->cur_msg; /* * It is possible that one CPU is handling ROR interrupt and other diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 0e0d445f4028..e05af2a94d38 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -316,7 +316,7 @@ static void lpss_ssp_select_cs(struct driver_data *drv_data, value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); - cs = drv_data->cur_msg->spi->chip_select; + cs = drv_data->master->cur_msg->spi->chip_select; cs <<= config->cs_sel_shift; if (cs != (value & config->cs_sel_mask)) { /* @@ -508,7 +508,7 @@ static int u32_reader(struct driver_data *drv_data) void *pxa2xx_spi_next_transfer(struct driver_data *drv_data) { - struct spi_message *msg = drv_data->cur_msg; + struct spi_message *msg = drv_data->master->cur_msg; struct spi_transfer *trans = drv_data->cur_transfer; /* Move to next transfer */ @@ -529,8 +529,7 @@ static void giveback(struct driver_data *drv_data) struct spi_message *msg; unsigned long timeout; - msg = drv_data->cur_msg; - drv_data->cur_msg = NULL; + msg = drv_data->master->cur_msg; drv_data->cur_transfer = NULL; last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, @@ -610,7 +609,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) dev_err(&drv_data->pdev->dev, "%s\n", msg); - drv_data->cur_msg->state = ERROR_STATE; + drv_data->master->cur_msg->state = ERROR_STATE; tasklet_schedule(&drv_data->pump_transfers); } @@ -623,7 +622,7 @@ static void int_transfer_complete(struct driver_data *drv_data) pxa2xx_spi_write(drv_data, SSTO, 0); /* Update total byte transferred return count actual bytes read */ - drv_data->cur_msg->actual_length += drv_data->len - + drv_data->master->cur_msg->actual_length += drv_data->len - (drv_data->rx_end - drv_data->rx); /* Transfer delays and chip select release are @@ -631,7 +630,7 @@ static void int_transfer_complete(struct driver_data *drv_data) */ /* Move to next transfer */ - drv_data->cur_msg->state = pxa2xx_spi_next_transfer(drv_data); + drv_data->master->cur_msg->state = pxa2xx_spi_next_transfer(drv_data); /* Schedule transfer tasklet */ tasklet_schedule(&drv_data->pump_transfers); @@ -746,7 +745,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!(status & mask)) return IRQ_NONE; - if (!drv_data->cur_msg) { + if (!drv_data->master->cur_msg) { pxa2xx_spi_write(drv_data, SSCR0, pxa2xx_spi_read(drv_data, SSCR0) @@ -934,7 +933,7 @@ static void pump_transfers(unsigned long data) { struct driver_data *drv_data = (struct driver_data *)data; struct spi_master *master = drv_data->master; - struct spi_message *message; + struct spi_message *message = master->cur_msg; struct spi_transfer *transfer; struct spi_transfer *previous; struct chip_data *chip; @@ -950,7 +949,6 @@ static void pump_transfers(unsigned long data) int dma_mapped; /* Get current state information */ - message = drv_data->cur_msg; transfer = drv_data->cur_transfer; chip = drv_data->cur_chip; @@ -1146,16 +1144,15 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master, { struct driver_data *drv_data = spi_master_get_devdata(master); - drv_data->cur_msg = msg; /* Initial message state*/ - drv_data->cur_msg->state = START_STATE; - drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + msg->state = START_STATE; + drv_data->cur_transfer = list_entry(msg->transfers.next, struct spi_transfer, transfer_list); /* prepare to setup the SSP, in pump_transfers, using the per * chip configuration */ - drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + drv_data->cur_chip = spi_get_ctldata(msg->spi); /* Mark as busy and launch transfers */ tasklet_schedule(&drv_data->pump_transfers); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index d217ad55cc12..4f858664cee1 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -53,7 +53,6 @@ struct driver_data { atomic_t dma_running; /* Current message transfer state info */ - struct spi_message *cur_msg; struct spi_transfer *cur_transfer; struct chip_data *cur_chip; size_t len; -- cgit v1.2.3 From 96579a4e56bdecfb4642cfb68eb85d079acb9d28 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 7 Sep 2016 17:04:07 +0300 Subject: spi: pxa2xx: Remove pointer to chip data from driver data Transfer state machine in this driver does not need to set/unset pointer to chip data between queueing and finalizing message as it is not actually used as a state info itself but just pointer passing. Since this per SPI device specific chip data is already carried in ctldata use that and remove pointer to chip data from driver data. While at it, group initialized variables before uninitialized variables in pump_transfers(). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 3 ++- drivers/spi/spi-pxa2xx.c | 28 +++++++++++++--------------- drivers/spi/spi-pxa2xx.h | 1 - 3 files changed, 15 insertions(+), 17 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 38efac33da47..04f3eecf5cf3 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -76,7 +76,8 @@ static struct dma_async_tx_descriptor * pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, enum dma_transfer_direction dir) { - struct chip_data *chip = drv_data->cur_chip; + struct chip_data *chip = + spi_get_ctldata(drv_data->master->cur_msg->spi); struct spi_transfer *xfer = drv_data->cur_transfer; enum dma_slave_buswidth width; struct dma_slave_config cfg; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e05af2a94d38..6a0eb32408b6 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -355,10 +355,11 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) static void cs_assert(struct driver_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct chip_data *chip = + spi_get_ctldata(drv_data->master->cur_msg->spi); if (drv_data->ssp_type == CE4100_SSP) { - pxa2xx_spi_write(drv_data, SSSR, drv_data->cur_chip->frm); + pxa2xx_spi_write(drv_data, SSSR, chip->frm); return; } @@ -378,7 +379,8 @@ static void cs_assert(struct driver_data *drv_data) static void cs_deassert(struct driver_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct chip_data *chip = + spi_get_ctldata(drv_data->master->cur_msg->spi); if (drv_data->ssp_type == CE4100_SSP) return; @@ -574,13 +576,13 @@ static void giveback(struct driver_data *drv_data) cs_deassert(drv_data); } - drv_data->cur_chip = NULL; spi_finalize_current_message(drv_data->master); } static void reset_sccr1(struct driver_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct chip_data *chip = + spi_get_ctldata(drv_data->master->cur_msg->spi); u32 sccr1_reg; sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; @@ -904,7 +906,8 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, int rate) { - struct chip_data *chip = drv_data->cur_chip; + struct chip_data *chip = + spi_get_ctldata(drv_data->master->cur_msg->spi); unsigned int clk_div; switch (drv_data->ssp_type) { @@ -934,23 +937,22 @@ static void pump_transfers(unsigned long data) struct driver_data *drv_data = (struct driver_data *)data; struct spi_master *master = drv_data->master; struct spi_message *message = master->cur_msg; + struct chip_data *chip = spi_get_ctldata(message->spi); + u32 dma_thresh = chip->dma_threshold; + u32 dma_burst = chip->dma_burst_size; + u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); struct spi_transfer *transfer; struct spi_transfer *previous; - struct chip_data *chip; u32 clk_div; u8 bits; u32 speed; u32 cr0; u32 cr1; - u32 dma_thresh = drv_data->cur_chip->dma_threshold; - u32 dma_burst = drv_data->cur_chip->dma_burst_size; - u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); int err; int dma_mapped; /* Get current state information */ transfer = drv_data->cur_transfer; - chip = drv_data->cur_chip; /* Handle for abort */ if (message->state == ERROR_STATE) { @@ -1150,10 +1152,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master, struct spi_transfer, transfer_list); - /* prepare to setup the SSP, in pump_transfers, using the per - * chip configuration */ - drv_data->cur_chip = spi_get_ctldata(msg->spi); - /* Mark as busy and launch transfers */ tasklet_schedule(&drv_data->pump_transfers); return 0; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 4f858664cee1..ae3b15ff6fb2 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -54,7 +54,6 @@ struct driver_data { /* Current message transfer state info */ struct spi_transfer *cur_transfer; - struct chip_data *cur_chip; size_t len; void *tx; void *tx_end; -- cgit v1.2.3 From 7c7289a40425d48bbfcaacc454a8caf5b47f63b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Sep 2016 15:43:22 +0300 Subject: spi: pxa2xx: Default thresholds to PXA configuration Most of the devices in the supported list have PXA configuration of FIFO. In particularly Intel Medfield and Merrifield have bigger FIFO, than it's defined for CE4100. Split CE4100 in the similar way how it was done for Intel Quark, i.e. prefix definitions by CE4100 and append necessary pieces of code to switch case conditions. We are on safe side since those bits are ignored on all LPSS IPs. Signed-off-by: Andy Shevchenko Reviewed-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 6a0eb32408b6..cab39b06bc89 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -62,6 +62,13 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | QUARK_X1000_SSCR1_TFT \ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) +#define CE4100_SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \ + | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \ + | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \ + | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \ + | CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \ + | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) + #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define LPSS_CS_CONTROL_SW_MODE BIT(0) #define LPSS_CS_CONTROL_CS_HIGH BIT(1) @@ -175,6 +182,8 @@ static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data) switch (drv_data->ssp_type) { case QUARK_X1000_SSP: return QUARK_X1000_SSCR1_CHANGE_MASK; + case CE4100_SSP: + return CE4100_SSCR1_CHANGE_MASK; default: return SSCR1_CHANGE_MASK; } @@ -186,6 +195,8 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data) switch (drv_data->ssp_type) { case QUARK_X1000_SSP: return RX_THRESH_QUARK_X1000_DFLT; + case CE4100_SSP: + return RX_THRESH_CE4100_DFLT; default: return RX_THRESH_DFLT; } @@ -199,6 +210,9 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) case QUARK_X1000_SSP: mask = QUARK_X1000_SSSR_TFL_MASK; break; + case CE4100_SSP: + mask = CE4100_SSSR_TFL_MASK; + break; default: mask = SSSR_TFL_MASK; break; @@ -216,6 +230,9 @@ static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, case QUARK_X1000_SSP: mask = QUARK_X1000_SSCR1_RFT; break; + case CE4100_SSP: + mask = CE4100_SSCR1_RFT; + break; default: mask = SSCR1_RFT; break; @@ -230,6 +247,9 @@ static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data, case QUARK_X1000_SSP: *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold); break; + case CE4100_SSP: + *sccr1_reg |= CE4100_SSCR1_RxTresh(threshold); + break; default: *sccr1_reg |= SSCR1_RxTresh(threshold); break; @@ -590,6 +610,9 @@ static void reset_sccr1(struct driver_data *drv_data) case QUARK_X1000_SSP: sccr1_reg &= ~QUARK_X1000_SSCR1_RFT; break; + case CE4100_SSP: + sccr1_reg &= ~CE4100_SSCR1_RFT; + break; default: sccr1_reg &= ~SSCR1_RFT; break; @@ -1220,6 +1243,11 @@ static int setup(struct spi_device *spi) tx_hi_thres = 0; rx_thres = RX_THRESH_QUARK_X1000_DFLT; break; + case CE4100_SSP: + tx_thres = TX_THRESH_CE4100_DFLT; + tx_hi_thres = 0; + rx_thres = RX_THRESH_CE4100_DFLT; + break; case LPSS_LPT_SSP: case LPSS_BYT_SSP: case LPSS_BSW_SSP: @@ -1304,6 +1332,10 @@ static int setup(struct spi_device *spi) | (QUARK_X1000_SSCR1_TxTresh(tx_thres) & QUARK_X1000_SSCR1_TFT); break; + case CE4100_SSP: + chip->threshold = (CE4100_SSCR1_RxTresh(rx_thres) & CE4100_SSCR1_RFT) | + (CE4100_SSCR1_TxTresh(tx_thres) & CE4100_SSCR1_TFT); + break; default: chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) | (SSCR1_TxTresh(tx_thres) & SSCR1_TFT); @@ -1625,15 +1657,20 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) pxa2xx_spi_write(drv_data, SSCR0, 0); switch (drv_data->ssp_type) { case QUARK_X1000_SSP: - tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) - | QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); + tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) | + QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); pxa2xx_spi_write(drv_data, SSCR1, tmp); /* using the Motorola SPI protocol and use 8 bit frame */ - pxa2xx_spi_write(drv_data, SSCR0, - QUARK_X1000_SSCR0_Motorola - | QUARK_X1000_SSCR0_DataSize(8)); + tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8); + pxa2xx_spi_write(drv_data, SSCR0, tmp); break; + case CE4100_SSP: + tmp = CE4100_SSCR1_RxTresh(RX_THRESH_CE4100_DFLT) | + CE4100_SSCR1_TxTresh(TX_THRESH_CE4100_DFLT); + pxa2xx_spi_write(drv_data, SSCR1, tmp); + tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8); + pxa2xx_spi_write(drv_data, SSCR0, tmp); default: tmp = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); -- cgit v1.2.3 From 99f499cd650405bbe6a9b5386d4b11ee81514fb7 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 26 Sep 2016 15:19:50 +0300 Subject: spi: pxa2xx: Add support for GPIO descriptor chip selects The driver uses custom chip_info coming from platform data for chip selects implemented as GPIOs. If the system lacks board files setting up the platform data, it is not possible to use GPIOs as chip selects. This adds support for GPIO descriptors so that regardless of the underlying firmware interface (DT, ACPI or platform data) the driver can request GPIOs used as chip selects and configure them accordingly. The custom chip_info GPIO support is still left there to make sure the existing systems keep working as expected. Signed-off-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 57 +++++++++++++++++++++++++++++++++++++++++++++--- drivers/spi/spi-pxa2xx.h | 3 +++ 2 files changed, 57 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index cab39b06bc89..5e2ed7d34487 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1194,9 +1194,26 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { + struct driver_data *drv_data = spi_master_get_devdata(spi->master); int err = 0; - if (chip == NULL || chip_info == NULL) + if (chip == NULL) + return 0; + + if (drv_data->cs_gpiods) { + struct gpio_desc *gpiod; + + gpiod = drv_data->cs_gpiods[spi->chip_select]; + if (gpiod) { + chip->gpio_cs = desc_to_gpio(gpiod); + chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; + gpiod_set_value(gpiod, chip->gpio_cs_inverted); + } + + return 0; + } + + if (chip_info == NULL) return 0; /* NOTE: setup() can be called multiple times, possibly with @@ -1379,7 +1396,8 @@ static void cleanup(struct spi_device *spi) if (!chip) return; - if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs)) + if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && + gpio_is_valid(chip->gpio_cs)) gpio_free(chip->gpio_cs); kfree(chip); @@ -1557,7 +1575,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) struct driver_data *drv_data; struct ssp_device *ssp; const struct lpss_config *config; - int status; + int status, count; u32 tmp; platform_info = dev_get_platdata(dev); @@ -1701,6 +1719,39 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } master->num_chipselect = platform_info->num_chipselect; + count = gpiod_count(&pdev->dev, "cs"); + if (count > 0) { + int i; + + master->num_chipselect = max_t(int, count, + master->num_chipselect); + + drv_data->cs_gpiods = devm_kcalloc(&pdev->dev, + master->num_chipselect, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!drv_data->cs_gpiods) { + status = -ENOMEM; + goto out_error_clock_enabled; + } + + for (i = 0; i < master->num_chipselect; i++) { + struct gpio_desc *gpiod; + + gpiod = devm_gpiod_get_index(dev, "cs", i, + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) { + /* Means use native chip select */ + if (PTR_ERR(gpiod) == -ENOENT) + continue; + + status = (int)PTR_ERR(gpiod); + goto out_error_clock_enabled; + } else { + drv_data->cs_gpiods[i] = gpiod; + } + } + } + tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index ae3b15ff6fb2..ce31b8199bb3 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -66,6 +66,9 @@ struct driver_data { void (*cs_control)(u32 command); void __iomem *lpss_base; + + /* GPIOs for chip selects */ + struct gpio_desc **cs_gpiods; }; struct chip_data { -- cgit v1.2.3 From 089bd46d8bc1fe5a28351e82e4adcaa5a40121b5 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 29 Sep 2016 09:45:20 +0300 Subject: spi: pxa2xx: Fix build error because of missing header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kbuild test robot reports: drivers/spi/spi-pxa2xx.c: In function ‘setup_cs’: drivers/spi/spi-pxa2xx.c:1190:20: error: implicit declaration of function ‘desc_to_gpio’ ... Reason for this is the fact that those functions are declared in linux/gpio/consumer.h which is not included in the driver. Fix this by including it. Reported-by: kbuild test robot Signed-off-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 5e2ed7d34487..dd7b5b47291d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3