aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-pxa2xx.c
diff options
context:
space:
mode:
authorJarkko Nikula <jarkko.nikula@linux.intel.com>2015-06-04 09:55:11 -0400
committerMark Brown <broonie@kernel.org>2015-06-05 06:40:45 -0400
commitdccf7369652f3934456345aab6a92fa905177886 (patch)
tree2d942ae9e9a14483a0962c7a9858d0cf026e9e61 /drivers/spi/spi-pxa2xx.c
parent03fbf488cece461468d3abb795f5e5f055e00040 (diff)
spi: pxa2xx: Prepare for new Intel LPSS SPI type
Some of the Intel LPSS SPI properties will be different in upcoming platforms compared to existing Lynxpoint and BayTrail/Braswell. LPSS SPI private registers will be at different offset and there will be changes in individual registers and default FIFO thresholds too. Add configuration for these differences and use them in runtime based on LPSS SSP type. With this change private registers offset autodetection becomes needless. Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-pxa2xx.c')
-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 a85b7496a3cd..3fec31dbf972 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -60,18 +60,51 @@ MODULE_ALIAS("platform:pxa2xx-spi");
60 | QUARK_X1000_SSCR1_TFT \ 60 | QUARK_X1000_SSCR1_TFT \
61 | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) 61 | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
62 62
63#define LPSS_RX_THRESH_DFLT 64
64#define LPSS_TX_LOTHRESH_DFLT 160
65#define LPSS_TX_HITHRESH_DFLT 224
66
67/* Offset from drv_data->lpss_base */
68#define GENERAL_REG 0x08
69#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) 63#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
70#define SSP_REG 0x0c
71#define SPI_CS_CONTROL 0x18
72#define SPI_CS_CONTROL_SW_MODE BIT(0) 64#define SPI_CS_CONTROL_SW_MODE BIT(0)
73#define SPI_CS_CONTROL_CS_HIGH BIT(1) 65#define SPI_CS_CONTROL_CS_HIGH BIT(1)
74 66
67struct lpss_config {
68 /* LPSS offset from drv_data->ioaddr */
69 unsigned offset;
70 /* Register offsets from drv_data->lpss_base or -1 */
71 int reg_general;
72 int reg_ssp;
73 int reg_cs_ctrl;
74 /* FIFO thresholds */
75 u32 rx_threshold;
76 u32 tx_threshold_lo;
77 u32 tx_threshold_hi;
78};
79
80/* Keep these sorted with enum pxa_ssp_type */
81static const struct lpss_config lpss_platforms[] = {
82 { /* LPSS_LPT_SSP */
83 .offset = 0x800,
84 .reg_general = 0x08,
85 .reg_ssp = 0x0c,
86 .reg_cs_ctrl = 0x18,
87 .rx_threshold = 64,
88 .tx_threshold_lo = 160,
89 .tx_threshold_hi = 224,
90 },
91 { /* LPSS_BYT_SSP */
92 .offset = 0x400,
93 .reg_general = 0x08,
94 .reg_ssp = 0x0c,
95 .reg_cs_ctrl = 0x18,
96 .rx_threshold = 64,
97 .tx_threshold_lo = 160,
98 .tx_threshold_hi = 224,
99 },
100};
101
102static inline const struct lpss_config
103*lpss_get_config(const struct driver_data *drv_data)
104{
105 return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP];
106}
107
75static bool is_lpss_ssp(const struct driver_data *drv_data) 108static bool is_lpss_ssp(const struct driver_data *drv_data)
76{ 109{
77 switch (drv_data->ssp_type) { 110 switch (drv_data->ssp_type) {
@@ -198,63 +231,39 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
198 */ 231 */
199static void lpss_ssp_setup(struct driver_data *drv_data) 232static void lpss_ssp_setup(struct driver_data *drv_data)
200{ 233{
201 unsigned offset = 0x400; 234 const struct lpss_config *config;
202 u32 value, orig; 235 u32 value;
203
204 /*
205 * Perform auto-detection of the LPSS SSP private registers. They
206 * can be either at 1k or 2k offset from the base address.
207 */
208 orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
209
210 /* Test SPI_CS_CONTROL_SW_MODE bit enabling */
211 value = orig | SPI_CS_CONTROL_SW_MODE;
212 writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
213 value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
214 if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
215 offset = 0x800;
216 goto detection_done;
217 }
218
219 orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
220
221 /* Test SPI_CS_CONTROL_SW_MODE bit disabling */
222 value = orig & ~SPI_CS_CONTROL_SW_MODE;
223 writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
224 value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
225 if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
226 offset = 0x800;
227 goto detection_done;
228 }
229 236
230detection_done: 237 config = lpss_get_config(drv_data);
231 /* Now set the LPSS base */ 238 drv_data->lpss_base = drv_data->ioaddr + config->offset;
232 drv_data->lpss_base = drv_data->ioaddr + offset;
233 239
234 /* Enable software chip select control */ 240 /* Enable software chip select control */
235 value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH; 241 value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
236 __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); 242 __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
237 243
238 /* Enable multiblock DMA transfers */ 244 /* Enable multiblock DMA transfers */
239 if (drv_data->master_info->enable_dma) { 245 if (drv_data->master_info->enable_dma) {
240 __lpss_ssp_write_priv(drv_data, SSP_REG, 1); 246 __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
241 247
242 value = __lpss_ssp_read_priv(drv_data, GENERAL_REG); 248 value = __lpss_ssp_read_priv(drv_data, config->reg_general);
243 value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; 249 value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
244 __lpss_ssp_write_priv(drv_data, GENERAL_REG, value); 250 __lpss_ssp_write_priv(drv_data, config->reg_general, value);
245 } 251 }
246} 252}
247 253
248static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) 254static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
249{ 255{
256 const struct lpss_config *config;
250 u32 value; 257 u32 value;
251 258
252 value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL); 259 config = lpss_get_config(drv_data);
260
261 value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
253 if (enable) 262 if (enable)
254 value &= ~SPI_CS_CONTROL_CS_HIGH; 263 value &= ~SPI_CS_CONTROL_CS_HIGH;
255 else 264 else
256 value |= SPI_CS_CONTROL_CS_HIGH; 265 value |= SPI_CS_CONTROL_CS_HIGH;
257 __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); 266 __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
258} 267}
259 268
260static void cs_assert(struct driver_data *drv_data) 269static void cs_assert(struct driver_data *drv_data)
@@ -1081,6 +1090,7 @@ static int setup(struct spi_device *spi)
1081{ 1090{
1082 struct pxa2xx_spi_chip *chip_info = NULL; 1091 struct pxa2xx_spi_chip *chip_info = NULL;
1083 struct chip_data *chip; 1092 struct chip_data *chip;
1093 const struct lpss_config *config;
1084 struct driver_data *drv_data = spi_master_get_devdata(spi->master); 1094 struct driver_data *drv_data = spi_master_get_devdata(spi->master);
1085 unsigned int clk_div; 1095 unsigned int clk_div;
1086 uint tx_thres, tx_hi_thres, rx_thres; 1096 uint tx_thres, tx_hi_thres, rx_thres;
@@ -1093,9 +1103,10 @@ static int setup(struct spi_device *spi)
1093 break; 1103 break;
1094 case LPSS_LPT_SSP: 1104 case LPSS_LPT_SSP:
1095 case LPSS_BYT_SSP: 1105 case LPSS_BYT_SSP:
1096 tx_thres = LPSS_TX_LOTHRESH_DFLT; 1106 config = lpss_get_config(drv_data);
1097 tx_hi_thres = LPSS_TX_HITHRESH_DFLT; 1107 tx_thres = config->tx_threshold_lo;
1098 rx_thres = LPSS_RX_THRESH_DFLT; 1108 tx_hi_thres = config->tx_threshold_hi;
1109 rx_thres = config->rx_threshold;
1099 break; 1110 break;
1100 default: 1111 default:
1101 tx_thres = TX_THRESH_DFLT; 1112 tx_thres = TX_THRESH_DFLT;