Merge remote-tracking branches 'spi/topic/mxs', 'spi/topic/pxa', 'spi/topic/rockchip', 'spi/topic/samsung' and 'spi/topic/sirf' into spi-next
commit
f56be67b19
|
@ -9,7 +9,7 @@ Required SoC Specific Properties:
|
||||||
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
|
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
|
||||||
- samsung,s3c6410-spi: for s3c6410 platforms
|
- samsung,s3c6410-spi: for s3c6410 platforms
|
||||||
- samsung,s5pv210-spi: for s5pv210 and s5pc110 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
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
|
|
|
@ -459,7 +459,7 @@ config SPI_S3C24XX_FIQ
|
||||||
|
|
||||||
config SPI_S3C64XX
|
config SPI_S3C64XX
|
||||||
tristate "Samsung S3C64XX series type SPI"
|
tristate "Samsung S3C64XX series type SPI"
|
||||||
depends on PLAT_SAMSUNG
|
depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
|
||||||
select S3C64XX_PL080 if ARCH_S3C64XX
|
select S3C64XX_PL080 if ARCH_S3C64XX
|
||||||
help
|
help
|
||||||
SPI driver for Samsung S3C64XX and newer SoCs.
|
SPI driver for Samsung S3C64XX and newer SoCs.
|
||||||
|
|
|
@ -182,7 +182,6 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
|
||||||
int min, ret;
|
int min, ret;
|
||||||
u32 ctrl0;
|
u32 ctrl0;
|
||||||
struct page *vm_page;
|
struct page *vm_page;
|
||||||
void *sg_buf;
|
|
||||||
struct {
|
struct {
|
||||||
u32 pio[4];
|
u32 pio[4];
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
|
@ -232,13 +231,14 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_vmalloc;
|
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 {
|
} 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,
|
ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
|
||||||
(flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
(flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
||||||
init_completion(&spi->c);
|
init_completion(&spi->c);
|
||||||
|
|
||||||
ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
|
ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
|
||||||
DRIVER_NAME, ssp);
|
dev_name(&pdev->dev), ssp);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_master_free;
|
goto out_master_free;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum {
|
||||||
PORT_BSW0,
|
PORT_BSW0,
|
||||||
PORT_BSW1,
|
PORT_BSW1,
|
||||||
PORT_BSW2,
|
PORT_BSW2,
|
||||||
|
PORT_QUARK_X1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pxa_spi_info {
|
struct pxa_spi_info {
|
||||||
|
@ -92,6 +93,12 @@ static struct pxa_spi_info spi_info_configs[] = {
|
||||||
.tx_param = &bsw2_tx_param,
|
.tx_param = &bsw2_tx_param,
|
||||||
.rx_param = &bsw2_rx_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,
|
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[] = {
|
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
|
||||||
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
|
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 },
|
||||||
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
|
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
|
||||||
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
|
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
|
||||||
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
|
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
|
||||||
|
|
|
@ -63,10 +63,64 @@ MODULE_ALIAS("platform:pxa2xx-spi");
|
||||||
| SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
|
| SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
|
||||||
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
|
| 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_RX_THRESH_DFLT 64
|
||||||
#define LPSS_TX_LOTHRESH_DFLT 160
|
#define LPSS_TX_LOTHRESH_DFLT 160
|
||||||
#define LPSS_TX_HITHRESH_DFLT 224
|
#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 */
|
/* Offset from drv_data->lpss_base */
|
||||||
#define GENERAL_REG 0x08
|
#define GENERAL_REG 0x08
|
||||||
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
|
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
|
||||||
|
@ -80,6 +134,96 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
|
||||||
return drv_data->ssp_type == LPSS_SSP;
|
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
|
* Read and write LPSS SSP private registers. Caller must first check that
|
||||||
* is_lpss_ssp() returns true before these can be called.
|
* is_lpss_ssp() returns true before these can be called.
|
||||||
|
@ -234,7 +378,7 @@ static int null_writer(struct driver_data *drv_data)
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
void __iomem *reg = drv_data->ioaddr;
|
||||||
u8 n_bytes = drv_data->n_bytes;
|
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))
|
|| (drv_data->tx == drv_data->tx_end))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -262,7 +406,7 @@ static int u8_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
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))
|
|| (drv_data->tx == drv_data->tx_end))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -289,7 +433,7 @@ static int u16_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
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))
|
|| (drv_data->tx == drv_data->tx_end))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -316,7 +460,7 @@ static int u32_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
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))
|
|| (drv_data->tx == drv_data->tx_end))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -508,8 +652,9 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
||||||
* remaining RX bytes.
|
* remaining RX bytes.
|
||||||
*/
|
*/
|
||||||
if (pxa25x_ssp_comp(drv_data)) {
|
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;
|
bytes_left = drv_data->rx_end - drv_data->rx;
|
||||||
switch (drv_data->n_bytes) {
|
switch (drv_data->n_bytes) {
|
||||||
|
@ -519,10 +664,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
||||||
bytes_left >>= 1;
|
bytes_left >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_left > RX_THRESH_DFLT)
|
rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data);
|
||||||
bytes_left = RX_THRESH_DFLT;
|
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);
|
write_SSCR1(sccr1_reg, reg);
|
||||||
}
|
}
|
||||||
|
@ -585,6 +731,28 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
||||||
return drv_data->transfer_handler(drv_data);
|
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)
|
static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
||||||
{
|
{
|
||||||
unsigned long ssp_clk = drv_data->max_clk_rate;
|
unsigned long ssp_clk = drv_data->max_clk_rate;
|
||||||
|
@ -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;
|
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)
|
static void pump_transfers(unsigned long data)
|
||||||
{
|
{
|
||||||
struct driver_data *drv_data = (struct driver_data *)data;
|
struct driver_data *drv_data = (struct driver_data *)data;
|
||||||
|
@ -613,6 +795,7 @@ static void pump_transfers(unsigned long data)
|
||||||
u32 cr1;
|
u32 cr1;
|
||||||
u32 dma_thresh = drv_data->cur_chip->dma_threshold;
|
u32 dma_thresh = drv_data->cur_chip->dma_threshold;
|
||||||
u32 dma_burst = drv_data->cur_chip->dma_burst_size;
|
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 */
|
/* Get current state information */
|
||||||
message = drv_data->cur_msg;
|
message = drv_data->cur_msg;
|
||||||
|
@ -699,7 +882,7 @@ static void pump_transfers(unsigned long data)
|
||||||
if (transfer->bits_per_word)
|
if (transfer->bits_per_word)
|
||||||
bits = 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) {
|
if (bits <= 8) {
|
||||||
drv_data->n_bytes = 1;
|
drv_data->n_bytes = 1;
|
||||||
|
@ -731,11 +914,7 @@ static void pump_transfers(unsigned long data)
|
||||||
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
|
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
cr0 = clk_div
|
cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
|
||||||
| SSCR0_Motorola
|
|
||||||
| SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
|
|
||||||
| SSCR0_SSE
|
|
||||||
| (bits > 16 ? SSCR0_EDSS : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message->state = RUNNING_STATE;
|
message->state = RUNNING_STATE;
|
||||||
|
@ -771,17 +950,20 @@ static void pump_transfers(unsigned long data)
|
||||||
write_SSITF(chip->lpss_tx_threshold, reg);
|
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 */
|
/* see if we need to reload the config registers */
|
||||||
if ((read_SSCR0(reg) != cr0)
|
if ((read_SSCR0(reg) != cr0) ||
|
||||||
|| (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
|
(read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) {
|
||||||
(cr1 & SSCR1_CHANGE_MASK)) {
|
|
||||||
|
|
||||||
/* stop the SSP, and update the other bits */
|
/* stop the SSP, and update the other bits */
|
||||||
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
|
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(chip->timeout, reg);
|
write_SSTO(chip->timeout, reg);
|
||||||
/* first set CR1 without interrupt and service enables */
|
/* first set CR1 without interrupt and service enables */
|
||||||
write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
|
write_SSCR1(cr1 & change_mask, reg);
|
||||||
/* restart the SSP */
|
/* restart the SSP */
|
||||||
write_SSCR0(cr0, reg);
|
write_SSCR0(cr0, reg);
|
||||||
|
|
||||||
|
@ -875,14 +1057,22 @@ static int setup(struct spi_device *spi)
|
||||||
unsigned int clk_div;
|
unsigned int clk_div;
|
||||||
uint tx_thres, tx_hi_thres, rx_thres;
|
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_thres = LPSS_TX_LOTHRESH_DFLT;
|
||||||
tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
|
tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
|
||||||
rx_thres = LPSS_RX_THRESH_DFLT;
|
rx_thres = LPSS_RX_THRESH_DFLT;
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
tx_thres = TX_THRESH_DFLT;
|
tx_thres = TX_THRESH_DFLT;
|
||||||
tx_hi_thres = 0;
|
tx_hi_thres = 0;
|
||||||
rx_thres = RX_THRESH_DFLT;
|
rx_thres = RX_THRESH_DFLT;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
|
@ -935,9 +1125,6 @@ static int setup(struct spi_device *spi)
|
||||||
chip->enable_dma = drv_data->master_info->enable_dma;
|
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_rx_threshold = SSIRF_RxThresh(rx_thres);
|
||||||
chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
|
chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
|
||||||
| SSITF_TxHiThresh(tx_hi_thres);
|
| SSITF_TxHiThresh(tx_hi_thres);
|
||||||
|
@ -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->speed_hz = spi->max_speed_hz;
|
||||||
|
|
||||||
chip->cr0 = clk_div
|
chip->cr0 = pxa2xx_configure_sscr0(drv_data, clk_div,
|
||||||
| SSCR0_Motorola
|
spi->bits_per_word);
|
||||||
| SSCR0_DataSize(spi->bits_per_word > 16 ?
|
switch (drv_data->ssp_type) {
|
||||||
spi->bits_per_word - 16 : spi->bits_per_word)
|
case QUARK_X1000_SSP:
|
||||||
| SSCR0_SSE
|
chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres)
|
||||||
| (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
|
& 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 &= ~(SSCR1_SPO | SSCR1_SPH);
|
||||||
chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
|
chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
|
||||||
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|
||||||
|
@ -993,7 +1189,8 @@ static int setup(struct spi_device *spi)
|
||||||
chip->read = u16_reader;
|
chip->read = u16_reader;
|
||||||
chip->write = u16_writer;
|
chip->write = u16_writer;
|
||||||
} else if (spi->bits_per_word <= 32) {
|
} 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->n_bytes = 4;
|
||||||
chip->read = u32_reader;
|
chip->read = u32_reader;
|
||||||
chip->write = u32_writer;
|
chip->write = u32_writer;
|
||||||
|
@ -1144,7 +1341,15 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||||
drv_data->ioaddr = ssp->mmio_base;
|
drv_data->ioaddr = ssp->mmio_base;
|
||||||
drv_data->ssdr_physical = ssp->phys_base + SSDR;
|
drv_data->ssdr_physical = ssp->phys_base + SSDR;
|
||||||
if (pxa25x_ssp_comp(drv_data)) {
|
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->int_cr1 = SSCR1_TIE | SSCR1_RIE;
|
||||||
drv_data->dma_cr1 = 0;
|
drv_data->dma_cr1 = 0;
|
||||||
drv_data->clear_sr = SSSR_ROR;
|
drv_data->clear_sr = SSSR_ROR;
|
||||||
|
@ -1182,16 +1387,35 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* Load default SSP configuration */
|
/* Load default SSP configuration */
|
||||||
write_SSCR0(0, drv_data->ioaddr);
|
write_SSCR0(0, drv_data->ioaddr);
|
||||||
write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
|
switch (drv_data->ssp_type) {
|
||||||
SSCR1_TxTresh(TX_THRESH_DFLT),
|
case QUARK_X1000_SSP:
|
||||||
drv_data->ioaddr);
|
write_SSCR1(QUARK_X1000_SSCR1_RxTresh(
|
||||||
write_SSCR0(SSCR0_SCR(2)
|
RX_THRESH_QUARK_X1000_DFLT) |
|
||||||
| SSCR0_Motorola
|
QUARK_X1000_SSCR1_TxTresh(
|
||||||
| SSCR0_DataSize(8),
|
TX_THRESH_QUARK_X1000_DFLT),
|
||||||
drv_data->ioaddr);
|
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))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, drv_data->ioaddr);
|
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);
|
lpss_ssp_setup(drv_data);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ struct driver_data {
|
||||||
struct chip_data {
|
struct chip_data {
|
||||||
u32 cr0;
|
u32 cr0;
|
||||||
u32 cr1;
|
u32 cr1;
|
||||||
|
u32 dds_rate;
|
||||||
u32 psp;
|
u32 psp;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
u8 n_bytes;
|
u8 n_bytes;
|
||||||
|
@ -126,6 +127,7 @@ DEFINE_SSP_REG(SSCR1, 0x04)
|
||||||
DEFINE_SSP_REG(SSSR, 0x08)
|
DEFINE_SSP_REG(SSSR, 0x08)
|
||||||
DEFINE_SSP_REG(SSITR, 0x0c)
|
DEFINE_SSP_REG(SSITR, 0x0c)
|
||||||
DEFINE_SSP_REG(SSDR, 0x10)
|
DEFINE_SSP_REG(SSDR, 0x10)
|
||||||
|
DEFINE_SSP_REG(DDS_RATE, 0x28) /* DDS Clock Rate */
|
||||||
DEFINE_SSP_REG(SSTO, 0x28)
|
DEFINE_SSP_REG(SSTO, 0x28)
|
||||||
DEFINE_SSP_REG(SSPSP, 0x2c)
|
DEFINE_SSP_REG(SSPSP, 0x2c)
|
||||||
DEFINE_SSP_REG(SSITF, SSITF)
|
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)
|
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;
|
return 1;
|
||||||
if (drv_data->ssp_type == CE4100_SSP)
|
default:
|
||||||
return 1;
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
|
static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
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;
|
val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
|
||||||
|
|
||||||
write_SSSR(val, reg);
|
write_SSSR(val, reg);
|
||||||
|
|
|
@ -749,8 +749,6 @@ static int rockchip_spi_remove(struct platform_device *pdev)
|
||||||
if (rs->dma_rx.ch)
|
if (rs->dma_rx.ch)
|
||||||
dma_release_channel(rs->dma_rx.ch);
|
dma_release_channel(rs->dma_rx.ch);
|
||||||
|
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,9 @@
|
||||||
|
|
||||||
#include <linux/platform_data/spi-s3c64xx.h>
|
#include <linux/platform_data/spi-s3c64xx.h>
|
||||||
|
|
||||||
#define MAX_SPI_PORTS 3
|
#define MAX_SPI_PORTS 6
|
||||||
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
|
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
|
||||||
|
#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
|
||||||
|
|
||||||
/* Registers and bit-fields */
|
/* Registers and bit-fields */
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
|
|
||||||
#define S3C64XX_SPI_SLAVE_AUTO (1<<1)
|
#define S3C64XX_SPI_SLAVE_AUTO (1<<1)
|
||||||
#define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0)
|
#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_TRAILING_EN (1<<6)
|
||||||
#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
|
#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
|
||||||
|
@ -344,16 +346,8 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
||||||
spi->dma_tx = sdd->tx_dma.ch;
|
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;
|
return 0;
|
||||||
|
|
||||||
out_tx:
|
|
||||||
dma_release_channel(sdd->tx_dma.ch);
|
|
||||||
out_rx:
|
out_rx:
|
||||||
dma_release_channel(sdd->rx_dma.ch);
|
dma_release_channel(sdd->rx_dma.ch);
|
||||||
out:
|
out:
|
||||||
|
@ -370,7 +364,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
|
||||||
dma_release_channel(sdd->tx_dma.ch);
|
dma_release_channel(sdd->tx_dma.ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,7 +710,12 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
|
||||||
enable_datapath(sdd, spi, xfer, use_dma);
|
enable_datapath(sdd, spi, xfer, use_dma);
|
||||||
|
|
||||||
/* Start the signals */
|
/* 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);
|
spin_unlock_irqrestore(&sdd->lock, flags);
|
||||||
|
|
||||||
|
@ -866,13 +864,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
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;
|
return 0;
|
||||||
|
|
||||||
setup_exit:
|
setup_exit:
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
pm_runtime_put(&sdd->pdev->dev);
|
||||||
/* setup() returns with device de-selected */
|
/* 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))
|
if (gpio_is_valid(spi->cs_gpio))
|
||||||
gpio_free(spi->cs_gpio);
|
gpio_free(spi->cs_gpio);
|
||||||
|
@ -946,7 +946,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
|
||||||
|
|
||||||
sdd->cur_speed = 0;
|
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 */
|
/* Disable Interrupts - we use Polling if not DMA mode */
|
||||||
writel(0, regs + S3C64XX_SPI_INT_EN);
|
writel(0, regs + S3C64XX_SPI_INT_EN);
|
||||||
|
@ -1341,6 +1342,15 @@ static struct s3c64xx_spi_port_config exynos5440_spi_port_config = {
|
||||||
.quirks = S3C64XX_SPI_QUIRK_POLL,
|
.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[] = {
|
static struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
||||||
{
|
{
|
||||||
.name = "s3c2443-spi",
|
.name = "s3c2443-spi",
|
||||||
|
@ -1374,6 +1384,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
||||||
{ .compatible = "samsung,exynos5440-spi",
|
{ .compatible = "samsung,exynos5440-spi",
|
||||||
.data = (void *)&exynos5440_spi_port_config,
|
.data = (void *)&exynos5440_spi_port_config,
|
||||||
},
|
},
|
||||||
|
{ .compatible = "samsung,exynos7-spi",
|
||||||
|
.data = (void *)&exynos7_spi_port_config,
|
||||||
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
|
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/dma-direction.h>
|
#include <linux/dma-direction.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
|
||||||
#define DRIVER_NAME "sirfsoc_spi"
|
#define DRIVER_NAME "sirfsoc_spi"
|
||||||
|
|
||||||
|
@ -134,6 +135,7 @@
|
||||||
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
|
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
|
||||||
|
|
||||||
#define SIRFSOC_MAX_CMD_BYTES 4
|
#define SIRFSOC_MAX_CMD_BYTES 4
|
||||||
|
#define SIRFSOC_SPI_DEFAULT_FRQ 1000000
|
||||||
|
|
||||||
struct sirfsoc_spi {
|
struct sirfsoc_spi {
|
||||||
struct spi_bitbang bitbang;
|
struct spi_bitbang bitbang;
|
||||||
|
@ -629,9 +631,6 @@ static int spi_sirfsoc_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct sirfsoc_spi *sspi;
|
struct sirfsoc_spi *sspi;
|
||||||
|
|
||||||
if (!spi->max_speed_hz)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
sspi = spi_master_get_devdata(spi->master);
|
sspi = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
if (spi->cs_gpio == -ENOENT)
|
if (spi->cs_gpio == -ENOENT)
|
||||||
|
@ -649,6 +648,12 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||||
int irq;
|
int irq;
|
||||||
int i, ret;
|
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));
|
master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
|
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
|
||||||
|
@ -683,6 +688,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
|
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) |
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
|
||||||
SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
|
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;
|
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
/* request DMA channels */
|
/* request DMA channels */
|
||||||
|
|
|
@ -108,6 +108,25 @@
|
||||||
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
|
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* QUARK_X1000 SSCR0 bit definition */
|
||||||
|
#define QUARK_X1000_SSCR0_DSS (0x1F) /* Data Size Select (mask) */
|
||||||
|
#define QUARK_X1000_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */
|
||||||
|
#define QUARK_X1000_SSCR0_FRF (0x3 << 5) /* FRame Format (mask) */
|
||||||
|
#define QUARK_X1000_SSCR0_Motorola (0x0 << 5) /* Motorola's Serial Peripheral Interface (SPI) */
|
||||||
|
|
||||||
|
#define RX_THRESH_QUARK_X1000_DFLT 1
|
||||||
|
#define TX_THRESH_QUARK_X1000_DFLT 16
|
||||||
|
|
||||||
|
#define QUARK_X1000_SSSR_TFL_MASK (0x1F << 8) /* Transmit FIFO Level mask */
|
||||||
|
#define QUARK_X1000_SSSR_RFL_MASK (0x1F << 13) /* Receive FIFO Level mask */
|
||||||
|
|
||||||
|
#define QUARK_X1000_SSCR1_TFT (0x1F << 6) /* Transmit FIFO Threshold (mask) */
|
||||||
|
#define QUARK_X1000_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..32] */
|
||||||
|
#define QUARK_X1000_SSCR1_RFT (0x1F << 11) /* Receive FIFO Threshold (mask) */
|
||||||
|
#define QUARK_X1000_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */
|
||||||
|
#define QUARK_X1000_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */
|
||||||
|
#define QUARK_X1000_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */
|
||||||
|
|
||||||
/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
|
/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
|
||||||
#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
|
#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
|
||||||
#define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */
|
#define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */
|
||||||
|
@ -175,6 +194,7 @@ enum pxa_ssp_type {
|
||||||
PXA910_SSP,
|
PXA910_SSP,
|
||||||
CE4100_SSP,
|
CE4100_SSP,
|
||||||
LPSS_SSP,
|
LPSS_SSP,
|
||||||
|
QUARK_X1000_SSP,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssp_device {
|
struct ssp_device {
|
||||||
|
|
Loading…
Reference in New Issue