do { switch (state) { case state_init: /* detect phase of upper layer sequence */
{ /* initial write ? */ if (flags & FALCON_SPI_XFER_BEGIN) { if (!txp) {
dev_err(dev, "BEGIN without tx data!\n"); return -ENODATA;
} /* * Prepare the parts of the sfcmd register, * which should not change during a sequence! * Only exception are the length fields, * especially alen and dumlen.
*/
priv->sfcmd = ((spi_get_chipselect(spi, 0)
<< SFCMD_CS_OFFSET)
& SFCMD_CS_MASK);
priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
priv->sfcmd |= *txp;
txp++;
bytelen--; if (bytelen) { /* * more data: * maybe address and/or dummy
*/
state = state_command_prepare; break;
} else {
dev_dbg(dev, "write cmd %02X\n",
priv->sfcmd & SFCMD_OPC_MASK);
}
} /* continued write ? */ if (txp && bytelen) {
state = state_write; break;
} /* read data? */ if (rxp && bytelen) {
state = state_read; break;
} /* end of sequence? */ if (flags & FALCON_SPI_XFER_END)
state = state_disable_cs; else
state = state_end; break;
} /* collect tx data for address and dummy phase */ case state_command_prepare:
{ /* txp is valid, already checked */
val = 0;
alen = 0;
dumlen = 0; while (bytelen > 0) { if (alen < 3) {
val = (val << 8) | (*txp++);
alen++;
} elseif ((dumlen < 15) && (*txp == 0)) { /* * assume dummy bytes are set to 0 * from upper layer
*/
dumlen++;
txp++;
} else { break;
}
bytelen--;
}
priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
(dumlen << SFCMD_DUMLEN_OFFSET); if (alen > 0)
ltq_ebu_w32(val, SFADDR);
if (spi->max_speed_hz >= CLOCK_100M) { /* set EBU clock to 100 MHz */
ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, EBUCC);
i = 1; /* divider */
} else { /* set EBU clock to 50 MHz */
ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, EBUCC);
/* search for suitable divider */ for (i = 1; i < 7; i++) { if (CLOCK_50M / i <= spi->max_speed_hz) break;
}
}
/* setup period of serial clock */
ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK
| SFTIME_SCKR_POS_MASK
| SFTIME_SCK_PER_MASK,
(i << SFTIME_SCKR_POS_OFFSET)
| (i << (SFTIME_SCK_PER_OFFSET + 1)),
SFTIME);
/* * set some bits of unused_wd, to not trigger HOLD/WP * signals on non QUAD flashes
*/
ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), SFIO);
ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
BUSRCON0);
ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, BUSWCON0); /* set address wrap around to maximum for 24-bit addresses */
ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, SFCON);
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.