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:
parent
d5d525562e
commit
d96943b04c
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_SPI_INTEL) = intel_spi.o
|
383
drivers/spi/intel_spi.c
Normal file
383
drivers/spi/intel_spi.c
Normal 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;
|
||||
}
|
91
drivers/spi/intel_spi_priv.h
Normal file
91
drivers/spi/intel_spi_priv.h
Normal 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__ */
|
106
include/drivers/spi/intel_spi.h
Normal file
106
include/drivers/spi/intel_spi.h
Normal 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__ */
|
Loading…
Reference in a new issue