i2c: import of Synopsis DesignWare I2C

Initial import of Synopsis DesignWare I2C driver functionality
for the Zephyr Project.  This import has been tested for host
master control.  While it does contain the code to work as a host
slave, this code has not yet been completely tested and validated.

Change-Id: I3df0214f6e3b6798f7dad4819d09c3ec5998e508
Signed-off-by: Dan Kalowsky <daniel.kalowsky@intel.com>
This commit is contained in:
Dan Kalowsky 2015-08-26 14:56:43 -07:00 committed by Anas Nashif
commit 998cc8e3d4
6 changed files with 999 additions and 0 deletions

View file

@ -88,6 +88,14 @@ by x86 platforms.
#endif /* CONFIG_SPI_INTEL_PORT_1 */
#endif /* CONFIG_SPI_INTEL */
#if defined(CONFIG_DW_I2C0)
ioapic_mkstub dw_i2c_0 dw_i2c_isr_0
#endif /* CONFIG_DW_I2C0 */
#if defined(CONFIG_DW_I2C1)
ioapic_mkstub dw_i2c_1 dw_i2c_isr_1
#endif /* CONFIG_DW_I2C1 */
/* externs (internal APIs) */
GTEXT(_IntEnt)

View file

@ -39,6 +39,11 @@ config I2C
bool "Enable I2C drivers"
default n
config DW_I2C
bool "Enable Design Ware I2C support"
default n
select I2C
config I2C_STATUS_DELAY
int "Delay for controller response"
depends on I2C

View file

@ -0,0 +1 @@
obj-$(CONFIG_DW_I2C) += dw_i2c.o

578
drivers/i2c/dw_i2c.c Normal file
View file

