doubao_chat/cpu/wl82/iic.c

352 lines
7.8 KiB
C

#include "asm/includes.h"
#include "device/gpio.h"
#include "device/iic.h"
#include "system/includes.h"
static u8 hw_iic_busy;
static const struct iic_outport *get_hw_iic_outport(const struct hardware_iic *iic)
{
int i;
for (i = 0; i < IIC_OUTPORT_NUM; i++) {
if (iic->clk_pin == iic->outport_map[i].clk_pin &&
iic->dat_pin == iic->outport_map[i].dat_pin) {
return &iic->outport_map[i];
}
}
return NULL;
}
static void iic_set_baudrate(const struct hardware_iic *iic, int baudrate)
{
iic->reg->BAUD = baudrate;
}
static void iic_start(const struct hardware_iic *iic)
{
iic_set_output(iic);
iic_add_start_bit(iic);
}
static void iic_stop(const struct hardware_iic *iic)
{
iic_add_end_bit(iic);
__asm_csync();
asm("nop");
iic_cfg_done(iic);
#if 0
u32 time = jiffies + msecs_to_jiffies(200);
while (time_before(jiffies, time)) {
if (iic_epnd(iic)) {
iic_clr_epnd(iic);
return;
}
}
log_e("iic_wait_stop_timeout\r\n");
#else
while (!iic_epnd(iic));
#endif
iic_clr_epnd(iic);
}
static int iic_wait_end(const struct hardware_iic *iic)
{
u32 time = jiffies + msecs_to_jiffies(200);
while (time_before(jiffies, time)) {
/* while (1) { */
if (iic_pnd(iic)) {
iic_clr_pnd(iic);
return 0;
}
}
log_e("iic_wait_end_timeout\r\n");
return -EFAULT;
}
static int iic_tx(const struct hardware_iic *iic, u8 dat)
{
iic_set_output(iic);
iic->reg->BUF = dat;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
return iic_wait_end(iic);
}
static int iic_tx_with_start_bit(const struct hardware_iic *iic, u8 dat)
{
iic_set_output(iic);
iic_add_start_bit(iic);
iic->reg->BUF = dat;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
return iic_wait_end(iic);
}
static int iic_tx_with_stop_bit(const struct hardware_iic *iic, u8 dat)
{
int err;
iic_set_output(iic);
iic->reg->BUF = dat;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
err = iic_wait_end(iic);
iic_stop(iic);
return err;
}
static u8 iic_rx(const struct hardware_iic *iic, int *err)
{
u8 res;
iic_set_input(iic);
iic_set_ack(iic);
iic->reg->BUF = 0xff;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
*err = iic_wait_end(iic);
res = iic->reg->BUF;
return res;
}
static u8 iic_rx_with_start_bit(const struct hardware_iic *iic, int *err)
{
u8 res;
iic_set_input(iic);
iic_add_start_bit(iic);
iic_set_ack(iic);
iic->reg->BUF = 0xff;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
*err = iic_wait_end(iic);
return iic->reg->BUF;
}
static u8 iic_rx_with_stop_bit(const struct hardware_iic *iic, int *err)
{
u8 res;
iic_set_input(iic);
iic_set_unack(iic);
iic->reg->BUF = 0xff;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
*err = iic_wait_end(iic);
res = iic->reg->BUF;
iic_stop(iic);
return res;
}
static u8 iic_rx_with_no_ack(const struct hardware_iic *iic, int *err)
{
iic_set_input(iic);
iic_set_unack(iic);
iic->reg->BUF = 0xff;
__asm_csync();
asm("nop");
iic_cfg_done(iic);
*err = iic_wait_end(iic);
return iic->reg->BUF;
}
static int iic_open(struct iic_device *iic)
{
int value;
const struct iic_outport *port;
const struct hardware_iic *hw = (const struct hardware_iic *)iic->hw;
port = get_hw_iic_outport(hw);
if (!port) {
return -EINVAL;
}
value = readl(hw->occupy_reg);
value &= hw->occupy_io_mask;
value |= port->value;
writel(hw->occupy_reg, value);
if (port->clk_pin == IO_PORT_USB_DPA && port->dat_pin == IO_PORT_USB_DMA) {
usb_iomode(0, 1);
}
gpio_direction_output(port->clk_pin, 1);
gpio_direction_output(port->dat_pin, 1);
gpio_set_pull_up(port->clk_pin, 1);
gpio_set_pull_up(port->dat_pin, 1);
gpio_set_pull_down(port->clk_pin, 0);
gpio_set_pull_down(port->dat_pin, 0);
gpio_set_hd(port->clk_pin, 0);
gpio_set_hd(port->dat_pin, 0);
gpio_set_die(port->clk_pin, 1);
gpio_set_die(port->dat_pin, 1);
hw->reg->BAUD = hw->baudrate;
hw->reg->CON0 = BIT(0) | BIT(9);
hw->reg->CON0 |= BIT(14) | BIT(12);
return 0;
}
static int iic_read(struct iic_device *iic, void *buf, int len)
{
int err = 0;
u8 *p = (u8 *)buf;
u32 rlen = 0;
if (len == 0) {
return 0;
}
p[rlen++] = iic_rx_with_start_bit((const struct hardware_iic *)iic->hw, &err);
while (rlen < (len - 1)) {
p[rlen++] = iic_rx((const struct hardware_iic *)iic->hw, &err);
}
if (len - rlen == 1) {
p[rlen++] = iic_rx_with_stop_bit((const struct hardware_iic *)iic->hw, &err);
} else {
iic_stop((const struct hardware_iic *)iic->hw);
}
return rlen;
}
static int iic_write(struct iic_device *iic, void *buf, int len)
{
u8 *p = (u8 *)buf;
u32 wlen = 0;
if (len == 0) {
return 0;
}
iic_tx_with_start_bit((const struct hardware_iic *)iic->hw, p[wlen++]);
while (wlen < (len - 1)) {
iic_tx((const struct hardware_iic *)iic->hw, p[wlen++]);
}
if (len - wlen == 1) {
iic_tx_with_stop_bit((const struct hardware_iic *)iic->hw, p[wlen++]);
} else {
iic_stop((const struct hardware_iic *)iic->hw);
}
return wlen;
}
static int iic_ioctl(struct iic_device *iic, int cmd, int arg)
{
int err = 0;
struct hardware_iic *hw_iic;
u8 tmp = 0;
switch (cmd) {
case IOCTL_SET_SPEED:
iic_set_baudrate(iic->hw, arg);
break;
case IIC_IOCTL_TX:
err = iic_tx(iic->hw, arg);
break;
case IIC_IOCTL_TX_WITH_START_BIT:
err = iic_tx_with_start_bit(iic->hw, arg);
break;
case IIC_IOCTL_TX_WITH_STOP_BIT:
err = iic_tx_with_stop_bit(iic->hw, arg);
break;
case IIC_IOCTL_TX_STOP_BIT:
iic_stop(iic->hw);
break;
case IIC_IOCTL_TX_START_BIT:
iic_start(iic->hw);
break;
case IIC_IOCTL_RX:
tmp = iic_rx(iic->hw, &err);
if (arg) {
*((u8 *)arg) = tmp;
}
break;
case IIC_IOCTL_RX_WITH_START_BIT:
tmp = iic_rx_with_start_bit(iic->hw, &err);
if (arg) {
*((u8 *)arg) = tmp;
}
break;
case IIC_IOCTL_RX_WITH_STOP_BIT:
tmp = iic_rx_with_stop_bit(iic->hw, &err);
if (arg) {
*((u8 *)arg) = tmp;
}
break;
case IIC_IOCTL_RX_WITH_NOACK:
tmp = iic_rx_with_no_ack(iic->hw, &err);
if (arg) {
*((u8 *)arg) = tmp;
}
break;
case IIC_IOCTL_RX_WITH_ACK:
tmp = iic_rx(iic->hw, &err);
if (arg) {
*((u8 *)arg) = tmp;
}
break;
case IIC_IOCTL_START:
hw_iic_busy = 1;
break;
case IIC_IOCTL_STOP:
hw_iic_busy = 0;
break;
default:
return -EINVAL;
}
return err;
}
static int iic_close(struct iic_device *iic)
{
const struct hardware_iic *hw = (const struct hardware_iic *)iic->hw;
const struct iic_outport *port = get_hw_iic_outport(hw);
hw->reg->CON0 = 0;
gpio_direction_input(port->clk_pin);
gpio_set_pull_down(port->clk_pin, 0);
gpio_set_pull_up(port->clk_pin, 0);
gpio_set_die(port->clk_pin, 0);
gpio_direction_input(port->dat_pin);
gpio_set_pull_down(port->dat_pin, 0);
gpio_set_pull_up(port->dat_pin, 0);
gpio_set_die(port->dat_pin, 0);
return 0;
}
REGISTER_IIC_DEVICE(hw_iic_ops) = {
.type = IIC_TYPE_HW,
.open = iic_open,
.read = iic_read,
.write = iic_write,
.ioctl = iic_ioctl,
.close = iic_close,
};
static u8 iic_idle_query(void)
{
return !hw_iic_busy;
}
REGISTER_LP_TARGET(iic_lp_target) = {
.name = "iic",
.is_idle = iic_idle_query,
};