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 21:43:52 +08:00
|
|
|
/* spi_dw_regs.h - Designware SPI driver private definitions */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Intel Corporation.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __SPI_DW_REGS_H__
|
|
|
|
#define __SPI_DW_REGS_H__
|
|
|
|
|
|
|
|
#define DW_SPI_REG_CTRLR0 (0x00)
|
|
|
|
#define DW_SPI_REG_CTRLR1 (0x04)
|
|
|
|
#define DW_SPI_REG_SSIENR (0x08)
|
|
|
|
#define DW_SPI_REG_MWCR (0x0c)
|
|
|
|
#define DW_SPI_REG_SER (0x10)
|
|
|
|
#define DW_SPI_REG_BAUDR (0x14)
|
|
|
|
#define DW_SPI_REG_TXFTLR (0x18)
|
|
|
|
#define DW_SPI_REG_RXFTLR (0x1c)
|
|
|
|
#define DW_SPI_REG_TXFLR (0x20)
|
|
|
|
#define DW_SPI_REG_RXFLR (0x24)
|
|
|
|
#define DW_SPI_REG_SR (0x28)
|
|
|
|
#define DW_SPI_REG_IMR (0x2c)
|
|
|
|
#define DW_SPI_REG_ISR (0x30)
|
|
|
|
#define DW_SPI_REG_RISR (0x34)
|
|
|
|
#define DW_SPI_REG_TXOICR (0x38)
|
|
|
|
#define DW_SPI_REG_RXOICR (0x3c)
|
|
|
|
#define DW_SPI_REG_RXUICR (0x40)
|
|
|
|
#define DW_SPI_REG_MSTICR (0x44)
|
|
|
|
#define DW_SPI_REG_ICR (0x48)
|
|
|
|
#define DW_SPI_REG_DMACR (0x4c)
|
|
|
|
#define DW_SPI_REG_DMATDLR (0x50)
|
|
|
|
#define DW_SPI_REG_DMARDLR (0x54)
|
|
|
|
#define DW_SPI_REG_IDR (0x58)
|
|
|
|
#define DW_SPI_REG_SSI_COMP_VERSION (0x5c)
|
|
|
|
#define DW_SPI_REG_DR (0x60)
|
|
|
|
#define DW_SPI_REG_RX_SAMPLE_DLY (0xf0)
|
|
|
|
|
|
|
|
#define DW_SSI_COMP_VERSION (0x3332332a)
|
|
|
|
|
|
|
|
/* Register helpers */
|
|
|
|
DEFINE_MM_REG_WRITE(ctrlr0, DW_SPI_REG_CTRLR0, 32)
|
|
|
|
DEFINE_MM_REG_WRITE(ser, DW_SPI_REG_SER, 8)
|
|
|
|
DEFINE_MM_REG_WRITE(txftlr, DW_SPI_REG_TXFTLR, 32)
|
|
|
|
DEFINE_MM_REG_WRITE(rxftlr, DW_SPI_REG_RXFTLR, 32)
|
|
|
|
DEFINE_MM_REG_READ(rxftlr, DW_SPI_REG_RXFTLR, 32)
|
2016-05-19 02:10:03 +08:00
|
|
|
DEFINE_MM_REG_READ(txftlr, DW_SPI_REG_TXFTLR, 32)
|
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 21:43:52 +08:00
|
|
|
DEFINE_MM_REG_WRITE(dr, DW_SPI_REG_DR, 32)
|
|
|
|
DEFINE_MM_REG_READ(dr, DW_SPI_REG_DR, 32)
|
|
|
|
DEFINE_MM_REG_READ(ssi_comp_version, DW_SPI_REG_SSI_COMP_VERSION, 32)
|
|
|
|
|
|
|
|
/* ICR is on a unique bit */
|
|
|
|
DEFINE_TEST_BIT_OP(icr, DW_SPI_REG_ICR, DW_SPI_SR_ICR_BIT)
|
|
|
|
#define clear_interrupts(addr) test_bit_icr(addr)
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPI_DW_CLOCK_GATE
|
|
|
|
static inline void _clock_config(struct device *dev)
|
|
|
|
{
|
|
|
|
struct device *clk;
|
|
|
|
char *drv = CONFIG_SPI_DW_CLOCK_GATE_DRV_NAME;
|
|
|
|
|
|
|
|
clk = device_get_binding(drv);
|
|
|
|
if (clk) {
|
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
|
|
|
|
|
|
spi->clock = clk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _clock_on(struct device *dev)
|
|
|
|
{
|
|
|
|
struct spi_dw_config *info = dev->config->config_info;
|
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
|
|
|
|
|
|
clock_control_on(spi->clock, info->clock_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _clock_off(struct device *dev)
|
|
|
|
{
|
|
|
|
struct spi_dw_config *info = dev->config->config_info;
|
|
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
|
|
|
|
|
|
clock_control_off(spi->clock, info->clock_data);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define _clock_config(...)
|
|
|
|
#define _clock_on(...)
|
|
|
|
#define _clock_off(...)
|
|
|
|
#endif /* CONFIG_SPI_DW_CLOCK_GATE */
|
|
|
|
|
|
|
|
#endif /* __SPI_DW_REGS_H__ */
|