From d0283eb2dbc11ec08375fdf6a436e96d25b3a593 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 28 Oct 2015 15:13:40 +0200 Subject: [PATCH] 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 Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 27 ++++++++++++++++++++++++--- 1 file 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"); #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define LPSS_CS_CONTROL_SW_MODE BIT(0) #define LPSS_CS_CONTROL_CS_HIGH BIT(1) +#define LPSS_CS_CONTROL_CS_SEL_SHIFT 8 +#define LPSS_CS_CONTROL_CS_SEL_MASK (3 << LPSS_CS_CONTROL_CS_SEL_SHIFT) struct lpss_config { /* LPSS offset from drv_data->ioaddr */ @@ -271,15 +273,34 @@ static void lpss_ssp_setup(struct driver_data *drv_data) static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) { const struct lpss_config *config; - u32 value; + u32 value, cs; config = lpss_get_config(drv_data); value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); - if (enable) + if (enable) { + cs = drv_data->cur_msg->spi->chip_select; + cs <<= LPSS_CS_CONTROL_CS_SEL_SHIFT; + if (cs != (value & LPSS_CS_CONTROL_CS_SEL_MASK)) { + /* + * When switching another chip select output active + * the output must be selected first and wait 2 ssp_clk + * cycles before changing state to active. Otherwise + * a short glitch will occur on the previous chip + * select since output select is latched but state + * control is not. + */ + value &= ~LPSS_CS_CONTROL_CS_SEL_MASK; + value |= cs; + __lpss_ssp_write_priv(drv_data, + config->reg_cs_ctrl, value); + ndelay(1000000000 / + (drv_data->master->max_speed_hz / 2)); + } value &= ~LPSS_CS_CONTROL_CS_HIGH; - else + } else { value |= LPSS_CS_CONTROL_CS_HIGH; + } __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); } -- 2.20.1