/* See how much data is available */
reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
if (len > cnt)
len = cnt;
while (len--) {
byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); if (sspi->rx_buf)
*sspi->rx_buf++ = byte;
}
}
/* We want to control the chip select manually */
reg |= SUN4I_CTL_CS_MANUAL;
if (enable)
reg |= SUN4I_CTL_CS_LEVEL; else
reg &= ~SUN4I_CTL_CS_LEVEL;
/* * Even though this looks irrelevant since we are supposed to * be controlling the chip select manually, this bit also * controls the levels of the chip select for inactive * devices. * * If we don't set it, the chip select level will go low by * default when the device is idle, which is not really * expected in the common case where the chip select is active * low.
*/ if (spi->mode & SPI_CS_HIGH)
reg &= ~SUN4I_CTL_CS_ACTIVE_LOW; else
reg |= SUN4I_CTL_CS_ACTIVE_LOW;
/* * Setup the transfer control register: Chip Select, * polarities, etc.
*/ if (spi->mode & SPI_CPOL)
reg |= SUN4I_CTL_CPOL; else
reg &= ~SUN4I_CTL_CPOL;
/* * If it's a TX only transfer, we don't want to fill the RX * FIFO with bogus data
*/ if (sspi->rx_buf)
reg &= ~SUN4I_CTL_DHB; else
reg |= SUN4I_CTL_DHB;
/* Now that the settings are correct, enable the interface */
reg |= SUN4I_CTL_ENABLE;
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk); if (mclk_rate < (2 * tfr->speed_hz)) {
clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
/* * Setup clock divider. * * We have two choices there. Either we can use the clock * divide rate 1, which is calculated thanks to this formula: * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) * Or we can use CDR2, which is calculated with the formula: * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) * Whether we use the former or the latter is set through the * DRS bit. * * First try CDR2, and if we can't reach the expected * frequency, fall back to CDR1.
*/
div = mclk_rate / (2 * tfr->speed_hz); if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { if (div > 0)
div--;
/* * Fill the TX FIFO * Filling the FIFO fully causes timeout for some reason * at least on spi2 on A10s
*/
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
/* Enable the interrupts */
sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
SUN4I_INT_CTL_RF_F34); /* Only enable Tx FIFO interrupt if we really need it */ if (tx_len > SUN4I_FIFO_DEPTH)
sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
/* Start the transfer */
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk); goto err_free_host;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk); goto err_free_host;
}
init_completion(&sspi->done);
/* * This wake-up/shutdown pattern is to be able to have the * device woken up, even if runtime_pm is disabled
*/
ret = sun4i_spi_runtime_resume(&pdev->dev); if (ret) {
dev_err(&pdev->dev, "Couldn't resume the device\n"); goto err_free_host;
}
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.