mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-08 15:04:45 +00:00
Merge remote-tracking branches 'spi/topic/orion', 'spi/topic/pxa2xx', 'spi/topic/qup', 'spi/topic/rockchip' and 'spi/topic/samsung' into spi-next
This commit is contained in:
commit
4f9f4548a5
@ -469,7 +469,6 @@ 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 || ARCH_EXYNOS)
|
depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
|
||||||
select S3C64XX_PL080 if ARCH_S3C64XX
|
|
||||||
help
|
help
|
||||||
SPI driver for Samsung S3C64XX and newer SoCs.
|
SPI driver for Samsung S3C64XX and newer SoCs.
|
||||||
|
|
||||||
|
@ -28,7 +28,12 @@
|
|||||||
/* Runtime PM autosuspend timeout: PM is fairly light on this driver */
|
/* Runtime PM autosuspend timeout: PM is fairly light on this driver */
|
||||||
#define SPI_AUTOSUSPEND_TIMEOUT 200
|
#define SPI_AUTOSUSPEND_TIMEOUT 200
|
||||||
|
|
||||||
#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/
|
/* Some SoCs using this driver support up to 8 chip selects.
|
||||||
|
* It is up to the implementer to only use the chip selects
|
||||||
|
* that are available.
|
||||||
|
*/
|
||||||
|
#define ORION_NUM_CHIPSELECTS 8
|
||||||
|
|
||||||
#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
|
#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
|
||||||
|
|
||||||
#define ORION_SPI_IF_CTRL_REG 0x00
|
#define ORION_SPI_IF_CTRL_REG 0x00
|
||||||
@ -44,6 +49,10 @@
|
|||||||
#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF
|
#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF
|
||||||
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
|
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
|
||||||
ORION_SPI_MODE_CPHA)
|
ORION_SPI_MODE_CPHA)
|
||||||
|
#define ORION_SPI_CS_MASK 0x1C
|
||||||
|
#define ORION_SPI_CS_SHIFT 2
|
||||||
|
#define ORION_SPI_CS(cs) ((cs << ORION_SPI_CS_SHIFT) & \
|
||||||
|
ORION_SPI_CS_MASK)
|
||||||
|
|
||||||
enum orion_spi_type {
|
enum orion_spi_type {
|
||||||
ORION_SPI,
|
ORION_SPI,
|
||||||
@ -215,9 +224,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
|
static void orion_spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
{
|
{
|
||||||
if (enable)
|
struct orion_spi *orion_spi;
|
||||||
|
|
||||||
|
orion_spi = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
|
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
|
||||||
|
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
|
||||||
|
ORION_SPI_CS(spi->chip_select));
|
||||||
|
|
||||||
|
/* Chip select logic is inverted from spi_set_cs */
|
||||||
|
if (!enable)
|
||||||
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
|
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
|
||||||
else
|
else
|
||||||
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
|
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
|
||||||
@ -332,64 +350,31 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
|||||||
return xfer->len - count;
|
return xfer->len - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int orion_spi_transfer_one_message(struct spi_master *master,
|
static int orion_spi_transfer_one(struct spi_master *master,
|
||||||
struct spi_message *m)
|
struct spi_device *spi,
|
||||||
|
struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct orion_spi *orion_spi = spi_master_get_devdata(master);
|
|
||||||
struct spi_device *spi = m->spi;
|
|
||||||
struct spi_transfer *t = NULL;
|
|
||||||
int par_override = 0;
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
int cs_active = 0;
|
|
||||||
|
|
||||||
/* Load defaults */
|
|
||||||
status = orion_spi_setup_transfer(spi, NULL);
|
|
||||||
|
|
||||||
if (status < 0)
|
|
||||||
goto msg_done;
|
|
||||||
|
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
|
||||||
if (par_override || t->speed_hz || t->bits_per_word) {
|
|
||||||
par_override = 1;
|
|
||||||
status = orion_spi_setup_transfer(spi, t);
|
status = orion_spi_setup_transfer(spi, t);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
break;
|
return status;
|
||||||
if (!t->speed_hz && !t->bits_per_word)
|
|
||||||
par_override = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cs_active) {
|
|
||||||
orion_spi_set_cs(orion_spi, 1);
|
|
||||||
cs_active = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->len)
|
if (t->len)
|
||||||
m->actual_length += orion_spi_write_read(spi, t);
|
orion_spi_write_read(spi, t);
|
||||||
|
|
||||||
if (t->delay_usecs)
|
return status;
|
||||||
udelay(t->delay_usecs);
|
}
|
||||||
|
|
||||||
if (t->cs_change) {
|
static int orion_spi_setup(struct spi_device *spi)
|
||||||
orion_spi_set_cs(orion_spi, 0);
|
{
|
||||||
cs_active = 0;
|
return orion_spi_setup_transfer(spi, NULL);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_done:
|
|
||||||
if (cs_active)
|
|
||||||
orion_spi_set_cs(orion_spi, 0);
|
|
||||||
|
|
||||||
m->status = status;
|
|
||||||
spi_finalize_current_message(master);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int orion_spi_reset(struct orion_spi *orion_spi)
|
static int orion_spi_reset(struct orion_spi *orion_spi)
|
||||||
{
|
{
|
||||||
/* Verify that the CS is deasserted */
|
/* Verify that the CS is deasserted */
|
||||||
orion_spi_set_cs(orion_spi, 0);
|
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,9 +427,10 @@ static int orion_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* we support only mode 0, and no options */
|
/* we support only mode 0, and no options */
|
||||||
master->mode_bits = SPI_CPHA | SPI_CPOL;
|
master->mode_bits = SPI_CPHA | SPI_CPOL;
|
||||||
|
master->set_cs = orion_spi_set_cs;
|
||||||
master->transfer_one_message = orion_spi_transfer_one_message;
|
master->transfer_one = orion_spi_transfer_one;
|
||||||
master->num_chipselect = ORION_NUM_CHIPSELECTS;
|
master->num_chipselect = ORION_NUM_CHIPSELECTS;
|
||||||
|
master->setup = orion_spi_setup;
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
|
|
||||||
|
@ -111,23 +111,24 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
|||||||
* by using ->dma_running.
|
* by using ->dma_running.
|
||||||
*/
|
*/
|
||||||
if (atomic_dec_and_test(&drv_data->dma_running)) {
|
if (atomic_dec_and_test(&drv_data->dma_running)) {
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the other CPU is still handling the ROR interrupt we
|
* If the other CPU is still handling the ROR interrupt we
|
||||||
* might not know about the error yet. So we re-check the
|
* might not know about the error yet. So we re-check the
|
||||||
* ROR bit here before we clear the status register.
|
* ROR bit here before we clear the status register.
|
||||||
*/
|
*/
|
||||||
if (!error) {
|
if (!error) {
|
||||||
u32 status = read_SSSR(reg) & drv_data->mask_sr;
|
u32 status = pxa2xx_spi_read(drv_data, SSSR)
|
||||||
|
& drv_data->mask_sr;
|
||||||
error = status & SSSR_ROR;
|
error = status & SSSR_ROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear status & disable interrupts */
|
/* Clear status & disable interrupts */
|
||||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
pxa2xx_spi_write(drv_data, SSCR1,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR1)
|
||||||
|
& ~drv_data->dma_cr1);
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||||
@ -139,7 +140,9 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
|||||||
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
||||||
} else {
|
} else {
|
||||||
/* In case we got an error we disable the SSP now */
|
/* In case we got an error we disable the SSP now */
|
||||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR0)
|
||||||
|
& ~SSCR0_SSE);
|
||||||
|
|
||||||
msg->state = ERROR_STATE;
|
msg->state = ERROR_STATE;
|
||||||
}
|
}
|
||||||
@ -247,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
|||||||
{
|
{
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr;
|
status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
|
||||||
if (status & SSSR_ROR) {
|
if (status & SSSR_ROR) {
|
||||||
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
|
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/pxa2xx_spi.h>
|
#include <linux/spi/pxa2xx_spi.h>
|
||||||
|
|
||||||
|
#include <mach/dma.h>
|
||||||
#include "spi-pxa2xx.h"
|
#include "spi-pxa2xx.h"
|
||||||
|
|
||||||
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
|
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
|
||||||
@ -114,11 +115,11 @@ static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
|
|||||||
drv_data->dma_mapped = 0;
|
drv_data->dma_mapped = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_ssp_rx_stall(void const __iomem *ioaddr)
|
static int wait_ssp_rx_stall(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
unsigned long limit = loops_per_jiffy << 1;
|
unsigned long limit = loops_per_jiffy << 1;
|
||||||
|
|
||||||
while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
|
while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit)
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
|
|
||||||
return limit;
|
return limit;
|
||||||
@ -137,17 +138,18 @@ static int wait_dma_channel_stop(int channel)
|
|||||||
static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
|
static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
|
||||||
const char *msg)
|
const char *msg)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
/* Stop and reset */
|
/* Stop and reset */
|
||||||
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
||||||
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
pxa2xx_spi_write(drv_data, SSCR1,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR1)
|
||||||
|
& ~drv_data->dma_cr1);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
pxa2xx_spi_flush(drv_data);
|
pxa2xx_spi_flush(drv_data);
|
||||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
|
||||||
|
|
||||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||||
|
|
||||||
@ -159,11 +161,12 @@ static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
|
|||||||
|
|
||||||
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
|
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
struct spi_message *msg = drv_data->cur_msg;
|
struct spi_message *msg = drv_data->cur_msg;
|
||||||
|
|
||||||
/* Clear and disable interrupts on SSP and DMA channels*/
|
/* Clear and disable interrupts on SSP and DMA channels*/
|
||||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
pxa2xx_spi_write(drv_data, SSCR1,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR1)
|
||||||
|
& ~drv_data->dma_cr1);
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
||||||
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
||||||
@ -224,7 +227,7 @@ void pxa2xx_spi_dma_handler(int channel, void *data)
|
|||||||
&& (drv_data->ssp_type == PXA25x_SSP)) {
|
&& (drv_data->ssp_type == PXA25x_SSP)) {
|
||||||
|
|
||||||
/* Wait for rx to stall */
|
/* Wait for rx to stall */
|
||||||
if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
|
if (wait_ssp_rx_stall(drv_data) == 0)
|
||||||
dev_err(&drv_data->pdev->dev,
|
dev_err(&drv_data->pdev->dev,
|
||||||
"dma_handler: ssp rx stall failed\n");
|
"dma_handler: ssp rx stall failed\n");
|
||||||
|
|
||||||
@ -236,9 +239,8 @@ void pxa2xx_spi_dma_handler(int channel, void *data)
|
|||||||
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
u32 irq_status;
|
u32 irq_status;
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
irq_status = read_SSSR(reg) & drv_data->mask_sr;
|
irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
|
||||||
if (irq_status & SSSR_ROR) {
|
if (irq_status & SSSR_ROR) {
|
||||||
pxa2xx_spi_dma_error_stop(drv_data,
|
pxa2xx_spi_dma_error_stop(drv_data,
|
||||||
"dma_transfer: fifo overrun");
|
"dma_transfer: fifo overrun");
|
||||||
@ -248,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
|||||||
/* Check for false positive timeout */
|
/* Check for false positive timeout */
|
||||||
if ((irq_status & SSSR_TINT)
|
if ((irq_status & SSSR_TINT)
|
||||||
&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
|
&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
|
||||||
write_SSSR(SSSR_TINT, reg);
|
pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +259,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
|||||||
/* Clear and disable timeout interrupt, do the rest in
|
/* Clear and disable timeout interrupt, do the rest in
|
||||||
* dma_transfer_complete */
|
* dma_transfer_complete */
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
|
|
||||||
/* finish this transfer, start the next */
|
/* finish this transfer, start the next */
|
||||||
pxa2xx_spi_dma_transfer_complete(drv_data);
|
pxa2xx_spi_dma_transfer_complete(drv_data);
|
||||||
|
@ -41,8 +41,6 @@ MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
|
|||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:pxa2xx-spi");
|
MODULE_ALIAS("platform:pxa2xx-spi");
|
||||||
|
|
||||||
#define MAX_BUSES 3
|
|
||||||
|
|
||||||
#define TIMOUT_DFLT 1000
|
#define TIMOUT_DFLT 1000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -158,7 +156,6 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data)
|
|||||||
|
|
||||||
static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
|
static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
u32 mask;
|
u32 mask;
|
||||||
|
|
||||||
switch (drv_data->ssp_type) {
|
switch (drv_data->ssp_type) {
|
||||||
@ -170,7 +167,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (read_SSSR(reg) & mask) == mask;
|
return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
|
static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
|
||||||
@ -249,9 +246,6 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
|
|||||||
unsigned offset = 0x400;
|
unsigned offset = 0x400;
|
||||||
u32 value, orig;
|
u32 value, orig;
|
||||||
|
|
||||||
if (!is_lpss_ssp(drv_data))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform auto-detection of the LPSS SSP private registers. They
|
* Perform auto-detection of the LPSS SSP private registers. They
|
||||||
* can be either at 1k or 2k offset from the base address.
|
* can be either at 1k or 2k offset from the base address.
|
||||||
@ -300,9 +294,6 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
|
|||||||
{
|
{
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
if (!is_lpss_ssp(drv_data))
|
|
||||||
return;
|
|
||||||
|
|
||||||
value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
|
value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
|
||||||
if (enable)
|
if (enable)
|
||||||
value &= ~SPI_CS_CONTROL_CS_HIGH;
|
value &= ~SPI_CS_CONTROL_CS_HIGH;
|
||||||
@ -316,7 +307,7 @@ static void cs_assert(struct driver_data *drv_data)
|
|||||||
struct chip_data *chip = drv_data->cur_chip;
|
struct chip_data *chip = drv_data->cur_chip;
|
||||||
|
|
||||||
if (drv_data->ssp_type == CE4100_SSP) {
|
if (drv_data->ssp_type == CE4100_SSP) {
|
||||||
write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSSR, drv_data->cur_chip->frm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +321,7 @@ static void cs_assert(struct driver_data *drv_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_cs_control(drv_data, true);
|
lpss_ssp_cs_control(drv_data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,6 +342,7 @@ static void cs_deassert(struct driver_data *drv_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_cs_control(drv_data, false);
|
lpss_ssp_cs_control(drv_data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,13 +350,10 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
|
|||||||
{
|
{
|
||||||
unsigned long limit = loops_per_jiffy << 1;
|
unsigned long limit = loops_per_jiffy << 1;
|
||||||
|
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
while (read_SSSR(reg) & SSSR_RNE) {
|
while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
|
||||||
read_SSDR(reg);
|
pxa2xx_spi_read(drv_data, SSDR);
|
||||||
}
|
} while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit);
|
||||||
} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
|
|
||||||
write_SSSR_CS(drv_data, SSSR_ROR);
|
write_SSSR_CS(drv_data, SSSR_ROR);
|
||||||
|
|
||||||
return limit;
|
return limit;
|
||||||
@ -371,14 +361,13 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int null_writer(struct driver_data *drv_data)
|
static int null_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
u8 n_bytes = drv_data->n_bytes;
|
u8 n_bytes = drv_data->n_bytes;
|
||||||
|
|
||||||
if (pxa2xx_spi_txfifo_full(drv_data)
|
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;
|
||||||
|
|
||||||
write_SSDR(0, reg);
|
pxa2xx_spi_write(drv_data, SSDR, 0);
|
||||||
drv_data->tx += n_bytes;
|
drv_data->tx += n_bytes;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -386,12 +375,11 @@ static int null_writer(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int null_reader(struct driver_data *drv_data)
|
static int null_reader(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
u8 n_bytes = drv_data->n_bytes;
|
u8 n_bytes = drv_data->n_bytes;
|
||||||
|
|
||||||
while ((read_SSSR(reg) & SSSR_RNE)
|
while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
|
||||||
&& (drv_data->rx < drv_data->rx_end)) {
|
&& (drv_data->rx < drv_data->rx_end)) {
|
||||||
read_SSDR(reg);
|
pxa2xx_spi_read(drv_data, SSDR);
|
||||||
drv_data->rx += n_bytes;
|
drv_data->rx += n_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,13 +388,11 @@ static int null_reader(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u8_writer(struct driver_data *drv_data)
|
static int u8_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
if (pxa2xx_spi_txfifo_full(drv_data)
|
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;
|
||||||
|
|
||||||
write_SSDR(*(u8 *)(drv_data->tx), reg);
|
pxa2xx_spi_write(drv_data, SSDR, *(u8 *)(drv_data->tx));
|
||||||
++drv_data->tx;
|
++drv_data->tx;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -414,11 +400,9 @@ static int u8_writer(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u8_reader(struct driver_data *drv_data)
|
static int u8_reader(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
|
||||||
|
|
||||||
while ((read_SSSR(reg) & SSSR_RNE)
|
|
||||||
&& (drv_data->rx < drv_data->rx_end)) {
|
&& (drv_data->rx < drv_data->rx_end)) {
|
||||||
*(u8 *)(drv_data->rx) = read_SSDR(reg);
|
*(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
|
||||||
++drv_data->rx;
|
++drv_data->rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,13 +411,11 @@ static int u8_reader(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u16_writer(struct driver_data *drv_data)
|
static int u16_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
if (pxa2xx_spi_txfifo_full(drv_data)
|
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;
|
||||||
|
|
||||||
write_SSDR(*(u16 *)(drv_data->tx), reg);
|
pxa2xx_spi_write(drv_data, SSDR, *(u16 *)(drv_data->tx));
|
||||||
drv_data->tx += 2;
|
drv_data->tx += 2;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -441,11 +423,9 @@ static int u16_writer(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u16_reader(struct driver_data *drv_data)
|
static int u16_reader(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
|
||||||
|
|
||||||
while ((read_SSSR(reg) & SSSR_RNE)
|
|
||||||
&& (drv_data->rx < drv_data->rx_end)) {
|
&& (drv_data->rx < drv_data->rx_end)) {
|
||||||
*(u16 *)(drv_data->rx) = read_SSDR(reg);
|
*(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
|
||||||
drv_data->rx += 2;
|
drv_data->rx += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,13 +434,11 @@ static int u16_reader(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u32_writer(struct driver_data *drv_data)
|
static int u32_writer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
if (pxa2xx_spi_txfifo_full(drv_data)
|
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;
|
||||||
|
|
||||||
write_SSDR(*(u32 *)(drv_data->tx), reg);
|
pxa2xx_spi_write(drv_data, SSDR, *(u32 *)(drv_data->tx));
|
||||||
drv_data->tx += 4;
|
drv_data->tx += 4;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -468,11 +446,9 @@ static int u32_writer(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static int u32_reader(struct driver_data *drv_data)
|
static int u32_reader(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
|
||||||
|
|
||||||
while ((read_SSSR(reg) & SSSR_RNE)
|
|
||||||
&& (drv_data->rx < drv_data->rx_end)) {
|
&& (drv_data->rx < drv_data->rx_end)) {
|
||||||
*(u32 *)(drv_data->rx) = read_SSDR(reg);
|
*(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
|
||||||
drv_data->rx += 4;
|
drv_data->rx += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,27 +524,25 @@ static void giveback(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static void reset_sccr1(struct driver_data *drv_data)
|
static void reset_sccr1(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
struct chip_data *chip = drv_data->cur_chip;
|
struct chip_data *chip = drv_data->cur_chip;
|
||||||
u32 sccr1_reg;
|
u32 sccr1_reg;
|
||||||
|
|
||||||
sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
|
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
|
||||||
sccr1_reg &= ~SSCR1_RFT;
|
sccr1_reg &= ~SSCR1_RFT;
|
||||||
sccr1_reg |= chip->threshold;
|
sccr1_reg |= chip->threshold;
|
||||||
write_SSCR1(sccr1_reg, reg);
|
pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void int_error_stop(struct driver_data *drv_data, const char* msg)
|
static void int_error_stop(struct driver_data *drv_data, const char* msg)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
/* Stop and reset SSP */
|
/* Stop and reset SSP */
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
reset_sccr1(drv_data);
|
reset_sccr1(drv_data);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
pxa2xx_spi_flush(drv_data);
|
pxa2xx_spi_flush(drv_data);
|
||||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
|
||||||
|
|
||||||
dev_err(&drv_data->pdev->dev, "%s\n", msg);
|
dev_err(&drv_data->pdev->dev, "%s\n", msg);
|
||||||
|
|
||||||
@ -578,13 +552,11 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
|
|||||||
|
|
||||||
static void int_transfer_complete(struct driver_data *drv_data)
|
static void int_transfer_complete(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
|
|
||||||
/* Stop SSP */
|
/* Stop SSP */
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
reset_sccr1(drv_data);
|
reset_sccr1(drv_data);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
|
|
||||||
/* Update total byte transferred return count actual bytes read */
|
/* Update total byte transferred return count actual bytes read */
|
||||||
drv_data->cur_msg->actual_length += drv_data->len -
|
drv_data->cur_msg->actual_length += drv_data->len -
|
||||||
@ -603,12 +575,10 @@ static void int_transfer_complete(struct driver_data *drv_data)
|
|||||||
|
|
||||||
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ?
|
||||||
|
|
||||||
u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
|
|
||||||
drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
|
drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
|
||||||
|
|
||||||
u32 irq_status = read_SSSR(reg) & irq_mask;
|
u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask;
|
||||||
|
|
||||||
if (irq_status & SSSR_ROR) {
|
if (irq_status & SSSR_ROR) {
|
||||||
int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
|
int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
|
||||||
@ -616,7 +586,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (irq_status & SSSR_TINT) {
|
if (irq_status & SSSR_TINT) {
|
||||||
write_SSSR(SSSR_TINT, reg);
|
pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
|
||||||
if (drv_data->read(drv_data)) {
|
if (drv_data->read(drv_data)) {
|
||||||
int_transfer_complete(drv_data);
|
int_transfer_complete(drv_data);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@ -640,7 +610,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|||||||
u32 bytes_left;
|
u32 bytes_left;
|
||||||
u32 sccr1_reg;
|
u32 sccr1_reg;
|
||||||
|
|
||||||
sccr1_reg = read_SSCR1(reg);
|
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
|
||||||
sccr1_reg &= ~SSCR1_TIE;
|
sccr1_reg &= ~SSCR1_TIE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -666,7 +636,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|||||||
|
|
||||||
pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre);
|
pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre);
|
||||||
}
|
}
|
||||||
write_SSCR1(sccr1_reg, reg);
|
pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We did something */
|
/* We did something */
|
||||||
@ -676,7 +646,6 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|||||||
static irqreturn_t ssp_int(int irq, void *dev_id)
|
static irqreturn_t ssp_int(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct driver_data *drv_data = dev_id;
|
struct driver_data *drv_data = dev_id;
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
u32 sccr1_reg;
|
u32 sccr1_reg;
|
||||||
u32 mask = drv_data->mask_sr;
|
u32 mask = drv_data->mask_sr;
|
||||||
u32 status;
|
u32 status;
|
||||||
@ -696,11 +665,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|||||||
* are all set to one. That means that the device is already
|
* are all set to one. That means that the device is already
|
||||||
* powered off.
|
* powered off.
|
||||||
*/
|
*/
|
||||||
status = read_SSSR(reg);
|
status = pxa2xx_spi_read(drv_data, SSSR);
|
||||||
if (status == ~0)
|
if (status == ~0)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
sccr1_reg = read_SSCR1(reg);
|
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
|
||||||
|
|
||||||
/* Ignore possible writes if we don't need to write */
|
/* Ignore possible writes if we don't need to write */
|
||||||
if (!(sccr1_reg & SSCR1_TIE))
|
if (!(sccr1_reg & SSCR1_TIE))
|
||||||
@ -711,10 +680,14 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|||||||
|
|
||||||
if (!drv_data->cur_msg) {
|
if (!drv_data->cur_msg) {
|
||||||
|
|
||||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
pxa2xx_spi_read(drv_data, SSCR0)
|
||||||
|
& ~SSCR0_SSE);
|
||||||
|
pxa2xx_spi_write(drv_data, SSCR1,
|
||||||
|
pxa2xx_spi_read(drv_data, SSCR1)
|
||||||
|
& ~drv_data->int_cr1);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, reg);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
|
|
||||||
dev_err(&drv_data->pdev->dev,
|
dev_err(&drv_data->pdev->dev,
|
||||||
@ -783,7 +756,6 @@ static void pump_transfers(unsigned long data)
|
|||||||
struct spi_transfer *transfer = NULL;
|
struct spi_transfer *transfer = NULL;
|
||||||
struct spi_transfer *previous = NULL;
|
struct spi_transfer *previous = NULL;
|
||||||
struct chip_data *chip = NULL;
|
struct chip_data *chip = NULL;
|
||||||
void __iomem *reg = drv_data->ioaddr;
|
|
||||||
u32 clk_div = 0;
|
u32 clk_div = 0;
|
||||||
u8 bits = 0;
|
u8 bits = 0;
|
||||||
u32 speed = 0;
|
u32 speed = 0;
|
||||||
@ -927,7 +899,7 @@ static void pump_transfers(unsigned long data)
|
|||||||
|
|
||||||
/* Clear status and start DMA engine */
|
/* Clear status and start DMA engine */
|
||||||
cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
|
cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
|
||||||
write_SSSR(drv_data->clear_sr, reg);
|
pxa2xx_spi_write(drv_data, SSSR, drv_data->clear_sr);
|
||||||
|
|
||||||
pxa2xx_spi_dma_start(drv_data);
|
pxa2xx_spi_dma_start(drv_data);
|
||||||
} else {
|
} else {
|
||||||
@ -940,39 +912,43 @@ static void pump_transfers(unsigned long data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_lpss_ssp(drv_data)) {
|
if (is_lpss_ssp(drv_data)) {
|
||||||
if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold)
|
if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
|
||||||
write_SSIRF(chip->lpss_rx_threshold, reg);
|
!= chip->lpss_rx_threshold)
|
||||||
if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold)
|
pxa2xx_spi_write(drv_data, SSIRF,
|
||||||
write_SSITF(chip->lpss_tx_threshold, reg);
|
chip->lpss_rx_threshold);
|
||||||
|
if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff)
|
||||||
|
!= chip->lpss_tx_threshold)
|
||||||
|
pxa2xx_spi_write(drv_data, SSITF,
|
||||||
|
chip->lpss_tx_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_quark_x1000_ssp(drv_data) &&
|
if (is_quark_x1000_ssp(drv_data) &&
|
||||||
(read_DDS_RATE(reg) != chip->dds_rate))
|
(pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate))
|
||||||
write_DDS_RATE(chip->dds_rate, reg);
|
pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate);
|
||||||
|
|
||||||
/* see if we need to reload the config registers */
|
/* see if we need to reload the config registers */
|
||||||
if ((read_SSCR0(reg) != cr0) ||
|
if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0)
|
||||||
(read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) {
|
|| (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
|
||||||
|
!= (cr1 & change_mask)) {
|
||||||
/* stop the SSP, and update the other bits */
|
/* stop the SSP, and update the other bits */
|
||||||
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
|
pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(chip->timeout, reg);
|
pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
|
||||||
/* first set CR1 without interrupt and service enables */
|
/* first set CR1 without interrupt and service enables */
|
||||||
write_SSCR1(cr1 & change_mask, reg);
|
pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask);
|
||||||
/* restart the SSP */
|
/* restart the SSP */
|
||||||
write_SSCR0(cr0, reg);
|
pxa2xx_spi_write(drv_data, SSCR0, cr0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(chip->timeout, reg);
|
pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
cs_assert(drv_data);
|
cs_assert(drv_data);
|
||||||
|
|
||||||
/* after chip select, release the data by enabling service
|
/* after chip select, release the data by enabling service
|
||||||
* requests and interrupts, without changing any mode bits */
|
* requests and interrupts, without changing any mode bits */
|
||||||
write_SSCR1(cr1, reg);
|
pxa2xx_spi_write(drv_data, SSCR1, cr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
|
static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
|
||||||
@ -1001,8 +977,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
|
|||||||
struct driver_data *drv_data = spi_master_get_devdata(master);
|
struct driver_data *drv_data = spi_master_get_devdata(master);
|
||||||
|
|
||||||
/* Disable the SSP now */
|
/* Disable the SSP now */
|
||||||
write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
drv_data->ioaddr);
|
pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1285,6 +1261,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
|||||||
struct driver_data *drv_data;
|
struct driver_data *drv_data;
|
||||||
struct ssp_device *ssp;
|
struct ssp_device *ssp;
|
||||||
int status;
|
int status;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
platform_info = dev_get_platdata(dev);
|
platform_info = dev_get_platdata(dev);
|
||||||
if (!platform_info) {
|
if (!platform_info) {
|
||||||
@ -1382,37 +1359,34 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
|||||||
drv_data->max_clk_rate = clk_get_rate(ssp->clk);
|
drv_data->max_clk_rate = clk_get_rate(ssp->clk);
|
||||||
|
|
||||||
/* Load default SSP configuration */
|
/* Load default SSP configuration */
|
||||||
write_SSCR0(0, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSCR0, 0);
|
||||||
switch (drv_data->ssp_type) {
|
switch (drv_data->ssp_type) {
|
||||||
case QUARK_X1000_SSP:
|
case QUARK_X1000_SSP:
|
||||||
write_SSCR1(QUARK_X1000_SSCR1_RxTresh(
|
tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT)
|
||||||
RX_THRESH_QUARK_X1000_DFLT) |
|
| QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
|
||||||
QUARK_X1000_SSCR1_TxTresh(
|
pxa2xx_spi_write(drv_data, SSCR1, tmp);
|
||||||
TX_THRESH_QUARK_X1000_DFLT),
|
|
||||||
drv_data->ioaddr);
|
|
||||||
|
|
||||||
/* using the Motorola SPI protocol and use 8 bit frame */
|
/* using the Motorola SPI protocol and use 8 bit frame */
|
||||||
write_SSCR0(QUARK_X1000_SSCR0_Motorola
|
pxa2xx_spi_write(drv_data, SSCR0,
|
||||||
| QUARK_X1000_SSCR0_DataSize(8),
|
QUARK_X1000_SSCR0_Motorola
|
||||||
drv_data->ioaddr);
|
| QUARK_X1000_SSCR0_DataSize(8));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
|
tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
|
||||||
SSCR1_TxTresh(TX_THRESH_DFLT),
|
SSCR1_TxTresh(TX_THRESH_DFLT);
|
||||||
drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSCR1, tmp);
|
||||||
write_SSCR0(SSCR0_SCR(2)
|
tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8);
|
||||||
| SSCR0_Motorola
|
pxa2xx_spi_write(drv_data, SSCR0, tmp);
|
||||||
| SSCR0_DataSize(8),
|
|
||||||
drv_data->ioaddr);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pxa25x_ssp_comp(drv_data))
|
if (!pxa25x_ssp_comp(drv_data))
|
||||||
write_SSTO(0, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||||
|
|
||||||
if (!is_quark_x1000_ssp(drv_data))
|
if (!is_quark_x1000_ssp(drv_data))
|
||||||
write_SSPSP(0, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSPSP, 0);
|
||||||
|
|
||||||
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_setup(drv_data);
|
lpss_ssp_setup(drv_data);
|
||||||
|
|
||||||
tasklet_init(&drv_data->pump_transfers, pump_transfers,
|
tasklet_init(&drv_data->pump_transfers, pump_transfers,
|
||||||
@ -1456,7 +1430,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_get_sync(&pdev->dev);
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
|
|
||||||
/* Disable the SSP at the peripheral and SOC level */
|
/* Disable the SSP at the peripheral and SOC level */
|
||||||
write_SSCR0(0, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSCR0, 0);
|
||||||
clk_disable_unprepare(ssp->clk);
|
clk_disable_unprepare(ssp->clk);
|
||||||
|
|
||||||
/* Release DMA */
|
/* Release DMA */
|
||||||
@ -1493,7 +1467,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
|
|||||||
status = spi_master_suspend(drv_data->master);
|
status = spi_master_suspend(drv_data->master);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
return status;
|
return status;
|
||||||
write_SSCR0(0, drv_data->ioaddr);
|
pxa2xx_spi_write(drv_data, SSCR0, 0);
|
||||||
|
|
||||||
if (!pm_runtime_suspended(dev))
|
if (!pm_runtime_suspended(dev))
|
||||||
clk_disable_unprepare(ssp->clk);
|
clk_disable_unprepare(ssp->clk);
|
||||||
@ -1514,6 +1488,7 @@ static int pxa2xx_spi_resume(struct device *dev)
|
|||||||
clk_prepare_enable(ssp->clk);
|
clk_prepare_enable(ssp->clk);
|
||||||
|
|
||||||
/* Restore LPSS private register bits */
|
/* Restore LPSS private register bits */
|
||||||
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_setup(drv_data);
|
lpss_ssp_setup(drv_data);
|
||||||
|
|
||||||
/* Start the queue running */
|
/* Start the queue running */
|
||||||
|
@ -115,23 +115,17 @@ struct chip_data {
|
|||||||
void (*cs_control)(u32 command);
|
void (*cs_control)(u32 command);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFINE_SSP_REG(reg, off) \
|
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data,
|
||||||
static inline u32 read_##reg(void const __iomem *p) \
|
unsigned reg)
|
||||||
{ return __raw_readl(p + (off)); } \
|
{
|
||||||
\
|
return __raw_readl(drv_data->ioaddr + reg);
|
||||||
static inline void write_##reg(u32 v, void __iomem *p) \
|
}
|
||||||
{ __raw_writel(v, p + (off)); }
|
|
||||||
|
|
||||||
DEFINE_SSP_REG(SSCR0, 0x00)
|
static inline void pxa2xx_spi_write(const struct driver_data *drv_data,
|
||||||
DEFINE_SSP_REG(SSCR1, 0x04)
|
unsigned reg, u32 val)
|
||||||
DEFINE_SSP_REG(SSSR, 0x08)
|
{
|
||||||
DEFINE_SSP_REG(SSITR, 0x0c)
|
__raw_writel(val, drv_data->ioaddr + reg);
|
||||||
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)
|
|
||||||
DEFINE_SSP_REG(SSIRF, SSIRF)
|
|
||||||
|
|
||||||
#define START_STATE ((void *)0)
|
#define START_STATE ((void *)0)
|
||||||
#define RUNNING_STATE ((void *)1)
|
#define RUNNING_STATE ((void *)1)
|
||||||
@ -155,13 +149,11 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
|
|||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (drv_data->ssp_type == CE4100_SSP ||
|
if (drv_data->ssp_type == CE4100_SSP ||
|
||||||
drv_data->ssp_type == QUARK_X1000_SSP)
|
drv_data->ssp_type == QUARK_X1000_SSP)
|
||||||
val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
|
val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK;
|
||||||
|
|
||||||
write_SSSR(val, reg);
|
pxa2xx_spi_write(drv_data, SSSR, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int pxa2xx_spi_flush(struct driver_data *drv_data);
|
extern int pxa2xx_spi_flush(struct driver_data *drv_data);
|
||||||
|
@ -337,7 +337,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
|
|||||||
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
{
|
{
|
||||||
struct spi_qup *controller = spi_master_get_devdata(spi->master);
|
struct spi_qup *controller = spi_master_get_devdata(spi->master);
|
||||||
u32 config, iomode, mode;
|
u32 config, iomode, mode, control;
|
||||||
int ret, n_words, w_size;
|
int ret, n_words, w_size;
|
||||||
|
|
||||||
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
|
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
|
||||||
@ -392,6 +392,15 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
|||||||
|
|
||||||
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
|
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
|
||||||
|
|
||||||
|
control = readl_relaxed(controller->base + SPI_IO_CONTROL);
|
||||||
|
|
||||||
|
if (spi->mode & SPI_CPOL)
|
||||||
|
control |= SPI_IO_C_CLK_IDLE_HIGH;
|
||||||
|
else
|
||||||
|
control &= ~SPI_IO_C_CLK_IDLE_HIGH;
|
||||||
|
|
||||||
|
writel_relaxed(control, controller->base + SPI_IO_CONTROL);
|
||||||
|
|
||||||
config = readl_relaxed(controller->base + SPI_CONFIG);
|
config = readl_relaxed(controller->base + SPI_CONFIG);
|
||||||
|
|
||||||
if (spi->mode & SPI_LOOP)
|
if (spi->mode & SPI_LOOP)
|
||||||
|
@ -437,6 +437,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
|
|||||||
rs->state &= ~TXBUSY;
|
rs->state &= ~TXBUSY;
|
||||||
spin_unlock_irqrestore(&rs->lock, flags);
|
spin_unlock_irqrestore(&rs->lock, flags);
|
||||||
|
|
||||||
|
rxdesc = NULL;
|
||||||
if (rs->rx) {
|
if (rs->rx) {
|
||||||
rxconf.direction = rs->dma_rx.direction;
|
rxconf.direction = rs->dma_rx.direction;
|
||||||
rxconf.src_addr = rs->dma_rx.addr;
|
rxconf.src_addr = rs->dma_rx.addr;
|
||||||
@ -453,6 +454,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
|
|||||||
rxdesc->callback_param = rs;
|
rxdesc->callback_param = rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txdesc = NULL;
|
||||||
if (rs->tx) {
|
if (rs->tx) {
|
||||||
txconf.direction = rs->dma_tx.direction;
|
txconf.direction = rs->dma_tx.direction;
|
||||||
txconf.dst_addr = rs->dma_tx.addr;
|
txconf.dst_addr = rs->dma_tx.addr;
|
||||||
@ -470,7 +472,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* rx must be started before tx due to spi instinct */
|
/* rx must be started before tx due to spi instinct */
|
||||||
if (rs->rx) {
|
if (rxdesc) {
|
||||||
spin_lock_irqsave(&rs->lock, flags);
|
spin_lock_irqsave(&rs->lock, flags);
|
||||||
rs->state |= RXBUSY;
|
rs->state |= RXBUSY;
|
||||||
spin_unlock_irqrestore(&rs->lock, flags);
|
spin_unlock_irqrestore(&rs->lock, flags);
|
||||||
@ -478,7 +480,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
|
|||||||
dma_async_issue_pending(rs->dma_rx.ch);
|
dma_async_issue_pending(rs->dma_rx.ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rs->tx) {
|
if (txdesc) {
|
||||||
spin_lock_irqsave(&rs->lock, flags);
|
spin_lock_irqsave(&rs->lock, flags);
|
||||||
rs->state |= TXBUSY;
|
rs->state |= TXBUSY;
|
||||||
spin_unlock_irqrestore(&rs->lock, flags);
|
spin_unlock_irqrestore(&rs->lock, flags);
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#define SSDR (0x10) /* SSP Data Write/Data Read Register */
|
#define SSDR (0x10) /* SSP Data Write/Data Read Register */
|
||||||
|
|
||||||
#define SSTO (0x28) /* SSP Time Out Register */
|
#define SSTO (0x28) /* SSP Time Out Register */
|
||||||
|
#define DDS_RATE (0x28) /* SSP DDS Clock Rate Register (Intel Quark) */
|
||||||
#define SSPSP (0x2C) /* SSP Programmable Serial Protocol */
|
#define SSPSP (0x2C) /* SSP Programmable Serial Protocol */
|
||||||
#define SSTSA (0x30) /* SSP Tx Timeslot Active */
|
#define SSTSA (0x30) /* SSP Tx Timeslot Active */
|
||||||
#define SSRSA (0x34) /* SSP Rx Timeslot Active */
|
#define SSRSA (0x34) /* SSP Rx Timeslot Active */
|
||||||
|
@ -53,7 +53,6 @@ struct pxa2xx_spi_chip {
|
|||||||
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <mach/dma.h>
|
|
||||||
|
|
||||||
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
|
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user