diff options
author | Jarkko Nikula <jarkko.nikula@linux.intel.com> | 2015-10-28 09:13:40 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-10-29 22:18:05 -0400 |
commit | d0283eb2dbc11ec08375fdf6a436e96d25b3a593 (patch) | |
tree | c9de914503d305c722eba4bafa2fb0e9c4c2fb86 /drivers/spi/spi-pxa2xx.c | |
parent | 624ea72ebddc1f61d32c9e6265f8d6f6dacd26d6 (diff) |
spi: pxa2xx: Add output control for multiple Intel LPSS chip selects
Intel LPSS SPI host controllers in upcoming Intel platforms can have up
to 4 chip selects per port. Extend chip select control in
lpss_ssp_cs_control() by adding a code that selects the active chip
select output prior to changing the state. Detection for number of
enabled chip select signals will be added by another patch.
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.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 9060aee5a7b1..040f6bb566a1 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c | |||
@@ -64,6 +64,8 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | |||
64 | #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) | 64 | #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) |
65 | #define LPSS_CS_CONTROL_SW_MODE BIT(0) | 65 | #define LPSS_CS_CONTROL_SW_MODE BIT(0) |
66 | #define LPSS_CS_CONTROL_CS_HIGH BIT(1) | 66 | #define LPSS_CS_CONTROL_CS_HIGH BIT(1) |
67 | #define LPSS_CS_CONTROL_CS_SEL_SHIFT 8 | ||
68 | #define LPSS_CS_CONTROL_CS_SEL_MASK (3 << LPSS_CS_CONTROL_CS_SEL_SHIFT) | ||
67 | 69 | ||
68 | struct lpss_config { | 70 | struct lpss_config { |
69 | /* LPSS offset from drv_data->ioaddr */ | 71 | /* LPSS offset from drv_data->ioaddr */ |
@@ -271,15 +273,34 @@ static void lpss_ssp_setup(struct driver_data *drv_data) | |||
271 | static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) | 273 | static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) |
272 | { | 274 | { |
273 | const struct lpss_config *config; | 275 | const struct lpss_config *config; |
274 | u32 value; | 276 | u32 value, cs; |
275 | 277 | ||
276 | config = lpss_get_config(drv_data); | 278 | config = lpss_get_config(drv_data); |
277 | 279 | ||
278 | value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); | 280 | value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); |
279 | if (enable) | 281 | if (enable) { |
282 | cs = drv_data->cur_msg->spi->chip_select; | ||
283 | cs <<= LPSS_CS_CONTROL_CS_SEL_SHIFT; | ||
284 | if (cs != (value & LPSS_CS_CONTROL_CS_SEL_MASK)) { | ||
285 | /* | ||
286 | * When switching another chip select output active | ||
287 | * the output must be selected first and wait 2 ssp_clk | ||
288 | * cycles before changing state to active. Otherwise | ||
289 | * a short glitch will occur on the previous chip | ||
290 | * select since output select is latched but state | ||
291 | * control is not. | ||
292 | */ | ||
293 | value &= ~LPSS_CS_CONTROL_CS_SEL_MASK; | ||
294 | value |= cs; | ||
295 | __lpss_ssp_write_priv(drv_data, | ||
296 | config->reg_cs_ctrl, value); | ||
297 | ndelay(1000000000 / | ||
298 | (drv_data->master->max_speed_hz / 2)); | ||
299 | } | ||
280 | value &= ~LPSS_CS_CONTROL_CS_HIGH; | 300 | value &= ~LPSS_CS_CONTROL_CS_HIGH; |
281 | else | 301 | } else { |
282 | value |= LPSS_CS_CONTROL_CS_HIGH; | 302 | value |= LPSS_CS_CONTROL_CS_HIGH; |
303 | } | ||
283 | __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); | 304 | __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); |
284 | } | 305 | } |
285 | 306 | ||