|
@@ -80,6 +80,73 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
|
|
|
return drv_data->ssp_type == LPSS_SSP;
|
|
|
}
|
|
|
|
|
|
+static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
|
|
|
+{
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ return SSCR1_CHANGE_MASK;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static u32
|
|
|
+pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data)
|
|
|
+{
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ return RX_THRESH_DFLT;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
|
|
|
+{
|
|
|
+ void __iomem *reg = drv_data->ioaddr;
|
|
|
+ u32 mask;
|
|
|
+
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ mask = SSSR_TFL_MASK;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (read_SSSR(reg) & mask) == mask;
|
|
|
+}
|
|
|
+
|
|
|
+static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
|
|
|
+ u32 *sccr1_reg)
|
|
|
+{
|
|
|
+ u32 mask;
|
|
|
+
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ mask = SSCR1_RFT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ *sccr1_reg &= ~mask;
|
|
|
+}
|
|
|
+
|
|
|
+static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data,
|
|
|
+ u32 *sccr1_reg, u32 threshold)
|
|
|
+{
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ *sccr1_reg |= SSCR1_RxTresh(threshold);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data,
|
|
|
+ u32 clk_div, u8 bits)
|
|
|
+{
|
|
|
+ switch (drv_data->ssp_type) {
|
|
|
+ default:
|
|
|
+ return clk_div
|
|
|
+ | SSCR0_Motorola
|
|
|
+ | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
|
|
|
+ | SSCR0_SSE
|
|
|
+ | (bits > 16 ? SSCR0_EDSS : 0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Read and write LPSS SSP private registers. Caller must first check that
|
|
|
* is_lpss_ssp() returns true before these can be called.
|
|
@@ -234,7 +301,7 @@ static int null_writer(struct driver_data *drv_data)
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
u8 n_bytes = drv_data->n_bytes;
|
|
|
|
|
|
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
+ if (pxa2xx_spi_txfifo_full(drv_data)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -262,7 +329,7 @@ static int u8_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
+ if (pxa2xx_spi_txfifo_full(drv_data)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -289,7 +356,7 @@ static int u16_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
+ if (pxa2xx_spi_txfifo_full(drv_data)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -316,7 +383,7 @@ static int u32_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
+ if (pxa2xx_spi_txfifo_full(drv_data)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -508,8 +575,9 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|
|
* remaining RX bytes.
|
|
|
*/
|
|
|
if (pxa25x_ssp_comp(drv_data)) {
|
|
|
+ u32 rx_thre;
|
|
|
|
|
|
- sccr1_reg &= ~SSCR1_RFT;
|
|
|
+ pxa2xx_spi_clear_rx_thre(drv_data, &sccr1_reg);
|
|
|
|
|
|
bytes_left = drv_data->rx_end - drv_data->rx;
|
|
|
switch (drv_data->n_bytes) {
|
|
@@ -519,10 +587,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|
|
bytes_left >>= 1;
|
|
|
}
|
|
|
|
|
|
- if (bytes_left > RX_THRESH_DFLT)
|
|
|
- bytes_left = RX_THRESH_DFLT;
|
|
|
+ rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data);
|
|
|
+ if (rx_thre > bytes_left)
|
|
|
+ rx_thre = bytes_left;
|
|
|
|
|
|
- sccr1_reg |= SSCR1_RxTresh(bytes_left);
|
|
|
+ pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre);
|
|
|
}
|
|
|
write_SSCR1(sccr1_reg, reg);
|
|
|
}
|
|
@@ -613,6 +682,7 @@ static void pump_transfers(unsigned long data)
|
|
|
u32 cr1;
|
|
|
u32 dma_thresh = drv_data->cur_chip->dma_threshold;
|
|
|
u32 dma_burst = drv_data->cur_chip->dma_burst_size;
|
|
|
+ u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
|
|
|
|
|
|
/* Get current state information */
|
|
|
message = drv_data->cur_msg;
|
|
@@ -731,11 +801,7 @@ static void pump_transfers(unsigned long data)
|
|
|
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
|
|
|
}
|
|
|
|
|
|
- cr0 = clk_div
|
|
|
- | SSCR0_Motorola
|
|
|
- | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
|
|
|
- | SSCR0_SSE
|
|
|
- | (bits > 16 ? SSCR0_EDSS : 0);
|
|
|
+ cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
|
|
|
}
|
|
|
|
|
|
message->state = RUNNING_STATE;
|
|
@@ -772,16 +838,15 @@ static void pump_transfers(unsigned long data)
|
|
|
}
|
|
|
|
|
|
/* see if we need to reload the config registers */
|
|
|
- if ((read_SSCR0(reg) != cr0)
|
|
|
- || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
|
|
|
- (cr1 & SSCR1_CHANGE_MASK)) {
|
|
|
+ if ((read_SSCR0(reg) != cr0) ||
|
|
|
+ (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) {
|
|
|
|
|
|
/* stop the SSP, and update the other bits */
|
|
|
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
|
|
|
if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(chip->timeout, reg);
|
|
|
/* first set CR1 without interrupt and service enables */
|
|
|
- write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
|
|
|
+ write_SSCR1(cr1 & change_mask, reg);
|
|
|
/* restart the SSP */
|
|
|
write_SSCR0(cr0, reg);
|
|
|
|
|
@@ -959,12 +1024,8 @@ static int setup(struct spi_device *spi)
|
|
|
clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
|
|
|
chip->speed_hz = spi->max_speed_hz;
|
|
|
|
|
|
- chip->cr0 = clk_div
|
|
|
- | SSCR0_Motorola
|
|
|
- | SSCR0_DataSize(spi->bits_per_word > 16 ?
|
|
|
- spi->bits_per_word - 16 : spi->bits_per_word)
|
|
|
- | SSCR0_SSE
|
|
|
- | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
|
|
|
+ chip->cr0 = pxa2xx_configure_sscr0(drv_data, clk_div,
|
|
|
+ spi->bits_per_word);
|
|
|
chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
|
|
|
chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
|
|
|
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|