343 lines
9.4 KiB
C
343 lines
9.4 KiB
C
/**
|
|
* @file sdrv_i2c_reg.c
|
|
* @sdrv i2c register api source file.
|
|
* relative basic register operation.
|
|
* only called by Semidrive i2c driver framework internal.
|
|
*
|
|
* @Copyright (c) 2022 Semidrive Semiconductor.
|
|
* @All rights reserved.
|
|
*
|
|
**/
|
|
|
|
#include <reg.h>
|
|
#include <udelay/udelay.h>
|
|
#include "sdrv_i2c_reg.h"
|
|
|
|
uint8_t sdrv_i2c_recv_data(paddr_t base)
|
|
{
|
|
return readl(base + I2C_RXFIFO);
|
|
}
|
|
|
|
void sdrv_i2c_send_data(paddr_t base, uint8_t data)
|
|
{
|
|
writel(data, base + I2C_TXFIFO);
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_psr_stat(paddr_t base, uint32_t psr_reg)
|
|
{
|
|
return readl(base + psr_reg);
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_wspace(paddr_t base)
|
|
{
|
|
return (readl(base + I2C_FSR) >> 8) & 0xff;
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_rspace(paddr_t base)
|
|
{
|
|
return readl(base + I2C_FSR) & 0xff;
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_fifo_empty_stat(paddr_t base)
|
|
{
|
|
return readl(base + I2C_FSR) & (0x1 << 24);
|
|
}
|
|
|
|
void sdrv_i2c_set_watermark(paddr_t base, uint32_t wml)
|
|
{
|
|
writel(wml, base + I2C_FCR);
|
|
}
|
|
|
|
void sdrv_i2c_clear_fifo(paddr_t base)
|
|
{
|
|
uint32_t val;
|
|
val = readl(base + I2C_FCR);
|
|
writel(val | 0x1 << 16, base + I2C_FCR);
|
|
}
|
|
|
|
void sdrv_i2c_set_cmdcsr(paddr_t base, uint32_t cmdcsr_reg, uint32_t val)
|
|
{
|
|
writel(val, base + cmdcsr_reg);
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_cmdcsr(paddr_t base, uint32_t cmdcsr_reg)
|
|
{
|
|
return readl(base + cmdcsr_reg);
|
|
}
|
|
|
|
void sdrv_i2c_clear_int(paddr_t base)
|
|
{
|
|
writel(~0x0, base + I2C_INTR0);
|
|
writel(~0x0, base + I2C_INTR1);
|
|
writel(~0x0, base + I2C_INTR2);
|
|
writel(~0x0, base + I2C_INTR3);
|
|
}
|
|
|
|
void sdrv_i2c_clear_int_bits(paddr_t base, uint32_t intr_reg, uint32_t bits)
|
|
{
|
|
writel(bits, base + intr_reg);
|
|
}
|
|
|
|
void sdrv_i2c_disable_int(paddr_t base)
|
|
{
|
|
sdrv_i2c_unmask_int(base, I2C_INTEN0, 0x0);
|
|
sdrv_i2c_unmask_int(base, I2C_INTEN1, 0x0);
|
|
sdrv_i2c_unmask_int(base, I2C_INTEN2, 0x0);
|
|
sdrv_i2c_unmask_int(base, I2C_INTEN3, 0x0);
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_int_stat(paddr_t base, uint32_t intr_reg)
|
|
{
|
|
return readl(base + intr_reg);
|
|
}
|
|
|
|
void sdrv_i2c_unmask_int(paddr_t base, uint32_t inten_reg, uint32_t int_flag)
|
|
{
|
|
writel(int_flag, base + inten_reg);
|
|
}
|
|
|
|
void sdrv_i2c_set_IO(paddr_t base, uint32_t io_reg, uint32_t val)
|
|
{
|
|
writel(val, base + io_reg);
|
|
}
|
|
|
|
void sdrv_i2c_set_speed(paddr_t base, uint32_t clk, uint32_t speed_mode)
|
|
{
|
|
uint32_t val;
|
|
uint32_t div = clk / 1000 / 108000;
|
|
val = readl(base + I2C_PCR0);
|
|
writel((val & ~0xff) | (speed_mode | div << 3), base + I2C_PCR0);
|
|
}
|
|
|
|
void sdrv_i2c_set_nack(paddr_t base)
|
|
{
|
|
uint32_t val;
|
|
val = readl(base + I2C_PCR0);
|
|
writel(val | 0x100, base + I2C_PCR0);
|
|
}
|
|
|
|
void sdrv_i2c_set_slvaddr(paddr_t base, uint8_t addr)
|
|
{
|
|
writel(addr, base + I2C_PCR1);
|
|
}
|
|
|
|
void sdrv_i2c_set_opmode(paddr_t base, uint32_t opmode)
|
|
{
|
|
uint32_t val;
|
|
val = readl(base + I2C_MCR0);
|
|
writel((val & ~0xf0) | (opmode << 4), base + I2C_MCR0);
|
|
}
|
|
|
|
uint32_t sdrv_i2c_get_parity_stat(paddr_t base)
|
|
{
|
|
return readl(base + I2C_PARITY_ERR_INT_STAT) & 0x1;
|
|
}
|
|
|
|
void sdrv_i2c_set_parity_stat(paddr_t base, bool enable)
|
|
{
|
|
uint32_t val = 0x0;
|
|
|
|
if (enable)
|
|
val = 0x1;
|
|
|
|
writel(val, base + I2C_PARITY_ERR_INT_STAT_EN);
|
|
}
|
|
|
|
void sdrv_i2c_set_parity_sig(paddr_t base, bool enable)
|
|
{
|
|
uint32_t val = 0x0;
|
|
|
|
if (enable)
|
|
val = 0x1;
|
|
|
|
writel(val, base + I2C_PARITY_ERR_INT_SIG_EN);
|
|
}
|
|
|
|
void sdrv_i2c_set_timing(paddr_t base, uint32_t clk, int idx)
|
|
{
|
|
uint32_t pcr_reg = 0;
|
|
uint32_t timscll = 0, timtasclh = 0, timtascll = 0, timtasdal = 0, timdvdat = 0;
|
|
uint32_t timscll_h = 0, timtasclh_h = 0, timtascll_h = 0, timtasdal_h = 0, timdvdat_h = 0;
|
|
uint32_t timunit = 0, timmext = 0, timsext = 0, timstuck = 0;
|
|
uint32_t timsdarxhld = 0, timdatspl = 0, timbuf = 0, timidle = 0;
|
|
uint32_t clk_khz = clk / 1000;
|
|
uint32_t divs = clk_khz / 108000;
|
|
|
|
if (divs)
|
|
clk_khz /= (divs + 1);
|
|
|
|
if (idx == 0) {
|
|
timscll = CAL_SCLL(5000, clk_khz);
|
|
timtasclh = CAL_TA(150, clk_khz);
|
|
timtascll = CAL_TA(150, clk_khz);
|
|
timtasdal = CAL_TA(150, clk_khz);
|
|
timdvdat = CAL_DVDAT(3400, clk_khz);
|
|
timunit = CAL_UNIT(6);
|
|
timmext = CAL_MEXT(0, clk_khz);
|
|
timsext = CAL_SEXT(0, clk_khz);
|
|
timstuck = CAL_STUCK(5000, clk_khz);
|
|
timsdarxhld = CAL_SDARXHLD(300, clk_khz);
|
|
timdatspl = CAL_DATSPL(2);
|
|
timbuf = CAL_BUF(5000, clk_khz);
|
|
timidle = CAL_IDLE(0, clk_khz);
|
|
}
|
|
else if (idx == 1) {
|
|
timscll = CAL_SCLL(1300, clk_khz);
|
|
timtasclh = CAL_TA(150, clk_khz);
|
|
timtascll = CAL_TA(150, clk_khz);
|
|
timtasdal = CAL_TA(150, clk_khz);
|
|
timdvdat = CAL_DVDAT(900, clk_khz);
|
|
timunit = CAL_UNIT(6);
|
|
timmext = CAL_MEXT(0, clk_khz);
|
|
timsext = CAL_SEXT(0, clk_khz);
|
|
timstuck = CAL_STUCK(5000, clk_khz);
|
|
timsdarxhld = CAL_SDARXHLD(300, clk_khz);
|
|
timdatspl = CAL_DATSPL(2);
|
|
timbuf = CAL_BUF(5000, clk_khz);
|
|
timidle = CAL_IDLE(0, clk_khz);
|
|
}
|
|
else if (idx == 2) {
|
|
timscll = CAL_SCLL(500, clk_khz);
|
|
timtasclh = CAL_TA(60, clk_khz);
|
|
timtascll = CAL_TA(60, clk_khz);
|
|
timtasdal = CAL_TA(60, clk_khz);
|
|
timdvdat = CAL_DVDAT(450, clk_khz);
|
|
timunit = CAL_UNIT(6);
|
|
timmext = CAL_MEXT(0, clk_khz);
|
|
timsext = CAL_SEXT(0, clk_khz);
|
|
timstuck = CAL_STUCK(5000, clk_khz);
|
|
timsdarxhld = CAL_SDARXHLD(120, clk_khz);
|
|
timdatspl = CAL_DATSPL(2);
|
|
timbuf = CAL_BUF(5000, clk_khz);
|
|
timidle = CAL_IDLE(0, clk_khz);
|
|
}
|
|
else if (idx == 3) {
|
|
timscll = CAL_SCLL(1300, clk_khz);
|
|
timtasclh = CAL_TA(150, clk_khz);
|
|
timtascll = CAL_TA(150, clk_khz);
|
|
timtasdal = CAL_TA(150, clk_khz);
|
|
timdvdat = CAL_DVDAT(900, clk_khz);
|
|
timscll_h = CAL_SCLL(160, clk_khz);
|
|
timtasclh_h = CAL_TA(30, clk_khz);
|
|
timtascll_h = CAL_TA(30, clk_khz);
|
|
timtasdal_h = CAL_TA(30, clk_khz);
|
|
timdvdat_h = CAL_DVDAT(40, clk_khz);
|
|
timunit = CAL_UNIT(6);
|
|
timmext = CAL_MEXT(0, clk_khz);
|
|
timsext = CAL_SEXT(0, clk_khz);
|
|
timstuck = CAL_STUCK(5000, clk_khz);
|
|
timsdarxhld = CAL_SDARXHLD(60, clk_khz);
|
|
timdatspl = CAL_DATSPL(2);
|
|
timbuf = CAL_BUF(5000, clk_khz);
|
|
timidle = CAL_IDLE(0, clk_khz);
|
|
}
|
|
else if (idx == 4) {
|
|
timscll = CAL_SCLL(125, clk_khz);
|
|
timtasclh = CAL_TA(25, clk_khz);
|
|
timtascll = CAL_TA(25, clk_khz);
|
|
timtasdal = CAL_TA(25, clk_khz);
|
|
timdvdat = CAL_DVDAT(20, clk_khz);
|
|
timunit = CAL_UNIT(6);
|
|
timmext = CAL_MEXT(0, clk_khz);
|
|
timsext = CAL_SEXT(0, clk_khz);
|
|
timstuck = CAL_STUCK(5000, clk_khz);
|
|
timsdarxhld = CAL_SDARXHLD(20, clk_khz);
|
|
timdatspl = CAL_DATSPL(0);
|
|
timbuf = CAL_BUF(5000, clk_khz);
|
|
timidle = CAL_IDLE(0, clk_khz);
|
|
}
|
|
|
|
pcr_reg = timscll | (timtasclh << 12) | (timtascll << 16) |
|
|
(timtasdal << 20) | (timdvdat << 24);
|
|
writel(pcr_reg, base + I2C_PCR2);
|
|
|
|
pcr_reg = timscll_h | (timtasclh_h << 12) | (timtascll_h << 16) |
|
|
(timtasdal_h << 20) | (timdvdat_h << 24);
|
|
writel(pcr_reg, base + I2C_PCR3);
|
|
|
|
pcr_reg = timunit | (timmext << 3) | (timsext << 9) | (timstuck << 16);
|
|
writel(pcr_reg, base + I2C_PCR4);
|
|
|
|
pcr_reg = timsdarxhld | (timdatspl << 6) | (timbuf << 18) | (timidle << 21);
|
|
writel(pcr_reg, base + I2C_PCR5);
|
|
}
|
|
|
|
void sdrv_i2c_disable(paddr_t base)
|
|
{
|
|
uint32_t val;
|
|
val = readl(base + I2C_MCR0);
|
|
writel(val & ~0x1, base + I2C_MCR0);
|
|
}
|
|
|
|
void sdrv_i2c_enable(paddr_t base)
|
|
{
|
|
uint32_t val;
|
|
val = readl(base + I2C_MCR0);
|
|
writel(val | 0x1, base + I2C_MCR0);
|
|
}
|
|
|
|
int sdrv_i2c_reset(paddr_t base)
|
|
{
|
|
uint32_t val;
|
|
uint32_t timeout = 100;
|
|
sdrv_i2c_disable(base);
|
|
val = readl(base + I2C_MCR0);
|
|
writel(val | 0x2, base + I2C_MCR0);
|
|
|
|
do {
|
|
if (!(readl(base + I2C_MCR0) & 0x2)) {
|
|
sdrv_i2c_enable(base);
|
|
return 0;
|
|
}
|
|
|
|
udelay(1);
|
|
} while (timeout--);
|
|
|
|
return -1;
|
|
}
|
|
|
|
void sdrv_i2c_dump_reg(paddr_t base, uint32_t *reg_val)
|
|
{
|
|
reg_val[0] = readl(base + I2C_MCR0);
|
|
reg_val[1] = readl(base + I2C_INTR0);
|
|
reg_val[2] = readl(base + I2C_INTR1);
|
|
reg_val[3] = readl(base + I2C_INTR2);
|
|
reg_val[4] = readl(base + I2C_INTR3);
|
|
reg_val[5] = readl(base + I2C_INTEN0);
|
|
reg_val[6] = readl(base + I2C_INTEN1);
|
|
reg_val[7] = readl(base + I2C_INTEN2);
|
|
reg_val[8] = readl(base + I2C_INTEN3);
|
|
reg_val[9] = readl(base + I2C_CMDCSR0);
|
|
reg_val[10] = readl(base + I2C_CMDCSR1);
|
|
reg_val[11] = readl(base + I2C_CMDCSR2);
|
|
reg_val[12] = readl(base + I2C_CMDCSR3);
|
|
reg_val[13] = readl(base + I2C_FCR);
|
|
reg_val[14] = readl(base + I2C_FSR);
|
|
reg_val[15] = readl(base + I2C_DMACR);
|
|
reg_val[16] = readl(base + I2C_DMASR);
|
|
reg_val[17] = readl(base + I2C_PCR0);
|
|
reg_val[18] = readl(base + I2C_PCR1);
|
|
reg_val[19] = readl(base + I2C_PCR2);
|
|
reg_val[20] = readl(base + I2C_PCR3);
|
|
reg_val[21] = readl(base + I2C_PCR4);
|
|
reg_val[22] = readl(base + I2C_PCR5);
|
|
reg_val[23] = readl(base + I2C_PCR6);
|
|
reg_val[24] = readl(base + I2C_PCR7);
|
|
reg_val[25] = readl(base + I2C_PCR8);
|
|
reg_val[26] = readl(base + I2C_PCR9);
|
|
reg_val[27] = readl(base + I2C_PCR10);
|
|
reg_val[28] = readl(base + I2C_PCR11);
|
|
reg_val[29] = readl(base + I2C_PSR0);
|
|
}
|
|
|
|
void sdrv_i2c_write_reg(paddr_t base, uint32_t reg, uint32_t val)
|
|
{
|
|
writel(val, base + reg);
|
|
}
|
|
|
|
void sdrv_i2c_read_reg(paddr_t base, uint32_t reg, uint32_t *val)
|
|
{
|
|
*val = readl(base + reg);
|
|
}
|
|
|