diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 7 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/spi-cavium-thunderx.c | 120 | ||||
-rw-r--r-- | drivers/spi/spi-cavium.h | 3 | ||||
-rw-r--r-- | drivers/spi/spi-pic32-sqi.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx-dma.c | 7 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 172 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.h | 5 | ||||
-rw-r--r-- | drivers/spi/spi-qup.c | 6 |
9 files changed, 273 insertions, 55 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3e1bfdda3e0c..a49343ba1e63 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -648,6 +648,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 c9484d3627f6..aa939d955521 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -93,6 +93,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..877937706240 --- /dev/null +++ b/drivers/spi/spi-cavium-thunderx.c @@ -0,0 +1,120 @@ +/* + * Cavium ThunderX SPI driver. + * + * Copyright (C) 2016 Cavium Inc. + * Authors: Jan Glauber <jglauber@cavium.com> + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/spi/spi.h> + +#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: + clk_disable_unprepare(p->clk); + 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; + + clk_disable_unprepare(p->clk); + /* 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 <linux/clk.h> + #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) 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, diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index db3ae1dd829e..04f3eecf5cf3 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 @@ -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; @@ -146,7 +147,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..dd7b5b47291d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -28,6 +28,7 @@ #include <linux/spi/spi.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/clk.h> #include <linux/pm_runtime.h> @@ -62,6 +63,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 +183,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 +196,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 +211,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 +231,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 +248,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; @@ -316,7 +337,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)) { /* @@ -355,10 +376,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 +400,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; @@ -508,7 +531,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 +552,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, @@ -575,13 +597,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; @@ -589,6 +611,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; @@ -610,7 +635,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 +648,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 +656,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 +771,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) @@ -905,7 +930,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,25 +960,23 @@ 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 = 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; + 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 */ - message = drv_data->cur_msg; transfer = drv_data->cur_transfer; - chip = drv_data->cur_chip; /* Handle for abort */ if (message->state == ERROR_STATE) { @@ -1146,17 +1170,12 @@ 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); - /* Mark as busy and launch transfers */ tasklet_schedule(&drv_data->pump_transfers); return 0; @@ -1176,9 +1195,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 @@ -1213,7 +1249,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); @@ -1225,6 +1261,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: @@ -1309,6 +1350,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); @@ -1352,7 +1397,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); @@ -1530,7 +1576,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); @@ -1630,15 +1676,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); @@ -1669,6 +1720,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); @@ -1742,7 +1826,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 +1843,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)) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index d217ad55cc12..ce31b8199bb3 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -53,9 +53,7 @@ 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; void *tx; void *tx_end; @@ -68,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 { diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 7f1555621f8e..1bfa889b8427 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; } |