276 lines
7.8 KiB
C
276 lines
7.8 KiB
C
/* spi_dw.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_H__
|
|
#define __SPI_DW_H__
|
|
|
|
#include <spi.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef void (*spi_dw_config_t)(void);
|
|
|
|
/* Private structures */
|
|
struct spi_dw_config {
|
|
uint32_t regs;
|
|
#ifdef CONFIG_SPI_DW_CLOCK_GATE
|
|
void *clock_data;
|
|
#endif /* CONFIG_SPI_DW_CLOCK_GATE */
|
|
#ifdef CONFIG_SPI_DW_CS_GPIO
|
|
char *cs_gpio_name;
|
|
uint32_t cs_gpio_pin;
|
|
#endif /* CONFIG_SPI_DW_CS_GPIO */
|
|
spi_dw_config_t config_func;
|
|
};
|
|
|
|
struct spi_dw_data {
|
|
struct k_sem device_sync_sem;
|
|
uint32_t error:1;
|
|
uint32_t dfs:3; /* dfs in bytes: 1,2 or 4 */
|
|
uint32_t slave:17; /* up 16 slaves */
|
|
uint32_t fifo_diff:9; /* cannot be bigger than FIFO depth */
|
|
uint32_t last_tx:1;
|
|
uint32_t _unused:1;
|
|
#ifdef CONFIG_SPI_DW_CLOCK_GATE
|
|
struct device *clock;
|
|
#endif /* CONFIG_SPI_DW_CLOCK_GATE */
|
|
#ifdef CONFIG_SPI_DW_CS_GPIO
|
|
struct device *cs_gpio_port;
|
|
#endif /* CONFIG_SPI_DW_CS_GPIO */
|
|
const uint8_t *tx_buf;
|
|
uint32_t tx_buf_len;
|
|
uint8_t *rx_buf;
|
|
uint32_t rx_buf_len;
|
|
};
|
|
|
|
/* Helper macros */
|
|
|
|
#ifdef CONFIG_SPI_DW_ARC_AUX_REGS
|
|
#define _REG_READ(__sz) sys_in##__sz
|
|
#define _REG_WRITE(__sz) sys_out##__sz
|
|
#define _REG_SET_BIT sys_io_set_bit
|
|
#define _REG_CLEAR_BIT sys_io_clear_bit
|
|
#define _REG_TEST_BIT sys_io_test_bit
|
|
#else
|
|
#define _REG_READ(__sz) sys_read##__sz
|
|
#define _REG_WRITE(__sz) sys_write##__sz
|
|
#define _REG_SET_BIT sys_set_bit
|
|
#define _REG_CLEAR_BIT sys_clear_bit
|
|
#define _REG_TEST_BIT sys_test_bit
|
|
#endif /* CONFIG_SPI_DW_ARC_AUX_REGS */
|
|
|
|
#define DEFINE_MM_REG_READ(__reg, __off, __sz) \
|
|
static inline uint32_t read_##__reg(uint32_t addr) \
|
|
{ \
|
|
return _REG_READ(__sz)(addr + __off); \
|
|
}
|
|
#define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \
|
|
static inline void write_##__reg(uint32_t data, uint32_t addr) \
|
|
{ \
|
|
_REG_WRITE(__sz)(data, addr + __off); \
|
|
}
|
|
|
|
#define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \
|
|
static inline void set_bit_##__reg_bit(uint32_t addr) \
|
|
{ \
|
|
_REG_SET_BIT(addr + __reg_off, __bit); \
|
|
}
|
|
|
|
#define DEFINE_CLEAR_BIT_OP(__reg_bit, __reg_off, __bit) \
|
|
static inline void clear_bit_##__reg_bit(uint32_t addr) \
|
|
{ \
|
|
_REG_CLEAR_BIT(addr + __reg_off, __bit); \
|
|
}
|
|
|
|
#define DEFINE_TEST_BIT_OP(__reg_bit, __reg_off, __bit) \
|
|
static inline int test_bit_##__reg_bit(uint32_t addr) \
|
|
{ \
|
|
return _REG_TEST_BIT(addr + __reg_off, __bit); \
|
|
}
|
|
|
|
/* Common registers settings, bits etc... */
|
|
|
|
/* CTRLR0 settings */
|
|
#define DW_SPI_CTRLR0_SCPH_BIT (6)
|
|
#define DW_SPI_CTRLR0_SCPOL_BIT (7)
|
|
#define DW_SPI_CTRLR0_SRL_BIT (11)
|
|
|
|
#define DW_SPI_CTRLR0_SCPH BIT(DW_SPI_CTRLR0_SCPH_BIT)
|
|
#define DW_SPI_CTRLR0_SCPOL BIT(DW_SPI_CTRLR0_SCPOL_BIT)
|
|
#define DW_SPI_CTRLR0_SRL BIT(DW_SPI_CTRLR0_SRL_BIT)
|
|
|
|
#define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1)
|
|
#define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16)
|
|
|
|
#ifdef CONFIG_ARC
|
|
#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_16
|
|
#else
|
|
#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_32
|
|
#endif
|
|
|
|
/* 0x38 represents the bits 8,16 and 32. Knowing that 24 is bits 8 and 16
|
|
* These are the bits were when you divide by 8, you keep the result as it is.
|
|
* For all the other ones, 4 to 7, 9 to 15, etc... you need a +1,
|
|
* since on such division it takes only the result above 0
|
|
*/
|
|
#define SPI_DFS_TO_BYTES(__bpw) (((__bpw) & ~0x38) ? \
|
|
(((__bpw) / 8) + 1) : \
|
|
((__bpw) / 8))
|
|
|
|
/* SSIENR bits */
|
|
#define DW_SPI_SSIENR_SSIEN_BIT (0)
|
|
|
|
/* SR bits and values */
|
|
#define DW_SPI_SR_BUSY_BIT (0)
|
|
#define DW_SPI_SR_TFNF_BIT (1)
|
|
#define DW_SPI_SR_RFNE_BIT (3)
|
|
|
|
/* IMR bits (ISR valid as well) */
|
|
#define DW_SPI_IMR_TXEIM_BIT (0)
|
|
#define DW_SPI_IMR_TXOIM_BIT (1)
|
|
#define DW_SPI_IMR_RXUIM_BIT (2)
|
|
#define DW_SPI_IMR_RXOIM_BIT (3)
|
|
#define DW_SPI_IMR_RXFIM_BIT (4)
|
|
#define DW_SPI_IMR_MSTIM_BIT (5)
|
|
|
|
/* IMR values */
|
|
#define DW_SPI_IMR_TXEIM BIT(DW_SPI_IMR_TXEIM_BIT)
|
|
#define DW_SPI_IMR_TXOIM BIT(DW_SPI_IMR_TXOIM_BIT)
|
|
#define DW_SPI_IMR_RXUIM BIT(DW_SPI_IMR_RXUIM_BIT)
|
|
#define DW_SPI_IMR_RXOIM BIT(DW_SPI_IMR_RXOIM_BIT)
|
|
#define DW_SPI_IMR_RXFIM BIT(DW_SPI_IMR_RXFIM_BIT)
|
|
#define DW_SPI_IMR_MSTIM BIT(DW_SPI_IMR_MSTIM_BIT)
|
|
|
|
/* ISR values (same as IMR) */
|
|
#define DW_SPI_ISR_TXEIS DW_SPI_IMR_TXEIM
|
|
#define DW_SPI_ISR_TXOIS DW_SPI_IMR_TXOIM
|
|
#define DW_SPI_ISR_RXUIS DW_SPI_IMR_RXUIM
|
|
#define DW_SPI_ISR_RXOIS DW_SPI_IMR_RXOIM
|
|
#define DW_SPI_ISR_RXFIS DW_SPI_IMR_RXFIM
|
|
#define DW_SPI_ISR_MSTIS DW_SPI_IMR_MSTIM
|
|
|
|
/* Error interrupt */
|
|
#define DW_SPI_ISR_ERRORS_MASK (DW_SPI_ISR_TXOIS | \
|
|
DW_SPI_ISR_RXUIS | \
|
|
DW_SPI_ISR_RXOIS | \
|
|
DW_SPI_ISR_MSTIS)
|
|
/* ICR Bit */
|
|
#define DW_SPI_SR_ICR_BIT (0)
|
|
|
|
/* Threshold defaults */
|
|
#define DW_SPI_FIFO_DEPTH CONFIG_SPI_DW_FIFO_DEPTH
|
|
#define DW_SPI_TXFTLR_DFLT ((DW_SPI_FIFO_DEPTH*1)/2) /* 50% */
|
|
#define DW_SPI_RXFTLR_DFLT ((DW_SPI_FIFO_DEPTH*5)/8)
|
|
|
|
/* Interrupt mask (IMR) */
|
|
#define DW_SPI_IMR_MASK (0x0)
|
|
#define DW_SPI_IMR_UNMASK (DW_SPI_IMR_TXEIM | \
|
|
DW_SPI_IMR_TXOIM | \
|
|
DW_SPI_IMR_RXUIM | \
|
|
DW_SPI_IMR_RXOIM | \
|
|
DW_SPI_IMR_RXFIM)
|
|
#define DW_SPI_IMR_MASK_TX (~(DW_SPI_IMR_TXEIM | \
|
|
DW_SPI_IMR_TXOIM))
|
|
#define DW_SPI_IMR_MASK_RX (~(DW_SPI_IMR_RXUIM | \
|
|
DW_SPI_IMR_RXOIM | \
|
|
DW_SPI_IMR_RXFIM))
|
|
|
|
/*
|
|
* Including the right register definition file
|
|
* SoC SPECIFIC!
|
|
*/
|
|
#ifdef CONFIG_SOC_QUARK_SE_C1000_SS
|
|
#include "spi_dw_quark_se_ss_regs.h"
|
|
#else
|
|
#include "spi_dw_regs.h"
|
|
#endif
|
|
|
|
/* GPIO used to emulate CS */
|
|
#ifdef CONFIG_SPI_DW_CS_GPIO
|
|
|
|
#include <gpio.h>
|
|
|
|
static inline void _spi_config_cs(struct device *dev)
|
|
{
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
struct device *gpio;
|
|
|
|
gpio = device_get_binding(info->cs_gpio_name);
|
|
if (!gpio) {
|
|
spi->cs_gpio_port = NULL;
|
|
return;
|
|
}
|
|
|
|
gpio_pin_configure(gpio, info->cs_gpio_pin, GPIO_DIR_OUT);
|
|
/* Default CS line to high (idling) */
|
|
gpio_pin_write(gpio, info->cs_gpio_pin, 1);
|
|
|
|
spi->cs_gpio_port = gpio;
|
|
}
|
|
|
|
static inline void _spi_control_cs(struct device *dev, int on)
|
|
{
|
|
const struct spi_dw_config *info = dev->config->config_info;
|
|
struct spi_dw_data *spi = dev->driver_data;
|
|
|
|
if (spi->cs_gpio_port) {
|
|
gpio_pin_write(spi->cs_gpio_port, info->cs_gpio_pin, !on);
|
|
}
|
|
}
|
|
#else
|
|
#define _spi_control_cs(...)
|
|
#define _spi_config_cs(...)
|
|
#endif /* CONFIG_SPI_DW_CS_GPIO */
|
|
|
|
/* Interrupt mask
|
|
* SoC SPECIFIC!
|
|
*/
|
|
#if defined(CONFIG_SOC_QUARK_SE_C1000) || defined(CONFIG_SOC_QUARK_SE_C1000_SS)
|
|
#ifdef CONFIG_ARC
|
|
#define _INT_UNMASK INT_ENABLE_ARC
|
|
#else
|
|
#define _INT_UNMASK INT_UNMASK_IA
|
|
#endif
|
|
|
|
#define _spi_int_unmask(__mask) \
|
|
sys_write32(sys_read32(__mask) & _INT_UNMASK, __mask)
|
|
#else
|
|
#define _spi_int_unmask(...)
|
|
#endif /* CONFIG_SOC_QUARK_SE_C1000 || CONFIG_SOC_QUARK_SE_C1000_SS */
|
|
|
|
/* Based on those macros above, here are common helpers for some registers */
|
|
DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 16)
|
|
DEFINE_MM_REG_READ(txflr, DW_SPI_REG_TXFLR, 32)
|
|
DEFINE_MM_REG_READ(rxflr, DW_SPI_REG_RXFLR, 32)
|
|
DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 8)
|
|
DEFINE_MM_REG_READ(isr, DW_SPI_REG_ISR, 8)
|
|
|
|
DEFINE_SET_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
|
|
DEFINE_CLEAR_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
|
|
DEFINE_TEST_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
|
|
DEFINE_TEST_BIT_OP(sr_busy, DW_SPI_REG_SR, DW_SPI_SR_BUSY_BIT)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* __SPI_DW_H__ */
|
|
|