mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/i2c_api.c

876 lines
23 KiB
C

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
****************************************************************************/
#if DEVICE_I2C
#include "i2c_api.h"
#include "i2c_def.h"
#include "cmsis.h"
#include "pinmap.h"
#include "mbed_error.h"
#include "mbed_wait_api.h"
/* States of a possibly combined I2C transfer */
typedef enum i2c_transfer_state_t {
I2C_TRANSFER_SINGLE, /* Non combined transfer */
I2C_TRANSFER_COMBINED_FIRST_MESSAGE, /*
* First message of a
* combined transfer
*/
I2C_TRANSFER_COMBINED_INTERMEDIATE_MESSAGE, /*
* Message in the middle
* of a combined
* transfer
*/
I2C_TRANSFER_COMBINED_LAST_MESSAGE, /*
* Last message of a combined
* transfer
*/
} i2c_transfer_state_t;
/*
* Driver private data structure that should not be shared by multiple
* instances of the driver
* (same driver for multiple instances of the IP)
*/
typedef struct private_i2c_t {
/* State of a possibly combined ongoing i2c transfer */
i2c_transfer_state_t transfer_state;
} private_i2c_t;
struct i2c_msg_s {
uint16_t addr; /**< Slave address */
uint16_t flags; /**< I2C flags; See I2C_M_* definitions */
#ifdef CONFIG_I2C_USERIO
uint16_t length; /**< The length of buffer */
uint8_t *buffer; /**< The Buffer for transferring message */
#else
uint8_t *buffer; /**< The Buffer for transferring message */
int length; /**< The length of buffer */
#endif
};
#define S5JS100_DEFAULT_I2CXFER_CLOCK (100 * 1000) // 100KHz
#define S5JS100_DEFAULT_I2C_TIMEOUT 10000
#define S5JS100_DEFAULT_I2CSLAVE_ADDR 0x69
#define HSI2C_INT_XFER_DONE (HSI2C_INT_XFER_DONE_NOACK_MANUAL | HSI2C_INT_XFER_DONE_MANUAL)
/*
* Retrieve the private data of the instance related to a given IP
*/
#if 0
static private_i2c_t *get_i2c_private(i2c_t *obj)
{
static private_i2c_t data0, data1;
/*
* Select which instance to give using the base
* address of registers
*/
switch ((intptr_t)obj->i2c) {
case I2C0_BASE:
return &data0;
case I2C1_BASE:
return &data1;
default:
error("i2c driver private data structure not found for this registers base address");
return (void *)0;
}
}
#endif
static const PinMap PinMap_I2C_SDA[] = {
{I2C_SDA, I2C_0, 0},
{NC, NC, 0}
};
static const PinMap PinMap_I2C_SCL[] = {
{I2C_SCL, I2C_0, 0},
{NC, NC, 0}
};
static void hsi2c_set_hs_timing(unsigned int base, unsigned int nClkDiv,
unsigned int tSTART_SU, unsigned int tSTART_HD,
unsigned int tSTOP_SU, unsigned int tSDA_SU,
unsigned int tDATA_SU, unsigned int tDATA_HD,
unsigned int tSCL_L, unsigned int tSCL_H,
unsigned int tSR_RELEASE)
{
tSTART_SU &= 0xFF;
tSTART_HD &= 0xFF;
tSTOP_SU &= 0xFF;
putreg32(((tSTART_SU << 24) | (tSTART_HD << 16) | (tSTOP_SU << 8)), base + I2C_TIMING_HS1);
tDATA_SU &= 0xFF;
tSCL_L &= 0xFF;
tSCL_H &= 0xFF;
putreg32(((tDATA_SU << 24) | (tSCL_L << 8) | (tSCL_H << 0)), base + I2C_TIMING_HS2);
nClkDiv &= 0xFF;
tSR_RELEASE &= 0xFF;
putreg32(((nClkDiv << 16) | (tSR_RELEASE << 0)), base + I2C_TIMING_HS3);
tDATA_HD &= 0xFFFF;
putreg32(tDATA_HD, base + I2C_TIMING_SLA);
}
static void hsi2c_set_fs_timing(unsigned int base, unsigned int nClkDiv,
unsigned int tSTART_SU, unsigned int tSTART_HD,
unsigned int tSTOP_SU, unsigned int tDATA_SU,
unsigned int tDATA_HD, unsigned int tSCL_L,
unsigned int tSCL_H, unsigned int tSR_RELEASE)
{
tSTART_SU &= 0xFF;
tSTART_HD &= 0xFF;
tSTOP_SU &= 0xFF;
putreg32(((tSTART_SU << 24) | (tSTART_HD << 16) | (tSTOP_SU << 8)), base + I2C_TIMING_FS1);
tDATA_SU &= 0xFF;
tSCL_L &= 0xFF;
tSCL_H &= 0xFF;
putreg32(((tDATA_SU << 24) | (tSCL_L << 8) | (tSCL_H << 0)), base + I2C_TIMING_FS2);
nClkDiv &= 0xFF;
tSR_RELEASE &= 0xFF;
putreg32(((nClkDiv << 16) | (tSR_RELEASE << 0)), base + I2C_TIMING_FS3);
tDATA_HD &= 0xFFFF;
putreg32(tDATA_HD, base + I2C_TIMING_SLA);
}
static void hsi2c_calculate_timing(unsigned int base, unsigned int nPclk,
unsigned int nOpClk)
{
unsigned int reg;
unsigned int nClkDiv;
uint32_t tFTL_CYCLE_SCL;
int i;
int uTemp0;
int uTemp1;
int uTemp2 = 0;
reg = getreg32(base + I2C_CONF);
reg &= ~(0x7 << 13);
putreg32(reg, base + I2C_CONF);
reg = getreg32(base + I2C_CONF);
reg &= ~(0x7 << 16);
putreg32(reg, base + I2C_CONF);
tFTL_CYCLE_SCL = (getreg32(base + I2C_CONF) >> 16) & 0x7;
uTemp0 = (float)(nPclk / nOpClk) - (tFTL_CYCLE_SCL + 3) * 2;
for (i = 0; i < 256; i++) {
uTemp1 = (uTemp0 + ((tFTL_CYCLE_SCL + 3) % (i + 1)) * 2) / (i + 1);
if (uTemp1 < 512) { /* TSCL_L/H max is 512 / 2 */
uTemp2 = uTemp1 - 2;
break;
}
}
unsigned int tSCL_H;
nClkDiv = i;
if (nOpClk > I2C_SPEED_400KHZ) {
tSCL_H = ((uTemp2 + 10) / 3) - 5;
} else {
tSCL_H = uTemp2 / 2;
}
unsigned int tSCL_L = uTemp2 - tSCL_H;
unsigned int tSTART_SU = tSCL_L;
unsigned int tSTART_HD = tSCL_L;
unsigned int tSTOP_SU = tSCL_L;
unsigned int tSDA_SU = tSCL_L;
unsigned int tDATA_SU = tSCL_L;
unsigned int tDATA_HD = tSCL_L / 2;
unsigned int tSR_RELEASE = uTemp2;
if (nOpClk > I2C_SPEED_400KHZ) {
/* 400Khz setting for Extended ID */
hsi2c_set_fs_timing(base, 1, 38, 38, 38, 19, 19, 38, 38, 76);
hsi2c_set_hs_timing(base, nClkDiv, tSTART_SU, tSTART_HD, tSTOP_SU,
tSDA_SU, tDATA_SU, tDATA_HD, tSCL_L, tSCL_H, tSR_RELEASE);
} else {
hsi2c_set_fs_timing(base, nClkDiv, tSTART_SU, tSTART_HD, tSTOP_SU,
tDATA_SU, tDATA_HD, tSCL_L, tSCL_H, tSR_RELEASE);
}
}
static void hsi2c_conf(unsigned int base, unsigned int nOpClk)
{
unsigned int val;
val = getreg32(base + I2C_CONF);
val &= ~(3 << 30);
if (nOpClk > I2C_SPEED_400KHZ) {
val |= (1 << 29);
} else {
val &= ~(1 << 29);
}
putreg32(val, base + I2C_CONF);
}
static void hsi2c_enable_int(unsigned int base, unsigned int bit)
{
unsigned int val;
val = getreg32(base + INT_EN);
val |= bit;
putreg32(val, base + INT_EN);
}
static void hsi2c_disable_int(unsigned int base, unsigned int bit)
{
unsigned int val;
val = getreg32(base + INT_EN);
val &= ~bit;
putreg32(val, base + INT_EN);
}
static int hsi2c_manual_fast_init(i2c_t *obj)
{
unsigned int val;
unsigned int base = obj->base;
hsi2c_conf(base, obj->xfer_speed);
hsi2c_calculate_timing(base, obj->clock, obj->xfer_speed);
hsi2c_enable_int(base, HSI2C_INT_XFER_DONE_MANUAL | HSI2C_INT_XFER_DONE_NOACK_MANUAL);
obj->initialized = 1;
val = getreg32(base + I2C_CONF);
val &= ~((1 << 31) | (1 << 29));
putreg32(val, base + I2C_CONF);
hsi2c_enable_int(base, HSI2C_INT_XFER_DONE);
return 0;
}
static void hsi2c_set_slave_addr(unsigned int base, unsigned short addr,
unsigned int is_master)
{
unsigned int val;
addr &= 0x3FF;
val = getreg32(base + I2C_ADDR);
if (is_master == 0) {
val &= ~0x3ff;
val |= addr;
} else {
val &= ~(0x3FF << 10);
val |= (addr << 10);
}
putreg32(val, base + I2C_ADDR);
}
static int hsi2c_wait_xfer_done(i2c_t *obj)
{
int val;
int timeout = obj->timeout;
unsigned int base = obj->base;
while (timeout-- > 0) {
val = getreg32(base + INT_STAT) & HSI2C_INT_XFER_DONE_MANUAL;
if (val) {
putreg32(val, base + INT_STAT);
return (val == HSI2C_INT_XFER_DONE_MANUAL);
}
}
return -1;
}
static void hsi2c_start(i2c_t *obj)
{
putreg32(0x88, I2C0_BASE + CTL);
putreg32(I2C_START, obj->base + I2C_MANUAL_CMD);
hsi2c_wait_xfer_done(obj);
}
static void hsi2c_stop(i2c_t *obj)
{
putreg32(I2C_STOP, obj->base + I2C_MANUAL_CMD);
hsi2c_wait_xfer_done(obj);
}
static void hsi2c_repstart(i2c_t *obj)
{
putreg32(I2C_RESTART, obj->base + I2C_MANUAL_CMD);
}
static int hsi2c_outb(i2c_t *obj, unsigned char data)
{
unsigned int val;
int ret;
val = ((unsigned int)data) << 24 | I2C_SEND_DATA;
putreg32(val, obj->base + I2C_MANUAL_CMD);
ret = hsi2c_wait_xfer_done(obj);
return ret;
}
static int hsi2c_inb(i2c_t *obj, unsigned char is_ack)
{
unsigned int val = I2C_READ_DATA;
unsigned char data;
int ret;
unsigned int base = obj->base;
/* Looks awkward, but if I2C_RX_ACK is set, ACK is NOT generated */
if (!is_ack) {
val |= I2C_RX_ACK;
}
putreg32(val, base + I2C_MANUAL_CMD);
ret = hsi2c_wait_xfer_done(obj);
if (ret < 0) {
return ret; /* timeout */
}
data = (getreg32(base + I2C_MANUAL_CMD) >> 16) & 0xff;
return data;
}
static int sendbytes(i2c_t *obj, struct i2c_msg_s *msg)
{
uint8_t *p = msg->buffer;
int count = msg->length;
int nak_ok = msg->flags & I2C_M_IGNORE_NAK;
int wrcount = 0, ret;
while (count > 0) {
ret = hsi2c_outb(obj, *p);
if ((ret == 1) || ((ret == 0) && nak_ok)) {
count--;
p++;
wrcount++;
} else if (ret == 0) {
/* NAK from the slave */
return -EIO;
} else {
/* Timeout */
return ret;
}
}
return wrcount;
}
static int readbytes(i2c_t *obj, struct i2c_msg_s *msg)
{
int val;
int rdcount = 0;
unsigned char *p = msg->buffer;
int count = msg->length;
while (count > 0) {
val = hsi2c_inb(obj, (count > 1));
if (val < 0) {
break;
}
*p++ = val;
rdcount++;
count--;
}
return rdcount;
}
static int try_address(i2c_t *obj, unsigned char addr, int retries)
{
int i, ret = 0;
for (i = 0; i <= retries; i++) {
ret = hsi2c_outb(obj, addr);
if (ret == 1 || i == retries) {
break;
}
hsi2c_stop(obj);
wait_us(obj->timeout / 2);
hsi2c_start(obj);
}
return ret;
}
static int do_address(i2c_t *obj, struct i2c_msg_s *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
unsigned char addr;
int ret;
int retries;
retries = nak_ok ? 0 : obj->retries;
if (flags & I2C_M_TEN) {
/* a 10-bit address in manual mode */
addr = 0xf0 | ((msg->addr >> 7) & 0x06);
ret = try_address(obj, addr, retries);
if ((ret != 1) && !nak_ok) {
return -ENXIO;
}
/* the remaining 8 bit address */
ret = hsi2c_outb(obj, msg->addr & 0xff);
if ((ret != 1) && !nak_ok) {
return -ENXIO;
}
if (flags & I2C_M_READ) {
hsi2c_repstart(obj);
hsi2c_wait_xfer_done(obj);
addr |= 0x1;
ret = try_address(obj, addr, retries);
if ((ret != 1) && !nak_ok) {
return -EIO;
}
}
} else {
/* 7-bit address */
addr = msg->addr << 1;
if (flags & I2C_M_READ) {
addr |= 0x1;
}
ret = try_address(obj, addr, retries);
if ((ret != 1) && !nak_ok) {
return -ENXIO;
}
}
return 0;
}
static void hsi2c_set_auto_config(unsigned int base, unsigned int stop,
unsigned int tx, unsigned int len)
{
unsigned int val = getreg32(base + I2C_AUTO_CONF);
if (stop) {
val |= (1 << 17);
} else {
val &= ~(1 << 17);
}
if (tx) {
val &= ~(1 << 16);
} else {
val |= (1 << 16);
}
val &= ~0xFFFF;
val |= len;
putreg32(val, base + I2C_AUTO_CONF);
}
static void hsi2c_set_trans_mode(unsigned int base, unsigned int master,
unsigned int tx)
{
unsigned int val = getreg32(base + CTL);
val |= (1 << 0); /* ctrl 0 bit write 1 */
if (master) {
val |= (1 << 3);
} else {
val &= ~(1 << 3);
}
val &= ~(3 << 6);
if (tx) {
val |= (1 << 7);
} else {
val |= (1 << 6);
}
putreg32(val, base + CTL);
}
static void hsi2c_set_hwacg_mode(unsigned int base, unsigned int slave)
{
unsigned int val = getreg32(base + CTL);
val &= ~(0x3 << 24);
if (slave) {
val |= (0x1 << 24);
} else {
val &= ~(0x1 << 24);
}
putreg32(val, base + CTL);
}
static void hsi2c_set_fifo_level(unsigned int base)
{
putreg32(0x10013, base + FIFO_CTL);
}
static void hsi2c_master_setup(i2c_t *obj, unsigned int mode,
unsigned int speed, unsigned int slave_addr)
{
if (obj->mode == I2C_POLLING) {
obj->xfer_speed = speed;
hsi2c_calculate_timing(obj->base, obj->clock, speed);
}
#ifdef CONFIG_S5JS100_I2C_INTERRUPT_MODE
else if (priv->mode == I2C_INTERRUPT) {
priv->master_test_data = (struct master_data *)malloc(sizeof(struct master_data));
/* complete_init(&priv->master_test_data->done); */
hsi2c_set_trans_mode(obj->base, 1, 1); /* set master mode */
hsi2c_conf(obj->base, speed);
hsi2c_calculate_timing(obj->base, obj->clock, speed);
hsi2c_set_slave_addr(obj->base, slave_addr, 1);
hsi2c_set_auto_mode(obj->base);
hsi2c_set_fifo_level(obj->base);
}
#endif
}
static void hsi2c_slave_setup(i2c_t *obj, unsigned int mode,
unsigned int speed, unsigned int slave_addr)
{
// obj->i2c->slave_test_data = (struct slave_data *)malloc(sizeof(struct slave_data));
/* slave mode is only support slave mode */
hsi2c_set_trans_mode(obj->base, 0, 0); /* set slave mode */
/*set hwacg for slave mode */
hsi2c_set_hwacg_mode(obj->base, 1);
hsi2c_conf(obj->base, speed);
hsi2c_calculate_timing(obj->base, obj->clock, speed);
hsi2c_set_slave_addr(obj->base, slave_addr, 0);
hsi2c_disable_int(obj->base, HSI2C_INT_ALL);
hsi2c_enable_int(obj->base, HSI2C_INT_SLAVE_ADDR_MATCH | HSI2C_INT_RX_ALMOST_FULL);
hsi2c_set_fifo_level(obj->base);
hsi2c_set_auto_config(obj->base, 0, 0, 0);
hsi2c_set_trans_mode(obj->base, 0, 0);
#ifdef CONFIG_S5JS100_I2C_INTERRUPT_MODE
if ((priv->master == I2C_SLAVE_MODE) || (priv->mode == I2C_INTERRUPT)) {
irq_attach(priv->config->irq, priv->config->isr, NULL);
}
#endif
}
static int hsi2c_setup(i2c_t *obj, unsigned int master,
unsigned int mode, unsigned int speed, unsigned int slave_addr)
{
obj->master = master;
obj->mode = mode;
obj->xfer_speed = speed;
obj->slave_addr = slave_addr;
hsi2c_manual_fast_init(obj);
if (master == I2C_MASTER) {
hsi2c_master_setup(obj, mode, speed, slave_addr);
} else if (master == I2C_SLAVE_MODE) {
hsi2c_slave_setup(obj, mode, speed, slave_addr);
}
return 0;
}
unsigned int i2c_setclock(i2c_t *obj, unsigned int frequency)
{
/* Has the I2C bus frequency changed? */
if (frequency != obj->xfer_speed) {
/*
* Calculate the clock divider that results in the highest frequency
* that is than or equal to the desired speed.
*/
if (obj->mode != I2C_POLLING) {
hsi2c_conf(obj->base, frequency);
}
hsi2c_calculate_timing(obj->base, obj->clock, frequency);
}
/* Save the new I2C frequency */
obj->xfer_speed = frequency;
return 0;
}
static void clear_isr(i2c_t *obj)
{
/*
* Writing to the IRQ status register clears set bits. Therefore, to
* clear indiscriminately, just read the register and write it back.
*/
uint32_t reg = obj->i2c->IRQ_STATUS;
obj->i2c->IRQ_STATUS = reg;
}
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
/* Determine the I2C to use */
I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
obj->i2c = (I2C_TypeDef *)pinmap_merge(i2c_sda, i2c_scl);
if ((int)obj->i2c == NC) {
error("I2C pin mapping failed");
}
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
/*
* Default configuration:
* - MS : Master mode
* - NEA : Normal (7-bit) addressing
* - ACKEN : Send ACKs when reading from slave
* - CLR_FIFO : Not a configuration bit => clears the FIFO
*/
uint32_t reg = I2C_CTRL_MS | \
I2C_CTRL_NEA | \
I2C_CTRL_ACKEN | \
I2C_CTRL_CLR_FIFO;
obj->i2c->CONTROL = reg;
obj->base = I2C0_BASE;
obj->retries = 0;
obj->timeout = S5JS100_DEFAULT_I2C_TIMEOUT;
obj->master = I2C_MASTER;
obj->initialized = 0;
obj->clock = cal_clk_getrate(d1_acpu_l3);
obj->slave_addr = S5JS100_DEFAULT_I2CSLAVE_ADDR;
obj->mode = I2C_POLLING;
obj->addrlen = 7;
hsi2c_setup(obj, obj->master, obj->mode, obj->xfer_speed, obj->slave_addr);
i2c_setclock(obj, S5JS100_DEFAULT_I2CXFER_CLOCK);
//get_i2c_private(obj)->transfer_state = I2C_TRANSFER_SINGLE;
//i2c_frequency(obj, 100000); /* Default to 100kHz SCL frequency */
}
int i2c_start(i2c_t *obj)
{
return 0;
}
int i2c_stop(i2c_t *obj)
{
/* Clear the hardware FIFO */
obj->i2c->CONTROL |= I2C_CTRL_CLR_FIFO;
/* Clear the HOLD bit used for performing combined transfers */
obj->i2c->CONTROL &= ~I2C_CTRL_HOLD;
/* Reset the transfer size (read and write) */
obj->i2c->TRANSFER_SIZE = 0;
/* Clear interrupts */
clear_isr(obj);
return 0;
}
void i2c_frequency(i2c_t *obj, int hz)
{
/*
* Divider is split in two halfs : A and B
* A is 2 bits wide and B is 6 bits wide
* The Fscl frequency (SCL clock) is calculated with the following
* equation:
* Fscl=SystemCoreClock/(22*(A+1)*(B+1))
* Here, we only calculate the B divisor which already enables a
* wide enough range of values
*/
unsigned int frequency = hz;
if (frequency != obj->xfer_speed) {
if (obj->mode != I2C_POLLING) {
hsi2c_conf(obj->base, frequency);
}
hsi2c_calculate_timing(obj->base, obj->clock, frequency);
}
}
int i2c_transfer(i2c_t *obj, struct i2c_msg_s *msgv, int msgc)
{
struct i2c_msg_s *pmsg;
int ret = 0;
int i;
int nak_ok;
int start = 1;
int stop = 1;
//unsigned int base = obj->base;
/* Ensure that address or flags don't change meanwhile */
//s5js100_i2c_sem_wait(priv);
/* TODO: initialization */
if (start) {
hsi2c_start(obj);
}
/*
if (obj->xfer_speed > I2C_SPEED_400KHZ) {
hsi2c_conf(base, I2C_SPEED_400KHZ);
putreg32((0xF << 24 | I2C_SEND_DATA), base + I2C_MANUAL_CMD);
hsi2c_wait_xfer_noack(priv);
hsi2c_conf(base, priv->xfer_speed);
hsi2c_repstart(priv);
hsi2c_wait_xfer_noack(priv);
}
*/
for (i = 0; i < msgc; i++) {
pmsg = &msgv[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (!(pmsg->flags & I2C_M_NOSTART)) {
if ((i > 0) || (start == 0)) {
hsi2c_repstart(obj);
hsi2c_wait_xfer_done(obj);
}
ret = do_address(obj, pmsg);
if ((ret != 0) && !nak_ok) {
goto fail;
}
}
if (pmsg->flags & I2C_M_READ) {
/* read bytes into buffer */
ret = readbytes(obj, pmsg);
if (ret < pmsg->length) {
if (ret >= 0) {
return -EIO;
}
goto fail;
}
} else {
/* write bytes from buffer */
ret = sendbytes(obj, pmsg);
if (ret < pmsg->length) {
if (ret >= 0) {
ret = -EIO;
}
goto fail;
}
}
}
fail:
if (stop) {
hsi2c_stop(obj);
}
/* Ensure that address or flags don't change meanwhile */
//s5js100_i2c_sem_post(priv);
return ret;
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
struct i2c_msg_s xfer[2];
xfer[0].addr = (unsigned int)address;
xfer[0].flags = 0;
xfer[0].buffer = (unsigned char *)&data[0];
xfer[0].length = 1;
xfer[1].addr = (unsigned int)address;
xfer[1].flags = I2C_M_READ;
xfer[1].buffer = (unsigned char *)&data[1];
xfer[1].length = length;
wait_us(100);
return i2c_transfer(obj, xfer, 2);
}
int i2c_write(i2c_t *obj, int address, const char *data, int length,
int stop)
{
struct i2c_msg_s msg;
msg.addr = address;
msg.flags = (obj->addrlen == 10) ? I2C_M_TEN : 0;
msg.buffer = (unsigned char *)data;
msg.length = length;
return i2c_transfer(obj, &msg, 1);
}
void i2c_reset(i2c_t *obj)
{
i2c_stop(obj);
}
int i2c_byte_read(i2c_t *obj, int last)
{
char i2c_ret = 0;
i2c_read(obj, obj->last_xfer_address, &i2c_ret, 1, last);
return i2c_ret;
}
int i2c_byte_write(i2c_t *obj, int data)
{
/* Store the number of written bytes */
uint32_t wb = i2c_write(obj, obj->last_xfer_address, (char *)&data, 1, 0);
if (wb == 1) {
return 1;
} else {
return 0;
}
}
void i2c_slave_mode(i2c_t *obj, int enable_slave)
{
}
int i2c_slave_receive(i2c_t *obj)
{
return 0;
}
int i2c_slave_read(i2c_t *obj, char *data, int length)
{
return 0;
}
int i2c_slave_write(i2c_t *obj, const char *data, int length)
{
return 0;
}
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
{
}
#endif // DEVICE_I2C