Skip to content

Commit 06f9155

Browse files
XenuIsWatchingcfriedt
authored andcommitted
drivers: i3c: dw: fix bus free timing for pure bus
For a i3c pure bus, the bus free timing shall be set to tcas which is 38.4ns according to table 49 of the MIPI I3C v1.2 specification. For a i3c mixed bus, the bus free timing shall be set to the scl low time. Based on the i2cs' lvrs, it can determine if any devices only support fast mode and won't do fast mode plus to determine which tLOW setting it should use for bus free. Signed-off-by: Ryan McClelland <[email protected]>
1 parent 65bf8f9 commit 06f9155

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

drivers/i3c/i3c_dw.c

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ LOG_MODULE_REGISTER(i3c_dw, CONFIG_I3C_DW_LOG_LEVEL);
321321
#define I3C_BUS_I2C_FM_TLOW_MIN_NS 1300
322322
#define I3C_BUS_I2C_FMP_TLOW_MIN_NS 500
323323
#define I3C_BUS_THIGH_MAX_NS 41
324+
#define I3C_BUS_TCAS_PS 38400
324325
#define I3C_PERIOD_NS 1000000000ULL
326+
#define I3C_PERIOD_PS I3C_PERIOD_NS * 1000ULL
325327

326328
#define I3C_BUS_MAX_I3C_SCL_RATE 12900000
327329
#define I3C_BUS_TYP_I3C_SCL_RATE 12500000
@@ -1408,13 +1410,33 @@ static int i3c_dw_irq(const struct device *dev)
14081410
return 0;
14091411
}
14101412

1413+
#ifdef CONFIG_I3C_CONTROLLER
1414+
/**
1415+
* @brief Return true if any i2c device only supports fast mode
1416+
*
1417+
* @param dev_list Pointer to device list
1418+
*
1419+
* @retval true if any i2c device only supports fast mode
1420+
* @retval false if all devices support fast mode plus
1421+
*/
1422+
static bool i3c_any_i2c_fast_mode(const struct i3c_dev_list *dev_list)
1423+
{
1424+
for (int i = 0; i < dev_list->num_i2c; i++) {
1425+
if (I3C_LVR_I2C_MODE(dev_list->i2c[i].lvr) == I3C_LVR_I2C_FM_MODE) {
1426+
return true;
1427+
}
1428+
}
1429+
return false;
1430+
}
1431+
#endif
1432+
14111433
static int dw_i3c_init_scl_timing(const struct device *dev, struct i3c_config_controller *ctrl_cfg)
14121434
{
14131435
const struct dw_i3c_config *config = dev->config;
14141436
uint32_t core_rate, scl_timing;
14151437
#ifdef CONFIG_I3C_CONTROLLER
14161438
struct dw_i3c_data *data = dev->data;
1417-
uint32_t hcnt, lcnt;
1439+
uint32_t hcnt, lcnt, fmlcnt, fmplcnt, free_cnt;
14181440
#endif /* CONFIG_I3C_CONTROLLER */
14191441

14201442
if (clock_control_get_rate(config->clock, config->clock_subsys, &core_rate) != 0) {
@@ -1441,9 +1463,6 @@ static int dw_i3c_init_scl_timing(const struct device *dev, struct i3c_config_co
14411463
scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
14421464
sys_write32(scl_timing, config->regs + SCL_I3C_OD_TIMING);
14431465

1444-
/* Set bus free timing to match tlow setting for OD clk config. */
1445-
sys_write32(BUS_I3C_MST_FREE(lcnt), config->regs + BUS_FREE_TIMING);
1446-
14471466
/* I3C_PP */
14481467
hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS * (uint64_t)core_rate, I3C_PERIOD_NS) - 1;
14491468
hcnt = CLAMP(hcnt, SCL_I3C_TIMING_CNT_MIN, SCL_I3C_TIMING_CNT_MAX);
@@ -1466,21 +1485,35 @@ static int dw_i3c_init_scl_timing(const struct device *dev, struct i3c_config_co
14661485
sys_write32(scl_timing, config->regs + SCL_EXT_LCNT_TIMING);
14671486

14681487
/* I2C FM+ */
1469-
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS);
1470-
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
1471-
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | SCL_I2C_FMP_TIMING_LCNT(lcnt);
1488+
fmplcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS);
1489+
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - fmplcnt;
1490+
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | SCL_I2C_FMP_TIMING_LCNT(fmplcnt);
14721491
sys_write32(scl_timing, config->regs + SCL_I2C_FMP_TIMING);
14731492

14741493
/* I2C FM */
1475-
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS);
1476-
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
1477-
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | SCL_I2C_FM_TIMING_LCNT(lcnt);
1494+
fmlcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS);
1495+
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - fmlcnt;
1496+
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | SCL_I2C_FM_TIMING_LCNT(fmlcnt);
14781497
sys_write32(scl_timing, config->regs + SCL_I2C_FM_TIMING);
14791498

14801499
if (data->mode != I3C_BUS_MODE_PURE) {
1481-
sys_write32(BUS_I3C_MST_FREE(lcnt), config->regs + BUS_FREE_TIMING);
1500+
/*
1501+
* Mixed bus: Set bus free timing to match tLOW of I2C timing. If any i2c devices
1502+
* only support fast mode, then it to the tLOW of that, otherwise set to the tLOW
1503+
* of fast mode plus.
1504+
*/
1505+
sys_write32(BUS_I3C_MST_FREE(i3c_any_i2c_fast_mode(&config->common.dev_list)
1506+
? fmlcnt
1507+
: fmplcnt),
1508+
config->regs + BUS_FREE_TIMING);
14821509
sys_write32(sys_read32(config->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT,
14831510
config->regs + DEVICE_CTRL);
1511+
} else {
1512+
/* Pure bus: Set bus free timing to t_cas of 38.4ns */
1513+
free_cnt = DIV_ROUND_UP(I3C_BUS_TCAS_PS * (uint64_t)core_rate, I3C_PERIOD_PS);
1514+
sys_write32(BUS_I3C_MST_FREE(free_cnt), config->regs + BUS_FREE_TIMING);
1515+
sys_write32(sys_read32(config->regs + DEVICE_CTRL) & ~DEV_CTRL_I2C_SLAVE_PRESENT,
1516+
config->regs + DEVICE_CTRL);
14841517
}
14851518
#endif /* CONFIG_I3C_CONTROLLER */
14861519
#ifdef CONFIG_I3C_TARGET

0 commit comments

Comments
 (0)