Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 1d08326

Browse files
billy-tsaialexandrebelloni
authored andcommitted
i3c: dw: Add hot-join support.
Add hot-join support for dw i3c master controller. By default, the hot-join acknowledgment is disabled, and the hardware will automatically send the DISEC CCC when it receives the hot-join request. Users can use the sys entry to enable it. Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com> Link: https://lore.kernel.org/r/20240429073624.256830-1-billy_tsai@aspeedtech.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 29391d9 commit 1d08326

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

drivers/i3c/master/dw-i3c-master.c

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,23 @@ static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev)
11361136
data->ibi_pool = NULL;
11371137
}
11381138

1139+
static void dw_i3c_master_enable_sir_signal(struct dw_i3c_master *master, bool enable)
1140+
{
1141+
u32 reg;
1142+
1143+
reg = readl(master->regs + INTR_STATUS_EN);
1144+
reg &= ~INTR_IBI_THLD_STAT;
1145+
if (enable)
1146+
reg |= INTR_IBI_THLD_STAT;
1147+
writel(reg, master->regs + INTR_STATUS_EN);
1148+
1149+
reg = readl(master->regs + INTR_SIGNAL_EN);
1150+
reg &= ~INTR_IBI_THLD_STAT;
1151+
if (enable)
1152+
reg |= INTR_IBI_THLD_STAT;
1153+
writel(reg, master->regs + INTR_SIGNAL_EN);
1154+
}
1155+
11391156
static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
11401157
struct i3c_dev_desc *dev,
11411158
u8 idx, bool enable)
@@ -1170,23 +1187,34 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
11701187
}
11711188
writel(reg, master->regs + IBI_SIR_REQ_REJECT);
11721189

1173-
if (global) {
1174-
reg = readl(master->regs + INTR_STATUS_EN);
1175-
reg &= ~INTR_IBI_THLD_STAT;
1176-
if (enable)
1177-
reg |= INTR_IBI_THLD_STAT;
1178-
writel(reg, master->regs + INTR_STATUS_EN);
1179-
1180-
reg = readl(master->regs + INTR_SIGNAL_EN);
1181-
reg &= ~INTR_IBI_THLD_STAT;
1182-
if (enable)
1183-
reg |= INTR_IBI_THLD_STAT;
1184-
writel(reg, master->regs + INTR_SIGNAL_EN);
1185-
}
1190+
if (global)
1191+
dw_i3c_master_enable_sir_signal(master, enable);
1192+
11861193

11871194
spin_unlock_irqrestore(&master->devs_lock, flags);
11881195
}
11891196

1197+
static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
1198+
{
1199+
struct dw_i3c_master *master = to_dw_i3c_master(m);
1200+
1201+
dw_i3c_master_enable_sir_signal(master, true);
1202+
writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK,
1203+
master->regs + DEVICE_CTRL);
1204+
1205+
return 0;
1206+
}
1207+
1208+
static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
1209+
{
1210+
struct dw_i3c_master *master = to_dw_i3c_master(m);
1211+
1212+
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
1213+
master->regs + DEVICE_CTRL);
1214+
1215+
return 0;
1216+
}
1217+
11901218
static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
11911219
{
11921220
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
@@ -1326,6 +1354,8 @@ static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master)
13261354

13271355
if (IBI_TYPE_SIRQ(reg)) {
13281356
dw_i3c_master_handle_ibi_sir(master, reg);
1357+
} else if (IBI_TYPE_HJ(reg)) {
1358+
queue_work(master->base.wq, &master->hj_work);
13291359
} else {
13301360
len = IBI_QUEUE_STATUS_DATA_LEN(reg);
13311361
dev_info(&master->base.dev,
@@ -1393,6 +1423,8 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ibi_ops = {
13931423
.enable_ibi = dw_i3c_master_enable_ibi,
13941424
.disable_ibi = dw_i3c_master_disable_ibi,
13951425
.recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot,
1426+
.enable_hotjoin = dw_i3c_master_enable_hotjoin,
1427+
.disable_hotjoin = dw_i3c_master_disable_hotjoin,
13961428
};
13971429

13981430
/* default platform ops implementations */
@@ -1412,6 +1444,14 @@ static const struct dw_i3c_platform_ops dw_i3c_platform_ops_default = {
14121444
.set_dat_ibi = dw_i3c_platform_set_dat_ibi_nop,
14131445
};
14141446

1447+
static void dw_i3c_hj_work(struct work_struct *work)
1448+
{
1449+
struct dw_i3c_master *master =
1450+
container_of(work, typeof(*master), hj_work);
1451+
1452+
i3c_master_do_daa(&master->base);
1453+
}
1454+
14151455
int dw_i3c_common_probe(struct dw_i3c_master *master,
14161456
struct platform_device *pdev)
14171457
{
@@ -1469,6 +1509,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
14691509
if (master->ibi_capable)
14701510
ops = &dw_mipi_i3c_ibi_ops;
14711511

1512+
INIT_WORK(&master->hj_work, dw_i3c_hj_work);
14721513
ret = i3c_master_register(&master->base, &pdev->dev, ops, false);
14731514
if (ret)
14741515
goto err_assert_rst;

drivers/i3c/master/dw-i3c-master.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct dw_i3c_master {
5757

5858
/* platform-specific data */
5959
const struct dw_i3c_platform_ops *platform_ops;
60+
61+
struct work_struct hj_work;
6062
};
6163

6264
struct dw_i3c_platform_ops {

0 commit comments

Comments
 (0)