spi: Add support for Intel's SPI controller

Such controllers are found in Quark's X1000 series, and thus are found
on Galileo boards v1 and v2.

Change-Id: Ib71486c9f27de1b6c48ce3cb3dd138d69833c2ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Tomasz Bursztyka 2015-08-21 13:01:08 +03:00 committed by Anas Nashif
parent d5d525562e
commit d96943b04c
9 changed files with 771 additions and 0 deletions

View file

@ -183,6 +183,13 @@ CONFIG_HPET_TIMER_LEVEL_LOW=y
# CONFIG_RANDOM_GENERATOR is not set
# CONFIG_TEST_RANDOM_GENERATOR is not set
#
# SPI Drivers
#
# CONFIG_SPI is not set
# CONFIG_SPI_DEBUG is not set
# CONFIG_SPI_INTEL is not set
#
# Networking
#

View file

@ -162,6 +162,13 @@ CONFIG_HPET_TIMER_LEVEL_LOW=y
# CONFIG_RANDOM_GENERATOR is not set
# CONFIG_TEST_RANDOM_GENERATOR is not set
#
# SPI Drivers
#
# CONFIG_SPI is not set
# CONFIG_SPI_DEBUG is not set
# CONFIG_SPI_INTEL is not set
#
# Networking
#

View file

@ -69,6 +69,24 @@ by x86 platforms.
#endif /* CONFIG_IOAPIC */
#endif /* CONFIG_UART_SIMPLE */
#if defined(CONFIG_SPI_INTEL)
#if defined(CONFIG_PIC)
#if defined(CONFIG_SPI_INTEL_PORT_0)
pic_master_mkstub spi_intel_irq_port_0 spi_intel_isr_0
#endif /* CONFIG_SPI_INTEL_PORT_0 */
#if defined(CONFIG_SPI_INTEL_PORT_1)
pic_master_mkstub spi_intel_irq_port_1 spi_intel_isr_1
#endif /* CONFIG_SPI_INTEL_PORT_1 */
#elif defined(CONFIG_IOAPIC)
#if defined(CONFIG_SPI_INTEL_PORT_0)
ioapic_mkstub spi_intel_irq_port_0 spi_intel_isr_0
#endif /* CONFIG_SPI_INTEL_PORT_0 */
#if defined(CONFIG_SPI_INTEL_PORT_1)
ioapic_mkstub spi_intel_irq_port_1 spi_intel_isr_1
#endif /* CONFIG_SPI_INTEL_PORT_1 */
#endif
#endif /* CONFIG_SPI_INTEL */
/* externs (internal APIs) */
GTEXT(_IntEnt)

View file

@ -142,3 +142,75 @@ struct device * const uart_devs[] = {
};
#endif
#ifdef CONFIG_SPI_INTEL
#include <spi/intel_spi.h>
#ifdef CONFIG_SPI_INTEL_PORT_0
void spi_config_0_irq(struct device *dev);
struct spi_intel_data spi_intel_data_port_0;
struct spi_intel_config spi_intel_config_0 = {
.regs = CONFIG_SPI_INTEL_PORT_0_REGS,
.irq = CONFIG_SPI_INTEL_PORT_0_IRQ,
.function = CONFIG_SPI_INTEL_PORT_0_FUNCTION,
.config_func = spi_config_0_irq
};
DECLARE_DEVICE_INIT_CONFIG(spi_intel_port_0, CONFIG_SPI_INTEL_PORT_0_DRV_NAME,
spi_intel_init, &spi_intel_config_0);
pure_init(spi_intel_port_0, &spi_intel_data_port_0);
void spi_intel_isr_0(void *unused)
{
spi_intel_isr(&__initconfig_spi_intel_port_01);
}
IRQ_CONNECT_STATIC(spi_intel_irq_port_0, CONFIG_SPI_INTEL_PORT_0_IRQ,
CONFIG_SPI_INTEL_PORT_0_PRI, spi_intel_isr_0, 0);
void spi_config_0_irq(struct device *dev)
{
struct spi_intel_config *config = dev->config->config_info;
IRQ_CONFIG(spi_intel_irq_port_0, config->irq);
}
#endif /* CONFIG_SPI_INTEL_PORT_0 */
#ifdef CONFIG_SPI_INTEL_PORT_1
void spi_config_1_irq(struct device *dev);
struct spi_intel_data spi_intel_data_port_1;
struct spi_intel_config spi_intel_config_1 = {
.regs = CONFIG_SPI_INTEL_PORT_1_REGS,
.irq = CONFIG_SPI_INTEL_PORT_1_IRQ,
.function = CONFIG_SPI_INTEL_PORT_1_FUNCTION,
.config_func = spi_config_1_irq
};
DECLARE_DEVICE_INIT_CONFIG(spi_intel_port_1, CONFIG_SPI_INTEL_PORT_1_DRV_NAME,
spi_intel_init, &spi_intel_config_1);
pure_init(spi_intel_port_1, &spi_intel_data_port_1);
void spi_intel_isr_1(void *unused)
{
spi_intel_isr(&__initconfig_spi_intel_port_11);
}
IRQ_CONNECT_STATIC(spi_intel_irq_port_1, CONFIG_SPI_INTEL_PORT_1_IRQ,
CONFIG_SPI_INTEL_PORT_1_PRI, spi_intel_isr_1, 0);
void spi_config_1_irq(struct device *dev)
{
struct spi_intel_config *config = dev->config->config_info;
IRQ_CONFIG(spi_intel_irq_port_1, config->irq);
}
#endif /* CONFIG_SPI_INTEL_PORT_1 */
#endif /* CONFIG_SPI_INTEL */

