brintos

brintos / linux-shallow public Read only

0
0
Text · 21.3 KiB · fda0411 Raw
790 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 *  Copyright (C) 2019 Microchip Technology Inc.4 *5 */6 7#include <linux/bitfield.h>8#include <linux/clk.h>9#include <linux/clk-provider.h>10#include <linux/clkdev.h>11#include <linux/clk/at91_pmc.h>12#include <linux/of.h>13#include <linux/mfd/syscon.h>14#include <linux/regmap.h>15 16#include "pmc.h"17 18#define	PMC_PLL_CTRL0_DIV_MSK	GENMASK(7, 0)19#define	PMC_PLL_CTRL1_MUL_MSK	GENMASK(31, 24)20#define	PMC_PLL_CTRL1_FRACR_MSK	GENMASK(21, 0)21 22#define PLL_DIV_MAX		(FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)23#define UPLL_DIV		224#define PLL_MUL_MAX		(FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)25 26#define PLL_MAX_ID		727 28struct sam9x60_pll_core {29	struct regmap *regmap;30	spinlock_t *lock;31	const struct clk_pll_characteristics *characteristics;32	const struct clk_pll_layout *layout;33	struct clk_hw hw;34	u8 id;35};36 37struct sam9x60_frac {38	struct sam9x60_pll_core core;39	struct at91_clk_pms pms;40	u32 frac;41	u16 mul;42};43 44struct sam9x60_div {45	struct sam9x60_pll_core core;46	struct at91_clk_pms pms;47	u8 div;48	u8 safe_div;49};50 51#define to_sam9x60_pll_core(hw)	container_of(hw, struct sam9x60_pll_core, hw)52#define to_sam9x60_frac(core)	container_of(core, struct sam9x60_frac, core)53#define to_sam9x60_div(core)	container_of(core, struct sam9x60_div, core)54 55static struct sam9x60_div *notifier_div;56 57static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)58{59	unsigned int status;60 61	regmap_read(regmap, AT91_PMC_PLL_ISR0, &status);62 63	return !!(status & BIT(id));64}65 66static bool sam9x60_frac_pll_ready(struct regmap *regmap, u8 id)67{68	return sam9x60_pll_ready(regmap, id);69}70 71static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,72						  unsigned long parent_rate)73{74	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);75	struct sam9x60_frac *frac = to_sam9x60_frac(core);76	unsigned long freq;77 78	freq = parent_rate * (frac->mul + 1) +79		DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));80 81	if (core->layout->div2)82		freq >>= 1;83 84	return freq;85}86 87static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)88{89	struct sam9x60_frac *frac = to_sam9x60_frac(core);90	struct regmap *regmap = core->regmap;91	unsigned int val, cfrac, cmul;92	unsigned long flags;93 94	spin_lock_irqsave(core->lock, flags);95 96	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,97			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);98	regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);99	cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;100	cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;101 102	if (sam9x60_frac_pll_ready(regmap, core->id) &&103	    (cmul == frac->mul && cfrac == frac->frac))104		goto unlock;105 106	/* Recommended value for PMC_PLL_ACR */107	if (core->characteristics->upll)108		val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;109	else110		val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;111	regmap_write(regmap, AT91_PMC_PLL_ACR, val);112 113	regmap_write(regmap, AT91_PMC_PLL_CTRL1,114		     (frac->mul << core->layout->mul_shift) |115		     (frac->frac << core->layout->frac_shift));116 117	if (core->characteristics->upll) {118		/* Enable the UTMI internal bandgap */119		val |= AT91_PMC_PLL_ACR_UTMIBG;120		regmap_write(regmap, AT91_PMC_PLL_ACR, val);121 122		udelay(10);123 124		/* Enable the UTMI internal regulator */125		val |= AT91_PMC_PLL_ACR_UTMIVR;126		regmap_write(regmap, AT91_PMC_PLL_ACR, val);127 128		udelay(10);129	}130 131	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,132			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,133			   AT91_PMC_PLL_UPDT_UPDATE | core->id);134 135	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,136			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,137			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);138 139	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,140			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,141			   AT91_PMC_PLL_UPDT_UPDATE | core->id);142 143	while (!sam9x60_pll_ready(regmap, core->id))144		cpu_relax();145 146unlock:147	spin_unlock_irqrestore(core->lock, flags);148 149	return 0;150}151 152static int sam9x60_frac_pll_prepare(struct clk_hw *hw)153{154	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);155 156	return sam9x60_frac_pll_set(core);157}158 159static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)160{161	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);162	struct regmap *regmap = core->regmap;163	unsigned long flags;164 165	spin_lock_irqsave(core->lock, flags);166 167	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,168			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);169 170	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0);171 172	if (core->characteristics->upll)173		regmap_update_bits(regmap, AT91_PMC_PLL_ACR,174				   AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0);175 176	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,177			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,178			   AT91_PMC_PLL_UPDT_UPDATE | core->id);179 180	spin_unlock_irqrestore(core->lock, flags);181}182 183static int sam9x60_frac_pll_is_prepared(struct clk_hw *hw)184{185	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);186 187	return sam9x60_pll_ready(core->regmap, core->id);188}189 190static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,191					      unsigned long rate,192					      unsigned long parent_rate,193					      bool update)194{195	struct sam9x60_frac *frac = to_sam9x60_frac(core);196	unsigned long tmprate, remainder;197	unsigned long nmul = 0;198	unsigned long nfrac = 0;199 200	if (rate < core->characteristics->core_output[0].min ||201	    rate > core->characteristics->core_output[0].max)202		return -ERANGE;203 204	/*205	 * Calculate the multiplier associated with the current206	 * divider that provide the closest rate to the requested one.207	 */208	nmul = mult_frac(rate, 1, parent_rate);209	tmprate = mult_frac(parent_rate, nmul, 1);210	remainder = rate - tmprate;211 212	if (remainder) {213		nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),214					      parent_rate);215 216		tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,217						 (1 << 22));218	}219 220	/* Check if resulted rate is a valid.  */221	if (tmprate < core->characteristics->core_output[0].min ||222	    tmprate > core->characteristics->core_output[0].max)223		return -ERANGE;224 225	if (update) {226		frac->mul = nmul - 1;227		frac->frac = nfrac;228	}229 230	return tmprate;231}232 233static long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate,234					unsigned long *parent_rate)235{236	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);237 238	return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false);239}240 241static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,242				     unsigned long parent_rate)243{244	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);245 246	return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);247}248 249static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,250					 unsigned long parent_rate)251{252	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);253	struct sam9x60_frac *frac = to_sam9x60_frac(core);254	struct regmap *regmap = core->regmap;255	unsigned long irqflags;256	unsigned int val, cfrac, cmul;257	long ret;258 259	ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);260	if (ret <= 0)261		return ret;262 263	spin_lock_irqsave(core->lock, irqflags);264 265	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,266			   core->id);267	regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);268	cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;269	cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;270 271	if (cmul == frac->mul && cfrac == frac->frac)272		goto unlock;273 274	regmap_write(regmap, AT91_PMC_PLL_CTRL1,275		     (frac->mul << core->layout->mul_shift) |276		     (frac->frac << core->layout->frac_shift));277 278	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,279			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,280			   AT91_PMC_PLL_UPDT_UPDATE | core->id);281 282	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,283			   AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,284			   AT91_PMC_PLL_CTRL0_ENLOCK |285			   AT91_PMC_PLL_CTRL0_ENPLL);286 287	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,288			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,289			   AT91_PMC_PLL_UPDT_UPDATE | core->id);290 291	while (!sam9x60_pll_ready(regmap, core->id))292		cpu_relax();293 294unlock:295	spin_unlock_irqrestore(core->lock, irqflags);296 297	return ret;298}299 300static int sam9x60_frac_pll_save_context(struct clk_hw *hw)301{302	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);303	struct sam9x60_frac *frac = to_sam9x60_frac(core);304 305	frac->pms.status = sam9x60_pll_ready(core->regmap, core->id);306 307	return 0;308}309 310static void sam9x60_frac_pll_restore_context(struct clk_hw *hw)311{312	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);313	struct sam9x60_frac *frac = to_sam9x60_frac(core);314 315	if (frac->pms.status)316		sam9x60_frac_pll_set(core);317}318 319static const struct clk_ops sam9x60_frac_pll_ops = {320	.prepare = sam9x60_frac_pll_prepare,321	.unprepare = sam9x60_frac_pll_unprepare,322	.is_prepared = sam9x60_frac_pll_is_prepared,323	.recalc_rate = sam9x60_frac_pll_recalc_rate,324	.round_rate = sam9x60_frac_pll_round_rate,325	.set_rate = sam9x60_frac_pll_set_rate,326	.save_context = sam9x60_frac_pll_save_context,327	.restore_context = sam9x60_frac_pll_restore_context,328};329 330static const struct clk_ops sam9x60_frac_pll_ops_chg = {331	.prepare = sam9x60_frac_pll_prepare,332	.unprepare = sam9x60_frac_pll_unprepare,333	.is_prepared = sam9x60_frac_pll_is_prepared,334	.recalc_rate = sam9x60_frac_pll_recalc_rate,335	.round_rate = sam9x60_frac_pll_round_rate,336	.set_rate = sam9x60_frac_pll_set_rate_chg,337	.save_context = sam9x60_frac_pll_save_context,338	.restore_context = sam9x60_frac_pll_restore_context,339};340 341/* This function should be called with spinlock acquired. */342static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div,343				    bool enable)344{345	struct regmap *regmap = core->regmap;346	u32 ena_msk = enable ? core->layout->endiv_mask : 0;347	u32 ena_val = enable ? (1 << core->layout->endiv_shift) : 0;348 349	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,350			   core->layout->div_mask | ena_msk,351			   (div << core->layout->div_shift) | ena_val);352 353	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,354			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,355			   AT91_PMC_PLL_UPDT_UPDATE | core->id);356 357	while (!sam9x60_pll_ready(regmap, core->id))358		cpu_relax();359}360 361static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)362{363	struct sam9x60_div *div = to_sam9x60_div(core);364	struct regmap *regmap = core->regmap;365	unsigned long flags;366	unsigned int val, cdiv;367 368	spin_lock_irqsave(core->lock, flags);369	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,370			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);371	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);372	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;373 374	/* Stop if enabled an nothing changed. */375	if (!!(val & core->layout->endiv_mask) && cdiv == div->div)376		goto unlock;377 378	sam9x60_div_pll_set_div(core, div->div, 1);379 380unlock:381	spin_unlock_irqrestore(core->lock, flags);382 383	return 0;384}385 386static int sam9x60_div_pll_prepare(struct clk_hw *hw)387{388	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);389 390	return sam9x60_div_pll_set(core);391}392 393static void sam9x60_div_pll_unprepare(struct clk_hw *hw)394{395	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);396	struct regmap *regmap = core->regmap;397	unsigned long flags;398 399	spin_lock_irqsave(core->lock, flags);400 401	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,402			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);403 404	regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,405			   core->layout->endiv_mask, 0);406 407	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,408			   AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,409			   AT91_PMC_PLL_UPDT_UPDATE | core->id);410 411	spin_unlock_irqrestore(core->lock, flags);412}413 414static int sam9x60_div_pll_is_prepared(struct clk_hw *hw)415{416	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);417	struct regmap *regmap = core->regmap;418	unsigned long flags;419	unsigned int val;420 421	spin_lock_irqsave(core->lock, flags);422 423	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,424			   AT91_PMC_PLL_UPDT_ID_MSK, core->id);425	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);426 427	spin_unlock_irqrestore(core->lock, flags);428 429	return !!(val & core->layout->endiv_mask);430}431 432static unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw,433						 unsigned long parent_rate)434{435	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);436	struct sam9x60_div *div = to_sam9x60_div(core);437 438	return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1));439}440 441static unsigned long sam9x60_fixed_div_pll_recalc_rate(struct clk_hw *hw,442						       unsigned long parent_rate)443{444	return parent_rate >> 1;445}446 447static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core,448					unsigned long *parent_rate,449					unsigned long rate)450{451	const struct clk_pll_characteristics *characteristics =452							core->characteristics;453	struct clk_hw *parent = clk_hw_get_parent(&core->hw);454	unsigned long tmp_rate, tmp_parent_rate, tmp_diff;455	long best_diff = -1, best_rate = -EINVAL;456	u32 divid;457 458	if (!rate)459		return 0;460 461	if (rate < characteristics->output[0].min ||462	    rate > characteristics->output[0].max)463		return -ERANGE;464 465	for (divid = 1; divid < core->layout->div_mask; divid++) {466		tmp_parent_rate = clk_hw_round_rate(parent, rate * divid);467		if (!tmp_parent_rate)468			continue;469 470		tmp_rate = DIV_ROUND_CLOSEST_ULL(tmp_parent_rate, divid);471		tmp_diff = abs(rate - tmp_rate);472 473		if (best_diff < 0 || best_diff > tmp_diff) {474			*parent_rate = tmp_parent_rate;475			best_rate = tmp_rate;476			best_diff = tmp_diff;477		}478 479		if (!best_diff)480			break;481	}482 483	if (best_rate < characteristics->output[0].min ||484	    best_rate > characteristics->output[0].max)485		return -ERANGE;486 487	return best_rate;488}489 490static long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate,491				       unsigned long *parent_rate)492{493	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);494 495	return sam9x60_div_pll_compute_div(core, parent_rate, rate);496}497 498static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,499				    unsigned long parent_rate)500{501	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);502	struct sam9x60_div *div = to_sam9x60_div(core);503 504	div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;505 506	return 0;507}508 509static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,510					unsigned long parent_rate)511{512	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);513	struct sam9x60_div *div = to_sam9x60_div(core);514	struct regmap *regmap = core->regmap;515	unsigned long irqflags;516	unsigned int val, cdiv;517 518	div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;519 520	spin_lock_irqsave(core->lock, irqflags);521	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,522			   core->id);523	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);524	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;525 526	/* Stop if nothing changed. */527	if (cdiv == div->div)528		goto unlock;529 530	sam9x60_div_pll_set_div(core, div->div, 0);531 532unlock:533	spin_unlock_irqrestore(core->lock, irqflags);534 535	return 0;536}537 538static int sam9x60_div_pll_save_context(struct clk_hw *hw)539{540	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);541	struct sam9x60_div *div = to_sam9x60_div(core);542 543	div->pms.status = sam9x60_div_pll_is_prepared(hw);544 545	return 0;546}547 548static void sam9x60_div_pll_restore_context(struct clk_hw *hw)549{550	struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);551	struct sam9x60_div *div = to_sam9x60_div(core);552 553	if (div->pms.status)554		sam9x60_div_pll_set(core);555}556 557static int sam9x60_div_pll_notifier_fn(struct notifier_block *notifier,558				       unsigned long code, void *data)559{560	struct sam9x60_div *div = notifier_div;561	struct sam9x60_pll_core core = div->core;562	struct regmap *regmap = core.regmap;563	unsigned long irqflags;564	u32 val, cdiv;565	int ret = NOTIFY_DONE;566 567	if (code != PRE_RATE_CHANGE)568		return ret;569 570	/*571	 * We switch to safe divider to avoid overclocking of other domains572	 * feed by us while the frac PLL (our parent) is changed.573	 */574	div->div = div->safe_div;575 576	spin_lock_irqsave(core.lock, irqflags);577	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,578			   core.id);579	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);580	cdiv = (val & core.layout->div_mask) >> core.layout->div_shift;581 582	/* Stop if nothing changed. */583	if (cdiv == div->safe_div)584		goto unlock;585 586	sam9x60_div_pll_set_div(&core, div->div, 0);587	ret = NOTIFY_OK;588 589unlock:590	spin_unlock_irqrestore(core.lock, irqflags);591 592	return ret;593}594 595static struct notifier_block sam9x60_div_pll_notifier = {596	.notifier_call = sam9x60_div_pll_notifier_fn,597};598 599static const struct clk_ops sam9x60_div_pll_ops = {600	.prepare = sam9x60_div_pll_prepare,601	.unprepare = sam9x60_div_pll_unprepare,602	.is_prepared = sam9x60_div_pll_is_prepared,603	.recalc_rate = sam9x60_div_pll_recalc_rate,604	.round_rate = sam9x60_div_pll_round_rate,605	.set_rate = sam9x60_div_pll_set_rate,606	.save_context = sam9x60_div_pll_save_context,607	.restore_context = sam9x60_div_pll_restore_context,608};609 610static const struct clk_ops sam9x60_div_pll_ops_chg = {611	.prepare = sam9x60_div_pll_prepare,612	.unprepare = sam9x60_div_pll_unprepare,613	.is_prepared = sam9x60_div_pll_is_prepared,614	.recalc_rate = sam9x60_div_pll_recalc_rate,615	.round_rate = sam9x60_div_pll_round_rate,616	.set_rate = sam9x60_div_pll_set_rate_chg,617	.save_context = sam9x60_div_pll_save_context,618	.restore_context = sam9x60_div_pll_restore_context,619};620 621static const struct clk_ops sam9x60_fixed_div_pll_ops = {622	.prepare = sam9x60_div_pll_prepare,623	.unprepare = sam9x60_div_pll_unprepare,624	.is_prepared = sam9x60_div_pll_is_prepared,625	.recalc_rate = sam9x60_fixed_div_pll_recalc_rate,626	.round_rate = sam9x60_div_pll_round_rate,627	.save_context = sam9x60_div_pll_save_context,628	.restore_context = sam9x60_div_pll_restore_context,629};630 631struct clk_hw * __init632sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,633			      const char *name, const char *parent_name,634			      struct clk_hw *parent_hw, u8 id,635			      const struct clk_pll_characteristics *characteristics,636			      const struct clk_pll_layout *layout, u32 flags)637{638	struct sam9x60_frac *frac;639	struct clk_hw *hw;640	struct clk_init_data init = {};641	unsigned long parent_rate, irqflags;642	unsigned int val;643	int ret;644 645	if (id > PLL_MAX_ID || !lock || !parent_hw)646		return ERR_PTR(-EINVAL);647 648	frac = kzalloc(sizeof(*frac), GFP_KERNEL);649	if (!frac)650		return ERR_PTR(-ENOMEM);651 652	init.name = name;653	if (parent_name)654		init.parent_names = &parent_name;655	else656		init.parent_hws = (const struct clk_hw **)&parent_hw;657	init.num_parents = 1;658	if (flags & CLK_SET_RATE_GATE)659		init.ops = &sam9x60_frac_pll_ops;660	else661		init.ops = &sam9x60_frac_pll_ops_chg;662 663	init.flags = flags;664 665	frac->core.id = id;666	frac->core.hw.init = &init;667	frac->core.characteristics = characteristics;668	frac->core.layout = layout;669	frac->core.regmap = regmap;670	frac->core.lock = lock;671 672	spin_lock_irqsave(frac->core.lock, irqflags);673	if (sam9x60_pll_ready(regmap, id)) {674		regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,675				   AT91_PMC_PLL_UPDT_ID_MSK, id);676		regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);677		frac->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);678		frac->frac = FIELD_GET(PMC_PLL_CTRL1_FRACR_MSK, val);679	} else {680		/*681		 * This means the PLL is not setup by bootloaders. In this682		 * case we need to set the minimum rate for it. Otherwise683		 * a clock child of this PLL may be enabled before setting684		 * its rate leading to enabling this PLL with unsupported685		 * rate. This will lead to PLL not being locked at all.686		 */687		parent_rate = clk_hw_get_rate(parent_hw);688		if (!parent_rate) {689			hw = ERR_PTR(-EINVAL);690			goto free;691		}692 693		ret = sam9x60_frac_pll_compute_mul_frac(&frac->core,694							characteristics->core_output[0].min,695							parent_rate, true);696		if (ret < 0) {697			hw = ERR_PTR(ret);698			goto free;699		}700	}701	spin_unlock_irqrestore(frac->core.lock, irqflags);702 703	hw = &frac->core.hw;704	ret = clk_hw_register(NULL, hw);705	if (ret) {706		kfree(frac);707		hw = ERR_PTR(ret);708	}709 710	return hw;711 712free:713	spin_unlock_irqrestore(frac->core.lock, irqflags);714	kfree(frac);715	return hw;716}717 718struct clk_hw * __init719sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,720			     const char *name, const char *parent_name,721			     struct clk_hw *parent_hw, u8 id,722			     const struct clk_pll_characteristics *characteristics,723			     const struct clk_pll_layout *layout, u32 flags,724			     u32 safe_div)725{726	struct sam9x60_div *div;727	struct clk_hw *hw;728	struct clk_init_data init = {};729	unsigned long irqflags;730	unsigned int val;731	int ret;732 733	/* We only support one changeable PLL. */734	if (id > PLL_MAX_ID || !lock || (safe_div && notifier_div))735		return ERR_PTR(-EINVAL);736 737	if (safe_div >= PLL_DIV_MAX)738		safe_div = PLL_DIV_MAX - 1;739 740	div = kzalloc(sizeof(*div), GFP_KERNEL);741	if (!div)742		return ERR_PTR(-ENOMEM);743 744	init.name = name;745	if (parent_hw)746		init.parent_hws = (const struct clk_hw **)&parent_hw;747	else748		init.parent_names = &parent_name;749	init.num_parents = 1;750 751	if (layout->div2)752		init.ops = &sam9x60_fixed_div_pll_ops;753	else if (flags & CLK_SET_RATE_GATE)754		init.ops = &sam9x60_div_pll_ops;755	else756		init.ops = &sam9x60_div_pll_ops_chg;757 758	init.flags = flags;759 760	div->core.id = id;761	div->core.hw.init = &init;762	div->core.characteristics = characteristics;763	div->core.layout = layout;764	div->core.regmap = regmap;765	div->core.lock = lock;766	div->safe_div = safe_div;767 768	spin_lock_irqsave(div->core.lock, irqflags);769 770	regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,771			   AT91_PMC_PLL_UPDT_ID_MSK, id);772	regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);773	div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);774 775	spin_unlock_irqrestore(div->core.lock, irqflags);776 777	hw = &div->core.hw;778	ret = clk_hw_register(NULL, hw);779	if (ret) {780		kfree(div);781		hw = ERR_PTR(ret);782	} else if (div->safe_div) {783		notifier_div = div;784		clk_notifier_register(hw->clk, &sam9x60_div_pll_notifier);785	}786 787	return hw;788}789 790