162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OMAP3/4 - specific DPLL control functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009-2010 Texas Instruments, Inc.
662306a36Sopenharmony_ci * Copyright (C) 2009-2010 Nokia Corporation
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Written by Paul Walmsley
962306a36Sopenharmony_ci * Testing and integration fixes by Jouni Högander
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth
1262306a36Sopenharmony_ci * Menon
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Parts of this code are based on code written by
1562306a36Sopenharmony_ci * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/device.h>
2062306a36Sopenharmony_ci#include <linux/list.h>
2162306a36Sopenharmony_ci#include <linux/errno.h>
2262306a36Sopenharmony_ci#include <linux/delay.h>
2362306a36Sopenharmony_ci#include <linux/clk.h>
2462306a36Sopenharmony_ci#include <linux/io.h>
2562306a36Sopenharmony_ci#include <linux/bitops.h>
2662306a36Sopenharmony_ci#include <linux/clkdev.h>
2762306a36Sopenharmony_ci#include <linux/clk/ti.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "clock.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* CM_AUTOIDLE_PLL*.AUTO_* bit values */
3262306a36Sopenharmony_ci#define DPLL_AUTOIDLE_DISABLE			0x0
3362306a36Sopenharmony_ci#define DPLL_AUTOIDLE_LOW_POWER_STOP		0x1
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define MAX_DPLL_WAIT_TRIES		1000000
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define OMAP3XXX_EN_DPLL_LOCKED		0x7
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Forward declarations */
4062306a36Sopenharmony_cistatic u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
4162306a36Sopenharmony_cistatic void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
4262306a36Sopenharmony_cistatic void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* Private functions */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
4762306a36Sopenharmony_cistatic void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	const struct dpll_data *dd;
5062306a36Sopenharmony_ci	u32 v;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	dd = clk->dpll_data;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
5562306a36Sopenharmony_ci	v &= ~dd->enable_mask;
5662306a36Sopenharmony_ci	v |= clken_bits << __ffs(dd->enable_mask);
5762306a36Sopenharmony_ci	ti_clk_ll_ops->clk_writel(v, &dd->control_reg);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
6162306a36Sopenharmony_cistatic int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	const struct dpll_data *dd;
6462306a36Sopenharmony_ci	int i = 0;
6562306a36Sopenharmony_ci	int ret = -EINVAL;
6662306a36Sopenharmony_ci	const char *clk_name;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	dd = clk->dpll_data;
6962306a36Sopenharmony_ci	clk_name = clk_hw_get_name(&clk->hw);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	state <<= __ffs(dd->idlest_mask);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	while (((ti_clk_ll_ops->clk_readl(&dd->idlest_reg) & dd->idlest_mask)
7462306a36Sopenharmony_ci		!= state) && i < MAX_DPLL_WAIT_TRIES) {
7562306a36Sopenharmony_ci		i++;
7662306a36Sopenharmony_ci		udelay(1);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (i == MAX_DPLL_WAIT_TRIES) {
8062306a36Sopenharmony_ci		pr_err("clock: %s failed transition to '%s'\n",
8162306a36Sopenharmony_ci		       clk_name, (state) ? "locked" : "bypassed");
8262306a36Sopenharmony_ci	} else {
8362306a36Sopenharmony_ci		pr_debug("clock: %s transition to '%s' in %d loops\n",
8462306a36Sopenharmony_ci			 clk_name, (state) ? "locked" : "bypassed", i);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		ret = 0;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return ret;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* From 3430 TRM ES2 4.7.6.2 */
9362306a36Sopenharmony_cistatic u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	unsigned long fint;
9662306a36Sopenharmony_ci	u16 f = 0;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	fint = clk_hw_get_rate(clk->dpll_data->clk_ref) / n;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	pr_debug("clock: fint is %lu\n", fint);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (fint >= 750000 && fint <= 1000000)
10362306a36Sopenharmony_ci		f = 0x3;
10462306a36Sopenharmony_ci	else if (fint > 1000000 && fint <= 1250000)
10562306a36Sopenharmony_ci		f = 0x4;
10662306a36Sopenharmony_ci	else if (fint > 1250000 && fint <= 1500000)
10762306a36Sopenharmony_ci		f = 0x5;
10862306a36Sopenharmony_ci	else if (fint > 1500000 && fint <= 1750000)
10962306a36Sopenharmony_ci		f = 0x6;
11062306a36Sopenharmony_ci	else if (fint > 1750000 && fint <= 2100000)
11162306a36Sopenharmony_ci		f = 0x7;
11262306a36Sopenharmony_ci	else if (fint > 7500000 && fint <= 10000000)
11362306a36Sopenharmony_ci		f = 0xB;
11462306a36Sopenharmony_ci	else if (fint > 10000000 && fint <= 12500000)
11562306a36Sopenharmony_ci		f = 0xC;
11662306a36Sopenharmony_ci	else if (fint > 12500000 && fint <= 15000000)
11762306a36Sopenharmony_ci		f = 0xD;
11862306a36Sopenharmony_ci	else if (fint > 15000000 && fint <= 17500000)
11962306a36Sopenharmony_ci		f = 0xE;
12062306a36Sopenharmony_ci	else if (fint > 17500000 && fint <= 21000000)
12162306a36Sopenharmony_ci		f = 0xF;
12262306a36Sopenharmony_ci	else
12362306a36Sopenharmony_ci		pr_debug("clock: unknown freqsel setting for %d\n", n);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return f;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/**
12962306a36Sopenharmony_ci * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness
13062306a36Sopenharmony_ci * @clk: pointer to a DPLL struct clk
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * Instructs a non-CORE DPLL to lock.  Waits for the DPLL to report
13362306a36Sopenharmony_ci * readiness before returning.  Will save and restore the DPLL's
13462306a36Sopenharmony_ci * autoidle state across the enable, per the CDP code.  If the DPLL
13562306a36Sopenharmony_ci * locked successfully, return 0; if the DPLL did not lock in the time
13662306a36Sopenharmony_ci * allotted, or DPLL3 was passed in, return -EINVAL.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	const struct dpll_data *dd;
14162306a36Sopenharmony_ci	u8 ai;
14262306a36Sopenharmony_ci	u8 state = 1;
14362306a36Sopenharmony_ci	int r = 0;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	pr_debug("clock: locking DPLL %s\n", clk_hw_get_name(&clk->hw));
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	dd = clk->dpll_data;
14862306a36Sopenharmony_ci	state <<= __ffs(dd->idlest_mask);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Check if already locked */
15162306a36Sopenharmony_ci	if ((ti_clk_ll_ops->clk_readl(&dd->idlest_reg) & dd->idlest_mask) ==
15262306a36Sopenharmony_ci	    state)
15362306a36Sopenharmony_ci		goto done;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ai = omap3_dpll_autoidle_read(clk);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (ai)
15862306a36Sopenharmony_ci		omap3_dpll_deny_idle(clk);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	_omap3_dpll_write_clken(clk, DPLL_LOCKED);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	r = _omap3_wait_dpll_status(clk, 1);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (ai)
16562306a36Sopenharmony_ci		omap3_dpll_allow_idle(clk);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cidone:
16862306a36Sopenharmony_ci	return r;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
17362306a36Sopenharmony_ci * @clk: pointer to a DPLL struct clk
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * Instructs a non-CORE DPLL to enter low-power bypass mode.  In
17662306a36Sopenharmony_ci * bypass mode, the DPLL's rate is set equal to its parent clock's
17762306a36Sopenharmony_ci * rate.  Waits for the DPLL to report readiness before returning.
17862306a36Sopenharmony_ci * Will save and restore the DPLL's autoidle state across the enable,
17962306a36Sopenharmony_ci * per the CDP code.  If the DPLL entered bypass mode successfully,
18062306a36Sopenharmony_ci * return 0; if the DPLL did not enter bypass in the time allotted, or
18162306a36Sopenharmony_ci * DPLL3 was passed in, or the DPLL does not support low-power bypass,
18262306a36Sopenharmony_ci * return -EINVAL.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistatic int _omap3_noncore_dpll_bypass(struct clk_hw_omap *clk)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	int r;
18762306a36Sopenharmony_ci	u8 ai;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS)))
19062306a36Sopenharmony_ci		return -EINVAL;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	pr_debug("clock: configuring DPLL %s for low-power bypass\n",
19362306a36Sopenharmony_ci		 clk_hw_get_name(&clk->hw));
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ai = omap3_dpll_autoidle_read(clk);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	_omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	r = _omap3_wait_dpll_status(clk, 0);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (ai)
20262306a36Sopenharmony_ci		omap3_dpll_allow_idle(clk);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return r;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/**
20862306a36Sopenharmony_ci * _omap3_noncore_dpll_stop - instruct a DPLL to stop
20962306a36Sopenharmony_ci * @clk: pointer to a DPLL struct clk
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci * Instructs a non-CORE DPLL to enter low-power stop. Will save and
21262306a36Sopenharmony_ci * restore the DPLL's autoidle state across the stop, per the CDP
21362306a36Sopenharmony_ci * code.  If DPLL3 was passed in, or the DPLL does not support
21462306a36Sopenharmony_ci * low-power stop, return -EINVAL; otherwise, return 0.
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_cistatic int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	u8 ai;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
22162306a36Sopenharmony_ci		return -EINVAL;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	pr_debug("clock: stopping DPLL %s\n", clk_hw_get_name(&clk->hw));
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ai = omap3_dpll_autoidle_read(clk);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	_omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (ai)
23062306a36Sopenharmony_ci		omap3_dpll_allow_idle(clk);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/**
23662306a36Sopenharmony_ci * _lookup_dco - Lookup DCO used by j-type DPLL
23762306a36Sopenharmony_ci * @clk: pointer to a DPLL struct clk
23862306a36Sopenharmony_ci * @dco: digital control oscillator selector
23962306a36Sopenharmony_ci * @m: DPLL multiplier to set
24062306a36Sopenharmony_ci * @n: DPLL divider to set
24162306a36Sopenharmony_ci *
24262306a36Sopenharmony_ci * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * XXX This code is not needed for 3430/AM35xx; can it be optimized
24562306a36Sopenharmony_ci * out in non-multi-OMAP builds for those chips?
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistatic void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	unsigned long fint, clkinp; /* watch out for overflow */
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	clkinp = clk_hw_get_rate(clk_hw_get_parent(&clk->hw));
25262306a36Sopenharmony_ci	fint = (clkinp / n) * m;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (fint < 1000000000)
25562306a36Sopenharmony_ci		*dco = 2;
25662306a36Sopenharmony_ci	else
25762306a36Sopenharmony_ci		*dco = 4;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/**
26162306a36Sopenharmony_ci * _lookup_sddiv - Calculate sigma delta divider for j-type DPLL
26262306a36Sopenharmony_ci * @clk: pointer to a DPLL struct clk
26362306a36Sopenharmony_ci * @sd_div: target sigma-delta divider
26462306a36Sopenharmony_ci * @m: DPLL multiplier to set
26562306a36Sopenharmony_ci * @n: DPLL divider to set
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci * XXX This code is not needed for 3430/AM35xx; can it be optimized
27062306a36Sopenharmony_ci * out in non-multi-OMAP builds for those chips?
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistatic void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	unsigned long clkinp, sd; /* watch out for overflow */
27562306a36Sopenharmony_ci	int mod1, mod2;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	clkinp = clk_hw_get_rate(clk_hw_get_parent(&clk->hw));
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/*
28062306a36Sopenharmony_ci	 * target sigma-delta to near 250MHz
28162306a36Sopenharmony_ci	 * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */
28462306a36Sopenharmony_ci	mod1 = (clkinp * m) % (250 * n);
28562306a36Sopenharmony_ci	sd = (clkinp * m) / (250 * n);
28662306a36Sopenharmony_ci	mod2 = sd % 10;
28762306a36Sopenharmony_ci	sd /= 10;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (mod1 || mod2)
29062306a36Sopenharmony_ci		sd++;
29162306a36Sopenharmony_ci	*sd_div = sd;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/**
29562306a36Sopenharmony_ci * omap3_noncore_dpll_ssc_program - set spread-spectrum clocking registers
29662306a36Sopenharmony_ci * @clk:	struct clk * of DPLL to set
29762306a36Sopenharmony_ci *
29862306a36Sopenharmony_ci * Enable the DPLL spread spectrum clocking if frequency modulation and
29962306a36Sopenharmony_ci * frequency spreading have been set, otherwise disable it.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cistatic void omap3_noncore_dpll_ssc_program(struct clk_hw_omap *clk)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct dpll_data *dd = clk->dpll_data;
30462306a36Sopenharmony_ci	unsigned long ref_rate;
30562306a36Sopenharmony_ci	u32 v, ctrl, mod_freq_divider, exponent, mantissa;
30662306a36Sopenharmony_ci	u32 deltam_step, deltam_ceil;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (dd->ssc_modfreq && dd->ssc_deltam) {
31162306a36Sopenharmony_ci		ctrl |= dd->ssc_enable_mask;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		if (dd->ssc_downspread)
31462306a36Sopenharmony_ci			ctrl |= dd->ssc_downspread_mask;
31562306a36Sopenharmony_ci		else
31662306a36Sopenharmony_ci			ctrl &= ~dd->ssc_downspread_mask;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		ref_rate = clk_hw_get_rate(dd->clk_ref);
31962306a36Sopenharmony_ci		mod_freq_divider =
32062306a36Sopenharmony_ci		    (ref_rate / dd->last_rounded_n) / (4 * dd->ssc_modfreq);
32162306a36Sopenharmony_ci		if (dd->ssc_modfreq > (ref_rate / 70))
32262306a36Sopenharmony_ci			pr_warn("clock: SSC modulation frequency of DPLL %s greater than %ld\n",
32362306a36Sopenharmony_ci				__clk_get_name(clk->hw.clk), ref_rate / 70);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		exponent = 0;
32662306a36Sopenharmony_ci		mantissa = mod_freq_divider;
32762306a36Sopenharmony_ci		while ((mantissa > 127) && (exponent < 7)) {
32862306a36Sopenharmony_ci			exponent++;
32962306a36Sopenharmony_ci			mantissa /= 2;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci		if (mantissa > 127)
33262306a36Sopenharmony_ci			mantissa = 127;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->ssc_modfreq_reg);
33562306a36Sopenharmony_ci		v &= ~(dd->ssc_modfreq_mant_mask | dd->ssc_modfreq_exp_mask);
33662306a36Sopenharmony_ci		v |= mantissa << __ffs(dd->ssc_modfreq_mant_mask);
33762306a36Sopenharmony_ci		v |= exponent << __ffs(dd->ssc_modfreq_exp_mask);
33862306a36Sopenharmony_ci		ti_clk_ll_ops->clk_writel(v, &dd->ssc_modfreq_reg);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		deltam_step = dd->last_rounded_m * dd->ssc_deltam;
34162306a36Sopenharmony_ci		deltam_step /= 10;
34262306a36Sopenharmony_ci		if (dd->ssc_downspread)
34362306a36Sopenharmony_ci			deltam_step /= 2;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		deltam_step <<= __ffs(dd->ssc_deltam_int_mask);
34662306a36Sopenharmony_ci		deltam_step /= 100;
34762306a36Sopenharmony_ci		deltam_step /= mod_freq_divider;
34862306a36Sopenharmony_ci		if (deltam_step > 0xFFFFF)
34962306a36Sopenharmony_ci			deltam_step = 0xFFFFF;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		deltam_ceil = (deltam_step & dd->ssc_deltam_int_mask) >>
35262306a36Sopenharmony_ci		    __ffs(dd->ssc_deltam_int_mask);
35362306a36Sopenharmony_ci		if (deltam_step & dd->ssc_deltam_frac_mask)
35462306a36Sopenharmony_ci			deltam_ceil++;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		if ((dd->ssc_downspread &&
35762306a36Sopenharmony_ci		     ((dd->last_rounded_m - (2 * deltam_ceil)) < 20 ||
35862306a36Sopenharmony_ci		      dd->last_rounded_m > 2045)) ||
35962306a36Sopenharmony_ci		    ((dd->last_rounded_m - deltam_ceil) < 20 ||
36062306a36Sopenharmony_ci		     (dd->last_rounded_m + deltam_ceil) > 2045))
36162306a36Sopenharmony_ci			pr_warn("clock: SSC multiplier of DPLL %s is out of range\n",
36262306a36Sopenharmony_ci				__clk_get_name(clk->hw.clk));
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->ssc_deltam_reg);
36562306a36Sopenharmony_ci		v &= ~(dd->ssc_deltam_int_mask | dd->ssc_deltam_frac_mask);
36662306a36Sopenharmony_ci		v |= deltam_step << __ffs(dd->ssc_deltam_int_mask |
36762306a36Sopenharmony_ci					  dd->ssc_deltam_frac_mask);
36862306a36Sopenharmony_ci		ti_clk_ll_ops->clk_writel(v, &dd->ssc_deltam_reg);
36962306a36Sopenharmony_ci	} else {
37062306a36Sopenharmony_ci		ctrl &= ~dd->ssc_enable_mask;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ti_clk_ll_ops->clk_writel(ctrl, &dd->control_reg);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * omap3_noncore_dpll_program - set non-core DPLL M,N values directly
37862306a36Sopenharmony_ci * @clk:	struct clk * of DPLL to set
37962306a36Sopenharmony_ci * @freqsel:	FREQSEL value to set
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * Program the DPLL with the last M, N values calculated, and wait for
38262306a36Sopenharmony_ci * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
38362306a36Sopenharmony_ci */
38462306a36Sopenharmony_cistatic int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct dpll_data *dd = clk->dpll_data;
38762306a36Sopenharmony_ci	u8 dco, sd_div, ai = 0;
38862306a36Sopenharmony_ci	u32 v;
38962306a36Sopenharmony_ci	bool errata_i810;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
39262306a36Sopenharmony_ci	_omap3_noncore_dpll_bypass(clk);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * Set jitter correction. Jitter correction applicable for OMAP343X
39662306a36Sopenharmony_ci	 * only since freqsel field is no longer present on other devices.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) {
39962306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
40062306a36Sopenharmony_ci		v &= ~dd->freqsel_mask;
40162306a36Sopenharmony_ci		v |= freqsel << __ffs(dd->freqsel_mask);
40262306a36Sopenharmony_ci		ti_clk_ll_ops->clk_writel(v, &dd->control_reg);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Set DPLL multiplier, divider */
40662306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* Handle Duty Cycle Correction */
40962306a36Sopenharmony_ci	if (dd->dcc_mask) {
41062306a36Sopenharmony_ci		if (dd->last_rounded_rate >= dd->dcc_rate)
41162306a36Sopenharmony_ci			v |= dd->dcc_mask; /* Enable DCC */
41262306a36Sopenharmony_ci		else
41362306a36Sopenharmony_ci			v &= ~dd->dcc_mask; /* Disable DCC */
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	v &= ~(dd->mult_mask | dd->div1_mask);
41762306a36Sopenharmony_ci	v |= dd->last_rounded_m << __ffs(dd->mult_mask);
41862306a36Sopenharmony_ci	v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Configure dco and sd_div for dplls that have these fields */
42162306a36Sopenharmony_ci	if (dd->dco_mask) {
42262306a36Sopenharmony_ci		_lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
42362306a36Sopenharmony_ci		v &= ~(dd->dco_mask);
42462306a36Sopenharmony_ci		v |= dco << __ffs(dd->dco_mask);
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci	if (dd->sddiv_mask) {
42762306a36Sopenharmony_ci		_lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
42862306a36Sopenharmony_ci			      dd->last_rounded_n);
42962306a36Sopenharmony_ci		v &= ~(dd->sddiv_mask);
43062306a36Sopenharmony_ci		v |= sd_div << __ffs(dd->sddiv_mask);
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/*
43462306a36Sopenharmony_ci	 * Errata i810 - DPLL controller can get stuck while transitioning
43562306a36Sopenharmony_ci	 * to a power saving state. Software must ensure the DPLL can not
43662306a36Sopenharmony_ci	 * transition to a low power state while changing M/N values.
43762306a36Sopenharmony_ci	 * Easiest way to accomplish this is to prevent DPLL autoidle
43862306a36Sopenharmony_ci	 * before doing the M/N re-program.
43962306a36Sopenharmony_ci	 */
44062306a36Sopenharmony_ci	errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (errata_i810) {
44362306a36Sopenharmony_ci		ai = omap3_dpll_autoidle_read(clk);
44462306a36Sopenharmony_ci		if (ai) {
44562306a36Sopenharmony_ci			omap3_dpll_deny_idle(clk);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci			/* OCP barrier */
44862306a36Sopenharmony_ci			omap3_dpll_autoidle_read(clk);
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Set 4X multiplier and low-power mode */
45562306a36Sopenharmony_ci	if (dd->m4xen_mask || dd->lpmode_mask) {
45662306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		if (dd->m4xen_mask) {
45962306a36Sopenharmony_ci			if (dd->last_rounded_m4xen)
46062306a36Sopenharmony_ci				v |= dd->m4xen_mask;
46162306a36Sopenharmony_ci			else
46262306a36Sopenharmony_ci				v &= ~dd->m4xen_mask;
46362306a36Sopenharmony_ci		}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (dd->lpmode_mask) {
46662306a36Sopenharmony_ci			if (dd->last_rounded_lpmode)
46762306a36Sopenharmony_ci				v |= dd->lpmode_mask;
46862306a36Sopenharmony_ci			else
46962306a36Sopenharmony_ci				v &= ~dd->lpmode_mask;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		ti_clk_ll_ops->clk_writel(v, &dd->control_reg);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (dd->ssc_enable_mask)
47662306a36Sopenharmony_ci		omap3_noncore_dpll_ssc_program(clk);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/* We let the clock framework set the other output dividers later */
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* REVISIT: Set ramp-up delay? */
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	_omap3_noncore_dpll_lock(clk);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (errata_i810 && ai)
48562306a36Sopenharmony_ci		omap3_dpll_allow_idle(clk);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return 0;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/* Public functions */
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/**
49362306a36Sopenharmony_ci * omap3_dpll_recalc - recalculate DPLL rate
49462306a36Sopenharmony_ci * @hw: struct clk_hw containing the DPLL struct clk
49562306a36Sopenharmony_ci * @parent_rate: clock rate of the DPLL parent
49662306a36Sopenharmony_ci *
49762306a36Sopenharmony_ci * Recalculate and propagate the DPLL rate.
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_ciunsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	return omap2_get_dpll_rate(clk);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/**
50962306a36Sopenharmony_ci * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
51062306a36Sopenharmony_ci * @hw: struct clk_hw containing then pointer to a DPLL struct clk
51162306a36Sopenharmony_ci *
51262306a36Sopenharmony_ci * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
51362306a36Sopenharmony_ci * The choice of modes depends on the DPLL's programmed rate: if it is
51462306a36Sopenharmony_ci * the same as the DPLL's parent clock, it will enter bypass;
51562306a36Sopenharmony_ci * otherwise, it will enter lock.  This code will wait for the DPLL to
51662306a36Sopenharmony_ci * indicate readiness before returning, unless the DPLL takes too long
51762306a36Sopenharmony_ci * to enter the target state.  Intended to be used as the struct clk's
51862306a36Sopenharmony_ci * enable function.  If DPLL3 was passed in, or the DPLL does not
51962306a36Sopenharmony_ci * support low-power stop, or if the DPLL took too long to enter
52062306a36Sopenharmony_ci * bypass or lock, return -EINVAL; otherwise, return 0.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_ciint omap3_noncore_dpll_enable(struct clk_hw *hw)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
52562306a36Sopenharmony_ci	int r;
52662306a36Sopenharmony_ci	struct dpll_data *dd;
52762306a36Sopenharmony_ci	struct clk_hw *parent;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	dd = clk->dpll_data;
53062306a36Sopenharmony_ci	if (!dd)
53162306a36Sopenharmony_ci		return -EINVAL;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (clk->clkdm) {
53462306a36Sopenharmony_ci		r = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
53562306a36Sopenharmony_ci		if (r) {
53662306a36Sopenharmony_ci			WARN(1,
53762306a36Sopenharmony_ci			     "%s: could not enable %s's clockdomain %s: %d\n",
53862306a36Sopenharmony_ci			     __func__, clk_hw_get_name(hw),
53962306a36Sopenharmony_ci			     clk->clkdm_name, r);
54062306a36Sopenharmony_ci			return r;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	parent = clk_hw_get_parent(hw);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (clk_hw_get_rate(hw) == clk_hw_get_rate(dd->clk_bypass)) {
54762306a36Sopenharmony_ci		WARN_ON(parent != dd->clk_bypass);
54862306a36Sopenharmony_ci		r = _omap3_noncore_dpll_bypass(clk);
54962306a36Sopenharmony_ci	} else {
55062306a36Sopenharmony_ci		WARN_ON(parent != dd->clk_ref);
55162306a36Sopenharmony_ci		r = _omap3_noncore_dpll_lock(clk);
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return r;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/**
55862306a36Sopenharmony_ci * omap3_noncore_dpll_disable - instruct a DPLL to enter low-power stop
55962306a36Sopenharmony_ci * @hw: struct clk_hw containing then pointer to a DPLL struct clk
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * Instructs a non-CORE DPLL to enter low-power stop.  This function is
56262306a36Sopenharmony_ci * intended for use in struct clkops.  No return value.
56362306a36Sopenharmony_ci */
56462306a36Sopenharmony_civoid omap3_noncore_dpll_disable(struct clk_hw *hw)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	_omap3_noncore_dpll_stop(clk);
56962306a36Sopenharmony_ci	if (clk->clkdm)
57062306a36Sopenharmony_ci		ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/* Non-CORE DPLL rate set code */
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/**
57662306a36Sopenharmony_ci * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
57762306a36Sopenharmony_ci * @hw: pointer to the clock to determine rate for
57862306a36Sopenharmony_ci * @req: target rate request
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * Determines which DPLL mode to use for reaching a desired target rate.
58162306a36Sopenharmony_ci * Checks whether the DPLL shall be in bypass or locked mode, and if
58262306a36Sopenharmony_ci * locked, calculates the M,N values for the DPLL via round-rate.
58362306a36Sopenharmony_ci * Returns a 0 on success, negative error value in failure.
58462306a36Sopenharmony_ci */
58562306a36Sopenharmony_ciint omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
58662306a36Sopenharmony_ci				      struct clk_rate_request *req)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
58962306a36Sopenharmony_ci	struct dpll_data *dd;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (!req->rate)
59262306a36Sopenharmony_ci		return -EINVAL;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	dd = clk->dpll_data;
59562306a36Sopenharmony_ci	if (!dd)
59662306a36Sopenharmony_ci		return -EINVAL;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (clk_hw_get_rate(dd->clk_bypass) == req->rate &&
59962306a36Sopenharmony_ci	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
60062306a36Sopenharmony_ci		req->best_parent_hw = dd->clk_bypass;
60162306a36Sopenharmony_ci	} else {
60262306a36Sopenharmony_ci		req->rate = omap2_dpll_round_rate(hw, req->rate,
60362306a36Sopenharmony_ci					  &req->best_parent_rate);
60462306a36Sopenharmony_ci		req->best_parent_hw = dd->clk_ref;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	req->best_parent_rate = req->rate;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return 0;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci/**
61362306a36Sopenharmony_ci * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
61462306a36Sopenharmony_ci * @hw: pointer to the clock to set parent for
61562306a36Sopenharmony_ci * @index: parent index to select
61662306a36Sopenharmony_ci *
61762306a36Sopenharmony_ci * Sets parent for a DPLL clock. This sets the DPLL into bypass or
61862306a36Sopenharmony_ci * locked mode. Returns 0 with success, negative error value otherwise.
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_ciint omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
62362306a36Sopenharmony_ci	int ret;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (!hw)
62662306a36Sopenharmony_ci		return -EINVAL;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (index)
62962306a36Sopenharmony_ci		ret = _omap3_noncore_dpll_bypass(clk);
63062306a36Sopenharmony_ci	else
63162306a36Sopenharmony_ci		ret = _omap3_noncore_dpll_lock(clk);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return ret;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/**
63762306a36Sopenharmony_ci * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
63862306a36Sopenharmony_ci * @hw: pointer to the clock to set parent for
63962306a36Sopenharmony_ci * @rate: target rate for the clock
64062306a36Sopenharmony_ci * @parent_rate: rate of the parent clock
64162306a36Sopenharmony_ci *
64262306a36Sopenharmony_ci * Sets rate for a DPLL clock. First checks if the clock parent is
64362306a36Sopenharmony_ci * reference clock (in bypass mode, the rate of the clock can't be
64462306a36Sopenharmony_ci * changed) and proceeds with the rate change operation. Returns 0
64562306a36Sopenharmony_ci * with success, negative error value otherwise.
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_ciint omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
64862306a36Sopenharmony_ci				unsigned long parent_rate)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
65162306a36Sopenharmony_ci	struct dpll_data *dd;
65262306a36Sopenharmony_ci	u16 freqsel = 0;
65362306a36Sopenharmony_ci	int ret;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (!hw || !rate)
65662306a36Sopenharmony_ci		return -EINVAL;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	dd = clk->dpll_data;
65962306a36Sopenharmony_ci	if (!dd)
66062306a36Sopenharmony_ci		return -EINVAL;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (clk_hw_get_parent(hw) != dd->clk_ref)
66362306a36Sopenharmony_ci		return -EINVAL;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (dd->last_rounded_rate == 0)
66662306a36Sopenharmony_ci		return -EINVAL;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Freqsel is available only on OMAP343X devices */
66962306a36Sopenharmony_ci	if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) {
67062306a36Sopenharmony_ci		freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
67162306a36Sopenharmony_ci		WARN_ON(!freqsel);
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
67562306a36Sopenharmony_ci		 clk_hw_get_name(hw), rate);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	ret = omap3_noncore_dpll_program(clk, freqsel);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return ret;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/**
68362306a36Sopenharmony_ci * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
68462306a36Sopenharmony_ci * @hw: pointer to the clock to set rate and parent for
68562306a36Sopenharmony_ci * @rate: target rate for the DPLL
68662306a36Sopenharmony_ci * @parent_rate: clock rate of the DPLL parent
68762306a36Sopenharmony_ci * @index: new parent index for the DPLL, 0 - reference, 1 - bypass
68862306a36Sopenharmony_ci *
68962306a36Sopenharmony_ci * Sets rate and parent for a DPLL clock. If new parent is the bypass
69062306a36Sopenharmony_ci * clock, only selects the parent. Otherwise proceeds with a rate
69162306a36Sopenharmony_ci * change, as this will effectively also change the parent as the
69262306a36Sopenharmony_ci * DPLL is put into locked mode. Returns 0 with success, negative error
69362306a36Sopenharmony_ci * value otherwise.
69462306a36Sopenharmony_ci */
69562306a36Sopenharmony_ciint omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
69662306a36Sopenharmony_ci					   unsigned long rate,
69762306a36Sopenharmony_ci					   unsigned long parent_rate,
69862306a36Sopenharmony_ci					   u8 index)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	int ret;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (!hw || !rate)
70362306a36Sopenharmony_ci		return -EINVAL;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/*
70662306a36Sopenharmony_ci	 * clk-ref at index[0], in which case we only need to set rate,
70762306a36Sopenharmony_ci	 * the parent will be changed automatically with the lock sequence.
70862306a36Sopenharmony_ci	 * With clk-bypass case we only need to change parent.
70962306a36Sopenharmony_ci	 */
71062306a36Sopenharmony_ci	if (index)
71162306a36Sopenharmony_ci		ret = omap3_noncore_dpll_set_parent(hw, index);
71262306a36Sopenharmony_ci	else
71362306a36Sopenharmony_ci		ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return ret;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci/* DPLL autoidle read/set code */
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/**
72162306a36Sopenharmony_ci * omap3_dpll_autoidle_read - read a DPLL's autoidle bits
72262306a36Sopenharmony_ci * @clk: struct clk * of the DPLL to read
72362306a36Sopenharmony_ci *
72462306a36Sopenharmony_ci * Return the DPLL's autoidle bits, shifted down to bit 0.  Returns
72562306a36Sopenharmony_ci * -EINVAL if passed a null pointer or if the struct clk does not
72662306a36Sopenharmony_ci * appear to refer to a DPLL.
72762306a36Sopenharmony_ci */
72862306a36Sopenharmony_cistatic u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	const struct dpll_data *dd;
73162306a36Sopenharmony_ci	u32 v;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (!clk || !clk->dpll_data)
73462306a36Sopenharmony_ci		return -EINVAL;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	dd = clk->dpll_data;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (!dd->autoidle_mask)
73962306a36Sopenharmony_ci		return -EINVAL;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->autoidle_reg);
74262306a36Sopenharmony_ci	v &= dd->autoidle_mask;
74362306a36Sopenharmony_ci	v >>= __ffs(dd->autoidle_mask);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return v;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/**
74962306a36Sopenharmony_ci * omap3_dpll_allow_idle - enable DPLL autoidle bits
75062306a36Sopenharmony_ci * @clk: struct clk * of the DPLL to operate on
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci * Enable DPLL automatic idle control.  This automatic idle mode
75362306a36Sopenharmony_ci * switching takes effect only when the DPLL is locked, at least on
75462306a36Sopenharmony_ci * OMAP3430.  The DPLL will enter low-power stop when its downstream
75562306a36Sopenharmony_ci * clocks are gated.  No return value.
75662306a36Sopenharmony_ci */
75762306a36Sopenharmony_cistatic void omap3_dpll_allow_idle(struct clk_hw_omap *clk)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	const struct dpll_data *dd;
76062306a36Sopenharmony_ci	u32 v;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (!clk || !clk->dpll_data)
76362306a36Sopenharmony_ci		return;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	dd = clk->dpll_data;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (!dd->autoidle_mask)
76862306a36Sopenharmony_ci		return;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/*
77162306a36Sopenharmony_ci	 * REVISIT: CORE DPLL can optionally enter low-power bypass
77262306a36Sopenharmony_ci	 * by writing 0x5 instead of 0x1.  Add some mechanism to
77362306a36Sopenharmony_ci	 * optionally enter this mode.
77462306a36Sopenharmony_ci	 */
77562306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->autoidle_reg);
77662306a36Sopenharmony_ci	v &= ~dd->autoidle_mask;
77762306a36Sopenharmony_ci	v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
77862306a36Sopenharmony_ci	ti_clk_ll_ops->clk_writel(v, &dd->autoidle_reg);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/**
78262306a36Sopenharmony_ci * omap3_dpll_deny_idle - prevent DPLL from automatically idling
78362306a36Sopenharmony_ci * @clk: struct clk * of the DPLL to operate on
78462306a36Sopenharmony_ci *
78562306a36Sopenharmony_ci * Disable DPLL automatic idle control.  No return value.
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_cistatic void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	const struct dpll_data *dd;
79062306a36Sopenharmony_ci	u32 v;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (!clk || !clk->dpll_data)
79362306a36Sopenharmony_ci		return;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	dd = clk->dpll_data;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (!dd->autoidle_mask)
79862306a36Sopenharmony_ci		return;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->autoidle_reg);
80162306a36Sopenharmony_ci	v &= ~dd->autoidle_mask;
80262306a36Sopenharmony_ci	v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
80362306a36Sopenharmony_ci	ti_clk_ll_ops->clk_writel(v, &dd->autoidle_reg);
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci/* Clock control for DPLL outputs */
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci/* Find the parent DPLL for the given clkoutx2 clock */
80962306a36Sopenharmony_cistatic struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct clk_hw_omap *pclk = NULL;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	/* Walk up the parents of clk, looking for a DPLL */
81462306a36Sopenharmony_ci	do {
81562306a36Sopenharmony_ci		do {
81662306a36Sopenharmony_ci			hw = clk_hw_get_parent(hw);
81762306a36Sopenharmony_ci		} while (hw && (!omap2_clk_is_hw_omap(hw)));
81862306a36Sopenharmony_ci		if (!hw)
81962306a36Sopenharmony_ci			break;
82062306a36Sopenharmony_ci		pclk = to_clk_hw_omap(hw);
82162306a36Sopenharmony_ci	} while (pclk && !pclk->dpll_data);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* clk does not have a DPLL as a parent?  error in the clock data */
82462306a36Sopenharmony_ci	if (!pclk) {
82562306a36Sopenharmony_ci		WARN_ON(1);
82662306a36Sopenharmony_ci		return NULL;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	return pclk;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci/**
83362306a36Sopenharmony_ci * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
83462306a36Sopenharmony_ci * @hw: pointer  struct clk_hw
83562306a36Sopenharmony_ci * @parent_rate: clock rate of the DPLL parent
83662306a36Sopenharmony_ci *
83762306a36Sopenharmony_ci * Using parent clock DPLL data, look up DPLL state.  If locked, set our
83862306a36Sopenharmony_ci * rate to the dpll_clk * 2; otherwise, just use dpll_clk.
83962306a36Sopenharmony_ci */
84062306a36Sopenharmony_ciunsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
84162306a36Sopenharmony_ci				    unsigned long parent_rate)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	const struct dpll_data *dd;
84462306a36Sopenharmony_ci	unsigned long rate;
84562306a36Sopenharmony_ci	u32 v;
84662306a36Sopenharmony_ci	struct clk_hw_omap *pclk = NULL;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (!parent_rate)
84962306a36Sopenharmony_ci		return 0;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	pclk = omap3_find_clkoutx2_dpll(hw);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (!pclk)
85462306a36Sopenharmony_ci		return 0;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	dd = pclk->dpll_data;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	WARN_ON(!dd->enable_mask);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg) & dd->enable_mask;
86162306a36Sopenharmony_ci	v >>= __ffs(dd->enable_mask);
86262306a36Sopenharmony_ci	if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
86362306a36Sopenharmony_ci		rate = parent_rate;
86462306a36Sopenharmony_ci	else
86562306a36Sopenharmony_ci		rate = parent_rate * 2;
86662306a36Sopenharmony_ci	return rate;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci/**
87062306a36Sopenharmony_ci * omap3_core_dpll_save_context - Save the m and n values of the divider
87162306a36Sopenharmony_ci * @hw: pointer  struct clk_hw
87262306a36Sopenharmony_ci *
87362306a36Sopenharmony_ci * Before the dpll registers are lost save the last rounded rate m and n
87462306a36Sopenharmony_ci * and the enable mask.
87562306a36Sopenharmony_ci */
87662306a36Sopenharmony_ciint omap3_core_dpll_save_context(struct clk_hw *hw)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
87962306a36Sopenharmony_ci	struct dpll_data *dd;
88062306a36Sopenharmony_ci	u32 v;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	dd = clk->dpll_data;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
88562306a36Sopenharmony_ci	clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (clk->context == DPLL_LOCKED) {
88862306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
88962306a36Sopenharmony_ci		dd->last_rounded_m = (v & dd->mult_mask) >>
89062306a36Sopenharmony_ci						__ffs(dd->mult_mask);
89162306a36Sopenharmony_ci		dd->last_rounded_n = ((v & dd->div1_mask) >>
89262306a36Sopenharmony_ci						__ffs(dd->div1_mask)) + 1;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return 0;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci/**
89962306a36Sopenharmony_ci * omap3_core_dpll_restore_context - restore the m and n values of the divider
90062306a36Sopenharmony_ci * @hw: pointer  struct clk_hw
90162306a36Sopenharmony_ci *
90262306a36Sopenharmony_ci * Restore the last rounded rate m and n
90362306a36Sopenharmony_ci * and the enable mask.
90462306a36Sopenharmony_ci */
90562306a36Sopenharmony_civoid omap3_core_dpll_restore_context(struct clk_hw *hw)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
90862306a36Sopenharmony_ci	const struct dpll_data *dd;
90962306a36Sopenharmony_ci	u32 v;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	dd = clk->dpll_data;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (clk->context == DPLL_LOCKED) {
91462306a36Sopenharmony_ci		_omap3_dpll_write_clken(clk, 0x4);
91562306a36Sopenharmony_ci		_omap3_wait_dpll_status(clk, 0);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
91862306a36Sopenharmony_ci		v &= ~(dd->mult_mask | dd->div1_mask);
91962306a36Sopenharmony_ci		v |= dd->last_rounded_m << __ffs(dd->mult_mask);
92062306a36Sopenharmony_ci		v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
92162306a36Sopenharmony_ci		ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		_omap3_dpll_write_clken(clk, DPLL_LOCKED);
92462306a36Sopenharmony_ci		_omap3_wait_dpll_status(clk, 1);
92562306a36Sopenharmony_ci	} else {
92662306a36Sopenharmony_ci		_omap3_dpll_write_clken(clk, clk->context);
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci/**
93162306a36Sopenharmony_ci * omap3_non_core_dpll_save_context - Save the m and n values of the divider
93262306a36Sopenharmony_ci * @hw: pointer  struct clk_hw
93362306a36Sopenharmony_ci *
93462306a36Sopenharmony_ci * Before the dpll registers are lost save the last rounded rate m and n
93562306a36Sopenharmony_ci * and the enable mask.
93662306a36Sopenharmony_ci */
93762306a36Sopenharmony_ciint omap3_noncore_dpll_save_context(struct clk_hw *hw)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
94062306a36Sopenharmony_ci	struct dpll_data *dd;
94162306a36Sopenharmony_ci	u32 v;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	dd = clk->dpll_data;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
94662306a36Sopenharmony_ci	clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (clk->context == DPLL_LOCKED) {
94962306a36Sopenharmony_ci		v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
95062306a36Sopenharmony_ci		dd->last_rounded_m = (v & dd->mult_mask) >>
95162306a36Sopenharmony_ci						__ffs(dd->mult_mask);
95262306a36Sopenharmony_ci		dd->last_rounded_n = ((v & dd->div1_mask) >>
95362306a36Sopenharmony_ci						__ffs(dd->div1_mask)) + 1;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return 0;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci/**
96062306a36Sopenharmony_ci * omap3_core_dpll_restore_context - restore the m and n values of the divider
96162306a36Sopenharmony_ci * @hw: pointer  struct clk_hw
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci * Restore the last rounded rate m and n
96462306a36Sopenharmony_ci * and the enable mask.
96562306a36Sopenharmony_ci */
96662306a36Sopenharmony_civoid omap3_noncore_dpll_restore_context(struct clk_hw *hw)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
96962306a36Sopenharmony_ci	const struct dpll_data *dd;
97062306a36Sopenharmony_ci	u32 ctrl, mult_div1;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	dd = clk->dpll_data;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg);
97562306a36Sopenharmony_ci	mult_div1 = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (clk->context == ((ctrl & dd->enable_mask) >>
97862306a36Sopenharmony_ci			     __ffs(dd->enable_mask)) &&
97962306a36Sopenharmony_ci	    dd->last_rounded_m == ((mult_div1 & dd->mult_mask) >>
98062306a36Sopenharmony_ci				   __ffs(dd->mult_mask)) &&
98162306a36Sopenharmony_ci	    dd->last_rounded_n == ((mult_div1 & dd->div1_mask) >>
98262306a36Sopenharmony_ci				   __ffs(dd->div1_mask)) + 1) {
98362306a36Sopenharmony_ci		/* nothing to be done */
98462306a36Sopenharmony_ci		return;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	if (clk->context == DPLL_LOCKED)
98862306a36Sopenharmony_ci		omap3_noncore_dpll_program(clk, 0);
98962306a36Sopenharmony_ci	else
99062306a36Sopenharmony_ci		_omap3_dpll_write_clken(clk, clk->context);
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/* OMAP3/4 non-CORE DPLL clkops */
99462306a36Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_omap3_dpll = {
99562306a36Sopenharmony_ci	.allow_idle	= omap3_dpll_allow_idle,
99662306a36Sopenharmony_ci	.deny_idle	= omap3_dpll_deny_idle,
99762306a36Sopenharmony_ci};
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci/**
100062306a36Sopenharmony_ci * omap3_dpll4_set_rate - set rate for omap3 per-dpll
100162306a36Sopenharmony_ci * @hw: clock to change
100262306a36Sopenharmony_ci * @rate: target rate for clock
100362306a36Sopenharmony_ci * @parent_rate: clock rate of the DPLL parent
100462306a36Sopenharmony_ci *
100562306a36Sopenharmony_ci * Check if the current SoC supports the per-dpll reprogram operation
100662306a36Sopenharmony_ci * or not, and then do the rate change if supported. Returns -EINVAL
100762306a36Sopenharmony_ci * if not supported, 0 for success, and potential error codes from the
100862306a36Sopenharmony_ci * clock rate change.
100962306a36Sopenharmony_ci */
101062306a36Sopenharmony_ciint omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
101162306a36Sopenharmony_ci			 unsigned long parent_rate)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * According to the 12-5 CDP code from TI, "Limitation 2.5"
101562306a36Sopenharmony_ci	 * on 3430ES1 prevents us from changing DPLL multipliers or dividers
101662306a36Sopenharmony_ci	 * on DPLL4.
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
101962306a36Sopenharmony_ci		pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
102062306a36Sopenharmony_ci		return -EINVAL;
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci/**
102762306a36Sopenharmony_ci * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
102862306a36Sopenharmony_ci * @hw: clock to change
102962306a36Sopenharmony_ci * @rate: target rate for clock
103062306a36Sopenharmony_ci * @parent_rate: rate of the parent clock
103162306a36Sopenharmony_ci * @index: parent index, 0 - reference clock, 1 - bypass clock
103262306a36Sopenharmony_ci *
103362306a36Sopenharmony_ci * Check if the current SoC support the per-dpll reprogram operation
103462306a36Sopenharmony_ci * or not, and then do the rate + parent change if supported. Returns
103562306a36Sopenharmony_ci * -EINVAL if not supported, 0 for success, and potential error codes
103662306a36Sopenharmony_ci * from the clock rate change.
103762306a36Sopenharmony_ci */
103862306a36Sopenharmony_ciint omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
103962306a36Sopenharmony_ci				    unsigned long parent_rate, u8 index)
104062306a36Sopenharmony_ci{
104162306a36Sopenharmony_ci	if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
104262306a36Sopenharmony_ci		pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
104362306a36Sopenharmony_ci		return -EINVAL;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
104762306a36Sopenharmony_ci						      index);
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci/* Apply DM3730 errata sprz319 advisory 2.1. */
105162306a36Sopenharmony_cistatic bool omap3_dpll5_apply_errata(struct clk_hw *hw,
105262306a36Sopenharmony_ci				     unsigned long parent_rate)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct omap3_dpll5_settings {
105562306a36Sopenharmony_ci		unsigned int rate, m, n;
105662306a36Sopenharmony_ci	};
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	static const struct omap3_dpll5_settings precomputed[] = {
105962306a36Sopenharmony_ci		/*
106062306a36Sopenharmony_ci		 * From DM3730 errata advisory 2.1, table 35 and 36.
106162306a36Sopenharmony_ci		 * The N value is increased by 1 compared to the tables as the
106262306a36Sopenharmony_ci		 * errata lists register values while last_rounded_field is the
106362306a36Sopenharmony_ci		 * real divider value.
106462306a36Sopenharmony_ci		 */
106562306a36Sopenharmony_ci		{ 12000000,  80,  0 + 1 },
106662306a36Sopenharmony_ci		{ 13000000, 443,  5 + 1 },
106762306a36Sopenharmony_ci		{ 19200000,  50,  0 + 1 },
106862306a36Sopenharmony_ci		{ 26000000, 443, 11 + 1 },
106962306a36Sopenharmony_ci		{ 38400000,  25,  0 + 1 }
107062306a36Sopenharmony_ci	};
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	const struct omap3_dpll5_settings *d;
107362306a36Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
107462306a36Sopenharmony_ci	struct dpll_data *dd;
107562306a36Sopenharmony_ci	unsigned int i;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(precomputed); ++i) {
107862306a36Sopenharmony_ci		if (parent_rate == precomputed[i].rate)
107962306a36Sopenharmony_ci			break;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (i == ARRAY_SIZE(precomputed))
108362306a36Sopenharmony_ci		return false;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	d = &precomputed[i];
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	/* Update the M, N and rounded rate values and program the DPLL. */
108862306a36Sopenharmony_ci	dd = clk->dpll_data;
108962306a36Sopenharmony_ci	dd->last_rounded_m = d->m;
109062306a36Sopenharmony_ci	dd->last_rounded_n = d->n;
109162306a36Sopenharmony_ci	dd->last_rounded_rate = div_u64((u64)parent_rate * d->m, d->n);
109262306a36Sopenharmony_ci	omap3_noncore_dpll_program(clk, 0);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return true;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci/**
109862306a36Sopenharmony_ci * omap3_dpll5_set_rate - set rate for omap3 dpll5
109962306a36Sopenharmony_ci * @hw: clock to change
110062306a36Sopenharmony_ci * @rate: target rate for clock
110162306a36Sopenharmony_ci * @parent_rate: rate of the parent clock
110262306a36Sopenharmony_ci *
110362306a36Sopenharmony_ci * Set rate for the DPLL5 clock. Apply the sprz319 advisory 2.1 on OMAP36xx if
110462306a36Sopenharmony_ci * the DPLL is used for USB host (detected through the requested rate).
110562306a36Sopenharmony_ci */
110662306a36Sopenharmony_ciint omap3_dpll5_set_rate(struct clk_hw *hw, unsigned long rate,
110762306a36Sopenharmony_ci			 unsigned long parent_rate)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	if (rate == OMAP3_DPLL5_FREQ_FOR_USBHOST * 8) {
111062306a36Sopenharmony_ci		if (omap3_dpll5_apply_errata(hw, parent_rate))
111162306a36Sopenharmony_ci			return 0;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
111562306a36Sopenharmony_ci}
1116