Page MenuHomeFreeBSD

D15031.id43638.diff
No OneTemporary

D15031.id43638.diff

Index: sys/arm/broadcom/bcm2835/bcm2835_spi.c
===================================================================
--- sys/arm/broadcom/bcm2835/bcm2835_spi.c
+++ sys/arm/broadcom/bcm2835/bcm2835_spi.c
@@ -56,6 +56,8 @@
#include "spibus_if.h"
+#define BCM2835_SPI_DEFAULT_CLOCK 500000 /* default clock speed */
+
static struct ofw_compat_data compat_data[] = {
{"broadcom,bcm2835-spi", 1},
{"brcm,bcm2835-spi", 1},
@@ -132,17 +134,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 +154,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 +185,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 +206,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
@@ -304,7 +299,8 @@
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);
+ /* TODO: read this from fdt data; if not specified use default */
+ BCM_SPI_WRITE(sc, SPI_CLK, SPI_CORE_CLK / BCM2835_SPI_DEFAULT_CLOCK);
#ifdef BCM_SPI_DEBUG
bcm_spi_printr(dev);
@@ -412,7 +408,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);
@@ -424,10 +420,7 @@
/* Get the proper chip select for this child. */
spibus_get_cs(child, &cs);
-
- cs &= ~SPIBUS_CS_HIGH;
-
- if (cs > 2) {
+ if ((cs & (~SPIBUS_CS_HIGH)) > 2) {
device_printf(dev,
"Invalid chip select %d requested by %s\n", cs,
device_get_nameunit(child));
@@ -436,6 +429,21 @@
BCM_SPI_LOCK(sc);
+ /* obtain clock, mode from spibus after locking it */
+ spibus_get_clock(child, &clock);
+ spibus_get_mode(child, &mode);
+
+ if(clock == 0) {
+ /* clock == 0 no longer means 'default', now an error */
+ BCM_SPI_UNLOCK(sc);
+
+ device_printf(dev,
+ "Invalid clock %d requested by %s\n", clock,
+ device_get_nameunit(child));
+
+ return (EINVAL);
+ }
+
/* If the controller is in use wait until it is available. */
while (sc->sc_flags & BCM_SPI_BUSY)
mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0);
@@ -454,13 +462,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);

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 19, 4:16 PM (7 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27749450
Default Alt Text
D15031.id43638.diff (5 KB)

Event Timeline