Commit cd1a6a0c authored by Carlos Song's avatar Carlos Song Committed by Alexandre Belloni
Browse files

i3c: master: svc: switch to bulk clk API for flexible clock support



Use the clk_bulk API to handle clocks, so the code can support different
numbers of clocks more easily. Make the code cleaner and more flexible.

No change in functionality.

Signed-off-by: default avatarCarlos Song <carlos.song@nxp.com>
Reviewed-by: default avatarFrank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20250427083230.3325700-3-carlos.song@nxp.com


Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 489c773a
Loading
Loading
Loading
Loading
+26 −50
Original line number Diff line number Diff line
@@ -202,9 +202,9 @@ struct svc_i3c_drvdata {
 * @descs: Array of descriptors, one per attached device
 * @hj_work: Hot-join work
 * @irq: Main interrupt
 * @pclk: System clock
 * @num_clks: I3C clock number
 * @fclk: Fast clock (bus)
 * @sclk: Slow clock (other events)
 * @clks: I3C clock array
 * @xferqueue: Transfer queue structure
 * @xferqueue.list: List member
 * @xferqueue.cur: Current ongoing transfer
@@ -229,9 +229,9 @@ struct svc_i3c_master {
	struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS];
	struct work_struct hj_work;
	int irq;
	struct clk *pclk;
	int num_clks;
	struct clk *fclk;
	struct clk *sclk;
	struct clk_bulk_data *clks;
	struct {
		struct list_head list;
		struct svc_i3c_xfer *cur;
@@ -1871,42 +1871,11 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
	.set_speed = svc_i3c_master_set_speed,
};

static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
{
	int ret = 0;

	ret = clk_prepare_enable(master->pclk);
	if (ret)
		return ret;

	ret = clk_prepare_enable(master->fclk);
	if (ret) {
		clk_disable_unprepare(master->pclk);
		return ret;
	}

	ret = clk_prepare_enable(master->sclk);
	if (ret) {
		clk_disable_unprepare(master->pclk);
		clk_disable_unprepare(master->fclk);
		return ret;
	}

	return 0;
}

static void svc_i3c_master_unprepare_clks(struct svc_i3c_master *master)
{
	clk_disable_unprepare(master->pclk);
	clk_disable_unprepare(master->fclk);
	clk_disable_unprepare(master->sclk);
}

static int svc_i3c_master_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct svc_i3c_master *master;
	int ret;
	int ret, i;

	master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
	if (!master)
@@ -1920,27 +1889,31 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
	if (IS_ERR(master->regs))
		return PTR_ERR(master->regs);

	master->pclk = devm_clk_get(dev, "pclk");
	if (IS_ERR(master->pclk))
		return PTR_ERR(master->pclk);
	master->num_clks = devm_clk_bulk_get_all(dev, &master->clks);
	if (master->num_clks < 0)
		return dev_err_probe(dev, -EINVAL, "can't get I3C clocks\n");

	for (i = 0; i < master->num_clks; i++) {
		if (!strcmp(master->clks[i].id, "fast_clk"))
			break;
	}

	if (i == master->num_clks)
		return dev_err_probe(dev, -EINVAL,
				     "can't get I3C peripheral clock\n");

	master->fclk = devm_clk_get(dev, "fast_clk");
	master->fclk = master->clks[i].clk;
	if (IS_ERR(master->fclk))
		return PTR_ERR(master->fclk);

	master->sclk = devm_clk_get(dev, "slow_clk");
	if (IS_ERR(master->sclk))
		return PTR_ERR(master->sclk);

	master->irq = platform_get_irq(pdev, 0);
	if (master->irq < 0)
		return master->irq;

	master->dev = dev;

	ret = svc_i3c_master_prepare_clks(master);
	ret = clk_bulk_prepare_enable(master->num_clks, master->clks);
	if (ret)
		return ret;
		return dev_err_probe(dev, ret, "can't enable I3C clocks\n");

	INIT_WORK(&master->hj_work, svc_i3c_master_hj_work);
	mutex_init(&master->lock);
@@ -1993,7 +1966,7 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
	pm_runtime_set_suspended(&pdev->dev);

err_disable_clks:
	svc_i3c_master_unprepare_clks(master);
	clk_bulk_disable_unprepare(master->num_clks, master->clks);

	return ret;
}
@@ -2031,7 +2004,7 @@ static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
	struct svc_i3c_master *master = dev_get_drvdata(dev);

	svc_i3c_save_regs(master);
	svc_i3c_master_unprepare_clks(master);
	clk_bulk_disable_unprepare(master->num_clks, master->clks);
	pinctrl_pm_select_sleep_state(dev);

	return 0;
@@ -2040,9 +2013,12 @@ static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
static int __maybe_unused svc_i3c_runtime_resume(struct device *dev)
{
	struct svc_i3c_master *master = dev_get_drvdata(dev);
	int ret;

	pinctrl_pm_select_default_state(dev);
	svc_i3c_master_prepare_clks(master);
	ret = clk_bulk_prepare_enable(master->num_clks, master->clks);
	if (ret)
		return ret;

	svc_i3c_restore_regs(master);