|
@@ -163,7 +163,10 @@ struct chip_data {
|
|
u8 enable_dma;
|
|
u8 enable_dma;
|
|
u8 bits_per_word;
|
|
u8 bits_per_word;
|
|
u32 speed_hz;
|
|
u32 speed_hz;
|
|
- int gpio_cs;
|
|
|
|
|
|
+ union {
|
|
|
|
+ int gpio_cs;
|
|
|
|
+ unsigned int frm;
|
|
|
|
+ };
|
|
int gpio_cs_inverted;
|
|
int gpio_cs_inverted;
|
|
int (*write)(struct driver_data *drv_data);
|
|
int (*write)(struct driver_data *drv_data);
|
|
int (*read)(struct driver_data *drv_data);
|
|
int (*read)(struct driver_data *drv_data);
|
|
@@ -176,6 +179,11 @@ 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) {
|
|
|
|
+ write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (chip->cs_control) {
|
|
if (chip->cs_control) {
|
|
chip->cs_control(PXA2XX_CS_ASSERT);
|
|
chip->cs_control(PXA2XX_CS_ASSERT);
|
|
return;
|
|
return;
|
|
@@ -189,6 +197,9 @@ static void cs_deassert(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)
|
|
|
|
+ return;
|
|
|
|
+
|
|
if (chip->cs_control) {
|
|
if (chip->cs_control) {
|
|
chip->cs_control(PXA2XX_CS_DEASSERT);
|
|
chip->cs_control(PXA2XX_CS_DEASSERT);
|
|
return;
|
|
return;
|
|
@@ -198,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
|
|
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
|
|
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
|
|
|
|
+{
|
|
|
|
+ void __iomem *reg = drv_data->ioaddr;
|
|
|
|
+
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
|
+ val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
|
|
|
|
+
|
|
|
|
+ write_SSSR(val, reg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pxa25x_ssp_comp(struct driver_data *drv_data)
|
|
|
|
+{
|
|
|
|
+ if (drv_data->ssp_type == PXA25x_SSP)
|
|
|
|
+ return 1;
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
|
+ return 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int flush(struct driver_data *drv_data)
|
|
static int flush(struct driver_data *drv_data)
|
|
{
|
|
{
|
|
unsigned long limit = loops_per_jiffy << 1;
|
|
unsigned long limit = loops_per_jiffy << 1;
|
|
@@ -209,7 +239,7 @@ static int flush(struct driver_data *drv_data)
|
|
read_SSDR(reg);
|
|
read_SSDR(reg);
|
|
}
|
|
}
|
|
} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
|
|
} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
|
|
- write_SSSR(SSSR_ROR, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, SSSR_ROR);
|
|
|
|
|
|
return limit;
|
|
return limit;
|
|
}
|
|
}
|
|
@@ -502,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
|
|
/* 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(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, reg);
|
|
write_SSTO(0, reg);
|
|
flush(drv_data);
|
|
flush(drv_data);
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
@@ -524,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data)
|
|
|
|
|
|
/* 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);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
@@ -617,7 +647,7 @@ static irqreturn_t 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 (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, reg);
|
|
write_SSTO(0, reg);
|
|
|
|
|
|
/* finish this transfer, start the next */
|
|
/* finish this transfer, start the next */
|
|
@@ -635,9 +665,9 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
/* Stop and reset SSP */
|
|
/* Stop and reset SSP */
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, reg);
|
|
write_SSTO(0, reg);
|
|
flush(drv_data);
|
|
flush(drv_data);
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
@@ -653,9 +683,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
/* Stop SSP */
|
|
/* Stop SSP */
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, reg);
|
|
write_SSTO(0, reg);
|
|
|
|
|
|
/* Update total byte transfered return count actual bytes read */
|
|
/* Update total byte transfered return count actual bytes read */
|
|
@@ -711,7 +741,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|
if (drv_data->tx == drv_data->tx_end) {
|
|
if (drv_data->tx == drv_data->tx_end) {
|
|
write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
|
|
/* PXA25x_SSP has no timeout, read trailing bytes */
|
|
/* PXA25x_SSP has no timeout, read trailing bytes */
|
|
- if (drv_data->ssp_type == PXA25x_SSP) {
|
|
|
|
|
|
+ if (pxa25x_ssp_comp(drv_data)) {
|
|
if (!wait_ssp_rx_stall(reg))
|
|
if (!wait_ssp_rx_stall(reg))
|
|
{
|
|
{
|
|
int_error_stop(drv_data, "interrupt_transfer: "
|
|
int_error_stop(drv_data, "interrupt_transfer: "
|
|
@@ -754,9 +784,9 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|
|
|
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, reg);
|
|
write_SSTO(0, reg);
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
|
|
|
dev_err(&drv_data->pdev->dev, "bad message state "
|
|
dev_err(&drv_data->pdev->dev, "bad message state "
|
|
"in interrupt handler\n");
|
|
"in interrupt handler\n");
|
|
@@ -869,7 +899,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
|
|
{
|
|
{
|
|
unsigned long ssp_clk = clk_get_rate(ssp->clk);
|
|
unsigned long ssp_clk = clk_get_rate(ssp->clk);
|
|
|
|
|
|
- if (ssp->type == PXA25x_SSP)
|
|
|
|
|
|
+ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
|
|
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
|
|
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
|
|
else
|
|
else
|
|
return ((ssp_clk / rate - 1) & 0xfff) << 8;
|
|
return ((ssp_clk / rate - 1) & 0xfff) << 8;
|
|
@@ -1095,7 +1125,7 @@ static void pump_transfers(unsigned long data)
|
|
|
|
|
|
/* Clear status */
|
|
/* Clear status */
|
|
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
|
|
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
}
|
|
}
|
|
|
|
|
|
/* see if we need to reload the config registers */
|
|
/* see if we need to reload the config registers */
|
|
@@ -1105,7 +1135,7 @@ static void pump_transfers(unsigned long data)
|
|
|
|
|
|
/* 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 (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ 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 & SSCR1_CHANGE_MASK, reg);
|
|
@@ -1113,7 +1143,7 @@ static void pump_transfers(unsigned long data)
|
|
write_SSCR0(cr0, reg);
|
|
write_SSCR0(cr0, reg);
|
|
|
|
|
|
} else {
|
|
} else {
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(chip->timeout, reg);
|
|
write_SSTO(chip->timeout, reg);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1240,14 +1270,13 @@ static int setup(struct spi_device *spi)
|
|
uint tx_thres = TX_THRESH_DFLT;
|
|
uint tx_thres = TX_THRESH_DFLT;
|
|
uint rx_thres = RX_THRESH_DFLT;
|
|
uint rx_thres = RX_THRESH_DFLT;
|
|
|
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data)
|
|
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
|
|
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
"b/w not 4-32 for type non-PXA25x_SSP\n",
|
|
"b/w not 4-32 for type non-PXA25x_SSP\n",
|
|
drv_data->ssp_type, spi->bits_per_word);
|
|
drv_data->ssp_type, spi->bits_per_word);
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- }
|
|
|
|
- else if (drv_data->ssp_type == PXA25x_SSP
|
|
|
|
|
|
+ } else if (pxa25x_ssp_comp(drv_data)
|
|
&& (spi->bits_per_word < 4
|
|
&& (spi->bits_per_word < 4
|
|
|| spi->bits_per_word > 16)) {
|
|
|| spi->bits_per_word > 16)) {
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
@@ -1266,7 +1295,17 @@ static int setup(struct spi_device *spi)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- chip->gpio_cs = -1;
|
|
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP) {
|
|
|
|
+ if (spi->chip_select > 4) {
|
|
|
|
+ dev_err(&spi->dev, "failed setup: "
|
|
|
|
+ "cs number must not be > 4.\n");
|
|
|
|
+ kfree(chip);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ chip->frm = spi->chip_select;
|
|
|
|
+ } else
|
|
|
|
+ chip->gpio_cs = -1;
|
|
chip->enable_dma = 0;
|
|
chip->enable_dma = 0;
|
|
chip->timeout = TIMOUT_DFLT;
|
|
chip->timeout = TIMOUT_DFLT;
|
|
chip->dma_burst_size = drv_data->master_info->enable_dma ?
|
|
chip->dma_burst_size = drv_data->master_info->enable_dma ?
|
|
@@ -1322,7 +1361,7 @@ static int setup(struct spi_device *spi)
|
|
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|
|
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|
|
|
|
|
|
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
|
|
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
|
|
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
|
|
clk_get_rate(ssp->clk)
|
|
clk_get_rate(ssp->clk)
|
|
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
|
|
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
|
|
@@ -1357,17 +1396,21 @@ static int setup(struct spi_device *spi)
|
|
|
|
|
|
spi_set_ctldata(spi, chip);
|
|
spi_set_ctldata(spi, chip);
|
|
|
|
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
return setup_cs(spi, chip, chip_info);
|
|
return setup_cs(spi, chip, chip_info);
|
|
}
|
|
}
|
|
|
|
|
|
static void cleanup(struct spi_device *spi)
|
|
static void cleanup(struct spi_device *spi)
|
|
{
|
|
{
|
|
struct chip_data *chip = spi_get_ctldata(spi);
|
|
struct chip_data *chip = spi_get_ctldata(spi);
|
|
|
|
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
|
|
|
|
|
|
if (!chip)
|
|
if (!chip)
|
|
return;
|
|
return;
|
|
|
|
|
|
- if (gpio_is_valid(chip->gpio_cs))
|
|
|
|
|
|
+ if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
|
|
gpio_free(chip->gpio_cs);
|
|
gpio_free(chip->gpio_cs);
|
|
|
|
|
|
kfree(chip);
|
|
kfree(chip);
|
|
@@ -1507,7 +1550,7 @@ static int __devinit 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 (ssp->type == PXA25x_SSP) {
|
|
|
|
|
|
+ if (pxa25x_ssp_comp(drv_data)) {
|
|
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;
|
|
@@ -1569,7 +1612,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
|
|
| SSCR0_Motorola
|
|
| SSCR0_Motorola
|
|
| SSCR0_DataSize(8),
|
|
| SSCR0_DataSize(8),
|
|
drv_data->ioaddr);
|
|
drv_data->ioaddr);
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
write_SSTO(0, drv_data->ioaddr);
|
|
write_SSTO(0, drv_data->ioaddr);
|
|
write_SSPSP(0, drv_data->ioaddr);
|
|
write_SSPSP(0, drv_data->ioaddr);
|
|
|
|
|