summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-pxa2xx.c107
1 files changed, 59 insertions, 48 deletions
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index a85b749..3fec31d 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -60,18 +60,51 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| QUARK_X1000_SSCR1_TFT \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
-#define LPSS_RX_THRESH_DFLT 64
-#define LPSS_TX_LOTHRESH_DFLT 160
-#define LPSS_TX_HITHRESH_DFLT 224
-
-/* Offset from drv_data->lpss_base */
-#define GENERAL_REG 0x08
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
-#define SSP_REG 0x0c
-#define SPI_CS_CONTROL 0x18
#define SPI_CS_CONTROL_SW_MODE BIT(0)
#define SPI_CS_CONTROL_CS_HIGH BIT(1)
+struct lpss_config {
+ /* LPSS offset from drv_data->ioaddr */
+ unsigned offset;
+ /* Register offsets from drv_data->lpss_base or -1 */
+ int reg_general;
+ int reg_ssp;
+ int reg_cs_ctrl;
+ /* FIFO thresholds */
+ u32 rx_threshold;
+ u32 tx_threshold_lo;
+ u32 tx_threshold_hi;
+};
+
+/* Keep these sorted with enum pxa_ssp_type */
+static const struct lpss_config lpss_platforms[] = {
+ { /* LPSS_LPT_SSP */
+ .offset = 0x800,
+ .reg_general = 0x08,
+ .reg_ssp = 0x0c,
+ .reg_cs_ctrl = 0x18,
+ .rx_threshold = 64,
+ .tx_threshold_lo = 160,
+ .tx_threshold_hi = 224,
+ },
+ { /* LPSS_BYT_SSP */
+ .offset = 0x400,
+ .reg_general = 0x08,
+ .reg_ssp = 0x0c,
+ .reg_cs_ctrl = 0x18,
+ .rx_threshold = 64,
+ .tx_threshold_lo = 160,
+ .tx_threshold_hi = 224,
+ },
+};
+
+static inline const struct lpss_config
+*lpss_get_config(const struct driver_data *drv_data)
+{
+ return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP];
+}
+
static bool is_lpss_ssp(const struct driver_data *drv_data)
{
switch (drv_data->ssp_type) {
@@ -198,63 +231,39 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
*/
static void lpss_ssp_setup(struct driver_data *drv_data)
{
- unsigned offset = 0x400;
- u32 value, orig;
-
- /*
- * Perform auto-detection of the LPSS SSP private registers. They
- * can be either at 1k or 2k offset from the base address.
- */
- orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-
- /* Test SPI_CS_CONTROL_SW_MODE bit enabling */
- value = orig | SPI_CS_CONTROL_SW_MODE;
- writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
- value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
- if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
- offset = 0x800;
- goto detection_done;
- }
-
- orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
-
- /* Test SPI_CS_CONTROL_SW_MODE bit disabling */
- value = orig & ~SPI_CS_CONTROL_SW_MODE;
- writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
- value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
- if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
- offset = 0x800;
- goto detection_done;
- }
+ const struct lpss_config *config;
+ u32 value;
-detection_done:
- /* Now set the LPSS base */
- drv_data->lpss_base = drv_data->ioaddr + offset;
+ config = lpss_get_config(drv_data);
+ drv_data->lpss_base = drv_data->ioaddr + config->offset;
/* Enable software chip select control */
value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
- __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+ __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
/* Enable multiblock DMA transfers */
if (drv_data->master_info->enable_dma) {
- __lpss_ssp_write_priv(drv_data, SSP_REG, 1);
+ __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
- value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
+ value = __lpss_ssp_read_priv(drv_data, config->reg_general);
value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
- __lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
+ __lpss_ssp_write_priv(drv_data, config->reg_general, value);
}
}
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
{
+ const struct lpss_config *config;
u32 value;
- value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
+ config = lpss_get_config(drv_data);
+
+ value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
if (enable)
value &= ~SPI_CS_CONTROL_CS_HIGH;
else
value |= SPI_CS_CONTROL_CS_HIGH;
- __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+ __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
}
static void cs_assert(struct driver_data *drv_data)
@@ -1081,6 +1090,7 @@ static int setup(struct spi_device *spi)
{
struct pxa2xx_spi_chip *chip_info = NULL;
struct chip_data *chip;
+ const struct lpss_config *config;
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
unsigned int clk_div;
uint tx_thres, tx_hi_thres, rx_thres;
@@ -1093,9 +1103,10 @@ static int setup(struct spi_device *spi)
break;
case LPSS_LPT_SSP:
case LPSS_BYT_SSP:
- tx_thres = LPSS_TX_LOTHRESH_DFLT;
- tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
- rx_thres = LPSS_RX_THRESH_DFLT;
+ config = lpss_get_config(drv_data);
+ tx_thres = config->tx_threshold_lo;
+ tx_hi_thres = config->tx_threshold_hi;
+ rx_thres = config->rx_threshold;
break;
default:
tx_thres = TX_THRESH_DFLT;