[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20231129221225.387952-3-Frank.Li@nxp.com>
Date: Wed, 29 Nov 2023 17:12:21 -0500
From: Frank Li <Frank.Li@....com>
To: alexandre.belloni@...tlin.com
Cc: Frank.li@....com, conor.culhane@...vaco.com, imx@...ts.linux.dev,
joe@...ches.com, linux-i3c@...ts.infradead.org,
linux-kernel@...r.kernel.org, miquel.raynal@...tlin.com,
zbigniew.lukwinski@...ux.intel.com
Subject: [PATCH v4 2/6] i3c: master: svc: add hot join support
Add hot join support for svc master controller. Enable hot join defaultly.
User can use sys entry to disable hot join.
Signed-off-by: Frank Li <Frank.Li@....com>
---
drivers/i3c/master/svc-i3c-master.c | 58 +++++++++++++++++++++++++++--
1 file changed, 54 insertions(+), 4 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 6b6bdd163af4f..880c6ae76c013 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -128,6 +128,9 @@
/* This parameter depends on the implementation and may be tuned */
#define SVC_I3C_FIFO_SIZE 16
+#define SVC_I3C_EVENT_IBI BIT(0)
+#define SVC_I3C_EVENT_HOTJOIN BIT(1)
+
struct svc_i3c_cmd {
u8 addr;
bool rnw;
@@ -176,6 +179,7 @@ struct svc_i3c_regs_save {
* @ibi.tbq_slot: To be queued IBI slot
* @ibi.lock: IBI lock
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
+ * @enabled_events: Bit masks for enable events (IBI, HotJoin).
*/
struct svc_i3c_master {
struct i3c_master_controller base;
@@ -205,6 +209,7 @@ struct svc_i3c_master {
spinlock_t lock;
} ibi;
struct mutex lock;
+ int enabled_events;
};
/**
@@ -428,13 +433,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
switch (ibitype) {
case SVC_I3C_MSTATUS_IBITYPE_IBI:
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
- if (!dev)
+ if (!dev || !(master->enabled_events & SVC_I3C_EVENT_IBI))
svc_i3c_master_nack_ibi(master);
else
svc_i3c_master_handle_ibi(master, dev);
break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
- svc_i3c_master_ack_ibi(master, false);
+ if (master->enabled_events & SVC_I3C_EVENT_HOTJOIN)
+ svc_i3c_master_ack_ibi(master, false);
+ else
+ svc_i3c_master_nack_ibi(master);
break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
svc_i3c_master_nack_ibi(master);
@@ -471,7 +479,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
svc_i3c_master_emit_stop(master);
break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
- queue_work(master->base.wq, &master->hj_work);
+ svc_i3c_master_emit_stop(master);
+ if (master->enabled_events & SVC_I3C_EVENT_HOTJOIN)
+ queue_work(master->base.wq, &master->hj_work);
break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
default:
@@ -1471,6 +1481,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
return ret;
}
+ master->enabled_events |= SVC_I3C_EVENT_IBI;
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1482,7 +1493,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
struct svc_i3c_master *master = to_svc_i3c_master(m);
int ret;
- svc_i3c_master_disable_interrupts(master);
+ master->enabled_events &= ~SVC_I3C_EVENT_IBI;
+ if (!master->enabled_events)
+ svc_i3c_master_disable_interrupts(master);
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1492,6 +1505,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
return ret;
}
+static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
+{
+ struct svc_i3c_master *master = to_svc_i3c_master(m);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(master->dev);
+ if (ret < 0) {
+ dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
+ return ret;
+ }
+
+ master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
+
+ svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
+
+ return 0;
+}
+
+static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
+{
+ struct svc_i3c_master *master = to_svc_i3c_master(m);
+
+ master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
+
+ if (!master->enabled_events)
+ svc_i3c_master_disable_interrupts(master);
+
+ pm_runtime_mark_last_busy(master->dev);
+ pm_runtime_put_autosuspend(master->dev);
+
+ return 0;
+}
+
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
struct i3c_ibi_slot *slot)
{
@@ -1518,6 +1564,8 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
.recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
.enable_ibi = svc_i3c_master_enable_ibi,
.disable_ibi = svc_i3c_master_disable_ibi,
+ .enable_hotjoin = svc_i3c_master_enable_hotjoin,
+ .disable_hotjoin = svc_i3c_master_disable_hotjoin,
};
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
@@ -1630,6 +1678,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
+ i3c_master_enable_hotjoin(&master->base);
+
return 0;
rpm_disable:
--
2.34.1
Powered by blists - more mailing lists