mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
Merge tag 'i3c/for-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: - svc: fix suspend/resume on some platforms, fix locking issues * tag 'i3c/for-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: master: svc: add NACK check after start byte sent i3c: master: svc: fix cpu schedule in spin lock i3c: master: svc: fix i3c suspend/resume issue
This commit is contained in:
@@ -92,6 +92,7 @@
|
|||||||
#define SVC_I3C_MINTCLR 0x094
|
#define SVC_I3C_MINTCLR 0x094
|
||||||
#define SVC_I3C_MINTMASKED 0x098
|
#define SVC_I3C_MINTMASKED 0x098
|
||||||
#define SVC_I3C_MERRWARN 0x09C
|
#define SVC_I3C_MERRWARN 0x09C
|
||||||
|
#define SVC_I3C_MERRWARN_NACK BIT(2)
|
||||||
#define SVC_I3C_MDMACTRL 0x0A0
|
#define SVC_I3C_MDMACTRL 0x0A0
|
||||||
#define SVC_I3C_MDATACTRL 0x0AC
|
#define SVC_I3C_MDATACTRL 0x0AC
|
||||||
#define SVC_I3C_MDATACTRL_FLUSHTB BIT(0)
|
#define SVC_I3C_MDATACTRL_FLUSHTB BIT(0)
|
||||||
@@ -145,6 +146,11 @@ struct svc_i3c_xfer {
|
|||||||
struct svc_i3c_cmd cmds[];
|
struct svc_i3c_cmd cmds[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct svc_i3c_regs_save {
|
||||||
|
u32 mconfig;
|
||||||
|
u32 mdynaddr;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct svc_i3c_master - Silvaco I3C Master structure
|
* struct svc_i3c_master - Silvaco I3C Master structure
|
||||||
* @base: I3C master controller
|
* @base: I3C master controller
|
||||||
@@ -173,6 +179,7 @@ struct svc_i3c_master {
|
|||||||
struct i3c_master_controller base;
|
struct i3c_master_controller base;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
|
struct svc_i3c_regs_save saved_regs;
|
||||||
u32 free_slots;
|
u32 free_slots;
|
||||||
u8 addrs[SVC_I3C_MAX_DEVS];
|
u8 addrs[SVC_I3C_MAX_DEVS];
|
||||||
struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS];
|
struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS];
|
||||||
@@ -1008,6 +1015,11 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto emit_stop;
|
goto emit_stop;
|
||||||
|
|
||||||
|
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto emit_stop;
|
||||||
|
}
|
||||||
|
|
||||||
if (rnw)
|
if (rnw)
|
||||||
ret = svc_i3c_master_read(master, in, xfer_len);
|
ret = svc_i3c_master_read(master, in, xfer_len);
|
||||||
else
|
else
|
||||||
@@ -1090,12 +1102,6 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
|
|||||||
if (!xfer)
|
if (!xfer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = pm_runtime_resume_and_get(master->dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
svc_i3c_master_clear_merrwarn(master);
|
svc_i3c_master_clear_merrwarn(master);
|
||||||
svc_i3c_master_flush_fifo(master);
|
svc_i3c_master_flush_fifo(master);
|
||||||
|
|
||||||
@@ -1110,9 +1116,6 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(master->dev);
|
|
||||||
pm_runtime_put_autosuspend(master->dev);
|
|
||||||
|
|
||||||
xfer->ret = ret;
|
xfer->ret = ret;
|
||||||
complete(&xfer->comp);
|
complete(&xfer->comp);
|
||||||
|
|
||||||
@@ -1133,6 +1136,13 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
|
|||||||
struct svc_i3c_xfer *xfer)
|
struct svc_i3c_xfer *xfer)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
init_completion(&xfer->comp);
|
init_completion(&xfer->comp);
|
||||||
spin_lock_irqsave(&master->xferqueue.lock, flags);
|
spin_lock_irqsave(&master->xferqueue.lock, flags);
|
||||||
@@ -1143,6 +1153,9 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
|
|||||||
svc_i3c_master_start_xfer_locked(master);
|
svc_i3c_master_start_xfer_locked(master);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
|
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
|
||||||
|
|
||||||
|
pm_runtime_mark_last_busy(master->dev);
|
||||||
|
pm_runtime_put_autosuspend(master->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -1579,10 +1592,28 @@ static void svc_i3c_master_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void svc_i3c_save_regs(struct svc_i3c_master *master)
|
||||||
|
{
|
||||||
|
master->saved_regs.mconfig = readl(master->regs + SVC_I3C_MCONFIG);
|
||||||
|
master->saved_regs.mdynaddr = readl(master->regs + SVC_I3C_MDYNADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void svc_i3c_restore_regs(struct svc_i3c_master *master)
|
||||||
|
{
|
||||||
|
if (readl(master->regs + SVC_I3C_MDYNADDR) !=
|
||||||
|
master->saved_regs.mdynaddr) {
|
||||||
|
writel(master->saved_regs.mconfig,
|
||||||
|
master->regs + SVC_I3C_MCONFIG);
|
||||||
|
writel(master->saved_regs.mdynaddr,
|
||||||
|
master->regs + SVC_I3C_MDYNADDR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
|
static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct svc_i3c_master *master = dev_get_drvdata(dev);
|
struct svc_i3c_master *master = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
svc_i3c_save_regs(master);
|
||||||
svc_i3c_master_unprepare_clks(master);
|
svc_i3c_master_unprepare_clks(master);
|
||||||
pinctrl_pm_select_sleep_state(dev);
|
pinctrl_pm_select_sleep_state(dev);
|
||||||
|
|
||||||
@@ -1596,6 +1627,8 @@ static int __maybe_unused svc_i3c_runtime_resume(struct device *dev)
|
|||||||
pinctrl_pm_select_default_state(dev);
|
pinctrl_pm_select_default_state(dev);
|
||||||
svc_i3c_master_prepare_clks(master);
|
svc_i3c_master_prepare_clks(master);
|
||||||
|
|
||||||
|
svc_i3c_restore_regs(master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user