View file

@ -47,3 +47,89 @@ config SPI_DEBUG
default n
help
Enable debug output for SPI drivers
config SPI_INTEL
bool
prompt "Intel SPI controller driver"
depends on SPI && CPU_MINUTEIA
default n
help
Enable support for Intel's SPI controllers. Such controller
was formelly found on XScale chips. It can be found nowadays
on CEXXXX Intel media controller and Quark CPU (2 of them).
config SPI_INTEL_PORT_0
bool
prompt "Intel SPI port 0"
depends on SPI_INTEL
default n
help
Enable Intel's SPI controller port 0.
config SPI_INTEL_PORT_0_DRV_NAME
string
prompt "Intel SPI port 0 device name"
depends on SPI_INTEL_PORT_0
default "intel_spi_0"
config SPI_INTEL_PORT_0_FUNCTION
int
prompt "Port 0 PCI function"
depends on SPI_INTEL_PORT_0 && PCI
default 0
config SPI_INTEL_PORT_0_REGS
hex
prompt "Port 0 registers address"
depends on SPI_INTEL_PORT_0
default 0x00000000
config SPI_INTEL_PORT_0_IRQ
int
prompt "Port 0 interrupt"
depends on SPI_INTEL_PORT_0
default 0
config SPI_INTEL_PORT_0_PRI
int
prompt "Port 0 interrupt priority"
depends on SPI_INTEL_PORT_0
default 0
config SPI_INTEL_PORT_1
bool
prompt "Intel SPI port 1"
depends on SPI_INTEL
default n
help
Enable Intel's SPI controller port 1.
config SPI_INTEL_PORT_1_DRV_NAME
string
prompt "Intel SPI port 1 device name"
depends on SPI_INTEL_PORT_1
default "intel_spi_1"
config SPI_INTEL_PORT_1_FUNCTION
int
prompt "Port 1 PCI function"
depends on SPI_INTEL_PORT_1 && PCI
default 0
config SPI_INTEL_PORT_1_REGS
hex
prompt "Port 1 registers address"
depends on SPI_INTEL_PORT_1
default 0x00000000
config SPI_INTEL_PORT_1_IRQ
int
prompt "Port 1 interrupt"
depends on SPI_INTEL_PORT_1
default 0
config SPI_INTEL_PORT_1_PRI
int
prompt "Port 0 interrupt priority"
depends on SPI_INTEL_PORT_1
default 0

View file

@ -0,0 +1 @@
obj-$(CONFIG_SPI_INTEL) = intel_spi.o

383
drivers/spi/intel_spi.c Normal file
View file