@ -0,0 +1,578 @@
/* dw_i2c.c - I2C file for Design Ware */
/*
* 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 <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <i2c.h>
#include <nanokernel.h>
#include <arch/cpu.h>
#include <string.h>
#include <board.h>
#include <errno.h>
#include "dw_i2c.h"
#include "dw_i2c_registers.h"
#ifndef CONFIG_I2C_DEBUG
#define DBG(...) {;}
#else
#if defined(CONFIG_STDOUT_CONSOLE)
#include <stdio.h>
#define DBG printf
#else
#define DBG printk
#endif /* CONFIG_STDOUT_CONSOLE */
#endif /* CONFIG_I2C_DEBUG */
static inline uint32_t dw_i2c_memory_read(uint32_t base_addr, uint32_t offset)
{
return *(uint32_t *)(base_addr + offset);
}
static inline void dw_i2c_memory_write(uint32_t base_addr, uint32_t offset,
uint32_t val)
{
*(uint32_t *)(base_addr + offset) = val;
}
static void dw_i2c_data_read(struct device *dev)
{
struct dw_i2c_rom_config const * const rom = dev->config->config_info;
struct dw_i2c_dev_config * const dw = dev->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t i = 0;
uint32_t rx_cnt = 0;
/* Make sure we have some buffer to read/write to */
if (dw->rx_len == 0) {
return;
}
rx_cnt = regs->ic_rxflr;
if (rx_cnt > dw->rx_len) {
rx_cnt = dw->rx_len;
}
for (i = 0; i < rx_cnt; i++) {
dw->rx_buffer[i] = regs->ic_data_cmd.raw;
}
dw->rx_buffer += i;
dw->rx_len -= i;
}
static void dw_i2c_data_send(struct device *dev)
{
struct dw_i2c_rom_config const * const rom = dev->config->config_info;
struct dw_i2c_dev_config * const dw = dev->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t i = 0;
uint32_t tx_cnt = 0;
uint32_t data = 0;
if (dw->rx_tx_len == 0) {
return;
}
tx_cnt = DW_I2C_FIFO_DEPTH - regs->ic_txflr;
if (tx_cnt > dw->rx_tx_len) {
tx_cnt = dw->rx_tx_len;
}
for (i = 0; i < tx_cnt; i++) {
if (dw->tx_len > 0) {
/* We have something to transmit to a specific host */
data = dw->tx_buffer[i];
/* Is this the last byte to write */
if (dw->tx_len == 1) {
data |= (dw->rx_len > 0) ?
IC_DATA_CMD_RESTART : IC_DATA_CMD_STOP;
}
dw->tx_len -= 1;
} else {
/*
* We want to send out a request to read data from a
* specific host
*/
data = IC_DATA_CMD_CMD;
/* This is the last dummy byte to write */
if (dw->rx_tx_len == 1) {
data |= IC_DATA_CMD_STOP;
}
}
regs->ic_data_cmd.raw = data;
dw->rx_tx_len -= 1;
}
dw->tx_buffer += i;
if (dw->rx_tx_len <= 0) {
regs->ic_intr_mask.bits.tx_empty = 0;
regs->ic_intr_mask.bits.stop_det = 1;
}
}
void dw_i2c_isr(struct device *port)
{
struct dw_i2c_rom_config const * const rom = port->config->config_info;
struct dw_i2c_dev_config * const dw = port->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t value = 0;
/*
* Causes of an intterrupt:
* - STOP condition is detected
* - Transfer is aborted
* - Transmit FIFO is empy
* - Transmit FIFO is overflowing
* - Receive FIFO is full
* - Receive FIFO overflow
* - Received FIFO underrun
* - Transmit data required (tx_req)
* - Receive data available (rx_avail)
*/
DBG("I2C: interrupt received\n");
/*
* We got a STOP_DET, this means stop right after this byte has been
* handled.
*/
if (regs->ic_intr_stat.bits.stop_det) {
dw_i2c_data_read(port);
regs->ic_intr_mask.raw = DW_DISABLE_ALL_I2C_INT;
dw->state = DW_I2C_STATE_READY;
regs->ic_clr_intr = 0;
}
/* Check if we are configured as a master device */
if (regs->ic_con.bits.master_mode) {
/* Check if the Master TX is ready for sending */
if (regs->ic_intr_stat.bits.tx_empty) {
dw_i2c_data_send(port);
}
/* Check if the Master RX buffer is full */
if (regs->ic_intr_stat.bits.rx_full) {
dw_i2c_data_read(port);
}
if ((DW_INTR_STAT_TX_ABRT | DW_INTR_STAT_TX_OVER |
DW_INTR_STAT_RX_OVER | DW_INTR_STAT_RX_UNDER) &
regs->ic_intr_stat.raw) {
dw->state = DW_I2C_CMD_ERROR;
regs->ic_intr_mask.raw = DW_DISABLE_ALL_I2C_INT;
dw->state = DW_I2C_STATE_READY;
regs->ic_clr_intr = 0;
}
} else { /* we must be configured as a slave device */
/* We have a read requested by the master device */
if (regs->ic_intr_stat.bits.rd_req &&
(!dw->app_config.bits.is_slave_read)) {
/* data is not ready to send */
if (regs->ic_intr_stat.bits.tx_abrt) {
/* clear the TX_ABRT interrupt */
value = regs->ic_clr_tx_abrt;
}
dw_i2c_data_send(port);
value = regs->ic_clr_rd_req;
}
/* The slave device is ready to receive */
if (regs->ic_intr_stat.bits.rx_full &&
dw->app_config.bits.is_slave_read) {
dw_i2c_data_read(port);
}
}
}
static int dw_i2c_setup(struct device *dev)
{
struct dw_i2c_dev_config * const dw = dev->driver_data;
struct dw_i2c_rom_config const * const rom = dev->config->config_info;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t value = 0;
union ic_con_register ic_con;
int rc = DEV_OK;
ic_con.raw = 0;
/*
* Clear any interrupts currently waiting in the controller
* this is done by reading register 0x40
*/
value = regs->ic_clr_intr;
/* Set master or slave mode - (initialization = slave) */
if (dw->app_config.bits.is_master_device) {
/*
* Make sure to set both the master_mode and slave_disable_bit
* to both 0 or both 1
*/
DBG("I2C: host configured as Master Device\n");
ic_con.bits.master_mode = 1;
ic_con.bits.slave_disable = 1;
}
ic_con.bits.restart_en = 1;
/* Set addressing mode - (initialization = 7 bit) */
if (dw->app_config.bits.use_10_bit_addr) {
DBG("I2C: using 10-bit address\n");
ic_con.bits.addr_master_10bit = 1;
ic_con.bits.addr_slave_10bit = 1;
}
/* Setup the clock frequency and speed mode */
switch (dw->app_config.bits.speed) {
case I2C_SPEED_STANDARD:
DBG("I2C: speed set to STANDARD\n");
regs->ic_ss_scl_lcnt = dw->lcnt;
regs->ic_ss_scl_hcnt = dw->hcnt;
ic_con.bits.speed = DW_I2C_SPEED_STANDARD;
break;
case I2C_SPEED_FAST:
/* fall through */
case I2C_SPEED_FAST_PLUS:
DBG("I2C: speed set to FAST or FAST_PLUS\n");
regs->ic_fs_scl_lcnt = dw->lcnt;
regs->ic_fs_scl_hcnt = dw->hcnt;
ic_con.bits.speed = DW_I2C_SPEED_FAST;
break;
case I2C_SPEED_HIGH:
if (!dw->support_hs_mode) {
rc = DEV_INVALID_CONF;
break;
}
DBG("I2C: speed set to HIGH\n");
regs->ic_hs_scl_lcnt = dw->lcnt;
regs->ic_hs_scl_hcnt = dw->hcnt;
ic_con.bits.speed = DW_I2C_SPEED_HIGH;
break;
default:
DBG("I2C: invalid speed requested\n");
/* TODO change */
rc = DEV_INVALID_CONF;
}
DBG("I2C: lcnt = %d\n", dw->lcnt);
DBG("I2C: hcnt = %d\n", dw->hcnt);
/* Set TX interrupt mode */
ic_con.bits.tx_empty_ctl = 1;
/* Set the IC_CON register */
regs->ic_con = ic_con;
/* END of setup IC_CON */
/* Set RX fifo threshold level */
regs->ic_rx_tl = (regs->ic_comp_param_1.bits.rx_buffer_depth / 2);
/* Set TX fifo threshold level */
regs->ic_tx_tl = (regs->ic_comp_param_1.bits.tx_buffer_depth / 2);
return rc;
}
static int dw_i2c_transfer(struct device *dev,
uint8_t *write_buf, uint32_t write_len,
uint8_t *read_buf, uint32_t read_len,
uint16_t slave_address)
{
struct dw_i2c_rom_config const * const rom = dev->config->config_info;
struct dw_i2c_dev_config * const dw = dev->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t value = 0;
/* First step, check if there is current activity */
if (regs->ic_status.bits.activity) {
return DEV_FAIL;
}
dw->rx_len = read_len;
dw->rx_buffer = read_buf;
dw->tx_len = write_len;
dw->tx_buffer = write_buf;
dw->rx_tx_len = dw->rx_len + dw->tx_len;
/* Disable the device controller to be able set TAR */
regs->ic_enable.bits.enable = 0;
dw_i2c_setup(dev);
/* Disable interrupts */
regs->ic_intr_mask.raw = 0;
/* Clear interrupts */
value = regs->ic_clr_intr;
if (regs->ic_con.bits.master_mode) {
/* Set address of target slave */
regs->ic_tar.bits.ic_tar = slave_address;
/* Enable necessary interrupts */
regs->ic_intr_mask.raw = (DW_ENABLE_TX_INT_I2C_MASTER |
DW_ENABLE_RX_INT_I2C_MASTER);
} else {
/* Set slave address for device */
regs->ic_sar.bits.ic_sar = slave_address;
/* Enable necessary interrupts */
regs->ic_intr_mask.raw = DW_ENABLE_TX_INT_I2C_SLAVE;
}
/* Enable controller */
regs->ic_enable.bits.enable = 1;
return DEV_OK;
}
static int dw_i2c_runtime_configure(struct device *dev, uint32_t config)
{
struct dw_i2c_rom_config const * const rom = dev->config->config_info;
struct dw_i2c_dev_config * const dw = dev->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
uint32_t value = 0;
uint32_t rc = DEV_OK;
dw->app_config.raw = config;
/* Make sure we have a supported speed for the DesignWare model */
/* and have setup the clock frequency and speed mode */
switch (dw->app_config.bits.speed) {
case I2C_SPEED_STANDARD:
/* Following the directions on DW spec page 59, IC_SS_SCL_LCNT
* must have register values larger than IC_FS_SPKLEN + 7
*/
if (I2C_STD_LCNT <= (regs->ic_fs_spklen + 7)) {
value = regs->ic_fs_spklen + 8;
} else {
value = I2C_STD_LCNT;
}
dw->lcnt = value;
/* Following the directions on DW spec page 59, IC_SS_SCL_HCNT
* must have register values larger than IC_FS_SPKLEN + 5
*/
if (I2C_STD_HCNT <= (regs->ic_fs_spklen + 5)) {
value = regs->ic_fs_spklen + 6;
} else {
value = I2C_STD_HCNT;
}
dw->hcnt = value;
break;
case I2C_SPEED_FAST:
/* fall through */
case I2C_SPEED_FAST_PLUS:
/*
* Following the directions on DW spec page 59, IC_FS_SCL_LCNT
* must have register values larger than IC_FS_SPKLEN + 7
*/
if (I2C_FS_LCNT <= (regs->ic_fs_spklen + 7)) {
value = regs->ic_fs_spklen + 8;
} else {
value = I2C_FS_LCNT;
}
dw->lcnt = value;
/*
* Following the directions on DW spec page 59, IC_FS_SCL_HCNT
* must have register values larger than IC_FS_SPKLEN + 5
*/
if (I2C_FS_HCNT <= (regs->ic_fs_spklen + 5)) {
value = regs->ic_fs_spklen + 6;
} else {
value = I2C_FS_HCNT;
}
dw->hcnt = value;
break;
case I2C_SPEED_HIGH:
if (dw->support_hs_mode) {
if (I2C_HS_LCNT <= (regs->ic_hs_spklen + 7)) {
value = regs->ic_hs_spklen + 8;
} else {
value = I2C_HS_LCNT;
}
dw->lcnt = value;
if (I2C_HS_HCNT <= (regs->ic_hs_spklen + 5)) {
value = regs->ic_hs_spklen + 6;
} else {
value = I2C_HS_HCNT;
}
dw->hcnt = value;
} else {
rc = DEV_INVALID_CONF;
}
break;
default:
/* TODO change */
rc = DEV_INVALID_CONF;
}
/*
* Clear any interrupts currently waiting in the controller
*/
value = regs->ic_clr_intr;
/*
* TEMPORARY HACK - The I2C does not work in any mode other than Master
* currently. This "hack" forces us to always be configured for master
* mode, until we can verify that Slave mode works correctly.
*/
dw->app_config.bits.is_master_device = 1;
return rc;
}
static int dw_i2c_write(struct device *dev, uint8_t *buf,
uint32_t len, uint16_t slave_addr)
{
struct dw_i2c_dev_config * const dw = dev->driver_data;
dw->state = DW_I2C_CMD_SEND;
return dw_i2c_transfer(dev, buf, len, 0, 0, slave_addr);
}
static int dw_i2c_read(struct device *dev, uint8_t *buf,
uint32_t len, uint16_t slave_addr)
{
struct dw_i2c_dev_config * const dw = dev->driver_data;
dw->state = DW_I2C_CMD_RECV;
return dw_i2c_transfer(dev, 0, 0, buf, len, slave_addr);
}
static int dw_i2c_suspend(struct device *dev)
{
DBG("I2C: suspend called - function not yet implemented\n");
/* TODO - add this code */
return DEV_OK;
}
static int dw_i2c_resume(struct device *dev)
{
DBG("I2C: resume called - function not yet implemented\n");
/* TODO - add this code */
return DEV_OK;
}
static struct i2c_driver_api funcs = {
.configure = dw_i2c_runtime_configure,
.write = dw_i2c_write,
.read = dw_i2c_read,
.suspend = dw_i2c_suspend,
.resume = dw_i2c_resume,
};
int dw_i2c_initialize(struct device *port)
{
struct dw_i2c_rom_config const * const rom = port->config->config_info;
struct dw_i2c_dev_config * const dev = port->driver_data;
volatile struct dw_i2c_registers * const regs =
(struct dw_i2c_registers *)rom->base_address;
/* verify that we have a valid DesignWare register first */
if (regs->ic_comp_type != DW_I2C_MAGIC_KEY) {
port->driver_api = NULL;
DBG("I2C: DesignWare magic key not found, check base address.");
DBG(" Stopping initialization\n");
return DEV_NOT_CONFIG;
}
port->driver_api = &funcs;
dev->app_config.raw = 0;
rom->config_func(port);
/*
* grab the default value on initialization. This should be set to the
* IC_MAX_SPEED_MODE in the hardware. If it does support high speed we
* can move provide support for it
*/
if (regs->ic_con.bits.speed == DW_I2C_SPEED_HIGH) {
DBG("I2C: high speed supported\n");
dev->support_hs_mode = true;
} else {
DBG("I2C: high speed NOT supported\n");
dev->support_hs_mode = false;
}
dev->state = DW_I2C_STATE_READY;
irq_enable(rom->interrupt_vector);
return DEV_OK;
}

