i3c: master: dw-i3c-master: Fix OD_TIMING for spike filter
Fix the I3C device with spike filter unable to detect issue by setting tHIGH_INIT to 200ns for first broadcast address. This is according to MIPI SPEC 1.1.1 for first broadcast address which is already part of linux upstreamed patch. Signed-off-by: Dinesh Maniyam <dinesh.maniyam@altera.com>
This commit is contained in:
committed by
Heiko Schocher
parent
b5cf7cd174
commit
82cc368cd2
@@ -334,6 +334,14 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
|
||||
if (hcnt < SCL_I3C_TIMING_CNT_MIN)
|
||||
hcnt = SCL_I3C_TIMING_CNT_MIN;
|
||||
|
||||
/* set back to THIGH_MAX_NS, after disable spike filter */
|
||||
if (!master->first_broadcast) {
|
||||
lcnt = SCL_I3C_TIMING_LCNT(readl(master->regs + SCL_I3C_OD_TIMING));
|
||||
scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | lcnt;
|
||||
writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt;
|
||||
if (lcnt < SCL_I3C_TIMING_CNT_MIN)
|
||||
lcnt = SCL_I3C_TIMING_CNT_MIN;
|
||||
@@ -351,6 +359,9 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
|
||||
lcnt = max_t(u8,
|
||||
DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period), lcnt);
|
||||
|
||||
/* first broadcast thigh to 200ns, to disable spike filter */
|
||||
hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_INIT_OD_MIN_NS, core_period);
|
||||
|
||||
scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
|
||||
writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
|
||||
|
||||
@@ -406,6 +417,9 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
|
||||
u32 thld_ctrl;
|
||||
int ret;
|
||||
|
||||
/* first broadcast to disable spike filter */
|
||||
master->first_broadcast = true;
|
||||
|
||||
switch (bus->mode) {
|
||||
case I3C_BUS_MODE_MIXED_FAST:
|
||||
case I3C_BUS_MODE_MIXED_LIMITED:
|
||||
@@ -485,6 +499,15 @@ static void dw_i3c_master_irq_handler(struct dw_i3c_master *master)
|
||||
if (status & INTR_TRANSFER_ERR_STAT)
|
||||
writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS);
|
||||
|
||||
/* set back to THIGH_MAX_NS, after disable spike filter */
|
||||
if (master->first_broadcast) {
|
||||
master->first_broadcast = false;
|
||||
int ret = dw_i3c_clk_cfg(master);
|
||||
|
||||
if (ret)
|
||||
pr_err("Failed to set clk cfg\n");
|
||||
}
|
||||
|
||||
spin_unlock(&master->xferqueue.lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ struct dw_i3c_master {
|
||||
char version[5];
|
||||
char type[5];
|
||||
u8 addrs[MAX_DEVS];
|
||||
bool first_broadcast;
|
||||
};
|
||||
|
||||
struct dw_i3c_i2c_dev_data {
|
||||
|
||||
@@ -278,6 +278,7 @@ struct i3c_device {
|
||||
#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000
|
||||
#define I3C_BUS_I2C_FM_SCL_RATE 400000
|
||||
#define I3C_BUS_TLOW_OD_MIN_NS 200
|
||||
#define I3C_BUS_THIGH_INIT_OD_MIN_NS 200
|
||||
|
||||
/**
|
||||
* enum i3c_bus_mode - I3C bus mode
|
||||
|
||||
Reference in New Issue
Block a user