@ -0,0 +1,383 @@
/* intel_spi.c - Driver implementation for Intel SPI controller */
/*
* Copyright (c) 2015 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <nanokernel.h>
#include <arch/cpu.h>
#include <misc/__assert.h>
#include <board.h>
#include <sys_io.h>
#ifdef CONFIG_PCI
#include <pci/pci.h>
#include <pci/pci_mgr.h>
#endif
#include <spi.h>
#include <spi/intel_spi.h>
#include "intel_spi_priv.h"
#ifndef CONFIG_SPI_DEBUG
#define DBG(...) {;}
#else
#if defined(CONFIG_STDOUT_CONSOLE)
#include <stdio.h>
#define DBG printf
#else
#include <misc/printk.h>
#define DBG printk
#endif /* CONFIG_STDOUT_CONSOLE */
#endif /* CONFIG_SPI_DEBUG */
#define DEFINE_MM_REG_READ(__reg, __off, __sz) \
static inline uint32_t read_##__reg(uint32_t addr) \
{ \
DBG("Reading 0x%x\n", addr + __off); \
return sys_read##__sz(addr + __off); \
}
#define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \
static inline void write_##__reg(uint32_t data, uint32_t addr) \
{ \
DBG("Writing 0x%x\n", addr + __off); \
sys_write##__sz(data, addr + __off); \
}
DEFINE_MM_REG_WRITE(sscr0, INTEL_SPI_REG_SSCR0, 32)
DEFINE_MM_REG_WRITE(sscr1, INTEL_SPI_REG_SSRC1, 32)
DEFINE_MM_REG_READ(sssr, INTEL_SPI_REG_SSSR, 32)
DEFINE_MM_REG_READ(ssdr, INTEL_SPI_REG_SSDR, 32)
DEFINE_MM_REG_WRITE(ssdr, INTEL_SPI_REG_SSDR, 32)
DEFINE_MM_REG_WRITE(dds_rate, INTEL_SPI_REG_DDS_RATE, 32)
#define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \
static inline void set_bit_##__reg_bit(uint32_t addr) \
{ \
sys_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) \
{ \
sys_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 sys_test_bit(addr + __reg_off, __bit); \
}
DEFINE_SET_BIT_OP(sscr0_sse, INTEL_SPI_REG_SSCR0, INTEL_SPI_SSCR0_SSE_BIT)
DEFINE_CLEAR_BIT_OP(sscr0_sse, INTEL_SPI_REG_SSCR0, INTEL_SPI_SSCR0_SSE_BIT)
DEFINE_TEST_BIT_OP(sscr0_sse, INTEL_SPI_REG_SSCR0, INTEL_SPI_SSCR0_SSE_BIT)
DEFINE_TEST_BIT_OP(sssr_bsy, INTEL_SPI_REG_SSSR, INTEL_SPI_SSSR_BSY_BIT)
static void completed(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
struct spi_intel_data *spi = dev->driver_data;
enum spi_cb_type cb_type;
if (spi->t_len) {
return;
}
if (spi->tx_buf && spi->tx_buf_len == 0 && !spi->rx_buf) {
cb_type = SPI_CB_WRITE;
} else if (spi->rx_buf && spi->rx_buf_len == 0 && !spi->tx_buf) {
cb_type = SPI_CB_READ;
} else if (spi->tx_buf && spi->tx_buf_len == 0 &&
spi->rx_buf && spi->rx_buf_len == 0) {
cb_type = SPI_CB_TRANSCEIVE;
} else {
return;
}
spi->tx_buf = spi->rx_buf = NULL;
spi->tx_buf_len = spi->rx_buf_len = 0;
write_sscr1(spi->sscr1, info->regs);
if (spi->callback) {
spi->callback(dev, cb_type);
}
}
static void push_data(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
struct spi_intel_data *spi = dev->driver_data;
uint32_t cnt = 0;
uint8_t data;
DBG("spi: push_data\n");
while(read_sssr(info->regs) & INTEL_SPI_SSSR_TNF) {
if (spi->tx_buf && spi->tx_buf_len > 0) {
data = *(uint8_t *)(spi->tx_buf);
spi->tx_buf++;
spi->tx_buf_len--;
} else if (spi->rx_buf && spi->rx_buf_len > 0) {
/* No need to push more than necessary */
if (spi->rx_buf_len - cnt <= 0) {
break;
}
data = 0;
} else {
/* Nothing to push anymore for now */
break;
}
write_ssdr(data, info->regs);
cnt++;
}
DBG("Pushed: %d\n", cnt);
spi->t_len += cnt;
}
static void pull_data(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
struct spi_intel_data *spi = dev->driver_data;
uint32_t cnt = 0;
uint8_t data;
while(read_sssr(info->regs) & INTEL_SPI_SSSR_RNE) {
data = (uint8_t) read_ssdr(info->regs);
cnt++;
if (spi->rx_buf && spi->rx_buf_len > 0) {
*(uint8_t *)(spi->rx_buf) = data;
spi->rx_buf++;
spi->rx_buf_len--;
}
}
DBG("Pulled: %d\n", cnt);
spi->t_len -= cnt;
}
static int spi_intel_configure(struct device *dev, struct spi_config *config)
{
struct spi_intel_config *info = dev->config->config_info;
struct spi_intel_data *spi = dev->driver_data;
uint32_t flags = config->config;
uint32_t mode;
DBG("spi_intel_configure: %p (0x%x), %p\n", dev, info->regs, config);
/* Check status */
if (test_bit_sscr0_sse(info->regs) && test_bit_sssr_bsy(info->regs)) {
DBG("spi_intel_transceive: Controller is busy\n");
return DEV_USED;
}
/* Pre-configuring the registers to a clean state*/
spi->sscr0 = spi->sscr1 = 0;
write_sscr0(spi->sscr0, info->regs);
write_sscr1(spi->sscr1, info->regs);
/* Word size and clock rate */
spi->sscr0 = INTEL_SPI_SSCR0_DSS(SPI_WORD_SIZE_GET(flags)) |
INTEL_SPI_SSCR0_SCR(config->max_sys_freq);
/* SPI mode */
mode = SPI_MODE(flags);
if (mode & SPI_MODE_CPOL) {
spi->sscr1 |= INTEL_SPI_SSCR1_SPO;
}
if (mode & SPI_MODE_CPHA) {
spi->sscr1 |= INTEL_SPI_SSCR1_SPH;
}
if (mode & SPI_MODE_LOOP) {
spi->sscr1 |= INTEL_SPI_SSCR1_LBM;
}
/* Tx/Rx Threshold */
spi->sscr1 |= INTEL_SPI_SSCR1_TFT(INTEL_SPI_SSCR1_TFT_DFLT)
| INTEL_SPI_SSCR1_RFT(INTEL_SPI_SSCR1_RFT_DFLT);
/* Configuring the rate */
write_dds_rate(INTEL_SPI_DSS_RATE(config->max_sys_freq), info->regs);
spi->tx_buf = spi->rx_buf = NULL;
spi->tx_buf_len = spi->rx_buf_len = spi->t_len = 0;
spi->callback = config->callback;
return DEV_OK;
}
static int spi_intel_transceive(struct device *dev,
uint8_t *tx_buf, uint32_t tx_buf_len,
uint8_t *rx_buf, uint32_t rx_buf_len)
{
struct spi_intel_config *info = dev->config->config_info;
struct spi_intel_data *spi = dev->driver_data;
DBG("spi_dw_transceive: %p, %p, %u, %p, %u\n",
dev, tx_buf, tx_buf_len, rx_buf, rx_buf_len);
/* Check status */
if (test_bit_sscr0_sse(info->regs) && test_bit_sssr_bsy(info->regs)) {
DBG("spi_intel_transceive: Controller is busy\n");
return DEV_USED;
}
/* Set buffers info */
spi->tx_buf = tx_buf;
spi->tx_buf_len = tx_buf_len;
spi->rx_buf = rx_buf;
spi->rx_buf_len = rx_buf_len;
/* Installing the registers (enabling the controller as well) */
write_sscr1(spi->sscr1, info->regs);
write_sscr0(spi->sscr0 | INTEL_SPI_SSCR0_SSE, info->regs);
push_data(dev);
/* Enable receive interrupt */
write_sscr1(spi->sscr1 | INTEL_SPI_SSCR1_RIE
| INTEL_SPI_SSCR1_TIE, info->regs);
return DEV_OK;
}
static int spi_intel_suspend(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
DBG("spi_intel_suspend: %p\n", dev);
clear_bit_sscr0_sse(info->regs);
irq_disable(info->irq);
return DEV_OK;
}
static int spi_intel_resume(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
DBG("spi_intel_resume: %p\n", dev);
set_bit_sscr0_sse(info->regs);
irq_enable(info->irq);
return DEV_OK;
}
void spi_intel_isr(void *arg)
{
struct device *dev = arg;
struct spi_intel_config *info = dev->config->config_info;
uint32_t status;
DBG("spi_intel_isr: %p\n", dev);
status = read_sssr(info->regs);
if (!(status & (INTEL_SPI_SSSR_TFS | INTEL_SPI_SSSR_RFS))) {
DBG("None or unhandled interrupt\n");
return;
}
if (status & INTEL_SPI_SSSR_RFS) {
pull_data(dev);
}
if (status & INTEL_SPI_SSSR_TFS) {
push_data(dev);
}
completed(dev);
}
static struct spi_driver_api intel_spi_api = {
.configure = spi_intel_configure,
.slave_select = NULL,
.transceive = spi_intel_transceive,
.suspend = spi_intel_suspend,
.resume = spi_intel_resume,
};
#ifdef CONFIG_PCI
static inline int spi_intel_setup(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
struct pci_dev_info spi_intel_pci = {
.class = PCI_CLASS_SERIAL_BUS,
.function = info->function,
.vendor_id = 0x8086,
.device_id = 0x935,
};
pci_bus_scan_init();
if (!pci_bus_scan(&spi_intel_pci)) {
DBG("Could not find device\n");
return 0;
}
pci_enable_regs(&spi_intel_pci);
#ifdef CONFIG_PCI_DEBUG
pci_show(&spi_intel_pci);
#endif
return 1;
}
#else
#define spi_intel_setup(_unused_) { return 1;}
#endif /* CONFIG_PCI */
int spi_intel_init(struct device *dev)
{
struct spi_intel_config *info = dev->config->config_info;
dev->driver_api = &intel_spi_api;
if (!spi_intel_setup(dev)) {
return DEV_NOT_CONFIG;
}
info->config_func(dev);
irq_enable(info->irq);
DBG("SPI Intel Driver initialized on device: %p\n", dev);
return DEV_OK;
}

