Merge remote-tracking branches 'spi/topic/octeon', 'spi/topic/pic32-sqi', 'spi/topic/pxa2xx' and 'spi/topic/qup' into spi-next
This commit is contained in:
		
						commit
						66b5a337d0
					
				| @ -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) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										120
									
								
								drivers/spi/spi-cavium-thunderx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								drivers/spi/spi-cavium-thunderx.c
									
									
									
									
									
										Normal file
									
								
							| @ -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"); | ||||
| @ -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) | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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)) | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -83,7 +83,6 @@ | ||||
| #define SSSR_RFS	(1 << 6)	/* Receive FIFO Service Request */ | ||||
| #define SSSR_ROR	(1 << 7)	/* Receive FIFO Overrun */ | ||||
| 
 | ||||
| #ifdef CONFIG_ARCH_PXA | ||||
| #define RX_THRESH_DFLT	8 | ||||
| #define TX_THRESH_DFLT	8 | ||||
| 
 | ||||
| @ -95,19 +94,16 @@ | ||||
| #define SSCR1_RFT	(0x00003c00)	/* Receive FIFO Threshold (mask) */ | ||||
| #define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */ | ||||
| 
 | ||||
| #else | ||||
| #define RX_THRESH_CE4100_DFLT	2 | ||||
| #define TX_THRESH_CE4100_DFLT	2 | ||||
| 
 | ||||
| #define RX_THRESH_DFLT	2 | ||||
| #define TX_THRESH_DFLT	2 | ||||
| #define CE4100_SSSR_TFL_MASK	(0x3 << 8)	/* Transmit FIFO Level mask */ | ||||
| #define CE4100_SSSR_RFL_MASK	(0x3 << 12)	/* Receive FIFO Level mask */ | ||||
| 
 | ||||
| #define SSSR_TFL_MASK	(0x3 << 8)	/* Transmit FIFO Level mask */ | ||||
| #define SSSR_RFL_MASK	(0x3 << 12)	/* Receive FIFO Level mask */ | ||||
| 
 | ||||
| #define SSCR1_TFT	(0x000000c0)	/* Transmit FIFO Threshold (mask) */ | ||||
| #define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */ | ||||
| #define SSCR1_RFT	(0x00000c00)	/* Receive FIFO Threshold (mask) */ | ||||
| #define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */ | ||||
| #endif | ||||
| #define CE4100_SSCR1_TFT	(0x000000c0)	/* Transmit FIFO Threshold (mask) */ | ||||
| #define CE4100_SSCR1_TxTresh(x) (((x) - 1) << 6)	/* level [1..4] */ | ||||
| #define CE4100_SSCR1_RFT	(0x00000c00)	/* Receive FIFO Threshold (mask) */ | ||||
| #define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10)	/* level [1..4] */ | ||||
| 
 | ||||
| /* QUARK_X1000 SSCR0 bit definition */ | ||||
| #define QUARK_X1000_SSCR0_DSS	(0x1F)		/* Data Size Select (mask) */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user