338 lines
5.9 KiB
C
338 lines
5.9 KiB
C
|
//#include "system/init.h"
|
||
|
#include "asm/iic_soft.h"
|
||
|
#include "generic/gpio.h"
|
||
|
|
||
|
#define IIC_SCL_DIR(scl, val) \
|
||
|
gpio_set_direction(scl, val)
|
||
|
|
||
|
#define IIC_SCL_SET_PU(scl, on) \
|
||
|
gpio_set_pull_up(scl, on)
|
||
|
|
||
|
#define IIC_SCL_SET_PD(scl, on) \
|
||
|
gpio_set_pull_down(scl, on)
|
||
|
|
||
|
#define IIC_SCL_SET_DIE(scl, on) \
|
||
|
gpio_set_die(scl, on)
|
||
|
|
||
|
#define IIC_SCL_H(scl) \
|
||
|
gpio_direction_output(scl, 1)
|
||
|
|
||
|
#define IIC_SCL_L(scl) \
|
||
|
gpio_direction_output(scl, 0)
|
||
|
|
||
|
#define IIC_SDA_DIR(sda, val) \
|
||
|
gpio_set_direction(sda, val)
|
||
|
|
||
|
#define IIC_SDA_SET_PU(sda, on) \
|
||
|
gpio_set_pull_up(sda, on)
|
||
|
|
||
|
#define IIC_SDA_SET_PD(sda, on) \
|
||
|
gpio_set_pull_down(sda, on)
|
||
|
|
||
|
#define IIC_SDA_SET_DIE(sda, on) \
|
||
|
gpio_set_die(sda, on)
|
||
|
|
||
|
#define IIC_SDA_H(sda) \
|
||
|
gpio_direction_output(sda, 1)
|
||
|
|
||
|
#define IIC_SDA_L(sda) \
|
||
|
gpio_direction_output(sda, 0)
|
||
|
|
||
|
#define IIC_SDA_READ(sda) \
|
||
|
gpio_read(sda)
|
||
|
|
||
|
#define iic_get_id(iic) (iic)
|
||
|
|
||
|
static inline u32 iic_get_scl(soft_iic_dev iic)
|
||
|
{
|
||
|
u8 id = iic_get_id(iic);
|
||
|
return soft_iic_cfg[id].scl;
|
||
|
}
|
||
|
|
||
|
static inline u32 iic_get_sda(soft_iic_dev iic)
|
||
|
{
|
||
|
u8 id = iic_get_id(iic);
|
||
|
return soft_iic_cfg[id].sda;
|
||
|
}
|
||
|
|
||
|
static inline u32 iic_get_delay(soft_iic_dev iic)
|
||
|
{
|
||
|
u8 id = iic_get_id(iic);
|
||
|
return soft_iic_cfg[id].delay;
|
||
|
}
|
||
|
|
||
|
static inline u32 iic_get_io_pu(soft_iic_dev iic)
|
||
|
{
|
||
|
u8 id = iic_get_id(iic);
|
||
|
return soft_iic_cfg[id].io_pu;
|
||
|
}
|
||
|
|
||
|
|
||
|
int soft_iic_init(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
|
||
|
IIC_SCL_DIR(scl, 0);
|
||
|
IIC_SCL_SET_PD(scl, 0);
|
||
|
IIC_SCL_SET_DIE(scl, 1);
|
||
|
IIC_SCL_L(scl);
|
||
|
IIC_SDA_DIR(sda, 0);
|
||
|
IIC_SDA_SET_PD(sda, 0);
|
||
|
IIC_SDA_SET_DIE(sda, 1);
|
||
|
IIC_SDA_H(sda);
|
||
|
IIC_SCL_H(scl);
|
||
|
if (iic_get_io_pu(iic)) {
|
||
|
IIC_SCL_SET_PU(scl, 1);
|
||
|
IIC_SDA_SET_PU(sda, 1);
|
||
|
} else {
|
||
|
IIC_SCL_SET_PU(scl, 0);
|
||
|
IIC_SDA_SET_PU(sda, 0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void soft_iic_uninit(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
|
||
|
IIC_SCL_DIR(scl, 1);
|
||
|
IIC_SCL_SET_PU(scl, 0);
|
||
|
IIC_SCL_SET_PD(scl, 0);
|
||
|
IIC_SCL_SET_DIE(scl, 0);
|
||
|
IIC_SDA_DIR(sda, 1);
|
||
|
IIC_SDA_SET_PU(sda, 0);
|
||
|
IIC_SDA_SET_PD(sda, 0);
|
||
|
IIC_SDA_SET_DIE(sda, 0);
|
||
|
}
|
||
|
|
||
|
void soft_iic_suspend(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
|
||
|
IIC_SCL_SET_DIE(scl, 0);
|
||
|
IIC_SDA_SET_DIE(sda, 0);
|
||
|
}
|
||
|
|
||
|
void soft_iic_resume(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
|
||
|
IIC_SCL_SET_DIE(scl, 1);
|
||
|
IIC_SDA_SET_DIE(sda, 1);
|
||
|
}
|
||
|
|
||
|
void soft_iic_start(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_H(sda);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t * 2);
|
||
|
|
||
|
IIC_SDA_L(sda);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
|
||
|
void soft_iic_stop(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_L(sda);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t * 2);
|
||
|
|
||
|
IIC_SDA_H(sda);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
|
||
|
static u8 soft_iic_check_ack(soft_iic_dev iic)
|
||
|
{
|
||
|
u8 ack;
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_DIR(sda, 1);
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t);
|
||
|
|
||
|
if (IIC_SDA_READ(sda) == 0) {
|
||
|
ack = 1;
|
||
|
} else {
|
||
|
ack = 0;
|
||
|
}
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
IIC_SDA_DIR(sda, 0);
|
||
|
IIC_SDA_L(sda);
|
||
|
|
||
|
return ack;
|
||
|
}
|
||
|
|
||
|
static void soft_iic_rx_ack(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_L(sda);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t * 2);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
|
||
|
static void soft_iic_rx_nack(soft_iic_dev iic)
|
||
|
{
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_H(sda);
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t * 2);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
|
||
|
u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte)
|
||
|
{
|
||
|
u8 i, ret;
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
for (i = 0; i < 8; i++) { //MSB FIRST
|
||
|
if ((byte << i) & 0x80) {
|
||
|
IIC_SDA_H(sda);
|
||
|
} else {
|
||
|
IIC_SDA_L(sda);
|
||
|
}
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t * 2);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
return soft_iic_check_ack(iic);
|
||
|
}
|
||
|
|
||
|
u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack)
|
||
|
{
|
||
|
u8 byte = 0, i;
|
||
|
u32 scl, sda, dly_t;
|
||
|
|
||
|
scl = iic_get_scl(iic);
|
||
|
sda = iic_get_sda(iic);
|
||
|
dly_t = iic_get_delay(iic);
|
||
|
|
||
|
IIC_SDA_DIR(sda, 1);
|
||
|
|
||
|
for (i = 0; i < 8; i++) {
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_H(scl);
|
||
|
delay(dly_t);
|
||
|
|
||
|
byte = byte << 1;
|
||
|
if (IIC_SDA_READ(sda)) {
|
||
|
byte |= 1;
|
||
|
}
|
||
|
delay(dly_t);
|
||
|
|
||
|
IIC_SCL_L(scl);
|
||
|
delay(dly_t);
|
||
|
}
|
||
|
|
||
|
IIC_SDA_DIR(sda, 0);
|
||
|
if (ack) {
|
||
|
soft_iic_rx_ack(iic);
|
||
|
} else {
|
||
|
soft_iic_rx_nack(iic);
|
||
|
}
|
||
|
|
||
|
return byte;
|
||
|
}
|
||
|
|
||
|
|
||
|
int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
if (!buf || !len) {
|
||
|
return -1;
|
||
|
}
|
||
|
for (i = 0; i < len - 1; i++) {
|
||
|
((u8 *)buf)[i] = soft_iic_rx_byte(iic, 1);
|
||
|
}
|
||
|
((u8 *)buf)[len - 1] = soft_iic_rx_byte(iic, 0);
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len)
|
||
|
{
|
||
|
int i;
|
||
|
u8 ack;
|
||
|
|
||
|
if (!buf || !len) {
|
||
|
return -1;
|
||
|
}
|
||
|
for (i = 0; i < len; i++) {
|
||
|
ack = soft_iic_tx_byte(iic, ((u8 *)buf)[i]);
|
||
|
if (ack == 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return i;
|
||
|
}
|
||
|
|