View file

@ -0,0 +1,91 @@
/* intel_spi_priv.h - Intel's SPI driver private definitions */
/*
* Copyright (c) 2015 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __INTEL_SPI_PRIV_H__
#define __INTEL_SPI_PRIV_H__
/* Registers */
#define INTEL_SPI_REG_SSCR0 (0x00)
#define INTEL_SPI_REG_SSRC1 (0x04)
#define INTEL_SPI_REG_SSSR (0x08)
#define INTEL_SPI_REG_SSDR (0x10)
#define INTEL_SPI_REG_DDS_RATE (0x28)
#define INTEL_SPI_CLK_DIV_MASK (0x000000ff)
#define INTEL_SPI_DDS_RATE_MASK (0xffffff00)
/* SSCR0 settings */
#define INTEL_SPI_SSCR0_DSS(__bpw) ((__bpw) - 1)
#define INTEL_SPI_SSCR0_SSE (0x1 << 7)
#define INTEL_SPI_SSCR0_SSE_BIT (7)
#define INTEL_SPI_SSCR0_SCR(__msf) \
((__msf && INTEL_SPI_CLK_DIV_MASK) << 8)
/* SSCR1 settings */
#define INTEL_SPI_SSCR1_RIE (0x1)
#define INTEL_SPI_SSCR1_TIE (0x1 << 1)
#define INTEL_SPI_SSCR1_LBM (0x1 << 2)
#define INTEL_SPI_SSCR1_SPO (0x1 << 3)
#define INTEL_SPI_SSCR1_SPH (0x1 << 4)
#define INTEL_SPI_SSCR1_TFT(__tft) \
(((__tft) - 1) << 6)
#define INTEL_SPI_SSCR1_RFT(__rft) \
(((__rft) - 1) << 11)
#define INTEL_SPI_SSCR1_EFWR (0x1 << 16)
#define INTEL_SPI_SSCR1_STRF (0x1 << 17)
#define INTEL_SPI_SSCR1_TFT_DFLT (8)
#define INTEL_SPI_SSCR1_RFT_DFLT (8)
/* SSSR settings */
#define INTEL_SPI_SSSR_TNF (0x4)
#define INTEL_SPI_SSSR_RNE (0x8)
#define INTEL_SPI_SSSR_TFS (0x20)
#define INTEL_SPI_SSSR_RFS (0x40)
#define INTEL_SPI_SSSR_ROR (0x80)
#define INTEL_SPI_SSSR_TFL_MASK (0x1f << 8)
#define INTEL_SPI_SSSR_TFL_EMPTY (0x00)
#define INTEL_SPI_SSSR_RFL_MASK (0x1f << 13)
#define INTEL_SPI_SSSR_RFL_EMPTY (0x1f)
#define INTEL_SPI_SSSR_TFL(__status) \
((__status & INTEL_SPI_SSSR_TFL_MASK) >> 8)
#define INTEL_SPI_SSSR_RFL(__status) \
((__status & INTEL_SPI_SSSR_RFL_MASK) >> 13)
#define INTEL_SPI_SSSR_BSY_BIT (4)
/* DSS_RATE settings */
#define INTEL_SPI_DSS_RATE(__msf) \
((__msf && (INTEL_SPI_DDS_RATE_MASK)) >> 8)
#endif /* __INTEL_SPI_PRIV_H__ */

