I2C: remove obsolete i2c_quark_se_ss driver
i2c_quark_se_ss driver is deprecated and replaced by i2c_qmsi_ss. So remove i2c_quark_se_ss definition. Change-Id: Idcc6a7f01ffae626ae7d5f9966eac67be78599af Signed-off-by: Qiu Peiyang <peiyangx.qiu@intel.com>
This commit is contained in:
parent
c4c0ed414b
commit
76549c1b79
6 changed files with 0 additions and 943 deletions
|
@ -114,7 +114,6 @@
|
|||
/*
|
||||
* I2C
|
||||
*/
|
||||
#define I2C_QUARK_SE_SS_0_BASE_ADDR 0x80012000
|
||||
#define I2C_SS_0_ERR_VECTOR 22
|
||||
#define I2C_SS_0_ERR_MASK 0x410
|
||||
#define I2C_SS_0_RX_VECTOR 23
|
||||
|
@ -124,7 +123,6 @@
|
|||
#define I2C_SS_0_STOP_VECTOR 25
|
||||
#define I2C_SS_0_STOP_MASK 0x41C
|
||||
|
||||
#define I2C_QUARK_SE_SS_1_BASE_ADDR 0x80012100
|
||||
#define I2C_SS_1_ERR_VECTOR 26
|
||||
#define I2C_SS_1_ERR_MASK 0x420
|
||||
#define I2C_SS_1_RX_VECTOR 27
|
||||
|
|
|
@ -35,14 +35,6 @@ config I2C_DW
|
|||
help
|
||||
Enable Design Ware I2C support on the selected board
|
||||
|
||||
config I2C_QUARK_SE_SS
|
||||
bool "I2C Driver for Quark SE Sensor Subsystem (SS)"
|
||||
default n
|
||||
depends on I2C
|
||||
help
|
||||
This option enables the driver to support the I2C on Quark SE Sensor
|
||||
Subsystem.
|
||||
|
||||
config I2C_QMSI_SS
|
||||
bool "QMSI I2C driver for the Sensor Subsystem"
|
||||
depends on I2C && QMSI
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
obj-$(CONFIG_I2C_DW) += i2c_dw.o
|
||||
obj-$(CONFIG_I2C_QMSI) += i2c_qmsi.o
|
||||
obj-$(CONFIG_I2C_QMSI_SS) += i2c_qmsi_ss.o
|
||||
obj-$(CONFIG_I2C_QUARK_SE_SS) += i2c_quark_se_ss.o
|
||||
obj-$(CONFIG_I2C_ATMEL_SAM3) += i2c_atmel_sam3.o
|
||||
obj-$(CONFIG_I2C_KSDK) += i2c_ksdk.o
|
||||
|
|
|
@ -1,749 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file I2C driver for Quark SE Sensor Subsystem.
|
||||
*
|
||||
* The I2C on Quark SE Sensor Subsystem is similar to DesignWare I2C IP block,
|
||||
* but with a different register set and different workflow.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <i2c.h>
|
||||
#include <nanokernel.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <sys_io.h>
|
||||
|
||||
#include <board.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#include "i2c_quark_se_ss.h"
|
||||
#include "i2c_quark_se_ss_registers.h"
|
||||
|
||||
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
|
||||
#include <misc/sys_log.h>
|
||||
|
||||
static inline uint32_t _i2c_qse_ss_memory_read(uint32_t base_addr,
|
||||
uint32_t offset)
|
||||
{
|
||||
return sys_read32(base_addr + offset);
|
||||
}
|
||||
|
||||
|
||||
static inline void _i2c_qse_ss_memory_write(uint32_t base_addr,
|
||||
uint32_t offset, uint32_t val)
|
||||
{
|
||||
sys_write32(val, base_addr + offset);
|
||||
}
|
||||
|
||||
static inline uint32_t _i2c_qse_ss_reg_read(struct device *dev,
|
||||
uint32_t reg)
|
||||
{
|
||||
struct i2c_qse_ss_rom_config * const rom = dev->config->config_info;
|
||||
|
||||
return _arc_v2_aux_reg_read(rom->base_address + reg);
|
||||
}
|
||||
|
||||
static inline void _i2c_qse_ss_reg_write(struct device *dev,
|
||||
uint32_t reg, uint32_t val)
|
||||
{
|
||||
struct i2c_qse_ss_rom_config * const rom = dev->config->config_info;
|
||||
|
||||
_arc_v2_aux_reg_write(rom->base_address + reg, val);
|
||||
}
|
||||
|
||||
static inline void _i2c_qse_ss_reg_write_and(struct device *dev,
|
||||
uint32_t reg, uint32_t mask)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
r = _i2c_qse_ss_reg_read(dev, reg);
|
||||
r &= mask;
|
||||
_i2c_qse_ss_reg_write(dev, reg, r);
|
||||
}
|
||||
|
||||
static inline void _i2c_qse_ss_reg_write_or(struct device *dev,
|
||||
uint32_t reg, uint32_t mask)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
r = _i2c_qse_ss_reg_read(dev, reg);
|
||||
r |= mask;
|
||||
_i2c_qse_ss_reg_write(dev, reg, r);
|
||||
}
|
||||
|
||||
static inline int _i2c_qse_ss_reg_check_bit(struct device *dev,
|
||||
uint32_t reg, uint32_t mask)
|
||||
{
|
||||
return _i2c_qse_ss_reg_read(dev, reg) & mask;
|
||||
}
|
||||
|
||||
/* Is the controller busy? */
|
||||
static inline bool _i2c_qse_ss_is_busy(struct device *dev)
|
||||
{
|
||||
return _i2c_qse_ss_reg_check_bit(dev, REG_STATUS, IC_STATUS_ACTIVITY);
|
||||
}
|
||||
|
||||
/* Is RX FIFO not empty? */
|
||||
static inline bool _i2c_qse_ss_is_rfne(struct device *dev)
|
||||
{
|
||||
return _i2c_qse_ss_reg_check_bit(dev, REG_STATUS, IC_STATUS_RFNE);
|
||||
}
|
||||
|
||||
/* Is TX FIFO not full? */
|
||||
static inline bool _i2c_qse_ss_is_tfnf(struct device *dev)
|
||||
{
|
||||
return _i2c_qse_ss_reg_check_bit(dev, REG_STATUS, IC_STATUS_TFNF);
|
||||
}
|
||||
|
||||
/* Is TX FIFO empty? */
|
||||
static inline bool _i2c_qse_ss_is_tfe(struct device *dev)
|
||||
{
|
||||
return _i2c_qse_ss_reg_check_bit(dev, REG_STATUS, IC_STATUS_TFE);
|
||||
}
|
||||
|
||||
/* Check a certain bit in the interrupt register */
|
||||
static inline bool _i2c_qse_ss_check_irq(struct device *dev, uint32_t mask)
|
||||
{
|
||||
return _i2c_qse_ss_reg_check_bit(dev, REG_INTR_STAT, mask);
|
||||
}
|
||||
|
||||
static inline void _i2c_qse_ss_data_ask(struct device *dev)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t data;
|
||||
uint8_t tx_empty;
|
||||
int8_t rx_empty;
|
||||
uint8_t cnt;
|
||||
|
||||
/* No more bytes to request, so command queue is no longer needed */
|
||||
if (dw->request_bytes == 0) {
|
||||
_i2c_qse_ss_reg_write_and(dev, REG_INTR_MASK,
|
||||
~(IC_INTR_TX_EMPTY));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* How many bytes we can actually ask */
|
||||
rx_empty = I2C_QSE_SS_FIFO_DEPTH
|
||||
- _i2c_qse_ss_reg_read(dev, REG_RXFLR);
|
||||
rx_empty -= dw->rx_pending;
|
||||
|
||||
if (rx_empty <= 0) {
|
||||
/* RX FIFO expected to be full.
|
||||
* So don't request any bytes, yet.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* How many empty slots in TX FIFO (as command queue) */
|
||||
tx_empty = I2C_QSE_SS_FIFO_DEPTH
|
||||
- _i2c_qse_ss_reg_read(dev, REG_TXFLR);
|
||||
|
||||
/* Figure out how many bytes we can request */
|
||||
cnt = min(I2C_QSE_SS_FIFO_DEPTH, dw->request_bytes);
|
||||
cnt = min(min(tx_empty, rx_empty), cnt);
|
||||
|
||||
while (cnt > 0) {
|
||||
/* Tell controller to get another byte */
|
||||
data = IC_DATA_CMD_CMD | IC_DATA_CMD_STROBE | IC_DATA_CMD_POP;
|
||||
|
||||
/* Send RESTART if needed */
|
||||
if (dw->xfr_flags & I2C_MSG_RESTART) {
|
||||
data |= IC_DATA_CMD_RESTART;
|
||||
dw->xfr_flags &= ~(I2C_MSG_RESTART);
|
||||
}
|
||||
|
||||
/* After receiving the last byte, send STOP if needed */
|
||||
if ((dw->xfr_flags & I2C_MSG_STOP)
|
||||
&& (dw->request_bytes == 1)) {
|
||||
data |= IC_DATA_CMD_STOP;
|
||||
}
|
||||
|
||||
_i2c_qse_ss_reg_write(dev, REG_DATA_CMD, data);
|
||||
|
||||
dw->rx_pending++;
|
||||
dw->request_bytes--;
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
static void _i2c_qse_ss_data_read(struct device *dev)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
|
||||
while (_i2c_qse_ss_is_rfne(dev) && (dw->xfr_len > 0)) {
|
||||
/* Need to write 0 to POP bit to
|
||||
* "pop" one byte from RX FIFO.
|
||||
*/
|
||||
_i2c_qse_ss_reg_write(dev, REG_DATA_CMD,
|
||||
IC_DATA_CMD_STROBE);
|
||||
|
||||
dw->xfr_buf[0] = _i2c_qse_ss_reg_read(dev, REG_DATA_CMD)
|
||||
& IC_DATA_CMD_DATA_MASK;
|
||||
|
||||
dw->xfr_buf++;
|
||||
dw->xfr_len--;
|
||||
dw->rx_pending--;
|
||||
|
||||
if (dw->xfr_len == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nothing to receive anymore */
|
||||
if (dw->xfr_len == 0) {
|
||||
dw->state &= ~I2C_QSE_SS_CMD_RECV;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int _i2c_qse_ss_data_send(struct device *dev)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t data;
|
||||
|
||||
/* Nothing to send anymore, mask the interrupt */
|
||||
if (dw->xfr_len == 0) {
|
||||
_i2c_qse_ss_reg_write_and(dev, REG_INTR_MASK,
|
||||
~(IC_INTR_TX_EMPTY));
|
||||
|
||||
dw->state &= ~I2C_QSE_SS_CMD_SEND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (_i2c_qse_ss_is_tfnf(dev) && (dw->xfr_len > 0)) {
|
||||
/* We have something to transmit to a specific host */
|
||||
data = dw->xfr_buf[0] | IC_DATA_CMD_STROBE | IC_DATA_CMD_POP;
|
||||
|
||||
/* Send RESTART if needed */
|
||||
if (dw->xfr_flags & I2C_MSG_RESTART) {
|
||||
data |= IC_DATA_CMD_RESTART;
|
||||
dw->xfr_flags &= ~(I2C_MSG_RESTART);
|
||||
}
|
||||
|
||||
/* Send STOP if needed */
|
||||
if ((dw->xfr_len == 1) && (dw->xfr_flags & I2C_MSG_STOP)) {
|
||||
data |= IC_DATA_CMD_STOP;
|
||||
}
|
||||
|
||||
_i2c_qse_ss_reg_write(dev, REG_DATA_CMD, data);
|
||||
|
||||
dw->xfr_len--;
|
||||
dw->xfr_buf++;
|
||||
|
||||
if (_i2c_qse_ss_check_irq(dev, IC_INTR_TX_ABRT)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void _i2c_qse_ss_transfer_complete(struct device *dev)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
|
||||
/* Disable and clear all pending interrupts */
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_MASK, IC_INTR_MASK_ALL);
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_CLR_ALL);
|
||||
|
||||
device_sync_call_complete(&dw->sync);
|
||||
}
|
||||
|
||||
|
||||
void i2c_qse_ss_isr(void *arg)
|
||||
{
|
||||
struct device *dev = (struct device *)arg;
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t ic_intr_stat;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Causes of an intterrupts:
|
||||
* - 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
|
||||
*/
|
||||
|
||||
SYS_LOG_DBG("I2C_SS: interrupt received");
|
||||
|
||||
ic_intr_stat = _i2c_qse_ss_reg_read(dev, REG_INTR_STAT);
|
||||
|
||||
/* Error conditions */
|
||||
if ((IC_INTR_TX_ABRT | IC_INTR_TX_OVER |
|
||||
IC_INTR_RX_OVER | IC_INTR_RX_UNDER) &
|
||||
ic_intr_stat) {
|
||||
dw->state = I2C_QSE_SS_CMD_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check if the RX FIFO reached threshold */
|
||||
if (ic_intr_stat & IC_INTR_RX_FULL) {
|
||||
_i2c_qse_ss_data_read(dev);
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_RX_FULL);
|
||||
}
|
||||
|
||||
/* Check if the TX FIFO is ready for commands.
|
||||
* TX FIFO also serves as command queue where read requests
|
||||
* are written to TX FIFO.
|
||||
*/
|
||||
if (ic_intr_stat & IC_INTR_TX_EMPTY) {
|
||||
if ((dw->xfr_flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
ret = _i2c_qse_ss_data_send(dev);
|
||||
} else {
|
||||
_i2c_qse_ss_data_ask(dev);
|
||||
}
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_TX_EMPTY);
|
||||
|
||||
/* If STOP is not expected, finish processing this
|
||||
* message if there is nothing left to do anymore.
|
||||
* Or bail if there is any error.
|
||||
*/
|
||||
if (((dw->xfr_len == 0)
|
||||
&& !(dw->xfr_flags & I2C_MSG_STOP))
|
||||
|| (ret != 0)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* STOP detected */
|
||||
if (ic_intr_stat & IC_INTR_STOP_DET) {
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_STOP_DET);
|
||||
goto done;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
done:
|
||||
_i2c_qse_ss_transfer_complete(dev);
|
||||
}
|
||||
|
||||
static int _i2c_qse_ss_setup(struct device *dev, uint16_t addr)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t ic_con;
|
||||
int rc = 0;
|
||||
|
||||
/* Disable the device controller but enable clock
|
||||
* so we can setup the controller.
|
||||
*/
|
||||
_i2c_qse_ss_reg_write_and(dev, REG_CON, ~(IC_CON_ENABLE));
|
||||
|
||||
/* Disable and clear all pending interrupts */
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_MASK, IC_INTR_MASK_ALL);
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_CLR_ALL);
|
||||
|
||||
ic_con = _i2c_qse_ss_reg_read(dev, REG_CON);
|
||||
ic_con &= IC_CON_SPKLEN_MASK;
|
||||
ic_con |= IC_CON_RESTART_EN | IC_CON_CLK_ENA;
|
||||
|
||||
/* Set addressing mode - (initialization = 7 bit) */
|
||||
if (dw->app_config.bits.use_10_bit_addr) {
|
||||
SYS_LOG_DBG("I2C: using 10-bit address");
|
||||
ic_con |= IC_CON_10BIT_ADDR;
|
||||
}
|
||||
|
||||
/* Setup the clock frequency and speed mode */
|
||||
switch (dw->app_config.bits.speed) {
|
||||
case I2C_SPEED_STANDARD:
|
||||
SYS_LOG_DBG("I2C: speed set to STANDARD");
|
||||
_i2c_qse_ss_reg_write(dev, REG_SS_SCL_CNT,
|
||||
(dw->hcnt << 16) | (dw->lcnt & 0xFFFF));
|
||||
ic_con |= I2C_QSE_SS_SPEED_STANDARD << IC_CON_SPEED_POS;
|
||||
|
||||
break;
|
||||
case I2C_SPEED_FAST:
|
||||
/* fall through */
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
SYS_LOG_DBG("I2C: speed set to FAST or FAST_PLUS");
|
||||
_i2c_qse_ss_reg_write(dev, REG_FS_SCL_CNT,
|
||||
(dw->hcnt << 16) | (dw->lcnt & 0xFFFF));
|
||||
ic_con |= I2C_QSE_SS_SPEED_FAST << IC_CON_SPEED_POS;
|
||||
|
||||
break;
|
||||
default:
|
||||
SYS_LOG_DBG("I2C: invalid speed requested");
|
||||
/* TODO change */
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set the target address */
|
||||
ic_con |= addr << IC_CON_TAR_SAR_POS;
|
||||
|
||||
_i2c_qse_ss_reg_write(dev, REG_CON, ic_con);
|
||||
|
||||
/* Set TX/RX fifo threshold level.
|
||||
*
|
||||
* RX:
|
||||
* Setting it to 1 so RX_FULL is set whenever there is
|
||||
* data in RX FIFO. (actual value is reg value +1)
|
||||
*
|
||||
* TX:
|
||||
* Setting it to 0 so TX_EMPTY is set only when
|
||||
* TX FIFO is truly empty. So that we can let
|
||||
* the controller do the transfers for longer period
|
||||
* before we need to fill the FIFO again. This may
|
||||
* cause some pauses during transfers, but this keeps
|
||||
* the device from interrupting often.
|
||||
*
|
||||
* TODO: extend the threshold for multi-byte RX FIFO.
|
||||
*/
|
||||
_i2c_qse_ss_reg_write(dev, REG_TL, 0x00000000);
|
||||
|
||||
/* SDA Hold time has to setup to minimal 2 according to spec. */
|
||||
_i2c_qse_ss_reg_write(dev, REG_SDA_CONFIG, 0x00020000);
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int i2c_qse_ss_intr_transfer(struct device *dev,
|
||||
struct i2c_msg *msgs, uint8_t num_msgs,
|
||||
uint16_t slave_address)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
struct i2c_msg *cur_msg = msgs;
|
||||
uint8_t msg_left = num_msgs;
|
||||
uint8_t pflags;
|
||||
int ret;
|
||||
|
||||
/* Why bother processing no messages */
|
||||
if (!msgs || !num_msgs) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* First step, check if device is idle */
|
||||
if (_i2c_qse_ss_is_busy(dev) || (dw->state & I2C_QSE_SS_BUSY)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dw->state |= I2C_QSE_SS_BUSY;
|
||||
|
||||
ret = _i2c_qse_ss_setup(dev, slave_address);
|
||||
if (ret) {
|
||||
dw->state = I2C_QSE_SS_STATE_READY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* To prevent RESTART for first message */
|
||||
dw->xfr_flags = msgs[0].flags;
|
||||
|
||||
/* Enable controller */
|
||||
_i2c_qse_ss_reg_write_or(dev, REG_CON, IC_CON_ENABLE);
|
||||
|
||||
/* Process all the messages */
|
||||
while (msg_left > 0) {
|
||||
pflags = dw->xfr_flags;
|
||||
|
||||
dw->xfr_buf = cur_msg->buf;
|
||||
dw->xfr_len = cur_msg->len;
|
||||
dw->xfr_flags = cur_msg->flags;
|
||||
dw->rx_pending = 0;
|
||||
|
||||
/* Need to RESTART if changing transfer direction */
|
||||
if ((pflags & I2C_MSG_RW_MASK)
|
||||
!= (dw->xfr_flags & I2C_MSG_RW_MASK)) {
|
||||
dw->xfr_flags |= I2C_MSG_RESTART;
|
||||
}
|
||||
|
||||
/* Send STOP if this is the last message */
|
||||
if (msg_left == 1) {
|
||||
dw->xfr_flags |= I2C_MSG_STOP;
|
||||
}
|
||||
|
||||
dw->state &= ~(I2C_QSE_SS_CMD_SEND | I2C_QSE_SS_CMD_RECV);
|
||||
|
||||
if ((dw->xfr_flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
dw->state |= I2C_QSE_SS_CMD_SEND;
|
||||
dw->request_bytes = 0;
|
||||
} else {
|
||||
dw->state |= I2C_QSE_SS_CMD_RECV;
|
||||
dw->request_bytes = dw->xfr_len;
|
||||
}
|
||||
|
||||
/* Enable interrupts to trigger ISR */
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_MASK,
|
||||
(IC_INTR_MASK_TX | IC_INTR_MASK_RX));
|
||||
|
||||
/* Wait for transfer to be done */
|
||||
device_sync_call_wait(&dw->sync);
|
||||
if (dw->state & I2C_QSE_SS_CMD_ERROR) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Something wrong if there is something left to do */
|
||||
if (dw->xfr_len > 0) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
cur_msg++;
|
||||
msg_left--;
|
||||
}
|
||||
|
||||
dw->state = I2C_QSE_SS_STATE_READY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_qse_ss_runtime_configure(struct device *dev, uint32_t config)
|
||||
{
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
uint32_t value = 0;
|
||||
uint32_t rc = 0;
|
||||
uint32_t ic_con;
|
||||
uint32_t spklen;
|
||||
|
||||
dw->app_config.raw = config;
|
||||
|
||||
ic_con = _i2c_qse_ss_reg_read(dev, REG_CON);
|
||||
|
||||
spklen = (ic_con & IC_CON_SPKLEN_MASK) >> IC_CON_SPKLEN_POS;
|
||||
|
||||
/* 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 <= (spklen + 7)) {
|
||||
value = 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 <= (spklen + 5)) {
|
||||
value = 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 <= (spklen + 7)) {
|
||||
value = 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 <= (spklen + 5)) {
|
||||
value = spklen + 6;
|
||||
} else {
|
||||
value = I2C_FS_HCNT;
|
||||
}
|
||||
|
||||
dw->hcnt = value;
|
||||
break;
|
||||
default:
|
||||
/* TODO change */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear any interrupts currently waiting in the controller
|
||||
*/
|
||||
_i2c_qse_ss_reg_write(dev, REG_INTR_CLR, IC_INTR_CLR_ALL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct i2c_driver_api api_funcs = {
|
||||
.configure = i2c_qse_ss_runtime_configure,
|
||||
.transfer = i2c_qse_ss_intr_transfer,
|
||||
};
|
||||
|
||||
int i2c_qse_ss_initialize(struct device *dev)
|
||||
{
|
||||
struct i2c_qse_ss_rom_config * const rom = dev->config->config_info;
|
||||
struct i2c_qse_ss_dev_config * const dw = dev->driver_data;
|
||||
|
||||
if (rom->config_func) {
|
||||
rom->config_func(dev);
|
||||
}
|
||||
|
||||
/* Enable clock for controller so we can talk to it */
|
||||
_i2c_qse_ss_reg_write_or(dev, REG_CON, IC_CON_CLK_ENA);
|
||||
|
||||
device_sync_call_init(&dw->sync);
|
||||
|
||||
if (i2c_qse_ss_runtime_configure(dev, dw->app_config.raw) != 0) {
|
||||
SYS_LOG_DBG("I2C_SS: Cannot set default configuration 0x%x",
|
||||
dw->app_config.raw);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
dw->state = I2C_QSE_SS_STATE_READY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_I2C_0
|
||||
#include <init.h>
|
||||
|
||||
static void _i2c_qse_ss_config_irq_0(struct device *port);
|
||||
|
||||
static const struct i2c_qse_ss_rom_config i2c_config_ss_0 = {
|
||||
.base_address = I2C_QUARK_SE_SS_0_BASE_ADDR,
|
||||
|
||||
.config_func = _i2c_qse_ss_config_irq_0,
|
||||
};
|
||||
|
||||
static struct i2c_qse_ss_dev_config i2c_ss_0_runtime = {
|
||||
.app_config.raw = CONFIG_I2C_0_DEFAULT_CFG,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(i2c_ss_0, CONFIG_I2C_0_NAME,
|
||||
&i2c_qse_ss_initialize,
|
||||
&i2c_ss_0_runtime, (void *)&i2c_config_ss_0,
|
||||
SECONDARY, CONFIG_I2C_INIT_PRIORITY,
|
||||
(void *)&api_funcs);
|
||||
|
||||
static void _i2c_qse_ss_config_irq_0(struct device *port)
|
||||
{
|
||||
uint32_t mask = 0;
|
||||
|
||||
/* Need to unmask the interrupts in System Control Subsystem (SCSS)
|
||||
* so the interrupt controller can route these interrupts to
|
||||
* the sensor subsystem.
|
||||
*/
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_0_ERR_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_0_ERR_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_0_TX_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_0_TX_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_0_RX_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_0_RX_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_0_STOP_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_0_STOP_MASK, mask);
|
||||
|
||||
/* Connect the IRQs to ISR */
|
||||
IRQ_CONNECT(I2C_SS_0_ERR_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_0), 0);
|
||||
IRQ_CONNECT(I2C_SS_0_RX_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_0), 0);
|
||||
IRQ_CONNECT(I2C_SS_0_TX_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_0), 0);
|
||||
IRQ_CONNECT(I2C_SS_0_STOP_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_0), 0);
|
||||
|
||||
irq_enable(I2C_SS_0_ERR_VECTOR);
|
||||
irq_enable(I2C_SS_0_RX_VECTOR);
|
||||
irq_enable(I2C_SS_0_TX_VECTOR);
|
||||
irq_enable(I2C_SS_0_STOP_VECTOR);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_I2C_0 */
|
||||
|
||||
#if CONFIG_I2C_1
|
||||
#include <init.h>
|
||||
|
||||
static void _i2c_qse_ss_config_irq_1(struct device *port);
|
||||
|
||||
static const struct i2c_qse_ss_rom_config i2c_config_ss_1 = {
|
||||
.base_address = I2C_QUARK_SE_SS_1_BASE_ADDR,
|
||||
|
||||
.config_func = _i2c_qse_ss_config_irq_1,
|
||||
};
|
||||
|
||||
static struct i2c_qse_ss_dev_config i2c_qse_ss_1_runtime = {
|
||||
.app_config.raw = CONFIG_I2C_1_DEFAULT_CFG,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(i2c_ss_1, CONFIG_I2C_1_NAME,
|
||||
&i2c_qse_ss_initialize,
|
||||
&i2c_qse_ss_1_runtime, (void *)&i2c_config_ss_1,
|
||||
SECONDARY, CONFIG_I2C_INIT_PRIORITY);
|
||||
(void *)&api_funcs);
|
||||
|
||||
|
||||
static void _i2c_qse_ss_config_irq_1(struct device *port)
|
||||
{
|
||||
uint32_t mask = 0;
|
||||
|
||||
/* Need to unmask the interrupts in System Control Subsystem (SCSS)
|
||||
* so the interrupt controller can route these interrupts to
|
||||
* the sensor subsystem.
|
||||
*/
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_1_ERR_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_1_ERR_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_1_TX_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_1_TX_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_1_RX_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_1_RX_MASK, mask);
|
||||
|
||||
mask = _i2c_qse_ss_memory_read(SCSS_REGISTER_BASE, I2C_SS_1_STOP_MASK);
|
||||
mask &= INT_ENABLE_ARC;
|
||||
_i2c_qse_ss_memory_write(SCSS_REGISTER_BASE, I2C_SS_1_STOP_MASK, mask);
|
||||
|
||||
/* Connect the IRQs to ISR */
|
||||
IRQ_CONNECT(I2C_SS_1_ERR_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_1), 0);
|
||||
IRQ_CONNECT(I2C_SS_1_RX_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_1), 0);
|
||||
IRQ_CONNECT(I2C_SS_1_TX_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_1), 0);
|
||||
IRQ_CONNECT(I2C_SS_1_STOP_VECTOR, 1, i2c_qse_ss_isr,
|
||||
DEVICE_GET(i2c_ss_1), 0);
|
||||
|
||||
irq_enable(I2C_SS_1_ERR_VECTOR);
|
||||
irq_enable(I2C_SS_1_RX_VECTOR);
|
||||
irq_enable(I2C_SS_1_TX_VECTOR);
|
||||
irq_enable(I2C_SS_1_STOP_VECTOR);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_I2C_1 */
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Header for I2C driver for Quark SE Sensor Subsystem
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_I2C_QUARK_SE_SS_H__
|
||||
#define __DRIVERS_I2C_QUARK_SE_SS_H__
|
||||
|
||||
#include <i2c.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* dev->state values from IC_DATA_CMD Data transfer mode settings (bit 8) */
|
||||
#define I2C_QSE_SS_STATE_READY (0)
|
||||
#define I2C_QSE_SS_CMD_SEND (1 << 0)
|
||||
#define I2C_QSE_SS_CMD_RECV (1 << 1)
|
||||
#define I2C_QSE_SS_CMD_ERROR (1 << 2)
|
||||
#define I2C_QSE_SS_BUSY (1 << 3)
|
||||
|
||||
/*
|
||||
* DesignWare speed values don't directly translate from the Zephyr speed
|
||||
* selections in include/i2c.h so here we do a little translation
|
||||
*/
|
||||
#define I2C_QSE_SS_SPEED_STANDARD 0x1
|
||||
#define I2C_QSE_SS_SPEED_FAST 0x2
|
||||
#define I2C_QSE_SS_SPEED_FAST_PLUS 0x2
|
||||
|
||||
/* IC_CON Low count and high count default values */
|
||||
/* TODO verify all values for Quark SE SS */
|
||||
#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_QSE_SS_FIFO_DEPTH 8
|
||||
|
||||
typedef void (*i2c_qse_ss_cfg_func_t)(struct device *port);
|
||||
|
||||
struct i2c_qse_ss_rom_config {
|
||||
uint32_t base_address;
|
||||
|
||||
i2c_qse_ss_cfg_func_t config_func;
|
||||
};
|
||||
|
||||
struct i2c_qse_ss_dev_config {
|
||||
device_sync_call_t sync;
|
||||
union dev_config app_config;
|
||||
|
||||
volatile uint8_t state; /* last direction of transfer */
|
||||
|
||||
uint8_t xfr_flags;
|
||||
|
||||
uint8_t *xfr_buf;
|
||||
uint32_t xfr_len;
|
||||
uint32_t request_bytes;
|
||||
uint32_t rx_pending;
|
||||
|
||||
uint16_t hcnt;
|
||||
uint16_t lcnt;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DRIVERS_I2C_QUARK_SE_SS_H__ */
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Register sets for I2C driver for Quark SE Sensor Subsystem
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_I2C_QUARK_SE_SS_REGISTERS_H__
|
||||
#define __DRIVERS_I2C_QUARK_SE_SS_REGISTERS_H__
|
||||
|
||||
/* Register offsets */
|
||||
#define REG_CON 0x00
|
||||
#define REG_DATA_CMD 0x01
|
||||
#define REG_SS_SCL_CNT 0x02
|
||||
#define REG_FS_SCL_CNT 0x04
|
||||
#define REG_INTR_STAT 0x06
|
||||
#define REG_INTR_MASK 0x07
|
||||
#define REG_TL 0x08
|
||||
#define REG_INTR_CLR 0x0A
|
||||
#define REG_STATUS 0x0B
|
||||
#define REG_TXFLR 0x0C
|
||||
#define REG_RXFLR 0x0D
|
||||
#define REG_SDA_CONFIG 0x0E
|
||||
#define REG_TX_ABRT_SOURCE 0x0F
|
||||
#define REG_ENABLE_STATUS 0x11
|
||||
|
||||
/* IC_CON bits */
|
||||
#define IC_CON_CLK_ENA (1 << 31)
|
||||
#define IC_CON_RSVP_4 (1 << 30)
|
||||
#define IC_CON_SPKLEN_MASK (0x8 << 22)
|
||||
#define IC_CON_SPKLEN_POS (22)
|
||||
#define IC_CON_RSVP_3 (0x7 << 19)
|
||||
#define IC_CON_TAR_SAR_MASK (0x7FF << 9)
|
||||
#define IC_CON_TAR_SAR_POS (9)
|
||||
#define IC_CON_RSVP_2 (1 << 8)
|
||||
#define IC_CON_RESTART_EN (1 << 7)
|
||||
#define IC_CON_RSVP_1 (1 << 6)
|
||||
#define IC_CON_10BIT_ADDR (1 << 5)
|
||||
#define IC_CON_SPEED_MASK (2 << 3)
|
||||
#define IC_CON_SPEED_POS (3)
|
||||
#define IC_CON_RSVP_0 (1 << 2)
|
||||
#define IC_CON_ABORT (1 << 1)
|
||||
#define IC_CON_ENABLE (1 << 0)
|
||||
|
||||
/* IC_DATA_CMD bits */
|
||||
#define IC_DATA_CMD_DATA_MASK 0xFF
|
||||
#define IC_DATA_CMD_CMD (1 << 8)
|
||||
#define IC_DATA_CMD_STOP (1 << 9)
|
||||
#define IC_DATA_CMD_RESTART (1 << 10)
|
||||
#define IC_DATA_CMD_POP (1 << 30)
|
||||
#define IC_DATA_CMD_STROBE (1 << 31)
|
||||
|
||||
/* IC_INTR_STAT, IC_INTR_MASK, IC_INTR_CLR bits */
|
||||
#define IC_INTR_RX_UNDER (1 << 0)
|
||||
#define IC_INTR_RX_OVER (1 << 1)
|
||||
#define IC_INTR_RX_FULL (1 << 2)
|
||||
#define IC_INTR_TX_OVER (1 << 3)
|
||||
#define IC_INTR_TX_EMPTY (1 << 4)
|
||||
#define IC_INTR_TX_ABRT (1 << 6)
|
||||
#define IC_INTR_RX_DONE (1 << 7)
|
||||
#define IC_INTR_ACTIVITY (1 << 8)
|
||||
#define IC_INTR_STOP_DET (1 << 9)
|
||||
#define IC_INTR_START_DET (1 << 10)
|
||||
|
||||
#define IC_INTR_CLR_ALL (0xFFFFFFFF)
|
||||
#define IC_INTR_MASK_ALL (0x0)
|
||||
|
||||
#define IC_INTR_MASK_TX (IC_INTR_TX_OVER | \
|
||||
IC_INTR_TX_EMPTY | \
|
||||
IC_INTR_TX_ABRT | \
|
||||
IC_INTR_STOP_DET)
|
||||
#define IC_INTR_MASK_RX (IC_INTR_RX_UNDER | \
|
||||
IC_INTR_RX_OVER | \
|
||||
IC_INTR_RX_FULL | \
|
||||
IC_INTR_STOP_DET)
|
||||
|
||||
/* IC_STATUS */
|
||||
#define IC_STATUS_ACTIVITY (1 << 0)
|
||||
#define IC_STATUS_TFNF (1 << 1)
|
||||
#define IC_STATUS_TFE (1 << 2)
|
||||
#define IC_STATUS_RFNE (1 << 3)
|
||||
#define IC_STATUS_RFF (1 << 4)
|
||||
#define IC_STATUS_MST_ACTIVITY (1 << 5)
|
||||
#define IC_STATUS_SLV_ACTIVITY (1 << 6)
|
||||
|
||||
#endif /* __DRIVERS_I2C_QUARK_SE_SS_REGISTERS_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue