Page MenuHomeFreeBSD

D15031.diff
No OneTemporary

D15031.diff

Index: head/sys/arm/broadcom/bcm2835/bcm2835_spi.c
===================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_spi.c
+++ head/sys/arm/broadcom/bcm2835/bcm2835_spi.c
@@ -132,17 +132,6 @@
if (error != 0 || req->newptr == NULL)
return (error);
- clk = SPI_CORE_CLK / clk;
- if (clk <= 1)
- clk = 2;
- else if (clk % 2)
- clk--;
- if (clk > 0xffff)
- clk = 0;
- BCM_SPI_LOCK(sc);
- BCM_SPI_WRITE(sc, SPI_CLK, clk);
- BCM_SPI_UNLOCK(sc);
-
return (0);
}
@@ -163,12 +152,6 @@
if (error != 0 || req->newptr == NULL)
return (error);
- if (reg)
- reg = bit;
- BCM_SPI_LOCK(sc);
- bcm_spi_modifyreg(sc, SPI_CS, bit, reg);
- BCM_SPI_UNLOCK(sc);
-
return (0);
}
@@ -200,6 +183,13 @@
return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL1));
}
+static int
+bcm_spi_cspol2_proc(SYSCTL_HANDLER_ARGS)
+{
+
+ return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL2));
+}
+
static void
bcm_spi_sysctl_init(struct bcm_spi_softc *sc)
{
@@ -214,20 +204,23 @@
tree_node = device_get_sysctl_tree(sc->sc_dev);
tree = SYSCTL_CHILDREN(tree_node);
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock",
- CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
bcm_spi_clock_proc, "IU", "SPI BUS clock frequency");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpol",
- CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
bcm_spi_cpol_proc, "IU", "SPI BUS clock polarity");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpha",
- CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
bcm_spi_cpha_proc, "IU", "SPI BUS clock phase");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol0",
- CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
bcm_spi_cspol0_proc, "IU", "SPI BUS chip select 0 polarity");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol1",
- CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
bcm_spi_cspol1_proc, "IU", "SPI BUS chip select 1 polarity");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol2",
+ CTLFLAG_RD | CTLTYPE_UINT, sc, sizeof(*sc),
+ bcm_spi_cspol2_proc, "IU", "SPI BUS chip select 2 polarity");
}
static int
@@ -303,9 +296,6 @@
*/
BCM_SPI_WRITE(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO);
- /* Set the SPI clock to 500Khz. */
- BCM_SPI_WRITE(sc, SPI_CLK, SPI_CORE_CLK / 500000);
-
#ifdef BCM_SPI_DEBUG
bcm_spi_printr(dev);
#endif
@@ -412,7 +402,7 @@
bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
{
struct bcm_spi_softc *sc;
- uint32_t cs;
+ uint32_t cs, mode, clock;
int err;
sc = device_get_softc(dev);
@@ -422,21 +412,34 @@
KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
("TX/RX data sizes should be equal"));
- /* Get the proper chip select for this child. */
+ /* Get the bus speed, mode, and chip select for this child. */
+
spibus_get_cs(child, &cs);
+ if ((cs & (~SPIBUS_CS_HIGH)) > 2) {
+ device_printf(dev,
+ "Invalid chip select %u requested by %s\n", cs,
+ device_get_nameunit(child));
+ return (EINVAL);
+ }
- cs &= ~SPIBUS_CS_HIGH;
+ spibus_get_clock(child, &clock);
+ if (clock == 0) {
+ device_printf(dev,
+ "Invalid clock %uHz requested by %s\n", clock,
+ device_get_nameunit(child));
+ return (EINVAL);
+ }
- if (cs > 2) {
+ spibus_get_mode(child, &mode);
+ if (mode > 3) {
device_printf(dev,
- "Invalid chip select %d requested by %s\n", cs,
+ "Invalid mode %u requested by %s\n", mode,
device_get_nameunit(child));
return (EINVAL);
}
- BCM_SPI_LOCK(sc);
-
/* If the controller is in use wait until it is available. */
+ BCM_SPI_LOCK(sc);
while (sc->sc_flags & BCM_SPI_BUSY)
mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0);
@@ -454,13 +457,63 @@
sc->sc_written = 0;
sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
+#ifdef BCM2835_SPI_USE_CS_HIGH /* TODO: for when behavior is correct */
/*
+ * Assign CS polarity first, while the CS indicates 'inactive'.
+ * This will need to set the correct polarity bit based on the 'cs', and
+ * the polarity bit will remain in this state, even after the transaction
+ * is complete.
+ */
+ if((cs & ~SPIBUS_CS_HIGH) == 0) {
+ bcm_spi_modifyreg(sc, SPI_CS,
+ SPI_CS_CSPOL0,
+ ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL0 : 0));
+ }
+ else if((cs & ~SPIBUS_CS_HIGH) == 1) {
+ bcm_spi_modifyreg(sc, SPI_CS,
+ SPI_CS_CSPOL1,
+ ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL1 : 0));
+ }
+ else if((cs & ~SPIBUS_CS_HIGH) == 2) {
+ bcm_spi_modifyreg(sc, SPI_CS,
+ SPI_CS_CSPOL2,
+ ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL2 : 0));
+ }
+#endif
+
+ /*
+ * Set the mode in 'SPI_CS' (clock phase and polarity bits).
+ * This must happen before CS output pin is active.
+ * Otherwise, you might glitch and drop the first bit.
+ */
+ bcm_spi_modifyreg(sc, SPI_CS,
+ SPI_CS_CPOL | SPI_CS_CPHA,
+ ((mode & SPIBUS_MODE_CPHA) ? SPI_CS_CPHA : 0) |
+ ((mode & SPIBUS_MODE_CPOL) ? SPI_CS_CPOL : 0));
+
+ /*
+ * Set the clock divider in 'SPI_CLK - see 'bcm_spi_clock_proc()'.
+ */
+
+ /* calculate 'clock' as a divider value from freq */
+ clock = SPI_CORE_CLK / clock;
+ if (clock <= 1)
+ clock = 2;
+ else if (clock % 2)
+ clock--;
+ if (clock > 0xffff)
+ clock = 0;
+
+ BCM_SPI_WRITE(sc, SPI_CLK, clock);
+
+ /*
* Set the CS for this transaction, enable interrupts and announce
* we're ready to tx. This will kick off the first interrupt.
*/
bcm_spi_modifyreg(sc, SPI_CS,
SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD,
- cs | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD);
+ (cs & (~SPIBUS_CS_HIGH)) | /* cs is the lower 2 bits of the reg */
+ SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD);
/* Wait for the transaction to complete. */
err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2);
@@ -478,7 +531,7 @@
* return errors.
*/
if (err == EWOULDBLOCK) {
- device_printf(sc->sc_dev, "SPI error\n");
+ device_printf(sc->sc_dev, "SPI error (timeout)\n");
err = EIO;
}

File Metadata

Mime Type
text/plain
Expires
Thu, Jul 16, 10:48 AM (15 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35133210
Default Alt Text
D15031.diff (6 KB)

Event Timeline