Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168023404
D15031.id41339.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D15031.id41339.diff
View Options
Index: sys/arm/broadcom/bcm2835/bcm2835_spi.c
===================================================================
--- sys/arm/broadcom/bcm2835/bcm2835_spi.c
+++ sys/arm/broadcom/bcm2835/bcm2835_spi.c
@@ -422,7 +422,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, reg_cs, reg_clk, mode, clock;
int err;
sc = device_get_softc(dev);
@@ -434,18 +434,26 @@
/* 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));
return (EINVAL);
}
+ /* obtain clock, mode from spibus */
+ spibus_get_clock(child, &clock);
+ spibus_get_mode(child, &mode);
+
BCM_SPI_LOCK(sc);
+ /* preserve SPI_CS and SPI_CLK so I can restore them */
+ /* these were originally controlled by sysctl vars. */
+ /* since spibus and spigen now control these via ivars */
+ /* there may no longer be a need for preserving them */
+ reg_cs = BCM_SPI_READ(sc, SPI_CS);
+ reg_clk = BCM_SPI_READ(sc, SPI_CLK);
+
/* 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);
@@ -469,8 +477,38 @@
* 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);
+ SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD |
+ SPI_CS_CSPOL,
+ (cs & (~SPIBUS_CS_HIGH)) |
+ ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL : 0) |
+ SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD);
+
+ /* set the mode in 'SPI_CS' */
+ 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() */
+ /* if the spibus device has 0 for clock, leave value alone */
+ /* a zero maximum clock implies 'use default' - see ofw_spibus.c */
+ /* since spibus clock is a maximum, if reg value is slower, keep it */
+ if(clock != 0) {
+ /* 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;
+
+ /* test if 'reg_clk' value is less than 'clock' */
+ /* if it is, then the frequency is higher, and clock */
+ /* should be assigned as the new divider. */
+ if((reg_clk & 0xffff) < clock)
+ BCM_SPI_WRITE(sc, SPI_CLK, clock);
+ }
/* Wait for the transaction to complete. */
err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2);
@@ -478,6 +516,11 @@
/* Make sure the SPI engine and interrupts are disabled. */
bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0);
+ /* restore the original mode in 'SPI_CS' and clock in 'SPI_CLK' */
+ bcm_spi_modifyreg(sc, SPI_CS,
+ SPI_CS_CPOL | SPI_CS_CPHA, reg_cs);
+ BCM_SPI_WRITE(sc, SPI_CLK, reg_clk);
+
/* Release the controller and wakeup the next thread waiting for it. */
sc->sc_flags = 0;
wakeup_one(dev);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Aug 26, 11:41 PM (1 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37335963
Default Alt Text
D15031.id41339.diff (3 KB)
Attached To
Mode
D15031: bcm2835_spi.c mod to support mode and clock in ivars from spibus
Attached
Detach File
Event Timeline
Log In to Comment