KT24-1110_65E-HA-651B/cpu/br25/iic_hw.c

472 lines
12 KiB
C
Raw Permalink Normal View History

2024-11-10 10:44:17 +00:00
#include "asm/iic_hw.h"
#include "system/generic/gpio.h"
#include "system/generic/log.h"
#include "asm/clock.h"
#include "asm/cpu.h"
#include "update.h"
/*
[[ !!! ]]
* cfg_done的硬件IICIIC另作说明
* IIC的START / ACK(NACK)cfg_done前设置
cfg_done单独发送STOP则应在发送或接收字节cfg_done后设置
cfg_done单独发送
*/
struct iic_iomapping {
u8 scl;
u8 sda;
};
static const struct iic_iomapping hwiic_iomap[IIC_HW_NUM][IIC_PORT_GROUP_NUM] = {
{
{IO_PORT_DP, IO_PORT_DM}, //group a
{IO_PORTC_04, IO_PORTC_05}, //group b
{IO_PORTB_06, IO_PORTB_07}, //group c
{IO_PORTA_05, IO_PORTA_06}, //group d
},
};
static JL_IIC_TypeDef *const iic_regs[IIC_HW_NUM] = {
JL_IIC,
};
#define iic_get_id(iic) (iic)
#define iic_info_port(iic) (hw_iic_cfg[iic_get_id(iic)].port - 'A')
#define iic_info_baud(iic) (hw_iic_cfg[iic_get_id(iic)].baudrate)
#define iic_info_hdrive(iic) (hw_iic_cfg[iic_get_id(iic)].hdrive)
#define iic_info_io_filt(iic) (hw_iic_cfg[iic_get_id(iic)].io_filter)
#define iic_info_io_pu(iic) (hw_iic_cfg[iic_get_id(iic)].io_pu)
#define iic_info_role(iic) (hw_iic_cfg[iic_get_id(iic)].role)
static inline u32 iic_get_scl(hw_iic_dev iic)
{
u8 port = iic_info_port(iic);
return hwiic_iomap[iic_get_id(iic)][port].scl;
}
static inline u32 iic_get_sda(hw_iic_dev iic)
{
u8 port = iic_info_port(iic);
return hwiic_iomap[iic_get_id(iic)][port].sda;
}
static int iic_port_init(hw_iic_dev iic)
{
u32 reg;
int ret = 0;
u8 port;
u8 id = iic_get_id(iic);
u32 scl, sda;
port = iic_info_port(iic);
if (port >= IIC_PORT_GROUP_NUM) {
return -EINVAL;
}
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
if (id == 0) {
reg = JL_IOMAP->CON1;
reg &= ~(0x3 << 18);
reg |= (port << 18);
JL_IOMAP->CON1 = reg;
#if 0
if (port == 0) {
//USB_DP, USB_DM init
log_w("warning!!! iic overwrite usb configuration\n");
JL_USB_IO->CON0 |= (BIT(11) | BIT(8)); //IO MODE
/* JL_USB_IO->CON0 &= ~BIT(2); //DP DIR OUT */
/* JL_USB_IO->CON0 &= ~BIT(3); //DM DIR OUT */
/* JL_USB_IO->CON0 |= BIT(0); //DP output 1 */
/* JL_USB_IO->CON0 |= BIT(1); //DM output 1 */
if (iic_info_io_pu(iic)) {
JL_USB_IO->CON0 |= BIT(6); //DP PU
JL_USB_IO->CON0 |= BIT(7); //DM PU
} else {
JL_USB_IO->CON0 &= ~BIT(6); //DP PU
JL_USB_IO->CON0 &= ~BIT(7); //DM PU
}
} else {
//gpio_direction_output(sca, 1);
//gpio_direction_output(sda, 1);
if (iic_info_hdrive(iic)) {
gpio_set_hd(scl, 1);
gpio_set_hd(sda, 1);
} else {
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
}
if (iic_info_io_pu(iic)) {
gpio_set_pull_up(scl, 1);
gpio_set_pull_up(sda, 1);
} else {
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
}
}
#else
if (port == 0) {
usb_iomode(1);
}
if (iic_info_hdrive(iic)) {
gpio_set_hd(scl, 1);
gpio_set_hd(sda, 1);
} else {
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
}
if (iic_info_io_pu(iic)) {
gpio_set_pull_up(scl, 1);
gpio_set_pull_up(sda, 1);
} else {
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
}
#endif
//} else if (fh->id == 1) {
} else {
ret = -EINVAL;
}
return ret;
}
int hw_iic_set_baud(hw_iic_dev iic, u32 baud)
{
//f_iic = f_sys / ((IIC_BAUD + 1) * 2)
//=> IIC_BAUD = f_sys / (2 * f_iic) - 1
u32 sysclk;
u8 id = iic_get_id(iic);
sysclk = clk_get("lsb");
if (sysclk < 2 * baud) {
return -EINVAL;
}
iic_baud_reg(iic_regs[id]) = sysclk / (2 * baud) - 1;
return 0;
}
static void hw_iic_set_die(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
u8 port = iic_info_port(iic);
u32 scl, sda;
if (port >= IIC_PORT_GROUP_NUM) {
return ;
}
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
if (id == 0) {
#if 0
if (port == 0) {
if (en) {
JL_USB_IO->CON0 |= BIT(9); //DP 1.2V digital input en
JL_USB_IO->CON0 |= BIT(10); //DM 1.2V digital input en
} else {
JL_USB_IO->CON0 &= ~BIT(9);
JL_USB_IO->CON0 &= ~BIT(10);
}
} else {
gpio_set_die(scl, en); //!!!must set
gpio_set_die(sda, en); //!!!must set
}
#else
gpio_set_die(scl, en);
gpio_set_die(sda, en);
#endif
} else {
//undefined
}
}
void hw_iic_suspend(hw_iic_dev iic)
{
hw_iic_set_die(iic, 0);
}
void hw_iic_resume(hw_iic_dev iic)
{
hw_iic_set_die(iic, 1);
}
int hw_iic_init(hw_iic_dev iic)
{
int ret;
u8 id = iic_get_id(iic);
if ((ret = iic_port_init(iic))) {
log_e("invalid hardware iic port\n");
return ret;
}
hw_iic_set_die(iic, 1);
if (iic_info_role(iic) == IIC_MASTER) {
iic_role_host(iic_regs[id]);
} else {
iic_role_slave(iic_regs[id]);
iic_si_mode_en(iic_regs[id]);
}
if (iic_info_io_filt(iic)) {
iic_isel_filter(iic_regs[id]);
} else {
iic_isel_direct(iic_regs[id]);
}
if ((ret = hw_iic_set_baud(iic, iic_info_baud(iic)))) {
log_e("iic baudrate is invalid\n");
return ret ;
}
iic_pnd_clr(iic_regs[id]);
iic_end_pnd_clr(iic_regs[id]);
iic_start_pnd_clr(iic_regs[id]);
iic_enable(iic_regs[id]);
#if 0
printf("info->scl = %d\n", iic_get_scl(iic));
printf("info->sda = %d\n", iic_get_sda(iic));
printf("info->baudrate = %d\n", iic_info_baud(iic));
printf("info->hdrive = %d\n", iic_info_hdrive(iic));
printf("info->io_filter = %d\n", iic_info_io_filt(iic));
printf("info->io_pu = %d\n", iic_info_io_pu(iic));
printf("info->role = %d\n", iic_info_role(iic));
printf("IIC_CON0 0x%04x\n", iic_regs[id]->CON0);
printf("IIC_CON1 0x%04x\n", iic_regs[id]->CON1);
printf("IIC_BAUD 0x%02x\n", iic_regs[id]->BAUD);
//printf("IIC_BUF %02x\n", iic_regs[id]->BUF);
printf("IOMC1 0x%08x\n", JL_IOMAP->CON1);
#endif
return 0;
}
void hw_iic_uninit(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
u8 port = iic_info_port(iic);
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
hw_iic_set_die(iic, 0);
if (id == 0) {
#if 0
if (port == 0) {
//JL_USB_IO->CON0 |= BIT(2); //DP DIR IN
//JL_USB_IO->CON0 |= BIT(3); //DM DIR IN
JL_USB_IO->CON0 &= ~(BIT(11) | BIT(8)); //disable IO_MODE
JL_USB_IO->CON0 &= ~BIT(6); //DP PU
JL_USB_IO->CON0 &= ~BIT(7); //DM PU
} else {
/* gpio_set_direction(scl, 1); */
/* gpio_set_direction(sda, 1); */
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
}
#else
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
if (port == 0) {
usb_iomode(0);
}
#endif
}
iic_disable(iic_regs[id]);
}
void hw_iic_start(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_preset_restart(iic_regs[id]);
//don't add iic_cfg_done() here, it must be used with send byte
}
void hw_iic_stop(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_preset_end(iic_regs[id]);
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte)
{
u8 id = iic_get_id(iic);
iic_dir_out(iic_regs[id]);
iic_buf_reg(iic_regs[id]) = byte;
iic_cfg_done(iic_regs[id]);
/* putchar('a'); */
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
/* putchar('b'); */
return iic_send_is_ack(iic_regs[id]);
}
u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack)
{
u8 id = iic_get_id(iic);
iic_dir_in(iic_regs[id]);
if (ack) {
iic_recv_ack(iic_regs[id]);
} else {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
/* putchar('c'); */
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
/* putchar('d'); */
return iic_buf_reg(iic_regs[id]);
}
int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len)
{
u8 id = iic_get_id(iic);
int i;
if (!buf || !len) {
return -1;
}
iic_dir_in(iic_regs[id]);
iic_recv_ack(iic_regs[id]);
for (i = 0; i < len; i++) {
if (i == len - 1) {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
((u8 *)buf)[i] = iic_buf_reg(iic_regs[id]);
}
return len;
}
int hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len)
{
u8 id = iic_get_id(iic);
int i = 0;
if (!buf || !len) {
return -1;
}
iic_dir_out(iic_regs[id]);
for (i = 0; i < len; i++) {
iic_buf_reg(iic_regs[id]) = ((u8 *)buf)[i];
iic_cfg_done(iic_regs[id]);
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
if (!iic_send_is_ack(iic_regs[id])) {
break;
}
}
return i;
}
void hw_iic_set_ie(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
if (en) {
iic_set_ie(iic_regs[id]);
} else {
iic_clr_ie(iic_regs[id]);
}
}
u8 hw_iic_get_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return !!iic_pnd(iic_regs[id]);
}
void hw_iic_clr_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_pnd_clr(iic_regs[id]);
}
void hw_iic_set_end_ie(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
if (en) {
iic_set_end_ie(iic_regs[id]);
} else {
iic_clr_end_ie(iic_regs[id]);
}
}
u8 hw_iic_get_end_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return !!iic_end_pnd(iic_regs[id]);
}
void hw_iic_clr_end_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_end_pnd_clr(iic_regs[id]);
}
void hw_iic_slave_set_addr(hw_iic_dev iic, u8 addr, u8 addr_ack)
{
u8 id = iic_get_id(iic);
iic_baud_reg(iic_regs[id]) = (addr & 0xfe) | !!addr_ack;
}
void hw_iic_slave_rx_prepare(hw_iic_dev iic, u8 ack)
{
u8 id = iic_get_id(iic);
iic_dir_in(iic_regs[id]);
if (ack) {
iic_recv_ack(iic_regs[id]);
} else {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_slave_rx_byte(hw_iic_dev iic, bool *is_start_addr)
{
u8 id = iic_get_id(iic);
if (iic_start_pnd(iic_regs[id])) {
iic_start_pnd_clr(iic_regs[id]);
is_start_addr ? (*is_start_addr = 1) : 0;
} else {
is_start_addr ? (*is_start_addr = 0) : 0;
}
return iic_buf_reg(iic_regs[id]);
}
void hw_iic_slave_tx_byte(hw_iic_dev iic, u8 byte)
{
u8 id = iic_get_id(iic);
iic_dir_out(iic_regs[id]);
iic_buf_reg(iic_regs[id]) = byte;
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_slave_tx_check_ack(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return iic_send_is_ack(iic_regs[id]);
}
void iic_disable_for_ota()
{
JL_IIC->CON0 = 0;
}
REGISTER_UPDATE_TARGET(iic_update_target) = {
.name = "iic",
.driver_close = iic_disable_for_ota,
};