Loading Documentation/devicetree/bindings/spi/spi-samsung.txt +1 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ Required SoC Specific Properties: - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms - samsung,s3c6410-spi: for s3c6410 platforms - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms - samsung,exynos4210-spi: for exynos4 and exynos5 platforms - samsung,exynos7-spi: for exynos7 platforms - reg: physical base address of the controller and length of memory mapped region. Loading drivers/spi/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -459,7 +459,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. Loading drivers/spi/spi-mxs.c +6 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading drivers/spi/spi-pxa2xx-pci.c +8 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ enum { PORT_BSW0, PORT_BSW1, PORT_BSW2, PORT_QUARK_X1000, }; struct pxa_spi_info { Loading Loading @@ -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, Loading Loading @@ -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 }, Loading drivers/spi/spi-pxa2xx.c +264 −40 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -80,6 +134,96 @@ 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; } } 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; } } 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) { case QUARK_X1000_SSP: mask = QUARK_X1000_SSSR_TFL_MASK; break; 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) { case QUARK_X1000_SSP: mask = QUARK_X1000_SSCR1_RFT; break; 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) { case QUARK_X1000_SSP: *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold); break; 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) { 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 | 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. Loading Loading @@ -234,7 +378,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; Loading Loading @@ -262,7 +406,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; Loading @@ -289,7 +433,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; Loading @@ -316,7 +460,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; Loading Loading @@ -508,8 +652,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) { Loading @@ -519,10 +664,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); } Loading Loading @@ -585,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; Loading @@ -598,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; Loading @@ -613,6 +795,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; Loading Loading @@ -699,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; Loading Loading @@ -731,11 +914,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; Loading Loading @@ -771,17 +950,20 @@ 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) & 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); Loading Loading @@ -875,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 */ Loading Loading @@ -935,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); Loading @@ -956,15 +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 = 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); 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); Loading Loading @@ -993,6 +1189,7 @@ static int setup(struct spi_device *spi) chip->read = u16_reader; chip->write = u16_writer; } else if (spi->bits_per_word <= 32) { if (!is_quark_x1000_ssp(drv_data)) chip->cr0 |= SSCR0_EDSS; chip->n_bytes = 4; chip->read = u32_reader; Loading Loading @@ -1144,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)) { 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; Loading Loading @@ -1182,6 +1387,20 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Load default SSP configuration */ write_SSCR0(0, 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); Loading @@ -1189,8 +1408,13 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | SSCR0_Motorola | SSCR0_DataSize(8), drv_data->ioaddr); break; } if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, drv_data->ioaddr); if (!is_quark_x1000_ssp(drv_data)) write_SSPSP(0, drv_data->ioaddr); lpss_ssp_setup(drv_data); Loading Loading
Documentation/devicetree/bindings/spi/spi-samsung.txt +1 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ Required SoC Specific Properties: - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms - samsung,s3c6410-spi: for s3c6410 platforms - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms - samsung,exynos4210-spi: for exynos4 and exynos5 platforms - samsung,exynos7-spi: for exynos7 platforms - reg: physical base address of the controller and length of memory mapped region. Loading
drivers/spi/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -459,7 +459,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. Loading
drivers/spi/spi-mxs.c +6 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading
drivers/spi/spi-pxa2xx-pci.c +8 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ enum { PORT_BSW0, PORT_BSW1, PORT_BSW2, PORT_QUARK_X1000, }; struct pxa_spi_info { Loading Loading @@ -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, Loading Loading @@ -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 }, Loading
drivers/spi/spi-pxa2xx.c +264 −40 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -80,6 +134,96 @@ 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; } } 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; } } 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) { case QUARK_X1000_SSP: mask = QUARK_X1000_SSSR_TFL_MASK; break; 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) { case QUARK_X1000_SSP: mask = QUARK_X1000_SSCR1_RFT; break; 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) { case QUARK_X1000_SSP: *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold); break; 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) { 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 | 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. Loading Loading @@ -234,7 +378,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; Loading Loading @@ -262,7 +406,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; Loading @@ -289,7 +433,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; Loading @@ -316,7 +460,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; Loading Loading @@ -508,8 +652,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) { Loading @@ -519,10 +664,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); } Loading Loading @@ -585,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; Loading @@ -598,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; Loading @@ -613,6 +795,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; Loading Loading @@ -699,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; Loading Loading @@ -731,11 +914,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; Loading Loading @@ -771,17 +950,20 @@ 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) & 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); Loading Loading @@ -875,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 */ Loading Loading @@ -935,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); Loading @@ -956,15 +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 = 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); 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); Loading Loading @@ -993,6 +1189,7 @@ static int setup(struct spi_device *spi) chip->read = u16_reader; chip->write = u16_writer; } else if (spi->bits_per_word <= 32) { if (!is_quark_x1000_ssp(drv_data)) chip->cr0 |= SSCR0_EDSS; chip->n_bytes = 4; chip->read = u32_reader; Loading Loading @@ -1144,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)) { 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; Loading Loading @@ -1182,6 +1387,20 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Load default SSP configuration */ write_SSCR0(0, 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); Loading @@ -1189,8 +1408,13 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | SSCR0_Motorola | SSCR0_DataSize(8), drv_data->ioaddr); break; } if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, drv_data->ioaddr); if (!is_quark_x1000_ssp(drv_data)) write_SSPSP(0, drv_data->ioaddr); lpss_ssp_setup(drv_data); Loading