|
|
|
@ -307,10 +307,16 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
|
|
|
|
|
x |= (u32)(*tx_buf++) << (i * 8);
|
|
|
|
|
tegra_spi_writel(tspi, x, SPI_TX_FIFO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned int write_bytes;
|
|
|
|
|
max_n_32bit = min(tspi->curr_dma_words, tx_empty_count);
|
|
|
|
|
written_words = max_n_32bit;
|
|
|
|
|
nbytes = written_words * tspi->bytes_per_word;
|
|
|
|
|
if (nbytes > t->len - tspi->cur_pos)
|
|
|
|
|
nbytes = t->len - tspi->cur_pos;
|
|
|
|
|
write_bytes = nbytes;
|
|
|
|
|
for (count = 0; count < max_n_32bit; count++) {
|
|
|
|
|
u32 x = 0;
|
|
|
|
|
|
|
|
|
@ -319,8 +325,10 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
|
|
|
|
|
x |= (u32)(*tx_buf++) << (i * 8);
|
|
|
|
|
tegra_spi_writel(tspi, x, SPI_TX_FIFO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->cur_tx_pos += write_bytes;
|
|
|
|
|
}
|
|
|
|
|
tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
|
|
|
|
|
|
|
|
|
|
return written_words;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -344,20 +352,27 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
|
|
|
|
|
for (i = 0; len && (i < 4); i++, len--)
|
|
|
|
|
*rx_buf++ = (x >> i*8) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
read_words += tspi->curr_dma_words;
|
|
|
|
|
tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
} else {
|
|
|
|
|
u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
|
|
|
|
|
u8 bytes_per_word = tspi->bytes_per_word;
|
|
|
|
|
unsigned int read_bytes;
|
|
|
|
|
|
|
|
|
|
len = rx_full_count * bytes_per_word;
|
|
|
|
|
if (len > t->len - tspi->cur_pos)
|
|
|
|
|
len = t->len - tspi->cur_pos;
|
|
|
|
|
read_bytes = len;
|
|
|
|
|
for (count = 0; count < rx_full_count; count++) {
|
|
|
|
|
u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (i < tspi->bytes_per_word); i++)
|
|
|
|
|
for (i = 0; len && (i < bytes_per_word); i++, len--)
|
|
|
|
|
*rx_buf++ = (x >> (i*8)) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word;
|
|
|
|
|
read_words += rx_full_count;
|
|
|
|
|
tspi->cur_rx_pos += read_bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return read_words;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -372,12 +387,17 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
|
|
|
|
|
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
|
|
|
|
|
memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
|
|
|
|
|
tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
unsigned int count;
|
|
|
|
|
u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
|
|
|
|
|
unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
unsigned int write_bytes;
|
|
|
|
|
|
|
|
|
|
if (consume > t->len - tspi->cur_pos)
|
|
|
|
|
consume = t->len - tspi->cur_pos;
|
|
|
|
|
write_bytes = consume;
|
|
|
|
|
for (count = 0; count < tspi->curr_dma_words; count++) {
|
|
|
|
|
u32 x = 0;
|
|
|
|
|
|
|
|
|
@ -386,8 +406,9 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
|
|
|
|
|
x |= (u32)(*tx_buf++) << (i * 8);
|
|
|
|
|
tspi->tx_dma_buf[count] = x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->cur_tx_pos += write_bytes;
|
|
|
|
|
}
|
|
|
|
|
tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
|
|
|
|
|
/* Make the dma buffer to read by dma */
|
|
|
|
|
dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys,
|
|
|
|
@ -405,20 +426,28 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
|
|
|
|
|
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
|
|
|
|
|
memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
|
|
|
|
|
tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
unsigned int count;
|
|
|
|
|
unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos;
|
|
|
|
|
u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
|
|
|
|
|
unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
unsigned int read_bytes;
|
|
|
|
|
|
|
|
|
|
if (consume > t->len - tspi->cur_pos)
|
|
|
|
|
consume = t->len - tspi->cur_pos;
|
|
|
|
|
read_bytes = consume;
|
|
|
|
|
for (count = 0; count < tspi->curr_dma_words; count++) {
|
|
|
|
|
u32 x = tspi->rx_dma_buf[count] & rx_mask;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (i < tspi->bytes_per_word); i++)
|
|
|
|
|
for (i = 0; consume && (i < tspi->bytes_per_word);
|
|
|
|
|
i++, consume--)
|
|
|
|
|
*rx_buf++ = (x >> (i*8)) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->cur_rx_pos += read_bytes;
|
|
|
|
|
}
|
|
|
|
|
tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
|
|
|
|
|
|
|
|
|
|
/* Make the dma buffer to read by dma */
|
|
|
|
|
dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
|
|
|
|
@ -470,21 +499,38 @@ static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int tegra_spi_flush_fifos(struct tegra_spi_data *tspi)
|
|
|
|
|
{
|
|
|
|
|
unsigned long timeout = jiffies + HZ;
|
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
|
|
status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
|
|
|
|
|
if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
|
|
|
|
|
status |= SPI_RX_FIFO_FLUSH | SPI_TX_FIFO_FLUSH;
|
|
|
|
|
tegra_spi_writel(tspi, status, SPI_FIFO_STATUS);
|
|
|
|
|
while ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
|
|
|
|
|
status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
|
|
|
|
|
if (time_after(jiffies, timeout)) {
|
|
|
|
|
dev_err(tspi->dev,
|
|
|
|
|
"timeout waiting for fifo flush\n");
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
udelay(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int tegra_spi_start_dma_based_transfer(
|
|
|
|
|
struct tegra_spi_data *tspi, struct spi_transfer *t)
|
|
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
unsigned int len;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
|
|
/* Make sure that Rx and Tx fifo are empty */
|
|
|
|
|
status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
|
|
|
|
|
if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
|
|
|
|
|
dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n",
|
|
|
|
|
(unsigned)status);
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
u8 dma_burst;
|
|
|
|
|
struct dma_slave_config dma_sconfig = {0};
|
|
|
|
|
|
|
|
|
|
val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1);
|
|
|
|
|
tegra_spi_writel(tspi, val, SPI_DMA_BLK);
|
|
|
|
@ -496,12 +542,16 @@ static int tegra_spi_start_dma_based_transfer(
|
|
|
|
|
len = tspi->curr_dma_words * 4;
|
|
|
|
|
|
|
|
|
|
/* Set attention level based on length of transfer */
|
|
|
|
|
if (len & 0xF)
|
|
|
|
|
if (len & 0xF) {
|
|
|
|
|
val |= SPI_TX_TRIG_1 | SPI_RX_TRIG_1;
|
|
|
|
|
else if (((len) >> 4) & 0x1)
|
|
|
|
|
dma_burst = 1;
|
|
|
|
|
} else if (((len) >> 4) & 0x1) {
|
|
|
|
|
val |= SPI_TX_TRIG_4 | SPI_RX_TRIG_4;
|
|
|
|
|
else
|
|
|
|
|
dma_burst = 4;
|
|
|
|
|
} else {
|
|
|
|
|
val |= SPI_TX_TRIG_8 | SPI_RX_TRIG_8;
|
|
|
|
|
dma_burst = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tspi->cur_direction & DATA_DIR_TX)
|
|
|
|
|
val |= SPI_IE_TX;
|
|
|
|
@ -512,7 +562,18 @@ static int tegra_spi_start_dma_based_transfer(
|
|
|
|
|
tegra_spi_writel(tspi, val, SPI_DMA_CTL);
|
|
|
|
|
tspi->dma_control_reg = val;
|
|
|
|
|
|
|
|
|
|
dma_sconfig.device_fc = true;
|
|
|
|
|
if (tspi->cur_direction & DATA_DIR_TX) {
|
|
|
|
|
dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO;
|
|
|
|
|
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
|
dma_sconfig.dst_maxburst = dma_burst;
|
|
|
|
|
ret = dmaengine_slave_config(tspi->tx_dma_chan, &dma_sconfig);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(tspi->dev,
|
|
|
|
|
"DMA slave config failed: %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tegra_spi_copy_client_txbuf_to_spi_txbuf(tspi, t);
|
|
|
|
|
ret = tegra_spi_start_tx_dma(tspi, len);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
@ -523,6 +584,16 @@ static int tegra_spi_start_dma_based_transfer(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tspi->cur_direction & DATA_DIR_RX) {
|
|
|
|
|
dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO;
|
|
|
|
|
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
|
dma_sconfig.src_maxburst = dma_burst;
|
|
|
|
|
ret = dmaengine_slave_config(tspi->rx_dma_chan, &dma_sconfig);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(tspi->dev,
|
|
|
|
|
"DMA slave config failed: %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the dma buffer to read by dma */
|
|
|
|
|
dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
|
|
|
|
|
tspi->dma_buf_size, DMA_FROM_DEVICE);
|
|
|
|
@ -582,7 +653,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
|
|
|
|
u32 *dma_buf;
|
|
|
|
|
dma_addr_t dma_phys;
|
|
|
|
|
int ret;
|
|
|
|
|
struct dma_slave_config dma_sconfig;
|
|
|
|
|
|
|
|
|
|
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
|
|
|
|
dma_to_memory ? "rx" : "tx");
|
|
|
|
@ -602,19 +672,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dma_to_memory) {
|
|
|
|
|
dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO;
|
|
|
|
|
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
|
dma_sconfig.src_maxburst = 0;
|
|
|
|
|
} else {
|
|
|
|
|
dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO;
|
|
|
|
|
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
|
dma_sconfig.dst_maxburst = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto scrub;
|
|
|
|
|
if (dma_to_memory) {
|
|
|
|
|
tspi->rx_dma_chan = dma_chan;
|
|
|
|
|
tspi->rx_dma_buf = dma_buf;
|
|
|
|
@ -625,11 +682,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
|
|
|
|
tspi->tx_dma_phys = dma_phys;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
scrub:
|
|
|
|
|
dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys);
|
|
|
|
|
dma_release_channel(dma_chan);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
|
|
|
|
@ -735,6 +787,8 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
|
|
|
|
|
|
|
|
|
if (tspi->is_packed)
|
|
|
|
|
command1 |= SPI_PACKED;
|
|
|
|
|
else
|
|
|
|
|
command1 &= ~SPI_PACKED;
|
|
|
|
|
|
|
|
|
|
command1 &= ~(SPI_CS_SEL_MASK | SPI_TX_EN | SPI_RX_EN);
|
|
|
|
|
tspi->cur_direction = 0;
|
|
|
|
@ -753,6 +807,9 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
|
|
|
|
dev_dbg(tspi->dev, "The def 0x%x and written 0x%x\n",
|
|
|
|
|
tspi->def_command1_reg, (unsigned)command1);
|
|
|
|
|
|
|
|
|
|
ret = tegra_spi_flush_fifos(tspi);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
if (total_fifo_words > SPI_FIFO_DEPTH)
|
|
|
|
|
ret = tegra_spi_start_dma_based_transfer(tspi, t);
|
|
|
|
|
else
|
|
|
|
@ -804,6 +861,19 @@ static void tegra_spi_transfer_delay(int delay)
|
|
|
|
|
udelay(delay % 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void tegra_spi_transfer_end(struct spi_device *spi)
|
|
|
|
|
{
|
|
|
|
|
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
|
|
|
|
int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
if (cs_val)
|
|
|
|
|
tspi->command1_reg |= SPI_CS_SW_VAL;
|
|
|
|
|
else
|
|
|
|
|
tspi->command1_reg &= ~SPI_CS_SW_VAL;
|
|
|
|
|
tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
|
|
|
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|
|
|
|
struct spi_message *msg)
|
|
|
|
|
{
|
|
|
|
@ -843,7 +913,17 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|
|
|
|
if (WARN_ON(ret == 0)) {
|
|
|
|
|
dev_err(tspi->dev,
|
|
|
|
|
"spi transfer timeout, err %d\n", ret);
|
|
|
|
|
if (tspi->is_curr_dma_xfer &&
|
|
|
|
|
(tspi->cur_direction & DATA_DIR_TX))
|
|
|
|
|
dmaengine_terminate_all(tspi->tx_dma_chan);
|
|
|
|
|
if (tspi->is_curr_dma_xfer &&
|
|
|
|
|
(tspi->cur_direction & DATA_DIR_RX))
|
|
|
|
|
dmaengine_terminate_all(tspi->rx_dma_chan);
|
|
|
|
|
ret = -EIO;
|
|
|
|
|
tegra_spi_flush_fifos(tspi);
|
|
|
|
|
reset_control_assert(tspi->rst);
|
|
|
|
|
udelay(2);
|
|
|
|
|
reset_control_deassert(tspi->rst);
|
|
|
|
|
goto complete_xfer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -856,8 +936,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|
|
|
|
|
|
|
|
|
complete_xfer:
|
|
|
|
|
if (ret < 0 || skip) {
|
|
|
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
|
|
|
|
SPI_COMMAND1);
|
|
|
|
|
tegra_spi_transfer_end(spi);
|
|
|
|
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
|
|
|
|
goto exit;
|
|
|
|
|
} else if (list_is_last(&xfer->transfer_list,
|
|
|
|
@ -865,13 +944,11 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|
|
|
|
if (xfer->cs_change)
|
|
|
|
|
tspi->cs_control = spi;
|
|
|
|
|
else {
|
|
|
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
|
|
|
|
SPI_COMMAND1);
|
|
|
|
|
tegra_spi_transfer_end(spi);
|
|
|
|
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
|
|
|
|
}
|
|
|
|
|
} else if (xfer->cs_change) {
|
|
|
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
|
|
|
|
SPI_COMMAND1);
|
|
|
|
|
tegra_spi_transfer_end(spi);
|
|
|
|
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -894,11 +971,13 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
|
|
|
|
|
tspi->status_reg);
|
|
|
|
|
dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n",
|
|
|
|
|
tspi->command1_reg, tspi->dma_control_reg);
|
|
|
|
|
tegra_spi_flush_fifos(tspi);
|
|
|
|
|
complete(&tspi->xfer_completion);
|
|
|
|
|
spin_unlock_irqrestore(&tspi->lock, flags);
|
|
|
|
|
reset_control_assert(tspi->rst);
|
|
|
|
|
udelay(2);
|
|
|
|
|
reset_control_deassert(tspi->rst);
|
|
|
|
|
complete(&tspi->xfer_completion);
|
|
|
|
|
goto exit;
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tspi->cur_direction & DATA_DIR_RX)
|
|
|
|
@ -966,11 +1045,12 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
|
|
|
|
|
tspi->status_reg);
|
|
|
|
|
dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n",
|
|
|
|
|
tspi->command1_reg, tspi->dma_control_reg);
|
|
|
|
|
tegra_spi_flush_fifos(tspi);
|
|
|
|
|
complete(&tspi->xfer_completion);
|
|
|
|
|
spin_unlock_irqrestore(&tspi->lock, flags);
|
|
|
|
|
reset_control_assert(tspi->rst);
|
|
|
|
|
udelay(2);
|
|
|
|
|
reset_control_deassert(tspi->rst);
|
|
|
|
|
complete(&tspi->xfer_completion);
|
|
|
|
|
spin_unlock_irqrestore(&tspi->lock, flags);
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1072,27 +1152,19 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
spi_irq = platform_get_irq(pdev, 0);
|
|
|
|
|
tspi->irq = spi_irq;
|
|
|
|
|
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
|
|
|
|
|
tegra_spi_isr_thread, IRQF_ONESHOT,
|
|
|
|
|
dev_name(&pdev->dev), tspi);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
|
|
|
|
tspi->irq);
|
|
|
|
|
goto exit_free_master;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->clk = devm_clk_get(&pdev->dev, "spi");
|
|
|
|
|
if (IS_ERR(tspi->clk)) {
|
|
|
|
|
dev_err(&pdev->dev, "can not get clock\n");
|
|
|
|
|
ret = PTR_ERR(tspi->clk);
|
|
|
|
|
goto exit_free_irq;
|
|
|
|
|
goto exit_free_master;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
|
|
|
|
|
if (IS_ERR(tspi->rst)) {
|
|
|
|
|
dev_err(&pdev->dev, "can not get reset\n");
|
|
|
|
|
ret = PTR_ERR(tspi->rst);
|
|
|
|
|
goto exit_free_irq;
|
|
|
|
|
goto exit_free_master;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
|
|
|
|
@ -1100,7 +1172,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
ret = tegra_spi_init_dma_param(tspi, true);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
goto exit_free_irq;
|
|
|
|
|
goto exit_free_master;
|
|
|
|
|
ret = tegra_spi_init_dma_param(tspi, false);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
goto exit_rx_dma_free;
|
|
|
|
@ -1122,18 +1194,32 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
|
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
|
|
|
|
|
goto exit_pm_disable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reset_control_assert(tspi->rst);
|
|
|
|
|
udelay(2);
|
|
|
|
|
reset_control_deassert(tspi->rst);
|
|
|
|
|
tspi->def_command1_reg = SPI_M_S;
|
|
|
|
|
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
|
|
|
|
|
pm_runtime_put(&pdev->dev);
|
|
|
|
|
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
|
|
|
|
|
tegra_spi_isr_thread, IRQF_ONESHOT,
|
|
|
|
|
dev_name(&pdev->dev), tspi);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
|
|
|
|
tspi->irq);
|
|
|
|
|
goto exit_pm_disable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
master->dev.of_node = pdev->dev.of_node;
|
|
|
|
|
ret = devm_spi_register_master(&pdev->dev, master);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
|
|
|
|
goto exit_pm_disable;
|
|
|
|
|
goto exit_free_irq;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
exit_free_irq:
|
|
|
|
|
free_irq(spi_irq, tspi);
|
|
|
|
|
exit_pm_disable:
|
|
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
|
|
if (!pm_runtime_status_suspended(&pdev->dev))
|
|
|
|
@ -1141,8 +1227,6 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|
|
|
|
tegra_spi_deinit_dma_param(tspi, false);
|
|
|
|
|
exit_rx_dma_free:
|
|
|
|
|
tegra_spi_deinit_dma_param(tspi, true);
|
|
|
|
|
exit_free_irq:
|
|
|
|
|
free_irq(spi_irq, tspi);
|
|
|
|
|
exit_free_master:
|
|
|
|
|
spi_master_put(master);
|
|
|
|
|
return ret;
|
|
|
|
|