Skip to content

Commit 05b26c3

Browse files
nxpfranklialexandrebelloni
authored andcommitted
i3c: master: svc: add hot join support
Add hot join support for svc master controller. Disable hot join by default. User can use sysfs entry to enable hot join. Signed-off-by: Frank Li <Frank.Li@nxp.com> Link: https://lore.kernel.org/r/20231201222532.2431484-3-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 317bacf commit 05b26c3

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

drivers/i3c/master/svc-i3c-master.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@
128128
/* This parameter depends on the implementation and may be tuned */
129129
#define SVC_I3C_FIFO_SIZE 16
130130

131+
#define SVC_I3C_EVENT_IBI BIT(0)
132+
#define SVC_I3C_EVENT_HOTJOIN BIT(1)
133+
131134
struct svc_i3c_cmd {
132135
u8 addr;
133136
bool rnw;
@@ -177,6 +180,7 @@ struct svc_i3c_regs_save {
177180
* @ibi.tbq_slot: To be queued IBI slot
178181
* @ibi.lock: IBI lock
179182
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
183+
* @enabled_events: Bit masks for enable events (IBI, HotJoin).
180184
*/
181185
struct svc_i3c_master {
182186
struct i3c_master_controller base;
@@ -206,6 +210,7 @@ struct svc_i3c_master {
206210
spinlock_t lock;
207211
} ibi;
208212
struct mutex lock;
213+
int enabled_events;
209214
};
210215

211216
/**
@@ -220,6 +225,11 @@ struct svc_i3c_i2c_dev_data {
220225
struct i3c_generic_ibi_pool *ibi_pool;
221226
};
222227

228+
static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
229+
{
230+
return !!(master->enabled_events & mask);
231+
}
232+
223233
static bool svc_i3c_master_error(struct svc_i3c_master *master)
224234
{
225235
u32 mstatus, merrwarn;
@@ -429,13 +439,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
429439
switch (ibitype) {
430440
case SVC_I3C_MSTATUS_IBITYPE_IBI:
431441
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
432-
if (!dev)
442+
if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
433443
svc_i3c_master_nack_ibi(master);
434444
else
435445
svc_i3c_master_handle_ibi(master, dev);
436446
break;
437447
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
438-
svc_i3c_master_ack_ibi(master, false);
448+
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
449+
svc_i3c_master_ack_ibi(master, false);
450+
else
451+
svc_i3c_master_nack_ibi(master);
439452
break;
440453
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
441454
svc_i3c_master_nack_ibi(master);
@@ -472,7 +485,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
472485
svc_i3c_master_emit_stop(master);
473486
break;
474487
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
475-
queue_work(master->base.wq, &master->hj_work);
488+
svc_i3c_master_emit_stop(master);
489+
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
490+
queue_work(master->base.wq, &master->hj_work);
476491
break;
477492
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
478493
default:
@@ -1472,6 +1487,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
14721487
return ret;
14731488
}
14741489

1490+
master->enabled_events |= SVC_I3C_EVENT_IBI;
14751491
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
14761492

14771493
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1483,7 +1499,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
14831499
struct svc_i3c_master *master = to_svc_i3c_master(m);
14841500
int ret;
14851501

1486-
svc_i3c_master_disable_interrupts(master);
1502+
master->enabled_events &= ~SVC_I3C_EVENT_IBI;
1503+
if (!master->enabled_events)
1504+
svc_i3c_master_disable_interrupts(master);
14871505

14881506
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
14891507

@@ -1493,6 +1511,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
14931511
return ret;
14941512
}
14951513

1514+
static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
1515+
{
1516+
struct svc_i3c_master *master = to_svc_i3c_master(m);
1517+
int ret;
1518+
1519+
ret = pm_runtime_resume_and_get(master->dev);
1520+
if (ret < 0) {
1521+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
1522+
return ret;
1523+
}
1524+
1525+
master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
1526+
1527+
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
1528+
1529+
return 0;
1530+
}
1531+
1532+
static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
1533+
{
1534+
struct svc_i3c_master *master = to_svc_i3c_master(m);
1535+
1536+
master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
1537+
1538+
if (!master->enabled_events)
1539+
svc_i3c_master_disable_interrupts(master);
1540+
1541+
pm_runtime_mark_last_busy(master->dev);
1542+
pm_runtime_put_autosuspend(master->dev);
1543+
1544+
return 0;
1545+
}
1546+
14961547
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
14971548
struct i3c_ibi_slot *slot)
14981549
{
@@ -1519,6 +1570,8 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
15191570
.recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
15201571
.enable_ibi = svc_i3c_master_enable_ibi,
15211572
.disable_ibi = svc_i3c_master_disable_ibi,
1573+
.enable_hotjoin = svc_i3c_master_enable_hotjoin,
1574+
.disable_hotjoin = svc_i3c_master_disable_hotjoin,
15221575
};
15231576

15241577
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)

0 commit comments

Comments
 (0)