summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarkko Nikula <jarkko.nikula@linux.intel.com>2015-10-28 15:13:40 +0200
committerMark Brown <broonie@kernel.org>2015-10-30 11:18:05 +0900
commitd0283eb2dbc11ec08375fdf6a436e96d25b3a593 (patch)
treec9de914503d305c722eba4bafa2fb0e9c4c2fb86
parent624ea72ebddc1f61d32c9e6265f8d6f6dacd26d6 (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>
-rw-r--r--drivers/spi/spi-pxa2xx.c27
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");
#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);
}