Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9ba36b8 authored by Patrick Daly's avatar Patrick Daly
Browse files

qcom: clk: Support deferred clock initialization



Clocks may depend on other clocks which are not registered yet. Handle
the error code -EPROBE_DEFER during clock initialization by placing
the offender on a clock orphan list, which will redo clock
initialization when another clock is registered successfully. Client
drivers may not obtain references to clocks on the orphan list.

Change-Id: I1a12feebe003884b775381d881e434bc9376f693
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 3de56173
Loading
Loading
Loading
Loading
+36 −7
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ struct handoff_vdd {
static LIST_HEAD(handoff_vdd_list);

static DEFINE_MUTEX(msm_clock_init_lock);
static LIST_HEAD(orphan_clk_list);

/* Find the voltage level required for a given rate. */
int find_vdd_level(struct clk *clk, unsigned long rate)
@@ -701,6 +702,9 @@ static int __handoff_clk(struct clk *clk)
	if (clk->flags & CLKFLAG_INIT_ERR)
		return -ENXIO;

	if (clk->flags & CLKFLAG_EPROBE_DEFER)
		return -EPROBE_DEFER;

	/* Handoff any 'depends' clock first. */
	rc = __handoff_clk(clk->depends);
	if (rc)
@@ -761,6 +765,9 @@ static int __handoff_clk(struct clk *clk)
	}

	clk->flags |= CLKFLAG_INIT_DONE;
	/* if the clk is on orphan list, remove it */
	list_del_init(&clk->list);
	clock_debug_register(clk);

	return 0;

@@ -768,8 +775,14 @@ err_depends:
	clk_disable_unprepare(clk->parent);
err:
	kfree(h);
	clk->flags |= CLKFLAG_INIT_ERR;
	if (rc == -EPROBE_DEFER) {
		clk->flags |= CLKFLAG_EPROBE_DEFER;
		if (list_empty(&clk->list))
			list_add_tail(&clk->list, &orphan_clk_list);
	} else {
		pr_err("%s handoff failed (%d)\n", clk->dbg_name, rc);
		clk->flags |= CLKFLAG_INIT_ERR;
	}
	return rc;
}

@@ -783,7 +796,9 @@ err:
 */
int msm_clock_register(struct clk_lookup *table, size_t size)
{
	int n = 0;
	int n = 0, rc;
	struct clk *c, *safe;
	bool found_more_clks;

	mutex_lock(&msm_clock_init_lock);

@@ -803,13 +818,27 @@ int msm_clock_register(struct clk_lookup *table, size_t size)
	 * Detect and preserve initial clock state until clock_late_init() or
	 * a driver explicitly changes it, whichever is first.
	 */
	for (n = 0; n < size; n++) {

	for (n = 0; n < size; n++)
		__handoff_clk(table[n].clk);
		clock_debug_register(table[n].clk);
	}

	/* maintain backwards compatibility */
	if (table[0].con_id || table[0].dev_id)
		clkdev_add_table(table, size);

	do {
		found_more_clks = false;
		/* clear cached __handoff_clk return values */
		list_for_each_entry_safe(c, safe, &orphan_clk_list, list)
			c->flags &= ~CLKFLAG_EPROBE_DEFER;

		list_for_each_entry_safe(c, safe, &orphan_clk_list, list) {
			rc = __handoff_clk(c);
			if (!rc)
				found_more_clks = true;
		}
	} while (found_more_clks);

	mutex_unlock(&msm_clock_init_lock);

	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#define CLKFLAG_INIT_ERR		0x00002000
#define CLKFLAG_NO_RATE_CACHE		0x00004000
#define CLKFLAG_MEASURE			0x00008000
#define CLKFLAG_EPROBE_DEFER		0x00010000

struct clk_lookup;
struct clk;