From 617100c2711691e07728d3201fbcfa845a7c36d5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Nov 2014 17:25:24 -0200 Subject: spi: spi-mxs: Register the irq with the device name Instead of registering the irq name with the driver name, it's better to pass the device name so that we have a more explicit indication as to what spi instance the irq is related: $ cat /proc/interrupts CPU0 ... 27: 0 - 98 80014000.ssp Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 51460878af04..a9e72f9d385e 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -511,7 +511,7 @@ static int mxs_spi_probe(struct platform_device *pdev) init_completion(&spi->c); ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0, - DRIVER_NAME, ssp); + dev_name(&pdev->dev), ssp); if (ret) goto out_master_free; -- cgit v1.2.3 From dfcc2e3549b5d57886d4ce6b4762bd4b64f6f945 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Tue, 11 Nov 2014 15:22:51 +0200 Subject: spi/rockchip: remove redundant call to spi_master_put() The call to spi_master_put() in rockchip_spi_remove() is redundant since the master is registered using devm_. This patch removes it. Signed-off-by: Laurentiu Palcu Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index f96ea8a38d64..08897d34ce33 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -723,8 +723,6 @@ static int rockchip_spi_remove(struct platform_device *pdev) if (rs->dma_rx.ch) dma_release_channel(rs->dma_rx.ch); - spi_master_put(master); - return 0; } -- cgit v1.2.3 From fcc50e5cd2deb8316d19e446d8efdfc9b35646ef Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 17 Nov 2014 23:17:03 +0800 Subject: spi: sirf: assign spi_master's max_speed_hz member if spi device has no frequency, spi core will setup the default frequency to max_speed_hz of spi_master according to int spi_setup(struct spi_device *spi) { ... if (!spi->max_speed_hz) spi->max_speed_hz = spi->master->max_speed_hz; ... } this patch moves CSR SiRFSoC SPI frequency set to follow SPI core behaviour. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 39e2c0a55a28..bf3c6bc77530 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -134,6 +134,7 @@ ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) #define SIRFSOC_MAX_CMD_BYTES 4 +#define SIRFSOC_SPI_DEFAULT_FRQ 1000000 struct sirfsoc_spi { struct spi_bitbang bitbang; @@ -629,9 +630,6 @@ static int spi_sirfsoc_setup(struct spi_device *spi) { struct sirfsoc_spi *sspi; - if (!spi->max_speed_hz) - return -EINVAL; - sspi = spi_master_get_devdata(spi->master); if (spi->cs_gpio == -ENOENT) @@ -683,6 +681,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) | SPI_BPW_MASK(16) | SPI_BPW_MASK(32); + master->max_speed_hz = SIRFSOC_SPI_DEFAULT_FRQ; sspi->bitbang.master->dev.of_node = pdev->dev.of_node; /* request DMA channels */ -- cgit v1.2.3 From 8509c55fcb5192b7f70ec596a8752c2ec39942e3 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Thu, 20 Nov 2014 22:33:07 +0800 Subject: spi: sirf: reset SPI controller in init stage in SPI boot mode, romcode uses SPI controller to fetch data from NOR flash. Here we need to reset the hardware IP to restore its state. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index bf3c6bc77530..0a96a65f580f 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -23,6 +23,7 @@ #include #include #include +#include #define DRIVER_NAME "sirfsoc_spi" @@ -647,6 +648,12 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) int irq; int i, ret; + ret = device_reset(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "SPI reset failed!\n"); + return ret; + } + master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); -- cgit v1.2.3 From 9e8987acf051e48fc0e228b6f38c47a75352c58b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 17 Nov 2014 09:14:32 +0000 Subject: spi: spi-mxs: Fix mapping from vmalloc-ed buffer to scatter list We can only use page_address on memory that has been mapped using kmap, when the buffer passed to the SPI has been allocated by vmalloc the page has not necessarily been mapped through kmap. This means sometimes page_address will return NULL causing the pointer we pass to sg_init_one to be invalid. Currently, this issue doesn't show up on the MXS architecture as the defconfig defines CONFIG_HIGHMEM=n which means all pages are mapped. For the sake of robustness though it is best to correct the issue. As we only call page_address so that we can pass a virtual address to sg_init_one which will eventually call virt_to_page on it, fix this by calling sg_set_page directly rather then relying on the sg_init_one helper. Note this patch is only build tested as I don't have an MXS system to test on. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index a9e72f9d385e..06a11546a1a7 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -182,7 +182,6 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int min, ret; u32 ctrl0; struct page *vm_page; - void *sg_buf; struct { u32 pio[4]; struct scatterlist sg; @@ -232,13 +231,14 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, ret = -ENOMEM; goto err_vmalloc; } - sg_buf = page_address(vm_page) + - ((size_t)buf & ~PAGE_MASK); + + sg_init_table(&dma_xfer[sg_count].sg, 1); + sg_set_page(&dma_xfer[sg_count].sg, vm_page, + min, offset_in_page(buf)); } else { - sg_buf = buf; + sg_init_one(&dma_xfer[sg_count].sg, buf, min); } - sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -- cgit v1.2.3 From 4fdb2424cc4499237197a8c9d35b34d68c750475 Mon Sep 17 00:00:00 2001 From: Weike Chen Date: Wed, 8 Oct 2014 08:50:22 -0700 Subject: spi: spi-pxa2xx: Add helpers for regiseters' accessing There are several registers for SPI, and the registers of 'SSCR0' and 'SSCR1' are accessed frequently. This path is to introduce helper functions to simplify the accessing of 'SSCR0' and 'SSCR1'. Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Weike Chen Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 107 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 23 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 9e9e0f971e6c..d4d29c594156 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -80,6 +80,73 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) return drv_data->ssp_type == LPSS_SSP; } +static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data) +{ + switch (drv_data->ssp_type) { + default: + return SSCR1_CHANGE_MASK; + } +} + +static u32 +pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data) +{ + switch (drv_data->ssp_type) { + default: + return RX_THRESH_DFLT; + } +} + +static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) +{ + void __iomem *reg = drv_data->ioaddr; + u32 mask; + + switch (drv_data->ssp_type) { + default: + mask = SSSR_TFL_MASK; + break; + } + + return (read_SSSR(reg) & mask) == mask; +} + +static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, + u32 *sccr1_reg) +{ + u32 mask; + + switch (drv_data->ssp_type) { + default: + mask = SSCR1_RFT; + break; + } + *sccr1_reg &= ~mask; +} + +static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data, + u32 *sccr1_reg, u32 threshold) +{ + switch (drv_data->ssp_type) { + default: + *sccr1_reg |= SSCR1_RxTresh(threshold); + break; + } +} + +static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data, + u32 clk_div, u8 bits) +{ + switch (drv_data->ssp_type) { + default: + return clk_div + | SSCR0_Motorola + | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) + | SSCR0_SSE + | (bits > 16 ? SSCR0_EDSS : 0); + } +} + /* * Read and write LPSS SSP private registers. Caller must first check that * is_lpss_ssp() returns true before these can be called. @@ -234,7 +301,7 @@ static int null_writer(struct driver_data *drv_data) void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; - if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) + if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -262,7 +329,7 @@ static int u8_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) + if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -289,7 +356,7 @@ static int u16_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) + if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -316,7 +383,7 @@ static int u32_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) + if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -508,8 +575,9 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) * remaining RX bytes. */ if (pxa25x_ssp_comp(drv_data)) { + u32 rx_thre; - sccr1_reg &= ~SSCR1_RFT; + pxa2xx_spi_clear_rx_thre(drv_data, &sccr1_reg); bytes_left = drv_data->rx_end - drv_data->rx; switch (drv_data->n_bytes) { @@ -519,10 +587,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) bytes_left >>= 1; } - if (bytes_left > RX_THRESH_DFLT) - bytes_left = RX_THRESH_DFLT; + rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data); + if (rx_thre > bytes_left) + rx_thre = bytes_left; - sccr1_reg |= SSCR1_RxTresh(bytes_left); + pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre); } write_SSCR1(sccr1_reg, reg); } @@ -613,6 +682,7 @@ static void pump_transfers(unsigned long data) 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); /* Get current state information */ message = drv_data->cur_msg; @@ -731,11 +801,7 @@ static void pump_transfers(unsigned long data) "pump_transfers: DMA burst size reduced to match bits_per_word\n"); } - cr0 = clk_div - | SSCR0_Motorola - | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) - | SSCR0_SSE - | (bits > 16 ? SSCR0_EDSS : 0); + cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits); } message->state = RUNNING_STATE; @@ -772,16 +838,15 @@ static void pump_transfers(unsigned long data) } /* see if we need to reload the config registers */ - if ((read_SSCR0(reg) != cr0) - || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) != - (cr1 & SSCR1_CHANGE_MASK)) { + if ((read_SSCR0(reg) != cr0) || + (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) { /* stop the SSP, and update the other bits */ write_SSCR0(cr0 & ~SSCR0_SSE, reg); if (!pxa25x_ssp_comp(drv_data)) write_SSTO(chip->timeout, reg); /* first set CR1 without interrupt and service enables */ - write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg); + write_SSCR1(cr1 & change_mask, reg); /* restart the SSP */ write_SSCR0(cr0, reg); @@ -959,12 +1024,8 @@ static int setup(struct spi_device *spi) clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz); chip->speed_hz = spi->max_speed_hz; - chip->cr0 = clk_div - | SSCR0_Motorola - | SSCR0_DataSize(spi->bits_per_word > 16 ? - spi->bits_per_word - 16 : spi->bits_per_word) - | SSCR0_SSE - | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0); + chip->cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, + spi->bits_per_word); chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); -- cgit v1.2.3 From e5262d0568dc9e10de79a726dfd7edb712a2c10b Mon Sep 17 00:00:00 2001 From: Weike Chen Date: Wed, 26 Nov 2014 02:35:10 -0800 Subject: spi: spi-pxa2xx: SPI support for Intel Quark X1000 There are two SPI controllers exported by PCI subsystem for Intel Quark X1000. The SPI memory mapped I/O registers supported by Quark are different from the current implementation, and Quark only supports the registers of 'SSCR0', 'SSCR1', 'SSSR', 'SSDR', and 'DDS_RATE'. This patch is to enable the SPI for Intel Quark X1000. This piece of work is derived from Dan O'Donovan's initial work for Intel Quark X1000 SPI enabling. Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Weike Chen Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 ++ drivers/spi/spi-pxa2xx.c | 197 +++++++++++++++++++++++++++++++++++++++---- drivers/spi/spi-pxa2xx.h | 16 ++-- 3 files changed, 199 insertions(+), 22 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 6beee8ce2d68..fa7399e84bbb 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -19,6 +19,7 @@ enum { PORT_BSW0, PORT_BSW1, PORT_BSW2, + PORT_QUARK_X1000, }; struct pxa_spi_info { @@ -92,6 +93,12 @@ static struct pxa_spi_info spi_info_configs[] = { .tx_param = &bsw2_tx_param, .rx_param = &bsw2_rx_param, }, + [PORT_QUARK_X1000] = { + .type = QUARK_X1000_SSP, + .port_id = -1, + .num_chipselect = 1, + .max_clk_rate = 50000000, + }, }; static int pxa2xx_spi_pci_probe(struct pci_dev *dev, @@ -191,6 +198,7 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev) static const struct pci_device_id pxa2xx_spi_pci_devices[] = { { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 }, + { PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 }, { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, { PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 }, { PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 }, diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index d4d29c594156..1a1df5092aca 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -63,10 +63,64 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) +#define QUARK_X1000_SSCR1_CHANGE_MASK (QUARK_X1000_SSCR1_STRF \ + | QUARK_X1000_SSCR1_EFWR \ + | QUARK_X1000_SSCR1_RFT \ + | QUARK_X1000_SSCR1_TFT \ + | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) + #define LPSS_RX_THRESH_DFLT 64 #define LPSS_TX_LOTHRESH_DFLT 160 #define LPSS_TX_HITHRESH_DFLT 224 +struct quark_spi_rate { + u32 bitrate; + u32 dds_clk_rate; + u32 clk_div; +}; + +/* + * 'rate', 'dds', 'clk_div' lookup table, which is defined in + * the Quark SPI datasheet. + */ +static const struct quark_spi_rate quark_spi_rate_table[] = { +/* bitrate, dds_clk_rate, clk_div */ + {50000000, 0x800000, 0}, + {40000000, 0x666666, 0}, + {25000000, 0x400000, 0}, + {20000000, 0x666666, 1}, + {16667000, 0x800000, 2}, + {13333000, 0x666666, 2}, + {12500000, 0x200000, 0}, + {10000000, 0x800000, 4}, + {8000000, 0x666666, 4}, + {6250000, 0x400000, 3}, + {5000000, 0x400000, 4}, + {4000000, 0x666666, 9}, + {3125000, 0x80000, 0}, + {2500000, 0x400000, 9}, + {2000000, 0x666666, 19}, + {1563000, 0x40000, 0}, + {1250000, 0x200000, 9}, + {1000000, 0x400000, 24}, + {800000, 0x666666, 49}, + {781250, 0x20000, 0}, + {625000, 0x200000, 19}, + {500000, 0x400000, 49}, + {400000, 0x666666, 99}, + {390625, 0x10000, 0}, + {250000, 0x400000, 99}, + {200000, 0x666666, 199}, + {195313, 0x8000, 0}, + {125000, 0x100000, 49}, + {100000, 0x200000, 124}, + {50000, 0x100000, 124}, + {25000, 0x80000, 124}, + {10016, 0x20000, 77}, + {5040, 0x20000, 154}, + {1002, 0x8000, 194}, +}; + /* Offset from drv_data->lpss_base */ #define GENERAL_REG 0x08 #define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) @@ -80,9 +134,16 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) return drv_data->ssp_type == LPSS_SSP; } +static bool is_quark_x1000_ssp(const struct driver_data *drv_data) +{ + return drv_data->ssp_type == QUARK_X1000_SSP; +} + 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; default: return SSCR1_CHANGE_MASK; } @@ -92,6 +153,8 @@ static u32 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; default: return RX_THRESH_DFLT; } @@ -103,6 +166,9 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) u32 mask; switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + mask = QUARK_X1000_SSSR_TFL_MASK; + break; default: mask = SSSR_TFL_MASK; break; @@ -117,6 +183,9 @@ static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, u32 mask; switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + mask = QUARK_X1000_SSCR1_RFT; + break; default: mask = SSCR1_RFT; break; @@ -128,6 +197,9 @@ static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data, u32 *sccr1_reg, u32 threshold) { switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold); + break; default: *sccr1_reg |= SSCR1_RxTresh(threshold); break; @@ -138,6 +210,11 @@ static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data, u32 clk_div, u8 bits) { switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + return clk_div + | QUARK_X1000_SSCR0_Motorola + | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits) + | SSCR0_SSE; default: return clk_div | SSCR0_Motorola @@ -654,6 +731,28 @@ static irqreturn_t ssp_int(int irq, void *dev_id) return drv_data->transfer_handler(drv_data); } +/* + * The Quark SPI data sheet gives a table, and for the given 'rate', + * the 'dds' and 'clk_div' can be found in the table. + */ +static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) { + if (rate >= quark_spi_rate_table[i].bitrate) { + *dds = quark_spi_rate_table[i].dds_clk_rate; + *clk_div = quark_spi_rate_table[i].clk_div; + return quark_spi_rate_table[i].bitrate; + } + } + + *dds = quark_spi_rate_table[i-1].dds_clk_rate; + *clk_div = quark_spi_rate_table[i-1].clk_div; + + return quark_spi_rate_table[i-1].bitrate; +} + static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) { unsigned long ssp_clk = drv_data->max_clk_rate; @@ -667,6 +766,20 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) return ((ssp_clk / rate - 1) & 0xfff) << 8; } +static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, + struct chip_data *chip, int rate) +{ + u32 clk_div; + + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div); + return clk_div << 8; + default: + return ssp_get_clk_div(drv_data, rate); + } +} + static void pump_transfers(unsigned long data) { struct driver_data *drv_data = (struct driver_data *)data; @@ -769,7 +882,7 @@ static void pump_transfers(unsigned long data) if (transfer->bits_per_word) bits = transfer->bits_per_word; - clk_div = ssp_get_clk_div(drv_data, speed); + clk_div = pxa2xx_ssp_get_clk_div(drv_data, chip, speed); if (bits <= 8) { drv_data->n_bytes = 1; @@ -837,6 +950,10 @@ static void pump_transfers(unsigned long data) write_SSITF(chip->lpss_tx_threshold, reg); } + if (is_quark_x1000_ssp(drv_data) && + (read_DDS_RATE(reg) != chip->dds_rate)) + write_DDS_RATE(chip->dds_rate, reg); + /* see if we need to reload the config registers */ if ((read_SSCR0(reg) != cr0) || (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) { @@ -940,14 +1057,22 @@ static int setup(struct spi_device *spi) unsigned int clk_div; uint tx_thres, tx_hi_thres, rx_thres; - if (is_lpss_ssp(drv_data)) { + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + tx_thres = TX_THRESH_QUARK_X1000_DFLT; + tx_hi_thres = 0; + rx_thres = RX_THRESH_QUARK_X1000_DFLT; + break; + case LPSS_SSP: tx_thres = LPSS_TX_LOTHRESH_DFLT; tx_hi_thres = LPSS_TX_HITHRESH_DFLT; rx_thres = LPSS_RX_THRESH_DFLT; - } else { + break; + default: tx_thres = TX_THRESH_DFLT; tx_hi_thres = 0; rx_thres = RX_THRESH_DFLT; + break; } /* Only alloc on first setup */ @@ -1000,9 +1125,6 @@ static int setup(struct spi_device *spi) chip->enable_dma = drv_data->master_info->enable_dma; } - chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) | - (SSCR1_TxTresh(tx_thres) & SSCR1_TFT); - chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres); chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) | SSITF_TxHiThresh(tx_hi_thres); @@ -1021,11 +1143,24 @@ static int setup(struct spi_device *spi) } } - clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz); + clk_div = pxa2xx_ssp_get_clk_div(drv_data, chip, spi->max_speed_hz); chip->speed_hz = spi->max_speed_hz; chip->cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, spi->bits_per_word); + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres) + & QUARK_X1000_SSCR1_RFT) + | (QUARK_X1000_SSCR1_TxTresh(tx_thres) + & QUARK_X1000_SSCR1_TFT); + break; + default: + chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) | + (SSCR1_TxTresh(tx_thres) & SSCR1_TFT); + break; + } + chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); @@ -1054,7 +1189,8 @@ static int setup(struct spi_device *spi) chip->read = u16_reader; chip->write = u16_writer; } else if (spi->bits_per_word <= 32) { - chip->cr0 |= SSCR0_EDSS; + if (!is_quark_x1000_ssp(drv_data)) + chip->cr0 |= SSCR0_EDSS; chip->n_bytes = 4; chip->read = u32_reader; chip->write = u32_writer; @@ -1205,7 +1341,15 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base + SSDR; if (pxa25x_ssp_comp(drv_data)) { - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + break; + default: + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + break; + } + drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; drv_data->dma_cr1 = 0; drv_data->clear_sr = SSSR_ROR; @@ -1243,16 +1387,35 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Load default SSP configuration */ write_SSCR0(0, drv_data->ioaddr); - write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) | - SSCR1_TxTresh(TX_THRESH_DFLT), - drv_data->ioaddr); - write_SSCR0(SSCR0_SCR(2) - | SSCR0_Motorola - | SSCR0_DataSize(8), - drv_data->ioaddr); + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + write_SSCR1(QUARK_X1000_SSCR1_RxTresh( + RX_THRESH_QUARK_X1000_DFLT) | + QUARK_X1000_SSCR1_TxTresh( + TX_THRESH_QUARK_X1000_DFLT), + drv_data->ioaddr); + + /* using the Motorola SPI protocol and use 8 bit frame */ + write_SSCR0(QUARK_X1000_SSCR0_Motorola + | QUARK_X1000_SSCR0_DataSize(8), + drv_data->ioaddr); + break; + default: + write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) | + SSCR1_TxTresh(TX_THRESH_DFLT), + drv_data->ioaddr); + write_SSCR0(SSCR0_SCR(2) + | SSCR0_Motorola + | SSCR0_DataSize(8), + drv_data->ioaddr); + break; + } + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, drv_data->ioaddr); - write_SSPSP(0, drv_data->ioaddr); + + if (!is_quark_x1000_ssp(drv_data)) + write_SSPSP(0, drv_data->ioaddr); lpss_ssp_setup(drv_data); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 5adc2a11c7bc..6bec59c90cd4 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -93,6 +93,7 @@ struct driver_data { struct chip_data { u32 cr0; u32 cr1; + u32 dds_rate; u32 psp; u32 timeout; u8 n_bytes; @@ -126,6 +127,7 @@ DEFINE_SSP_REG(SSCR1, 0x04) DEFINE_SSP_REG(SSSR, 0x08) DEFINE_SSP_REG(SSITR, 0x0c) DEFINE_SSP_REG(SSDR, 0x10) +DEFINE_SSP_REG(DDS_RATE, 0x28) /* DDS Clock Rate */ DEFINE_SSP_REG(SSTO, 0x28) DEFINE_SSP_REG(SSPSP, 0x2c) DEFINE_SSP_REG(SSITF, SSITF) @@ -141,18 +143,22 @@ DEFINE_SSP_REG(SSIRF, SSIRF) static inline int pxa25x_ssp_comp(struct driver_data *drv_data) { - if (drv_data->ssp_type == PXA25x_SSP) + switch (drv_data->ssp_type) { + case PXA25x_SSP: + case CE4100_SSP: + case QUARK_X1000_SSP: return 1; - if (drv_data->ssp_type == CE4100_SSP) - return 1; - return 0; + default: + return 0; + } } static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) { void __iomem *reg = drv_data->ioaddr; - if (drv_data->ssp_type == CE4100_SSP) + if (drv_data->ssp_type == CE4100_SSP || + drv_data->ssp_type == QUARK_X1000_SSP) val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; write_SSSR(val, reg); -- cgit v1.2.3 From bf77cba95f8c06bbf76869d3bdfb03e18a33e673 Mon Sep 17 00:00:00 2001 From: Padmavathi Venna Date: Thu, 6 Nov 2014 15:21:49 +0530 Subject: spi: s3c64xx: add support for exynos7 SPI controller Exynos7 SPI controller supports only the auto Selection of CS toggle mode and Exynos7 SoC includes six SPI controllers. Add support for these changes in Exynos7 SPI controller driver. Signed-off-by: Padmavathi Venna Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- drivers/spi/spi-s3c64xx.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 84e7c9e6ccef..de2d33dea8b8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -444,7 +444,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on PLAT_SAMSUNG + depends on (PLAT_SAMSUNG || ARCH_EXYNOS) select S3C64XX_PL080 if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 480133ee1eb3..59e07cf31598 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -33,8 +33,9 @@ #include -#define MAX_SPI_PORTS 3 +#define MAX_SPI_PORTS 6 #define S3C64XX_SPI_QUIRK_POLL (1 << 0) +#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1) /* Registers and bit-fields */ @@ -78,6 +79,7 @@ #define S3C64XX_SPI_SLAVE_AUTO (1<<1) #define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0) +#define S3C64XX_SPI_SLAVE_NSC_CNT_2 (2<<4) #define S3C64XX_SPI_INT_TRAILING_EN (1<<6) #define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5) @@ -717,7 +719,12 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, enable_datapath(sdd, spi, xfer, use_dma); /* Start the signals */ - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + else + writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL) + | S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2, + sdd->regs + S3C64XX_SPI_SLAVE_SEL); spin_unlock_irqrestore(&sdd->lock, flags); @@ -866,13 +873,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } pm_runtime_put(&sdd->pdev->dev); - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); return 0; setup_exit: pm_runtime_put(&sdd->pdev->dev); /* setup() returns with device de-selected */ - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); if (gpio_is_valid(spi->cs_gpio)) gpio_free(spi->cs_gpio); @@ -946,7 +955,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) sdd->cur_speed = 0; - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); /* Disable Interrupts - we use Polling if not DMA mode */ writel(0, regs + S3C64XX_SPI_INT_EN); @@ -1341,6 +1351,15 @@ static struct s3c64xx_spi_port_config exynos5440_spi_port_config = { .quirks = S3C64XX_SPI_QUIRK_POLL, }; +static struct s3c64xx_spi_port_config exynos7_spi_port_config = { + .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, + .rx_lvl_offset = 15, + .tx_st_done = 25, + .high_speed = true, + .clk_from_cmu = true, + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, +}; + static struct platform_device_id s3c64xx_spi_driver_ids[] = { { .name = "s3c2443-spi", @@ -1374,6 +1393,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "samsung,exynos5440-spi", .data = (void *)&exynos5440_spi_port_config, }, + { .compatible = "samsung,exynos7-spi", + .data = (void *)&exynos7_spi_port_config, + }, { }, }; MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match); -- cgit v1.2.3 From bc88f11baf5a7e6671eac6fe3131c087d71a646f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Dec 2014 20:23:06 +0000 Subject: spi/s3c64xx: Remove redundant runtime PM management The device already asks the core to hold a runtime PM reference while it is active so it is redundant to open code that in the driver itself. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 59e07cf31598..0f602cba1989 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -346,16 +346,8 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) spi->dma_tx = sdd->tx_dma.ch; } - ret = pm_runtime_get_sync(&sdd->pdev->dev); - if (ret < 0) { - dev_err(dev, "Failed to enable device: %d\n", ret); - goto out_tx; - } - return 0; -out_tx: - dma_release_channel(sdd->tx_dma.ch); out_rx: dma_release_channel(sdd->rx_dma.ch); out: @@ -372,7 +364,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) dma_release_channel(sdd->tx_dma.ch); } - pm_runtime_put(&sdd->pdev->dev); return 0; } -- cgit v1.2.3