Changeset View
Standalone View
sys/arm/broadcom/bcm2835/bcm2835_spi.c
Context not available. | |||||
#include <arm/broadcom/bcm2835/bcm2835_spireg.h> | #include <arm/broadcom/bcm2835/bcm2835_spireg.h> | ||||
#include <arm/broadcom/bcm2835/bcm2835_spivar.h> | #include <arm/broadcom/bcm2835/bcm2835_spivar.h> | ||||
#include "spibus_if.h" | #include "spibus_if.h" | ||||
#define BCM2835_SPI_DEFAULT_CLOCK 500000 /* default clock speed */ | |||||
bobf_mrp3.com: 'magic number' within the code now a macro value
| |||||
static struct ofw_compat_data compat_data[] = { | static struct ofw_compat_data compat_data[] = { | ||||
{"broadcom,bcm2835-spi", 1}, | {"broadcom,bcm2835-spi", 1}, | ||||
{"brcm,bcm2835-spi", 1}, | {"brcm,bcm2835-spi", 1}, | ||||
{NULL, 0} | {NULL, 0} | ||||
}; | }; | ||||
Context not available. | |||||
error = sysctl_handle_int(oidp, &clk, sizeof(clk), req); | error = sysctl_handle_int(oidp, &clk, sizeof(clk), req); | ||||
if (error != 0 || req->newptr == NULL) | if (error != 0 || req->newptr == NULL) | ||||
return (error); | return (error); | ||||
clk = SPI_CORE_CLK / clk; | /* commented out, temporarily left for reference | ||||
if (clk <= 1) | * clk = SPI_CORE_CLK / clk; | ||||
clk = 2; | * if (clk <= 1) | ||||
else if (clk % 2) | * clk = 2; | ||||
clk--; | * else if (clk % 2) | ||||
if (clk > 0xffff) | * clk--; | ||||
clk = 0; | * if (clk > 0xffff) | ||||
BCM_SPI_LOCK(sc); | * clk = 0; | ||||
BCM_SPI_WRITE(sc, SPI_CLK, clk); | * BCM_SPI_LOCK(sc); | ||||
BCM_SPI_UNLOCK(sc); | * BCM_SPI_WRITE(sc, SPI_CLK, clk); | ||||
* BCM_SPI_UNLOCK(sc); | |||||
*/ | |||||
Not Done Inline Actionsthis next section removed since it's read-only now, and the code below handles writes. bobf_mrp3.com: this next section removed since it's read-only now, and the code below handles writes. | |||||
return (0); | return (0); | ||||
bobf_mrp3.comAuthorUnsubmitted Done Inline Actionsthis code was only relevant when the clock value was assigned via sysctl. It was commented out for reference since this is the official way to set the clock freq. It can be removed once the 'per transaction' clock assignment is verified correct. bobf_mrp3.com: this code was only relevant when the clock value was assigned via sysctl. It was commented out… | |||||
} | } | ||||
static int | static int | ||||
bcm_spi_cs_bit_proc(SYSCTL_HANDLER_ARGS, uint32_t bit) | bcm_spi_cs_bit_proc(SYSCTL_HANDLER_ARGS, uint32_t bit) | ||||
Context not available. | |||||
error = sysctl_handle_int(oidp, ®, sizeof(reg), req); | error = sysctl_handle_int(oidp, ®, sizeof(reg), req); | ||||
if (error != 0 || req->newptr == NULL) | if (error != 0 || req->newptr == NULL) | ||||
return (error); | return (error); | ||||
if (reg) | /* commented out, temporarily left for reference | ||||
reg = bit; | * if (reg) | ||||
BCM_SPI_LOCK(sc); | * reg = bit; | ||||
bcm_spi_modifyreg(sc, SPI_CS, bit, reg); | * BCM_SPI_LOCK(sc); | ||||
BCM_SPI_UNLOCK(sc); | * bcm_spi_modifyreg(sc, SPI_CS, bit, reg); | ||||
* BCM_SPI_UNLOCK(sc); | |||||
*/ | |||||
bobf_mrp3.comAuthorUnsubmitted Done Inline Actionsthis code is only called for sysctl vars implemented within this source file. Since they're all read-only now, the write code has been effectively removed. It has been commented out and left for reference. bobf_mrp3.com: this code is only called for sysctl vars implemented within this source file. Since they're… | |||||
Not Done Inline Actionsthis next section removed since it's read-only now, and the code below handles writes. bobf_mrp3.com: this next section removed since it's read-only now, and the code below handles writes. | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
bcm_spi_cpol_proc(SYSCTL_HANDLER_ARGS) | bcm_spi_cpol_proc(SYSCTL_HANDLER_ARGS) | ||||
Context not available. | |||||
{ | { | ||||
return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL1)); | 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 | static void | ||||
bcm_spi_sysctl_init(struct bcm_spi_softc *sc) | bcm_spi_sysctl_init(struct bcm_spi_softc *sc) | ||||
{ | { | ||||
struct sysctl_ctx_list *ctx; | struct sysctl_ctx_list *ctx; | ||||
struct sysctl_oid *tree_node; | struct sysctl_oid *tree_node; | ||||
Context not available. | |||||
*/ | */ | ||||
ctx = device_get_sysctl_ctx(sc->sc_dev); | ctx = device_get_sysctl_ctx(sc->sc_dev); | ||||
tree_node = device_get_sysctl_tree(sc->sc_dev); | tree_node = device_get_sysctl_tree(sc->sc_dev); | ||||
tree = SYSCTL_CHILDREN(tree_node); | tree = SYSCTL_CHILDREN(tree_node); | ||||
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock", | 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"); | bcm_spi_clock_proc, "IU", "SPI BUS clock frequency"); | ||||
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpol", | 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"); | bcm_spi_cpol_proc, "IU", "SPI BUS clock polarity"); | ||||
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpha", | 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"); | bcm_spi_cpha_proc, "IU", "SPI BUS clock phase"); | ||||
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol0", | 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"); | bcm_spi_cspol0_proc, "IU", "SPI BUS chip select 0 polarity"); | ||||
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol1", | 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"); | bcm_spi_cspol1_proc, "IU", "SPI BUS chip select 1 polarity"); | ||||
Done Inline ActionsI think all these sysctls should be removed. CS polarity is an attribute of the slave device, not the controller. ian: I think all these sysctls should be removed. CS polarity is an attribute of the slave device… | |||||
Done Inline ActionsI am not opposed to making that change. If there's a consensus, I'll do it. I only added 'cspol2' because the cs==2 case wasn't being handled the same way. bobf_mrp3.com: I am not opposed to making that change. If there's a consensus, I'll do it. I only added… | |||||
Done Inline ActionsI have made them all read-only. Let me know if you'd rather have them removed. bobf_mrp3.com: I have made them all read-only. Let me know if you'd rather have them removed. | |||||
Not Done Inline ActionsIf they're only valid during a transfer they don't have any real use at all, we should just remove them. ian: If they're only valid during a transfer they don't have any real use at all, we should just… | |||||
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 | static int | ||||
bcm_spi_probe(device_t dev) | bcm_spi_probe(device_t dev) | ||||
{ | { | ||||
Context not available. | |||||
* Defaults to SPI mode 0. | * Defaults to SPI mode 0. | ||||
*/ | */ | ||||
BCM_SPI_WRITE(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO); | BCM_SPI_WRITE(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO); | ||||
/* Set the SPI clock to 500Khz. */ | /* 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); | |||||
bobf_mrp3.comAuthorUnsubmitted Not Done Inline ActionsI'm not sure how to get the correct maximum frequency from the fdt data. I'll research it. Additionally, I changed the magic number '500000' into a macro BCM2835_SPI_DEFAULT_CLOCK (defined near the top of the file). bobf_mrp3.com: I'm not sure how to get the correct maximum frequency from the fdt data. I'll research it. | |||||
#ifdef BCM_SPI_DEBUG | #ifdef BCM_SPI_DEBUG | ||||
bcm_spi_printr(dev); | bcm_spi_printr(dev); | ||||
#endif | #endif | ||||
Context not available. | |||||
static int | static int | ||||
bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) | bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) | ||||
{ | { | ||||
struct bcm_spi_softc *sc; | struct bcm_spi_softc *sc; | ||||
uint32_t cs; | uint32_t cs, mode, clock; | ||||
int err; | int err; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, | KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, | ||||
Context not available. | |||||
KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, | KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, | ||||
("TX/RX data sizes should be equal")); | ("TX/RX data sizes should be equal")); | ||||
/* Get the proper chip select for this child. */ | /* Get the proper chip select for this child. */ | ||||
spibus_get_cs(child, &cs); | spibus_get_cs(child, &cs); | ||||
if ((cs & (~SPIBUS_CS_HIGH)) > 2) { | |||||
cs &= ~SPIBUS_CS_HIGH; | |||||
if (cs > 2) { | |||||
device_printf(dev, | device_printf(dev, | ||||
"Invalid chip select %d requested by %s\n", cs, | "Invalid chip select %d requested by %s\n", cs, | ||||
device_get_nameunit(child)); | device_get_nameunit(child)); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
BCM_SPI_LOCK(sc); | 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 */ | |||||
Done Inline ActionsDon't do these reads until after waiting for BCM_SPI_BUSY below. ian: Don't do these reads until after waiting for BCM_SPI_BUSY below. | |||||
Done Inline ActionsI also moved the 2 calls that get the transaction's mode and clock to be after doing BCM_SPI_LOCK [same kind of thinking]. Good point. Although they probably will not change, in theory they _might_ change, and it's a simple thing to place the calls to be _after_ locking the bus. bobf_mrp3.com: I also moved the 2 calls that get the transaction's mode and clock to be after doing… | |||||
bobf_mrp3.comAuthorUnsubmitted Done Inline Actionsnew behavior does not allow clock == 0 and assumes that this is the speed you want the bus to run at, with a maximum being the max capabilities of the device. It is, however, a clock speed that's assigned on a per-cs basis in spibus. If this is a problem the overlays could address it, setting the maximum frequency for every device on the spibus to something that doesn't cause problems. But if anything more is required let's put it into spibus... bobf_mrp3.com: new behavior does not allow clock == 0 and assumes that this is the speed you want the bus to… | |||||
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. */ | /* If the controller is in use wait until it is available. */ | ||||
while (sc->sc_flags & BCM_SPI_BUSY) | while (sc->sc_flags & BCM_SPI_BUSY) | ||||
mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0); | mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0); | ||||
Done Inline Actionsthis call needs to happen after modifying the clock speed, phase, and polarity. Apparently the interrupt bits are what start the transaction, and if the clock phase and polarity and speed are modified AFTER that, it might be causing a glitch that I observed when doing a mode 3 transfer. bobf_mrp3.com: this call needs to happen after modifying the clock speed, phase, and polarity. Apparently the… | |||||
/* Now we have control over SPI controller. */ | /* Now we have control over SPI controller. */ | ||||
Done Inline Actionsif all 3 CS pins have the same polarity this will work. however, there's only a single polarity bit for all 3 CS lines. Given that fact, it may be better to NOT set the SPI_CS_CSPOL bit, but have a sysctl var for it (or device parameter) instead? For now it may simply need to be documented that having different polarities for the 3 CS pins is going to cause problems if you're using multiple SPI devices on the same bus. once the SPI_CS_TA bit is set, the CS lines flip to whatever state is described. This also suggests that the SPI_CS_CSPOL bit should be 'sticky' across transactions, or you could have a real _mess_, depending on the state of the clock line following the transaction. It should also be verified as being properly set when the 'spibus' devices are first created from FDT info, though setting it correctly on the very first transaction will probably work in most cases. This is all because clock polarities, depending on the mode, may attempt to shift in/out a bit if the CS line has the wrong polarity while the clock mode is being changed. Further, if the default clock polarity is opposite, it's possible that the mode switch itself might trigger something if CS polarity is wrong at the moment this all happens. It really complicates things and suggests that CS polarity should probably happen first, then the mode and clock speed, and finally the SPI_CS_TA bit [with int flags on as well, like before]. If all of this can't be accomplished 'safely', the SPI_CS_CSPOL bit should probably be left as 0, with 'TODO' comments in the code to implement this when it can be done. bobf_mrp3.com: if all 3 CS pins have the same polarity this will work. however, there's only a single… | |||||
Done Inline Actionsthere may be a better way: assign the 3 polarity bits SPI_CS_CSPOL0, through SPI_CS_CSPOL2 and leave SPI_CS_CSPOL at zero. Unfortunately this would have to be done during device initialization to prevent any problems. however, there's an inherent problem: _some_how, the clock polarity _must_ be assigned correctly before _any_ device on the SPI bus sees the clock wiggling. Because, clock pulses with an 'active high' device are going to cause that device to start accepting input and sending output, along with the device you intend to communicate with, which of course is _bad_. On the other hand, there does not seem to be a mechanism for this, although I'll be looking to see what happens during the initialization phase with things like 'ofw_bus_gen_setup_devinfo()' to see if that helps in any way. A short reference to ofw_spibus_attach near line 120 in ofw_spibus.c where the child devices are being set up from FDT info. bobf_mrp3.com: there may be a better way: assign the 3 polarity bits SPI_CS_CSPOL0, through SPI_CS_CSPOL2 and… | |||||
Context not available. | |||||
sc->sc_cmd = cmd; | sc->sc_cmd = cmd; | ||||
sc->sc_read = 0; | sc->sc_read = 0; | ||||
sc->sc_written = 0; | sc->sc_written = 0; | ||||
Done Inline ActionsI'm inclined to just comment out this section, and not support the SPIBUS_CS_HIGH bit, mostly because it's rarely used, and because its implementation may require additional support from spibus that affects every single SPI driver. bobf_mrp3.com: I'm inclined to just comment out this section, and not support the SPIBUS_CS_HIGH bit, mostly… | |||||
sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz; | sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz; | ||||
#ifdef BCM2835_SPI_USE_CS_CSPOL /* 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). | |||||
Done Inline ActionsI have to wonder whether it would be better to leave the clock phase, polarity, and speed the way it is, rather than restoring it. bobf_mrp3.com: I have to wonder whether it would be better to leave the clock phase, polarity, and speed the… | |||||
Done Inline Actionsafter working on this a bit, it seems that the clock speed should be restored, and the mode CAN be restored (but does not necessarily have to be restored). what is accidentally correct here is that the 'SPI_CS_CSPOL' is _not_ being restored, which is a good thing. Restoring the CS polarity, i.e. 'flipping' it, would be nothing less than a major problem on the SPI bus. So it has to remain 'sticky' with the previous transaction, and be (hopefully) restricted to 'same polarity' for all of the cs definitions in the FDT info. bobf_mrp3.com: after working on this a bit, it seems that the clock speed should be restored, and the mode CAN… | |||||
* 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)); | |||||
Done Inline ActionsThe interpretation of clock is that the device wants the bus to go as fast as possible, but no faster than clock. The clock should be reset for each transfer using that logic. That is, if clock is 1mhz for cs 0 and 50mhz for cs 1, it's not okay to do 1mhz transfers on cs 1 just because that's the value already in the register and it's lower than the max. This concept of "0 means default" is insane. What does that even mean? I can't remember a single spi controller I've ever seen that has the idea of a default speed. About the closest we might come to that is to capture whatever is in the clock divider register at attach() time and call that the default (i.e., default means "whatever uboot set up"). But if that value is zero or an uninitialized invalid value, who knows what happens. ian: The interpretation of clock is that the device wants the bus to go as fast as possible, but no… | |||||
Done Inline ActionsI'm good with what you say. Right now the ivars definition (used to?) includes 'clock == 0' as "default" . I checked and it looks like your patch adds an additional comment about this in ofw_spibus.c (which wasn't there before). So, do you have a suggestion for how the logic _should_ work? Should I simply check for 'maximum of' but NOT handle a value of zero as 'use default' ? Or, just assign it 'as-is' every time? [I actually like this better] This logic that assumes that the overlay correctly assigns the maximum frequency would require changing the overlay appropriately. The driver default is currently 500khz [which becomes the maximum]. It can be changed by tweeking the sysctl var for it. The current behavior (as posted here) would use the 500khz value if the clock were assigned to '0' in spibus (assuming it hadn't been changed by tweeking the sysctl var for it). The data sheet says that the SPI speed can be up to 1/2 of the APB clock, which is defined as SPI_CORE_CLK in the driver code. "bcm2835_spireg.h" defines this value as 250Mhz (although in theory it should be read from fdt data) so, if I interpret this correctly, the max clock is 125Mhz. This also means that the minimum SPI speed for this device is around 3.8khz. bobf_mrp3.com: I'm good with what you say. Right now the ivars definition (used to?) includes 'clock == 0' as… | |||||
Done Inline Actions0 means default has been removed - see commend near line 465 bobf_mrp3.com: 0 means default has been removed - see commend near line 465 | |||||
/* | |||||
* 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 | * Set the CS for this transaction, enable interrupts and announce | ||||
* we're ready to tx. This will kick off the first interrupt. | * we're ready to tx. This will kick off the first interrupt. | ||||
*/ | */ | ||||
bcm_spi_modifyreg(sc, SPI_CS, | bcm_spi_modifyreg(sc, SPI_CS, | ||||
SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, | 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. */ | /* Wait for the transaction to complete. */ | ||||
err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2); | err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2); | ||||
/* Make sure the SPI engine and interrupts are disabled. */ | /* Make sure the SPI engine and interrupts are disabled. */ | ||||
Context not available. | |||||
Done Inline ActionsI don't think there's any need to restore anything. Each new transfer should set up mode and clock before starting the transfer. If we're going to have the idea of a default clock, we should capture its value once at attach time. ian: I don't think there's any need to restore anything. Each new transfer should set up mode and… | |||||
Done Inline ActionsI'll leave this as-is for now, until I get the necessary clarity on how to handle clock speed assignment. bobf_mrp3.com: I'll leave this as-is for now, until I get the necessary clarity on how to handle clock speed… | |||||
Not Done Inline ActionsIn general, we're making this driver work properly with fdt data, and the device bindings require a spi-max-frequency property in each child, so we can require that a speed be present. The bindings say nothing about 0, it just says the value is frequency in Hz. 0Hz is insane, so let's just call that an error (1 would also be insane, but at least the transfer would finish some day). ian: In general, we're making this driver work properly with fdt data, and the device bindings… |
'magic number' within the code now a macro value