KT24-1110_65E-HA-651B/cpu/br25/iic_hw.c
2024-11-10 18:44:17 +08:00

472 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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的硬件IIC另一种硬件IIC另作说明
* 硬件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,
};