@@ -290,6 +290,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
int status = -EINVAL;
int dummy_cs;
u32 reg;
+ bool restore_polarity = true;
/* This controller does not support keeping CS active during idle.
* To work around this, we use the following ugly hack:
@@ -317,16 +318,29 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
spi_transfer_delay_exec(t);
- if (t->cs_change)
+ /*
+ * cs_change rules:
+ * (1) cs_change = 0 && last_xfer = 0:
+ * Do not touch the CS. On to the next xfer.
+ * (2) cs_change = 1 && last_xfer = 0:
+ * Set cs = false before the next xfer.
+ * (3) cs_change = 0 && last_xfer = 1:
+ * We want CS to be deactivated. So do NOT set cs = false,
+ * instead just restore the original polarity. This has the
+ * same effect of deactivating the CS.
+ * (4) cs_change = 1 && last_xfer = 1:
+ * We want to keep CS active. So do NOT set cs = false, and
+ * make sure we do NOT reverse polarity.
+ */
+ if (t->cs_change && !list_is_last(&t->transfer_list, &msg->transfers))
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
+
+ restore_polarity = !t->cs_change;
}
- mutex_lock(&bs->bus_mutex);
- reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
- reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK;
- reg |= bs->cs_polarity;
- __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
- mutex_unlock(&bs->bus_mutex);
+ bcm63xx_hsspi_set_cs(bs, dummy_cs, false);
+ if (restore_polarity)
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
msg->status = status;
spi_finalize_current_message(master);