130
drivers/i2c/dw_i2c.h Normal file
View file

@ -0,0 +1,130 @@
/* dw_i2c.h - header for Design Ware I2C operations */
/*
* 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 __DRIVERS_DW_I2C_H
#define __DRIVERS_DW_I2C_H
#include <i2c.h>
#include <stdbool.h>
#define DW_I2C_MAGIC_KEY 0x44570140
typedef void (*i2c_isr_cb_t)(struct device *port);
#define IC_ACTIVITY (1 << 0)
#define IC_ENABLE_BIT (1 << 0)
/* dev->state values from IC_DATA_CMD Data transfer mode settings (bit 8) */
#define DW_I2C_STATE_READY (0)
#define DW_I2C_CMD_SEND (1 << 0)
#define DW_I2C_CMD_RECV (1 << 1)
#define DW_I2C_CMD_ERROR (1 << 2)
#define DW_ENABLE_TX_INT_I2C_MASTER (DW_INTR_STAT_TX_OVER | \
DW_INTR_STAT_TX_EMPTY | \
DW_INTR_STAT_TX_ABRT | \
DW_INTR_STAT_STOP_DET)
#define DW_ENABLE_RX_INT_I2C_MASTER (DW_INTR_STAT_RX_UNDER | \
DW_INTR_STAT_RX_OVER | \
DW_INTR_STAT_RX_FULL | \
DW_INTR_STAT_STOP_DET)
#define DW_ENABLE_TX_INT_I2C_SLAVE (DW_INTR_STAT_RD_REQ | \
DW_INTR_STAT_TX_ABRT | \
DW_INTR_STAT_STOP_DET)
#define DW_ENABLE_RX_INT_I2C_SLAVE (DW_INTR_STAT_RX_FULL | \
DW_INTR_STAT_STOP_DET)
#define DW_DISABLE_ALL_I2C_INT 0x00000000
/* IC_CON Low count and high count default values */
/* TODO verify values for high and fast speed */
#define I2C_STD_HCNT (CONFIG_I2C_CLOCK_SPEED * 4)
#define I2C_STD_LCNT (CONFIG_I2C_CLOCK_SPEED * 5)
#define I2C_FS_HCNT ((CONFIG_I2C_CLOCK_SPEED * 6) / 8)
#define I2C_FS_LCNT ((CONFIG_I2C_CLOCK_SPEED * 7) / 8)
#define I2C_HS_HCNT ((CONFIG_I2C_CLOCK_SPEED * 6) / 8)
#define I2C_HS_LCNT ((CONFIG_I2C_CLOCK_SPEED * 7) / 8)
/*
* DesignWare speed values don't directly translate from the Zephyr speed
* selections in include/i2c.h so here we do a little translation
*/
#define DW_I2C_SPEED_STANDARD 0x1
#define DW_I2C_SPEED_FAST 0x2
#define DW_I2C_SPEED_FAST_PLUS 0x2
#define DW_I2C_SPEED_HIGH 0x3
/*
* These values have been randomly selected. It would be good to test different
* watermark levels for performance capabilities
*/
#define DW_I2C_TX_WATERMARK 2
#define DW_I2C_RX_WATERMARK 7
#define DW_I2C_FIFO_DEPTH 16
struct dw_i2c_rom_config {
uint32_t base_address;
uint32_t interrupt_vector;
uint32_t interrupt_mask;
i2c_isr_cb_t config_func;
};
struct dw_i2c_dev_config {
union dev_config app_config;
volatile uint8_t state; /* last direction of transfer */
uint8_t slave_mode;
uint8_t rx_len;
uint8_t *rx_buffer;
uint8_t tx_len;
uint8_t *tx_buffer;
uint8_t rx_tx_len;
bool support_hs_mode;
uint16_t hcnt;
uint16_t lcnt;
};
void dw_i2c_isr(struct device *port);
extern int dw_i2c_initialize(struct device *port);
#endif /* __DRIVERS_DW_I2C_H */