View file

@ -0,0 +1,106 @@
/* intel_spi.h - Intel's SPI controller driver utilities */
/*
* Copyright (c) 2015 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __INTEL_SPI_H__
#define __INTEL_SPI_H__
#include <spi.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void spi_intel_isr(void *data);
int spi_intel_init(struct device *dev);
typedef void (*spi_intel_config_t)(struct device *dev);
struct spi_intel_config {
uint32_t regs;
uint32_t irq;
#ifdef CONFIG_PCI
uint32_t function:4;
uint32_t _unused:28;
#endif /* CONFIG_PCI */
spi_intel_config_t config_func;
};
struct spi_intel_data {
uint32_t sscr0;
uint32_t sscr1;
spi_callback callback;
uint8_t *tx_buf;
uint32_t tx_buf_len;
uint8_t *rx_buf;
uint32_t rx_buf_len;
uint32_t t_len;
};
/* SPI Maximum supported system frequencies */
#define SPI_MAX_CLK_FREQ_25MHZ ((800000 << 8))
#define SPI_MAX_CLK_FREQ_20MHz ((666666 << 8) | 1)
#define SPI_MAX_CLK_FREQ_166667KHZ ((800000 << 8) | 2)
#define SPI_MAX_CLK_FREQ_13333KHZ ((666666 << 8) | 2)
#define SPI_MAX_CLK_FREQ_12500KHZ ((200000 << 8))
#define SPI_MAX_CLK_FREQ_10MHZ ((800000 << 8) | 4)
#define SPI_MAX_CLK_FREQ_8MHZ ((666666 << 8) | 4)
#define SPI_MAX_CLK_FREQ_6250HZ ((400000 << 8) | 3)
#define SPI_MAX_CLK_FREQ_5MHZ ((400000 << 8) | 4)
#define SPI_MAX_CLK_FREQ_4MHZ ((666666 << 8) | 9)
#define SPI_MAX_CLK_FREQ_3125KHZ ((80000 << 8))
#define SPI_MAX_CLK_FREQ_2500KHZ ((400000 << 8) | 9)
#define SPI_MAX_CLK_FREQ_2MHZ ((666666 << 8) | 19)
#define SPI_MAX_CLK_FREQ_1563KHZ ((40000 << 8))
#define SPI_MAX_CLK_FREQ_1250KHZ ((200000 << 8) | 9)
#define SPI_MAX_CLK_FREQ_1MHZ ((400000 << 8) | 24)
#define SPI_MAX_CLK_FREQ_800KHZ ((666666 << 8) | 49)
#define SPI_MAX_CLK_FREQ_781KHZ ((20000 << 8))
#define SPI_MAX_CLK_FREQ_625KHZ ((200000 << 8) | 19)
#define SPI_MAX_CLK_FREQ_500KHZ ((400000 << 8) | 49)
#define SPI_MAX_CLK_FREQ_400KHZ ((666666 << 8) | 99)
#define SPI_MAX_CLK_FREQ_390KHZ ((10000 << 8))
#define SPI_MAX_CLK_FREQ_250KHZ ((400000 << 8) | 99)
#define SPI_MAX_CLK_FREQ_200KHZ ((666666 << 8) | 199)
#define SPI_MAX_CLK_FREQ_195KHZ ((8000 << 8))
#define SPI_MAX_CLK_FREQ_125KHZ ((100000 << 8) | 49)
#define SPI_MAX_CLK_FREQ_100KHZ ((200000 << 8) | 124)
#define SPI_MAX_CLK_FREQ_50KHZ ((100000 << 8) | 124)
#define SPI_MAX_CLK_FREQ_20KHZ ((80000 << 8) | 124)
#define SPI_MAX_CLK_FREQ_10KHZ ((20000 << 8) | 77)
#define SPI_MAX_CLK_FREQ_5KHZ ((20000 << 8) | 154)
#define SPI_MAX_CLK_FREQ_1KHZ ((8000 << 8) | 194)
#ifdef __cplusplus
}
#endif
#endif /* __INTEL_SPI_H__ */