zephyr/drivers/spi/spi_dw_quark_se_ss_regs.h

145 lines
4.4 KiB
C
Raw Normal View History

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_quark_se_ss.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_QUARK_SE_SS_H__
#define __SPI_DW_QUARK_SE_SS_H__
/* Registers:
* Some registers have been collapsed into one
* - SER is part of SSIENR
* - TXFTLR is part of RXFTLR
* This requires a little bit different access functions
* see below: write_ser(), write_rxftlr() and write_txftlr()
*/
#define DW_SPI_REG_CTRLR0 (0x00)
#define DW_SPI_REG_SSIENR (0x02)
#define DW_SPI_REG_BAUDR (0x04)
#define DW_SPI_REG_RXFTLR (0x05)
#define DW_SPI_REG_TXFLR (0x07)
#define DW_SPI_REG_RXFLR (0x08)
#define DW_SPI_REG_SR (0x09)
#define DW_SPI_REG_ISR (0x0a)
#define DW_SPI_REG_IMR (0x0b)
#define DW_SPI_REG_ICR (0x0c)
#define DW_SPI_REG_DR (0x0d)
#define DW_SPI_CTRLR0_CLK_ENA_BIT (15)
#define DW_SPI_CTRLR0_CLK_ENA_MASK BIT(DW_SPI_CTRLR0_CLK_ENA_BIT)
#define DW_SPI_QSS_SSIENR_SER(__slv) (__slv << 4)
#define DW_SPI_QSS_TXFTLR(__lvl) (__lvl << 16)
#define DW_SPI_QSS_SER_MASK (0xf0)
#define DW_SPI_QSS_RXFTLR_MASK (0x0000ffff)
#define DW_SPI_QSS_TXFTLR_MASK (0xffff0000)
#define DW_SPI_DR_WD_BIT (30)
#define DW_SPI_DR_WD_MASK BIT(DW_SPI_DR_WD_BIT)
#define DW_SPI_DR_STROBE_BIT (31)
#define DW_SPI_DR_STROBE_MASK BIT(DW_SPI_DR_STROBE_BIT)
#define DW_SPI_DR_WRITE (DW_SPI_DR_STROBE_MASK | \
DW_SPI_DR_WD_MASK)
#define DW_SPI_DR_READ (DW_SPI_DR_STROBE_MASK)
/* Register helpers
* *_b functions only used for creating proper ser one
*/
/* CTRLR0 on Quark SE SS has a CLK_ENA bit we want to keep
* as it is while writing the configuration.
* *_b function only used for creating proper ser one
*/
DEFINE_MM_REG_READ(ctrlr0_b, DW_SPI_REG_CTRLR0, 16)
DEFINE_MM_REG_WRITE(ctrlr0_b, DW_SPI_REG_CTRLR0, 16)
static inline void write_ctrlr0(uint32_t data, uint32_t addr)
{
write_ctrlr0_b((read_ctrlr0_b(addr) & DW_SPI_CTRLR0_CLK_ENA_MASK) |
data, addr);
}
DEFINE_MM_REG_READ(ssienr_b, DW_SPI_REG_SSIENR, 8)
DEFINE_MM_REG_WRITE(ssienr_b, DW_SPI_REG_SSIENR, 8)
static inline void write_ser(uint32_t data, uint32_t addr)
{
write_ssienr_b((read_ssienr_b(addr) & (~DW_SPI_QSS_SER_MASK)) |
DW_SPI_QSS_SSIENR_SER(data), addr);
}
DEFINE_MM_REG_READ(rxftlr_b, DW_SPI_REG_RXFTLR, 32)
DEFINE_MM_REG_WRITE(rxftlr_b, DW_SPI_REG_RXFTLR, 32)
DEFINE_MM_REG_READ(rxftlr, DW_SPI_REG_RXFTLR, 16)
static inline void write_rxftlr(uint32_t data, uint32_t addr)
{
write_rxftlr_b((read_rxftlr_b(addr) & (~DW_SPI_QSS_RXFTLR_MASK)) |
data, addr);
}
static inline void write_txftlr(uint32_t data, uint32_t addr)
{
write_rxftlr_b((read_rxftlr_b(addr) & (~DW_SPI_QSS_TXFTLR_MASK)) |
DW_SPI_QSS_TXFTLR(data), addr);
}
/* Quark SE SS requires to clear up all interrupts */
DEFINE_MM_REG_WRITE(icr, DW_SPI_REG_ICR, 8)
static inline void clear_interrupts(uint32_t addr)
{
write_icr(0x1f, addr);
}
/* Reading and Writing Data
* Quark SE SS DW SPI controller requires more logic from the driver which:
* - needs to tell when it has been pushing in bits for TX FIFO
* - needs to tell when it will be pulling out bits from RX FIFO
*/
DEFINE_MM_REG_WRITE(dr_b, DW_SPI_REG_DR, 32)
DEFINE_MM_REG_READ(dr_b, DW_SPI_REG_DR, 32)
static inline void write_dr(uint32_t data, uint32_t addr)
{
write_dr_b(data | DW_SPI_DR_WRITE, addr);
}
static inline uint32_t read_dr(uint32_t addr)
{
write_dr_b(DW_SPI_DR_READ, addr);
return read_dr_b(addr);
}
/* Internal clock gating */
DEFINE_SET_BIT_OP(clk_ena, DW_SPI_REG_CTRLR0, DW_SPI_CTRLR0_CLK_ENA_BIT)
DEFINE_CLEAR_BIT_OP(clk_ena, DW_SPI_REG_CTRLR0, DW_SPI_CTRLR0_CLK_ENA_BIT)
#define _clock_config(...)
static inline void _clock_on(struct device *dev)
{
struct spi_dw_config *info = dev->config->config_info;
set_bit_clk_ena(info->regs);
}
static inline void _clock_off(struct device *dev)
{
struct spi_dw_config *info = dev->config->config_info;
clear_bit_clk_ena(info->regs);
}
#endif /* __SPI_DW_QUARK_SE_SS_H__ */