View file

@ -0,0 +1,277 @@
/* dw_i2c_registers.h - array access for I2C Design Ware registers */
/*
* 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 __DRIVERS_DW_I2C_REGISTERS_H
#define __DRIVERS_DW_I2C_REGISTERS_H
/* IC_CON bits */
#define IC_CON_TX_INTR_MODE (1 << 8)
#define IC_CON_STOP_DET_IFADDR (1 << 7)
#define IC_CON_SLAVE_DISABLE (1 << 6)
#define IC_CON_RESTART_EN (1 << 5)
#define IC_CON_10BIT_ADDR_MASTER (1 << 4)
#define IC_CON_10BIT_ADDR_SLAVE (1 << 3)
#define IC_CON_SPEED_MASK (2 << 1)
#define IC_CON_MASTER_MODE (1 << 0)
union ic_con_register {
uint16_t raw;
struct {
uint16_t master_mode : 1 __packed;
uint16_t speed : 2 __packed;
uint16_t addr_slave_10bit : 1 __packed;
uint16_t addr_master_10bit : 1 __packed;
uint16_t restart_en : 1 __packed;
uint16_t slave_disable : 1 __packed;
uint16_t stop_det : 1 __packed;
uint16_t tx_empty_ctl : 1 __packed;
uint16_t rx_fifo_full : 1 __packed;
} bits;
};
/* IC_DATA_CMD bits */
#define IC_DATA_CMD_DAT_MASK 0xFF
#define IC_DATA_CMD_CMD (1 << 8)
#define IC_DATA_CMD_STOP (1 << 9)
#define IC_DATA_CMD_RESTART (1 << 10)
union ic_data_cmd_register {
uint16_t raw;
struct {
uint16_t dat : 8 __packed;
uint16_t cmd : 1 __packed;
uint16_t stop : 1 __packed;
uint16_t restart : 1 __packed;
uint16_t reserved : 4 __packed;
} bits;
};
/* IC_ENABLE register bits */
#define IC_ENABLE_ENABLE (1 << 0)
#define IC_ENABLE_ABORT (1 << 1)
union ic_enable_register {
uint16_t raw;
struct {
uint16_t enable : 1 __packed;
uint16_t abort : 1 __packed;
uint16_t reserved : 13 __packed;
} bits;
};
/* DesignWare Interrupt bits positions */
#define DW_INTR_STAT_RX_UNDER (1 << 0)
#define DW_INTR_STAT_RX_OVER (1 << 1)
#define DW_INTR_STAT_RX_FULL (1 << 2)
#define DW_INTR_STAT_TX_OVER (1 << 3)
#define DW_INTR_STAT_TX_EMPTY (1 << 4)
#define DW_INTR_STAT_RD_REQ (1 << 5)
#define DW_INTR_STAT_TX_ABRT (1 << 6)
#define DW_INTR_STAT_RX_DONE (1 << 7)
#define DW_INTR_STAT_ACTIVITY (1 << 8)
#define DW_INTR_STAT_STOP_DET (1 << 9)
#define DW_INTR_STAT_START_DET (1 << 10)
#define DW_INTR_STAT_GEN_CALL (1 << 11)
#define DW_INTR_STAT_RESTART_DET (1 << 12)
#define DW_INTR_STAT_MST_ON_HOLD (1 << 13)
union ic_interrupt_register {
uint16_t raw;
struct {
uint16_t rx_under : 1 __packed;
uint16_t rx_over : 1 __packed;
uint16_t rx_full : 1 __packed;
uint16_t tx_over : 1 __packed;
uint16_t tx_empty : 1 __packed;
uint16_t rd_req : 1 __packed;
uint16_t tx_abrt : 1 __packed;
uint16_t rx_done : 1 __packed;
uint16_t activity : 1 __packed;
uint16_t stop_det : 1 __packed;
uint16_t start_det : 1 __packed;
uint16_t gen_call : 1 __packed;
uint16_t restart_det : 1 __packed;
uint16_t mst_on_hold : 1 __packed;
uint16_t reserved : 2 __packed;
} bits;
};
/* IC_TAR */
union ic_tar_register {
uint16_t raw;
struct {
uint16_t ic_tar : 9 __packed;
uint16_t gc_or_start : 1 __packed;
uint16_t special : 1 __packed;
uint16_t ic_10bitaddr_master : 1 __packed;
uint16_t reserved : 3 __packed;
} bits;
};
/* IC_SAR */
union ic_sar_register {
uint16_t raw;
struct {
uint16_t ic_sar : 9 __packed;
uint16_t reserved : 6 __packed;
} bits;
};
/* IC_STATUS */
union ic_status_register {
uint32_t raw;
struct {
uint32_t activity : 1 __packed;
uint32_t tfnf : 1 __packed;
uint32_t tfe : 1 __packed;
uint32_t rfne : 1 __packed;
uint32_t rff : 1 __packed;
uint32_t mst_activity : 1 __packed;
uint32_t slv_activity : 1 __packed;
uint32_t reserved : 24 __packed;
} bits;
};
union ic_comp_param_1_register {
uint32_t raw;
struct {
uint32_t apb_data_width : 2 __packed;
uint32_t max_speed_mode : 2 __packed;
uint32_t hc_count_values : 1 __packed;
uint32_t intr_io : 1 __packed;
uint32_t has_dma : 1 __packed;
uint32_t add_encoded_params : 1 __packed;
uint32_t rx_buffer_depth : 8 __packed;
uint32_t tx_buffer_depth : 8 __packed;
uint32_t reserved : 7 __packed;
} bits;
};
/*
* instantiate this like:
* volatile struct dw_i2c_registers *regs = (struct dw_i2c_regs *)0x80000000;
*
* If this is being set as a global, use the following change to avoid the
* base pointer from being reloaded after function calls:
* volatile struct d2_i2c_regs* const *regs = (struct d2_i2c_regs*)0x80000000;
*
* This will allow access to the registers like so:
* x = regs->ctrlreg;
* regs->ctrlreg = newval;
*/
struct dw_i2c_registers {
union ic_con_register ic_con; /* offset 0x00 */
uint16_t dummy1;
union ic_tar_register ic_tar; /* offset 0x04 */
uint16_t dummy2;
union ic_sar_register ic_sar; /* offset 0x08 */
uint16_t dummy3;
uint16_t ic_hs_maddr; /* offset 0x0C */
uint16_t dummy4;
union ic_data_cmd_register ic_data_cmd; /* offset 0x10 */
uint16_t dummy5;
uint16_t ic_ss_scl_hcnt; /* offset 0x14 */
uint16_t dummy6;
uint16_t ic_ss_scl_lcnt; /* offset 0x18 */
uint16_t dummy7;
uint16_t ic_fs_scl_hcnt; /* offset 0x1C */
uint16_t dummy8;
uint16_t ic_fs_scl_lcnt; /* offset 0x20 */
uint16_t dummy9;
uint16_t ic_hs_scl_hcnt; /* offset 0x24 */
uint16_t dummy10;
uint16_t ic_hs_scl_lcnt; /* offset 0x28 */
uint16_t dummy11;
union ic_interrupt_register ic_intr_stat; /* offset 0x2C */
uint16_t dummy12;
union ic_interrupt_register ic_intr_mask; /* offset 0x30 */
uint16_t dummy13;
union ic_interrupt_register ic_raw_intr_stat; /* offset 0x34 */
uint16_t dummy14;
uint16_t ic_rx_tl; /* offset 0x38 */
uint16_t dummy15;
uint16_t ic_tx_tl; /* offset 0x3C */
uint16_t dummy16;
uint16_t ic_clr_intr; /* offset 0x40 */
uint16_t dummy17;
uint16_t ic_clr_rx_under; /* offset 0x44 */
uint16_t dummy18;
uint16_t ic_clr_rx_over; /* offset 0x48 */
uint16_t dummy19;
uint16_t ic_clr_tx_over; /* offset 0x4C */
uint16_t dummy20;
uint16_t ic_clr_rd_req; /* offset 0x50 */
uint16_t dummy21;
uint16_t ic_clr_tx_abrt; /* offset 0x54 */
uint16_t dummy22;
uint16_t ic_clr_rx_done; /* offset 0x58 */
uint16_t dummy23;
uint16_t ic_clr_activity; /* offset 0x5C */
uint16_t dummy24;
uint16_t ic_clr_stop_det; /* offset 0x60 */
uint16_t dummy25;
uint16_t ic_clr_start_det; /* offset 0x64 */
uint16_t dummy26;
uint16_t ic_clr_gen_call; /* offset 0x68 */
uint16_t dummy27;
union ic_enable_register ic_enable; /* offset 0x6c */
uint16_t dummy28;
union ic_status_register ic_status; /* offset 0x70 */
uint32_t ic_txflr; /* offset 0x74 */
uint32_t ic_rxflr; /* offset 0x78 */
uint32_t ic_sda_hold; /* offset 0x7C */
uint32_t ic_tx_abrt_source; /* offset 0x80 */
uint32_t ic_slv_data_nack_only; /* offset 0x84 */
uint32_t ic_dma_cr; /* offset 0x88 */
uint32_t ic_dma_tdlr; /* offset 0x8C */
uint32_t ic_dma_rdlr; /* offset 0x90 */
uint32_t ic_sda_setup; /* offset 0x94 */
uint32_t ic_ack_general_call; /* offset 0x98 */
uint32_t ic_enable_status; /* offset 0x9C */
uint32_t ic_fs_spklen; /* offset 0xA0 */
uint32_t ic_hs_spklen; /* offset 0xA4 */
uint16_t ic_clr_restart_det; /* offset 0xA8 */
uint8_t filler[72];
union ic_comp_param_1_register ic_comp_param_1; /* offset 0xF4 */
uint32_t ic_comp_version; /* offset 0xF8 */
uint32_t ic_comp_type; /* offset 0xFC */
};
#endif /* __DRIVERS_DW_I2C_REGISTERS_H */