/* FSM state return values */ #define FSM_STOP 0/* Nothing more for the state machine to */ /* do. If something interesting happens */ /* then an IRQ will be received */ #define FSM_POLL 1/* need to poll for completion, an IRQ is */ /* not expected */ #define FSM_CONTINUE 2/* Keep iterating the state machine */
/* Driver internal data */ struct mpc52xx_spi { struct spi_controller *host; void __iomem *regs; int irq0; /* MODF irq */ int irq1; /* SPIF irq */ unsignedint ipb_freq;
/* Statistics; not used now, but will be reintroduced for debugfs */ int msg_count; int wcol_count; int wcol_ticks;
u32 wcol_tx_timestamp; int modf_count; int byte_count;
/* Details of current transfer (length, and buffer pointers) */ struct spi_message *message; /* current message */ struct spi_transfer *transfer; /* current transfer */ int (*state)(int irq, struct mpc52xx_spi *ms, u8 status, u8 data); int len; int timestamp;
u8 *rx_buf; const u8 *tx_buf; int cs_change; int gpio_cs_count; struct gpio_desc **gpio_cs;
};
/* *CScontrolfunction
*/ staticvoid mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
{ int cs;
if (status & SPI_STATUS_WCOL) { /* The SPI controller is stoopid. At slower speeds, it may *raisetheSPIFflagbeforethestatemachineisactually *finished,whichcausesacollision(internaltothestate *machineonly).Themanualrecommendsinsertingadelay *betweenreceivingtheinterruptandsendingthenextbyte, *butitcanalsobeworkedaroundsimplybyretryingthe
* transfer which is what we do here. */
ms->wcol_count++;
ms->wcol_ticks += mftb() - ms->wcol_tx_timestamp;
ms->wcol_tx_timestamp = mftb();
data = 0; if (ms->tx_buf)
data = *(ms->tx_buf - 1);
out_8(ms->regs + SPI_DATA, data); /* try again */ return FSM_CONTINUE;
} elseif (status & SPI_STATUS_MODF) {
ms->modf_count++;
dev_err(&ms->host->dev, "mode fault\n");
mpc52xx_spi_chipsel(ms, 0);
ms->message->status = -EIO; if (ms->message->complete)
ms->message->complete(ms->message->context);
ms->state = mpc52xx_spi_fsmstate_idle; return FSM_CONTINUE;
}
/* Read data out of the spi device */
ms->byte_count++; if (ms->rx_buf)
*ms->rx_buf++ = data;
/* Is the transfer complete? */
ms->len--; if (ms->len == 0) {
ms->timestamp = mftb(); if (ms->transfer->delay.unit == SPI_DELAY_UNIT_USECS)
ms->timestamp += ms->transfer->delay.value *
tb_ticks_per_usec;
ms->state = mpc52xx_spi_fsmstate_wait; return FSM_CONTINUE;
}
/* Write out the next byte */
ms->wcol_tx_timestamp = mftb(); if (ms->tx_buf)
out_8(ms->regs + SPI_DATA, *ms->tx_buf++); else
out_8(ms->regs + SPI_DATA, 0);
if (((int)mftb()) - ms->timestamp < 0) return FSM_POLL;
ms->message->actual_length += ms->transfer->len;
/* Check if there is another transfer in this message. If there *aren'tthendeactivateCS,notifysender,anddropbacktoidle
* to start the next message. */ if (ms->transfer->transfer_list.next == &ms->message->transfers) {
ms->msg_count++;
mpc52xx_spi_chipsel(ms, 0);
ms->message->status = 0; if (ms->message->complete)
ms->message->complete(ms->message->context);
ms->state = mpc52xx_spi_fsmstate_idle; return FSM_CONTINUE;
}
while (rc == FSM_CONTINUE) { /* Interrupt cleared by read of STATUS followed by
* read of DATA registers */
status = in_8(ms->regs + SPI_STATUS);
data = in_8(ms->regs + SPI_DATA);
rc = ms->state(irq, ms, status, data);
}
/* Clear the status register and re-read it to check for a MODF *failure.Thisdrivercannotcurrentlyhandlemultiplehosts *ontheSPIbus.ThisfaultwillalsooccuriftheSPIsignals
* are not connected to any pins (port_config setting) */
in_8(regs + SPI_STATUS);
out_8(regs + SPI_CTRL1, ctrl1);
for (i = 0; i < ms->gpio_cs_count; i++) {
gpio_cs = gpiod_get_index(&op->dev,
NULL, i, GPIOD_OUT_LOW);
rc = PTR_ERR_OR_ZERO(gpio_cs); if (rc) {
dev_err(&op->dev, "failed to get spi cs gpio #%d: %d\n",
i, rc); goto err_gpio;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.