2016-01-14 14:48:12 +01:00
|
|
|
/* spi_dw.c - Designware SPI driver implementation */
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Intel Corporation.
|
|
|
|
*
|
2017-01-19 02:01:01 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2015-11-22 03:28:21 +01:00
|
|
|
*/
|
2017-05-04 10:03:13 +02:00
|
|
|
#define SYS_LOG_DOMAIN "SPI DW"
|
|
|
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SPI_LEVEL
|
|
|
|
#include <logging/sys_log.h>
|
|
|
|
|
|
|
|
#if (CONFIG_SYS_LOG_SPI_LEVEL == 4)
|
|
|
|
#define DBG_COUNTER_INIT() \
|
|
|
|
u32_t __cnt = 0
|
|
|
|
#define DBG_COUNTER_INC() \
|
|
|
|
(__cnt++)
|
|
|
|
#define DBG_COUNTER_RESULT() \
|
|
|
|
(__cnt)
|
|
|
|
#else
|
|
|
|
#define DBG_COUNTER_INIT() {; }
|
|
|
|
#define DBG_COUNTER_INC() {; }
|
|
|
|
#define DBG_COUNTER_RESULT() 0
|
|
|
|
#endif
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-03-09 18:38:02 +01:00
|
|
|
#include <errno.h>
|
|
|
|
|
2016-12-04 21:59:37 +01:00
|
|
|
#include <kernel.h>
|
2015-11-22 03:28:21 +01:00
|
|
|
#include <arch/cpu.h>
|
|
|
|
|
|
|
|
#include <board.h>
|
|
|
|
#include <device.h>
|
|
|
|
#include <init.h>
|
|
|
|
|
|
|
|
#include <sys_io.h>
|
|
|
|
#include <clock_control.h>
|
|
|
|
#include <misc/util.h>
|
|
|
|
|
2015-12-10 18:52:56 +01:00
|
|
|
#ifdef CONFIG_IOAPIC
|
|
|
|
#include <drivers/ioapic.h>
|
|
|
|
#endif
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
#include <spi.h>
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
#include "spi_dw.h"
|
|
|
|
#include "spi_context.h"
|
2016-04-01 08:41:30 +02:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
static void completed(struct device *dev, uint8_t error)
|
2015-11-22 03:28:21 +01:00
|
|
|
{
|
2016-10-06 20:28:52 +02:00
|
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
2015-11-22 03:28:21 +01:00
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
|
|
|
2016-02-04 13:57:52 +01:00
|
|
|
if (error) {
|
|
|
|
goto out;
|
2016-01-15 10:11:24 +01:00
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi_context_tx_on(&spi->ctx) ||
|
|
|
|
spi_context_rx_on(&spi->ctx)) {
|
|
|
|
return;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2016-02-04 13:57:52 +01:00
|
|
|
out:
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
/* need to give time for FIFOs to drain before issuing more commands */
|
|
|
|
while (test_bit_sr_busy(info->regs)) {
|
|
|
|
}
|
|
|
|
|
2015-12-08 13:30:41 +01:00
|
|
|
spi->error = error;
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
/* Disabling interrupts */
|
|
|
|
write_imr(DW_SPI_IMR_MASK, info->regs);
|
2016-01-18 17:27:21 +01:00
|
|
|
/* Disabling the controller */
|
|
|
|
clear_bit_ssienr(info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
spi_context_cs_control(&spi->ctx, false);
|
2016-02-04 17:02:03 +01:00
|
|
|
|
2016-05-08 01:15:28 +02:00
|
|
|
SYS_LOG_DBG("SPI transaction completed %s error",
|
2017-04-24 16:29:37 +02:00
|
|
|
error ? "with" : "without");
|
2016-02-04 17:02:03 +01:00
|
|
|
|
2017-05-08 09:40:56 +02:00
|
|
|
spi_context_complete(&spi->ctx, error ? -EIO : 0);
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void push_data(struct device *dev)
|
|
|
|
{
|
2016-10-06 20:28:52 +02:00
|
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
2015-11-22 03:28:21 +01:00
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
2017-04-21 17:03:20 +02:00
|
|
|
u32_t data = 0;
|
|
|
|
u32_t f_tx;
|
2017-05-04 10:03:13 +02:00
|
|
|
|
2016-02-04 17:02:03 +01:00
|
|
|
DBG_COUNTER_INIT();
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi_context_rx_on(&spi->ctx)) {
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs) -
|
2017-05-04 10:03:13 +02:00
|
|
|
read_rxflr(info->regs);
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
if ((int)f_tx < 0) {
|
|
|
|
f_tx = 0; /* if rx-fifo is full, hold off tx */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs);
|
|
|
|
}
|
2017-04-24 16:29:37 +02:00
|
|
|
|
2016-01-15 10:11:24 +01:00
|
|
|
while (f_tx) {
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi_context_tx_on(&spi->ctx)) {
|
2015-12-19 00:26:42 +01:00
|
|
|
switch (spi->dfs) {
|
|
|
|
case 1:
|
2017-05-04 10:03:13 +02:00
|
|
|
data = UNALIGNED_GET((u8_t *)
|
|
|
|
(spi->ctx.tx_buf));
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2017-05-04 10:03:13 +02:00
|
|
|
data = UNALIGNED_GET((u16_t *)
|
|
|
|
(spi->ctx.tx_buf));
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
#ifndef CONFIG_ARC
|
|
|
|
case 4:
|
2017-05-04 10:03:13 +02:00
|
|
|
data = UNALIGNED_GET((u32_t *)
|
|
|
|
(spi->ctx.tx_buf));
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2017-05-04 10:03:13 +02:00
|
|
|
} else if (spi_context_rx_on(&spi->ctx)) {
|
2015-11-22 03:28:21 +01:00
|
|
|
/* No need to push more than necessary */
|
2017-05-04 10:03:13 +02:00
|
|
|
if ((int)(spi->ctx.rx_len - spi->fifo_diff) <= 0) {
|
2015-11-22 03:28:21 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = 0;
|
|
|
|
} else {
|
|
|
|
/* Nothing to push anymore */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_dr(data, info->regs);
|
2017-05-04 10:03:13 +02:00
|
|
|
|
|
|
|
spi_context_update_tx(&spi->ctx, spi->dfs);
|
2016-01-15 10:11:24 +01:00
|
|
|
spi->fifo_diff++;
|
2017-05-04 10:03:13 +02:00
|
|
|
|
|
|
|
f_tx--;
|
|
|
|
|
2016-02-04 17:02:03 +01:00
|
|
|
DBG_COUNTER_INC();
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (!spi_context_tx_on(&spi->ctx)) {
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
/* prevents any further interrupts demanding TX fifo fill */
|
2017-05-04 10:03:13 +02:00
|
|
|
write_txftlr(0, info->regs);
|
2016-01-25 10:01:50 +01:00
|
|
|
}
|
|
|
|
|
2016-05-08 01:15:28 +02:00
|
|
|
SYS_LOG_DBG("Pushed: %d", DBG_COUNTER_RESULT());
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pull_data(struct device *dev)
|
|
|
|
{
|
2016-10-06 20:28:52 +02:00
|
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
2015-11-22 03:28:21 +01:00
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
2017-05-04 10:03:13 +02:00
|
|
|
|
2016-02-04 17:02:03 +01:00
|
|
|
DBG_COUNTER_INIT();
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-01-15 10:11:24 +01:00
|
|
|
while (read_rxflr(info->regs)) {
|
2017-05-04 10:03:13 +02:00
|
|
|
u32_t data = read_dr(info->regs);
|
|
|
|
|
2016-02-04 17:02:03 +01:00
|
|
|
DBG_COUNTER_INC();
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi_context_rx_on(&spi->ctx)) {
|
2015-12-19 00:26:42 +01:00
|
|
|
switch (spi->dfs) {
|
|
|
|
case 1:
|
2017-05-04 10:03:13 +02:00
|
|
|
UNALIGNED_PUT(data, (u8_t *)spi->ctx.rx_buf);
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2017-05-04 10:03:13 +02:00
|
|
|
UNALIGNED_PUT(data, (u16_t *)spi->ctx.rx_buf);
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
#ifndef CONFIG_ARC
|
|
|
|
case 4:
|
2017-05-04 10:03:13 +02:00
|
|
|
UNALIGNED_PUT(data, (u32_t *)spi->ctx.rx_buf);
|
2015-12-19 00:26:42 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
2016-01-15 10:11:24 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
spi_context_update_rx(&spi->ctx, spi->dfs);
|
2016-01-15 10:11:24 +01:00
|
|
|
spi->fifo_diff--;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (!spi->ctx.rx_len && spi->ctx.tx_len < DW_SPI_FIFO_DEPTH) {
|
|
|
|
write_rxftlr(spi->ctx.tx_len - 1, info->regs);
|
|
|
|
} else if (read_rxftlr(info->regs) >= spi->ctx.rx_len) {
|
|
|
|
write_rxftlr(spi->ctx.rx_len - 1, info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2016-05-08 01:15:28 +02:00
|
|
|
SYS_LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT());
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
static int spi_dw_configure(const struct spi_dw_config *info,
|
|
|
|
struct spi_dw_data *spi,
|
2017-04-24 16:29:37 +02:00
|
|
|
struct spi_config *config)
|
2015-11-22 03:28:21 +01:00
|
|
|
{
|
2017-04-21 17:03:20 +02:00
|
|
|
u32_t ctrlr0 = 0;
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
SYS_LOG_DBG("%p (prev %p)", config, spi->ctx.config);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi_context_configured(&spi->ctx, config)) {
|
|
|
|
/* Nothing to do */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config->operation & (SPI_OP_MODE_SLAVE || SPI_TRANSFER_LSB
|
|
|
|
|| SPI_LINES_DUAL || SPI_LINES_QUAD)) {
|
|
|
|
return -EINVAL;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Word size */
|
2017-05-04 10:03:13 +02:00
|
|
|
ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(config->operation));
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2015-12-19 00:26:42 +01:00
|
|
|
/* Determine how many bytes are required per-frame */
|
2017-05-04 10:03:13 +02:00
|
|
|
spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation));
|
2015-12-19 00:26:42 +01:00
|
|
|
|
2015-11-22 03:28:21 +01:00
|
|
|
/* SPI mode */
|
2017-05-04 10:03:13 +02:00
|
|
|
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) {
|
2015-11-22 03:28:21 +01:00
|
|
|
ctrlr0 |= DW_SPI_CTRLR0_SCPOL;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
|
2015-11-22 03:28:21 +01:00
|
|
|
ctrlr0 |= DW_SPI_CTRLR0_SCPH;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) {
|
2015-11-22 03:28:21 +01:00
|
|
|
ctrlr0 |= DW_SPI_CTRLR0_SRL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Installing the configuration */
|
|
|
|
write_ctrlr0(ctrlr0, info->regs);
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* Setting up baud rate */
|
|
|
|
write_baudr(SPI_DW_CLK_DIVIDER(config->frequency), info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* Slave select */
|
|
|
|
write_ser(config->slave, info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* At this point, it's mandatory to set this on the context! */
|
|
|
|
spi->ctx.config = config;
|
2016-02-04 17:02:03 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
spi_context_cs_configure(&spi->ctx);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
SYS_LOG_DBG("Installed config %p: freq %uHz (div = %u),"
|
|
|
|
" ws/dfs %u/%u, mode %u/%u/%u, slave %u",
|
|
|
|
config, config->frequency,
|
|
|
|
SPI_DW_CLK_DIVIDER(config->frequency), spi->dfs,
|
|
|
|
SPI_WORD_SIZE_GET(config->operation),
|
|
|
|
(SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) ? 1 : 0,
|
|
|
|
(SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) ? 1 : 0,
|
|
|
|
(SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) ? 1 : 0,
|
|
|
|
config->slave);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-03-09 18:01:20 +01:00
|
|
|
return 0;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-08 09:40:56 +02:00
|
|
|
static int transceive(struct spi_config *config,
|
|
|
|
const struct spi_buf **tx_bufs,
|
|
|
|
struct spi_buf **rx_bufs,
|
|
|
|
bool asynchronous,
|
|
|
|
struct k_poll_signal *signal)
|
2015-11-22 03:28:21 +01:00
|
|
|
{
|
2017-05-05 11:58:38 +02:00
|
|
|
const struct spi_dw_config *info = config->dev->config->config_info;
|
|
|
|
struct spi_dw_data *spi = config->dev->driver_data;
|
2017-04-21 17:03:20 +02:00
|
|
|
u32_t rx_thsld = DW_SPI_RXFTLR_DFLT;
|
2017-05-04 10:03:13 +02:00
|
|
|
u32_t imask = DW_SPI_IMR_UNMASK;
|
2017-05-05 13:28:17 +02:00
|
|
|
int ret = 0;
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
/* Check status */
|
2017-05-04 10:03:13 +02:00
|
|
|
if (test_bit_ssienr(info->regs) || test_bit_sr_busy(info->regs)) {
|
2017-04-24 16:29:37 +02:00
|
|
|
SYS_LOG_DBG("Controller is busy");
|
2016-03-09 19:26:12 +01:00
|
|
|
return -EBUSY;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-08 09:40:56 +02:00
|
|
|
spi_context_lock(&spi->ctx, asynchronous, signal);
|
2017-05-05 13:28:17 +02:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* Configure */
|
2017-05-05 13:28:17 +02:00
|
|
|
ret = spi_dw_configure(info, spi, config);
|
|
|
|
if (ret) {
|
|
|
|
goto out;
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
}
|
2017-05-04 10:03:13 +02:00
|
|
|
|
|
|
|
/* Set buffers info */
|
|
|
|
spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs);
|
|
|
|
|
2016-01-15 10:11:24 +01:00
|
|
|
spi->fifo_diff = 0;
|
|
|
|
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
/* Tx Threshold */
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
write_txftlr(DW_SPI_TXFTLR_DFLT, info->regs);
|
|
|
|
|
2016-01-15 10:11:24 +01:00
|
|
|
/* Does Rx thresholds needs to be lower? */
|
2017-05-04 10:03:13 +02:00
|
|
|
if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_FIFO_DEPTH) {
|
|
|
|
rx_thsld = spi->ctx.rx_len - 1;
|
2016-01-15 10:11:24 +01:00
|
|
|
}
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* Rx Threshold */
|
2016-01-15 10:11:24 +01:00
|
|
|
write_rxftlr(rx_thsld, info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
if (!rx_bufs) {
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
/* if there is no rx buffer, keep all rx interrupts masked */
|
|
|
|
imask &= DW_SPI_IMR_MASK_RX;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
/* Enable interrupts */
|
spi: Stability improvements to the DesignWare SPI driver
I've found many problems with the SPI driver and this repairs many of them.
The baud rate divisor was being derived from the CPU clock. But, some
targets may have a seperate clock attached to SPI. If the soc.h file
defines the symbol SPI_DW_SPI_CLOCK, it will use this instead
of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for the baud rate calculation.
completed() had a mistake where it would terminate the SPI transaction
too early, well before the tx data has cleared the FIFO. I found I couldn't
drive an OLED display correctly because completed() was wrong.
The repair is to now consider a new flag called spi->last_tx,
which will be set after the TX interrupt occurs with nothing to send any
longer. There is also a while loop added to SPIN until BUSY drops.
Another improvement is that push_data will NOT consider RX fifo size
if there is no RX going on. The calculation here when RX is going on
could go negative. I've added a check for that and prevent TX handling
if RX buffer is full. I think that is the intention -- to deal with RX first
if its fifos are more full.
In spi_dw_transceive, if we are only doing spi_write w/o reading,
don't enable RX interrupts at all. The OLED I'm working with failed
to have a pull-up on MISO SPI signal. As a result, a huge number of
garbage RX events arrive, and the interrupt handler finds there is
no rx buffer, so it tosses the data. But this is a waist of realtime.
It seems WRONG to enable RX interrupts if its something your not using,
so software can GATE these spurious events in this way.
With these changes, SPI can be used much more reliably, with FIFOs
that are deeper, and SPI devices that only require TX.
Change-Id: I0fe0745f2381c61c8a19ce086496b422a32a30a5
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-19 20:55:09 +02:00
|
|
|
write_imr(imask, info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
spi_context_cs_control(&spi->ctx, true);
|
|
|
|
|
2015-11-22 03:28:21 +01:00
|
|
|
/* Enable the controller */
|
|
|
|
set_bit_ssienr(info->regs);
|
|
|
|
|
2017-05-05 13:42:44 +02:00
|
|
|
spi_context_wait_for_completion(&spi->ctx);
|
2015-12-08 13:30:41 +01:00
|
|
|
|
|
|
|
if (spi->error) {
|
2017-05-05 13:28:17 +02:00
|
|
|
ret = -EIO;
|
2015-12-08 13:30:41 +01:00
|
|
|
}
|
2017-05-05 13:28:17 +02:00
|
|
|
out:
|
2017-05-08 09:40:56 +02:00
|
|
|
spi_context_release(&spi->ctx, ret);
|
2015-12-08 13:30:41 +01:00
|
|
|
|
2017-05-05 13:28:17 +02:00
|
|
|
return ret;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-08 09:40:56 +02:00
|
|
|
static int spi_dw_transceive(struct spi_config *config,
|
|
|
|
const struct spi_buf **tx_bufs,
|
|
|
|
struct spi_buf **rx_bufs)
|
|
|
|
{
|
|
|
|
SYS_LOG_DBG("%p, %p, %p", config->dev, tx_bufs, rx_bufs);
|
|
|
|
|
|
|
|
return transceive(config, tx_bufs, rx_bufs, false, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_POLL
|
|
|
|
static int spi_dw_transceive_async(struct spi_config *config,
|
|
|
|
const struct spi_buf **tx_bufs,
|
|
|
|
struct spi_buf **rx_bufs,
|
|
|
|
struct k_poll_signal *async)
|
|
|
|
{
|
|
|
|
SYS_LOG_DBG("%p, %p, %p, %p", config->dev, tx_bufs, rx_bufs, async);
|
|
|
|
|
|
|
|
return transceive(config, tx_bufs, rx_bufs, true, async);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_POLL */
|
|
|
|
|
2017-05-10 08:40:00 +02:00
|
|
|
static int spi_dw_release(struct spi_config *config)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
void spi_dw_isr(struct device *dev)
|
2015-11-22 03:28:21 +01:00
|
|
|
{
|
2016-10-06 20:28:52 +02:00
|
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
2017-04-21 17:03:20 +02:00
|
|
|
u32_t int_status;
|
2017-05-04 10:03:13 +02:00
|
|
|
u8_t error;
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
int_status = read_isr(info->regs);
|
|
|
|
|
2016-05-08 01:15:28 +02:00
|
|
|
SYS_LOG_DBG("SPI int_status 0x%x - (tx: %d, rx: %d)",
|
2017-04-24 16:29:37 +02:00
|
|
|
int_status, read_txflr(info->regs), read_rxflr(info->regs));
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
if (int_status & DW_SPI_ISR_ERRORS_MASK) {
|
|
|
|
error = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-05-04 10:03:13 +02:00
|
|
|
error = 0;
|
|
|
|
|
2015-11-22 03:28:21 +01:00
|
|
|
if (int_status & DW_SPI_ISR_RXFIS) {
|
|
|
|
pull_data(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (int_status & DW_SPI_ISR_TXEIS) {
|
|
|
|
push_data(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
clear_interrupts(info->regs);
|
2015-11-22 03:28:21 +01:00
|
|
|
completed(dev, error);
|
|
|
|
}
|
|
|
|
|
2016-10-24 09:39:15 +02:00
|
|
|
static const struct spi_driver_api dw_spi_api = {
|
2015-11-22 03:28:21 +01:00
|
|
|
.transceive = spi_dw_transceive,
|
2017-05-08 09:40:56 +02:00
|
|
|
#ifdef CONFIG_POLL
|
|
|
|
.transceive_async = spi_dw_transceive_async,
|
|
|
|
#endif
|
2017-05-10 08:40:00 +02:00
|
|
|
.release = spi_dw_release,
|
2015-11-22 03:28:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
int spi_dw_init(struct device *dev)
|
|
|
|
{
|
2016-10-06 20:28:52 +02:00
|
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
2016-01-21 11:25:26 +01:00
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
2015-11-22 03:28:21 +01:00
|
|
|
|
|
|
|
_clock_config(dev);
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
_clock_on(dev);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-01-21 11:15:38 +01:00
|
|
|
info->config_func();
|
2015-11-22 03:28:21 +01:00
|
|
|
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
/* Masking interrupt and making sure controller is disabled */
|
2015-11-22 03:28:21 +01:00
|
|
|
write_imr(DW_SPI_IMR_MASK, info->regs);
|
|
|
|
clear_bit_ssienr(info->regs);
|
|
|
|
|
2016-05-08 01:15:28 +02:00
|
|
|
SYS_LOG_DBG("Designware SPI driver initialized on device: %p", dev);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-08 09:40:56 +02:00
|
|
|
spi_context_release(&spi->ctx, 0);
|
2017-05-05 13:28:17 +02:00
|
|
|
|
2016-03-09 18:01:20 +01:00
|
|
|
return 0;
|
2015-11-22 03:28:21 +01:00
|
|
|
}
|
|
|
|
|
2015-12-10 18:52:56 +01:00
|
|
|
|
2016-05-08 00:57:14 +02:00
|
|
|
#ifdef CONFIG_SPI_0
|
2016-01-21 11:15:38 +01:00
|
|
|
void spi_config_0_irq(void);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-05 13:28:17 +02:00
|
|
|
struct spi_dw_data spi_dw_data_port_0 = {
|
|
|
|
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_0, ctx),
|
2017-05-05 13:42:44 +02:00
|
|
|
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_0, ctx),
|
2017-05-05 13:28:17 +02:00
|
|
|
};
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-10-19 23:16:49 +02:00
|
|
|
const struct spi_dw_config spi_dw_config_0 = {
|
2016-05-07 20:48:28 +02:00
|
|
|
.regs = SPI_DW_PORT_0_REGS,
|
2015-11-22 03:28:21 +01:00
|
|
|
#ifdef CONFIG_SPI_DW_CLOCK_GATE
|
2016-05-08 00:57:14 +02:00
|
|
|
.clock_data = UINT_TO_POINTER(CONFIG_SPI_0_CLOCK_GATE_SUBSYS),
|
2015-11-22 03:28:21 +01:00
|
|
|
#endif /* CONFIG_SPI_DW_CLOCK_GATE */
|
|
|
|
.config_func = spi_config_0_irq
|
|
|
|
};
|
|
|
|
|
2016-05-08 00:57:14 +02:00
|
|
|
DEVICE_AND_API_INIT(spi_dw_port_0, CONFIG_SPI_0_NAME, spi_dw_init,
|
2016-04-14 18:28:34 +02:00
|
|
|
&spi_dw_data_port_0, &spi_dw_config_0,
|
2016-11-08 20:06:55 +01:00
|
|
|
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
|
2016-04-14 18:28:34 +02:00
|
|
|
&dw_spi_api);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-01-21 11:15:38 +01:00
|
|
|
void spi_config_0_irq(void)
|
2016-01-08 09:46:14 +01:00
|
|
|
{
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
#ifdef CONFIG_SPI_DW_INTERRUPT_SINGLE_LINE
|
2016-05-15 20:11:16 +02:00
|
|
|
IRQ_CONNECT(SPI_DW_PORT_0_IRQ, CONFIG_SPI_0_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
|
2016-05-15 20:11:16 +02:00
|
|
|
irq_enable(SPI_DW_PORT_0_IRQ);
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
_spi_int_unmask(SPI_DW_PORT_0_INT_MASK);
|
|
|
|
#else /* SPI_DW_INTERRUPT_SEPARATED_LINES */
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI0_RX_AVAIL, CONFIG_SPI_0_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI0_TX_REQ, CONFIG_SPI_0_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI0_ERR_INT, CONFIG_SPI_0_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
|
|
|
|
|
2016-05-07 20:48:28 +02:00
|
|
|
irq_enable(IRQ_SPI0_RX_AVAIL);
|
|
|
|
irq_enable(IRQ_SPI0_TX_REQ);
|
|
|
|
irq_enable(IRQ_SPI0_ERR_INT);
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_0_RX_INT_MASK);
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_0_TX_INT_MASK);
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_0_ERROR_INT_MASK);
|
|
|
|
#endif
|
2016-01-08 09:46:14 +01:00
|
|
|
}
|
2016-05-08 00:57:14 +02:00
|
|
|
#endif /* CONFIG_SPI_0 */
|
|
|
|
#ifdef CONFIG_SPI_1
|
2016-01-21 11:15:38 +01:00
|
|
|
void spi_config_1_irq(void);
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2017-05-05 13:28:17 +02:00
|
|
|
struct spi_dw_data spi_dw_data_port_1 = {
|
|
|
|
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_1, ctx),
|
2017-05-05 13:42:44 +02:00
|
|
|
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_1, ctx),
|
2017-05-05 13:28:17 +02:00
|
|
|
};
|
2015-11-22 03:28:21 +01:00
|
|
|
|
2016-10-19 23:16:49 +02:00
|
|
|
static const struct spi_dw_config spi_dw_config_1 = {
|
2016-05-07 20:48:28 +02:00
|
|
|
.regs = SPI_DW_PORT_1_REGS,
|
2015-11-22 03:28:21 +01:00
|
|
|
#ifdef CONFIG_SPI_DW_CLOCK_GATE
|
2016-05-08 00:57:14 +02:00
|
|
|
.clock_data = UINT_TO_POINTER(CONFIG_SPI_1_CLOCK_GATE_SUBSYS),
|
2015-11-22 03:28:21 +01:00
|
|
|
#endif /* CONFIG_SPI_DW_CLOCK_GATE */
|
|
|
|
.config_func = spi_config_1_irq
|
|
|
|
};
|
|
|
|
|
2016-05-08 00:57:14 +02:00
|
|
|
DEVICE_AND_API_INIT(spi_dw_port_1, CONFIG_SPI_1_NAME, spi_dw_init,
|
2016-04-14 18:28:34 +02:00
|
|
|
&spi_dw_data_port_1, &spi_dw_config_1,
|
2016-11-08 20:06:55 +01:00
|
|
|
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
|
2016-04-14 18:28:34 +02:00
|
|
|
&dw_spi_api);
|
2016-01-21 11:15:38 +01:00
|
|
|
|
|
|
|
void spi_config_1_irq(void)
|
|
|
|
{
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
#ifdef CONFIG_SPI_DW_INTERRUPT_SINGLE_LINE
|
2016-05-15 20:11:16 +02:00
|
|
|
IRQ_CONNECT(SPI_DW_PORT_1_IRQ, CONFIG_SPI_1_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
|
2016-05-15 20:11:16 +02:00
|
|
|
irq_enable(SPI_DW_PORT_1_IRQ);
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
_spi_int_unmask(SPI_DW_PORT_1_INT_MASK);
|
|
|
|
#else /* SPI_DW_INTERRUPT_SEPARATED_LINES */
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI1_RX_AVAIL, CONFIG_SPI_1_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI1_TX_REQ, CONFIG_SPI_1_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
|
2016-05-08 00:57:14 +02:00
|
|
|
IRQ_CONNECT(IRQ_SPI1_ERR_INT, CONFIG_SPI_1_IRQ_PRI,
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
|
|
|
|
|
2016-05-07 20:48:28 +02:00
|
|
|
irq_enable(IRQ_SPI1_RX_AVAIL);
|
|
|
|
irq_enable(IRQ_SPI1_TX_REQ);
|
|
|
|
irq_enable(IRQ_SPI1_ERR_INT);
|
spi: dw: Quark SE Sensor Sub-System support
Though it's an ARC core, Quark SE SS does not follow the same registers
mapping as the official DesignWare document. Some parts are common, some
not.
Instead of bloating spi_dw.c with a lot of #ifdef or rewriting a whole
new driver though the logic is 99% the same, it's then better to:
- centralize common macros and definitions into spi_dw.h
- have a specific spi_dw_quark_se_ss_reg.h for register map, clock
gating and register helpers dedicated to Quark SE SS.
- have a spi_dw_regs.h for the common case, i.e. not Quark SE SS.
GPIO CS emulation and interrupt masking ends up then in spi_dw.h.
Clock gating is specific thus found in respective *_regs.h header.
Adding proper interrupt masks to quark_se_ss soc.h file as well.
One of the main difference is also the interrupt management: through one
line or multiple lines (one for each interrupt: rx, tx and error). On
Quark SE Sensor Sub-System it has been set to use multiple lines, thus
introducing relevant Kconfig options and managing those when configuring
the IRQs.
Quark SE SS SPI controller is also working on a lower level, i.e. it
requires a tiny bit more logic from the driver. Main example is the data
register which needs to be told what is happening from the driver.
Taking the opportunity to fix minor logic issues:
- ICR register should be cleared by reading, only on error in the ISR
handler, but it does not harm doing it anyway and because Quark SE SS
requires to clear up interrupt as soon as they have been handled,
introducing a clear_interrupts() function called at the and of the ISR
handler.
- TXFTLR should be set after each spi_transceive() since last pull_data
might set it to 0.
- Enable the clock (i.e. open the clock gate) at initialization.
- No need to mask interrupts at spi_configure() since these are already
masked at initialization and at the end of a transaction.
- Let's use BIT() macro when relevant.
Change-Id: I24344aaf8bff3390383a84436f516951c1a2d2a4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2016-01-19 14:43:52 +01:00
|
|
|
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_1_RX_INT_MASK);
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_1_TX_INT_MASK);
|
|
|
|
_spi_int_unmask(SPI_DW_PORT_1_ERROR_INT_MASK);
|
|
|
|
#endif
|
2016-01-21 11:15:38 +01:00
|
|
|
}
|
2016-05-08 00:57:14 +02:00
|
|
|
#endif /* CONFIG_SPI_1 */
|