brintos

brintos / linux-shallow public Read only

0
0
Text · 21.1 KiB · 88845ba Raw
913 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.4 */5 6#include <linux/kernel.h>7#include <linux/bitops.h>8#include <linux/err.h>9#include <linux/export.h>10#include <linux/clk-provider.h>11#include <linux/regmap.h>12 13#include <asm/div64.h>14 15#include "clk-rcg.h"16#include "common.h"17 18static u32 ns_to_src(struct src_sel *s, u32 ns)19{20	ns >>= s->src_sel_shift;21	ns &= SRC_SEL_MASK;22	return ns;23}24 25static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)26{27	u32 mask;28 29	mask = SRC_SEL_MASK;30	mask <<= s->src_sel_shift;31	ns &= ~mask;32 33	ns |= src << s->src_sel_shift;34	return ns;35}36 37static u8 clk_rcg_get_parent(struct clk_hw *hw)38{39	struct clk_rcg *rcg = to_clk_rcg(hw);40	int num_parents = clk_hw_get_num_parents(hw);41	u32 ns;42	int i, ret;43 44	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);45	if (ret)46		goto err;47	ns = ns_to_src(&rcg->s, ns);48	for (i = 0; i < num_parents; i++)49		if (ns == rcg->s.parent_map[i].cfg)50			return i;51 52err:53	pr_debug("%s: Clock %s has invalid parent, using default.\n",54		 __func__, clk_hw_get_name(hw));55	return 0;56}57 58static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)59{60	bank &= BIT(rcg->mux_sel_bit);61	return !!bank;62}63 64static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)65{66	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);67	int num_parents = clk_hw_get_num_parents(hw);68	u32 ns, reg;69	int bank;70	int i, ret;71	struct src_sel *s;72 73	ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);74	if (ret)75		goto err;76	bank = reg_to_bank(rcg, reg);77	s = &rcg->s[bank];78 79	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);80	if (ret)81		goto err;82	ns = ns_to_src(s, ns);83 84	for (i = 0; i < num_parents; i++)85		if (ns == s->parent_map[i].cfg)86			return i;87 88err:89	pr_debug("%s: Clock %s has invalid parent, using default.\n",90		 __func__, clk_hw_get_name(hw));91	return 0;92}93 94static int clk_rcg_set_parent(struct clk_hw *hw, u8 index)95{96	struct clk_rcg *rcg = to_clk_rcg(hw);97	u32 ns;98 99	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);100	ns = src_to_ns(&rcg->s, rcg->s.parent_map[index].cfg, ns);101	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);102 103	return 0;104}105 106static u32 md_to_m(struct mn *mn, u32 md)107{108	md >>= mn->m_val_shift;109	md &= BIT(mn->width) - 1;110	return md;111}112 113static u32 ns_to_pre_div(struct pre_div *p, u32 ns)114{115	ns >>= p->pre_div_shift;116	ns &= BIT(p->pre_div_width) - 1;117	return ns;118}119 120static u32 pre_div_to_ns(struct pre_div *p, u8 pre_div, u32 ns)121{122	u32 mask;123 124	mask = BIT(p->pre_div_width) - 1;125	mask <<= p->pre_div_shift;126	ns &= ~mask;127 128	ns |= pre_div << p->pre_div_shift;129	return ns;130}131 132static u32 mn_to_md(struct mn *mn, u32 m, u32 n, u32 md)133{134	u32 mask, mask_w;135 136	mask_w = BIT(mn->width) - 1;137	mask = (mask_w << mn->m_val_shift) | mask_w;138	md &= ~mask;139 140	if (n) {141		m <<= mn->m_val_shift;142		md |= m;143		md |= ~n & mask_w;144	}145 146	return md;147}148 149static u32 ns_m_to_n(struct mn *mn, u32 ns, u32 m)150{151	ns = ~ns >> mn->n_val_shift;152	ns &= BIT(mn->width) - 1;153	return ns + m;154}155 156static u32 reg_to_mnctr_mode(struct mn *mn, u32 val)157{158	val >>= mn->mnctr_mode_shift;159	val &= MNCTR_MODE_MASK;160	return val;161}162 163static u32 mn_to_ns(struct mn *mn, u32 m, u32 n, u32 ns)164{165	u32 mask;166 167	mask = BIT(mn->width) - 1;168	mask <<= mn->n_val_shift;169	ns &= ~mask;170 171	if (n) {172		n = n - m;173		n = ~n;174		n &= BIT(mn->width) - 1;175		n <<= mn->n_val_shift;176		ns |= n;177	}178 179	return ns;180}181 182static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val)183{184	u32 mask;185 186	mask = MNCTR_MODE_MASK << mn->mnctr_mode_shift;187	mask |= BIT(mn->mnctr_en_bit);188	val &= ~mask;189 190	if (n) {191		val |= BIT(mn->mnctr_en_bit);192		val |= MNCTR_MODE_DUAL << mn->mnctr_mode_shift;193	}194 195	return val;196}197 198static int configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f)199{200	u32 ns, md, reg;201	int bank, new_bank, ret, index;202	struct mn *mn;203	struct pre_div *p;204	struct src_sel *s;205	bool enabled;206	u32 md_reg, ns_reg;207	bool banked_mn = !!rcg->mn[1].width;208	bool banked_p = !!rcg->p[1].pre_div_width;209	struct clk_hw *hw = &rcg->clkr.hw;210 211	enabled = __clk_is_enabled(hw->clk);212 213	ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);214	if (ret)215		return ret;216	bank = reg_to_bank(rcg, reg);217	new_bank = enabled ? !bank : bank;218 219	ns_reg = rcg->ns_reg[new_bank];220	ret = regmap_read(rcg->clkr.regmap, ns_reg, &ns);221	if (ret)222		return ret;223 224	if (banked_mn) {225		mn = &rcg->mn[new_bank];226		md_reg = rcg->md_reg[new_bank];227 228		ns |= BIT(mn->mnctr_reset_bit);229		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);230		if (ret)231			return ret;232 233		ret = regmap_read(rcg->clkr.regmap, md_reg, &md);234		if (ret)235			return ret;236		md = mn_to_md(mn, f->m, f->n, md);237		ret = regmap_write(rcg->clkr.regmap, md_reg, md);238		if (ret)239			return ret;240		ns = mn_to_ns(mn, f->m, f->n, ns);241		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);242		if (ret)243			return ret;244 245		/* Two NS registers means mode control is in NS register */246		if (rcg->ns_reg[0] != rcg->ns_reg[1]) {247			ns = mn_to_reg(mn, f->m, f->n, ns);248			ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);249			if (ret)250				return ret;251		} else {252			reg = mn_to_reg(mn, f->m, f->n, reg);253			ret = regmap_write(rcg->clkr.regmap, rcg->bank_reg,254					   reg);255			if (ret)256				return ret;257		}258 259		ns &= ~BIT(mn->mnctr_reset_bit);260		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);261		if (ret)262			return ret;263	}264 265	if (banked_p) {266		p = &rcg->p[new_bank];267		ns = pre_div_to_ns(p, f->pre_div - 1, ns);268	}269 270	s = &rcg->s[new_bank];271	index = qcom_find_src_index(hw, s->parent_map, f->src);272	if (index < 0)273		return index;274	ns = src_to_ns(s, s->parent_map[index].cfg, ns);275	ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);276	if (ret)277		return ret;278 279	if (enabled) {280		ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);281		if (ret)282			return ret;283		reg ^= BIT(rcg->mux_sel_bit);284		ret = regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg);285		if (ret)286			return ret;287	}288	return 0;289}290 291static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index)292{293	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);294	u32 ns, md, reg;295	int bank;296	struct freq_tbl f = { 0 };297	bool banked_mn = !!rcg->mn[1].width;298	bool banked_p = !!rcg->p[1].pre_div_width;299 300	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);301	bank = reg_to_bank(rcg, reg);302 303	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);304 305	if (banked_mn) {306		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);307		f.m = md_to_m(&rcg->mn[bank], md);308		f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m);309	}310 311	if (banked_p)312		f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1;313 314	f.src = qcom_find_src_index(hw, rcg->s[bank].parent_map, index);315	return configure_bank(rcg, &f);316}317 318/*319 * Calculate m/n:d rate320 *321 *          parent_rate     m322 *   rate = ----------- x  ---323 *            pre_div       n324 */325static unsigned long326calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 pre_div)327{328	if (pre_div)329		rate /= pre_div + 1;330 331	if (mode) {332		u64 tmp = rate;333		tmp *= m;334		do_div(tmp, n);335		rate = tmp;336	}337 338	return rate;339}340 341static unsigned long342clk_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)343{344	struct clk_rcg *rcg = to_clk_rcg(hw);345	u32 pre_div, m = 0, n = 0, ns, md, mode = 0;346	struct mn *mn = &rcg->mn;347 348	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);349	pre_div = ns_to_pre_div(&rcg->p, ns);350 351	if (rcg->mn.width) {352		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);353		m = md_to_m(mn, md);354		n = ns_m_to_n(mn, ns, m);355		/* MN counter mode is in hw.enable_reg sometimes */356		if (rcg->clkr.enable_reg != rcg->ns_reg)357			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &mode);358		else359			mode = ns;360		mode = reg_to_mnctr_mode(mn, mode);361	}362 363	return calc_rate(parent_rate, m, n, mode, pre_div);364}365 366static unsigned long367clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)368{369	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);370	u32 m, n, pre_div, ns, md, mode, reg;371	int bank;372	struct mn *mn;373	bool banked_p = !!rcg->p[1].pre_div_width;374	bool banked_mn = !!rcg->mn[1].width;375 376	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);377	bank = reg_to_bank(rcg, reg);378 379	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);380	m = n = pre_div = mode = 0;381 382	if (banked_mn) {383		mn = &rcg->mn[bank];384		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);385		m = md_to_m(mn, md);386		n = ns_m_to_n(mn, ns, m);387		/* Two NS registers means mode control is in NS register */388		if (rcg->ns_reg[0] != rcg->ns_reg[1])389			reg = ns;390		mode = reg_to_mnctr_mode(mn, reg);391	}392 393	if (banked_p)394		pre_div = ns_to_pre_div(&rcg->p[bank], ns);395 396	return calc_rate(parent_rate, m, n, mode, pre_div);397}398 399static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,400		struct clk_rate_request *req,401		const struct parent_map *parent_map)402{403	unsigned long clk_flags, rate = req->rate;404	struct clk_hw *p;405	int index;406 407	f = qcom_find_freq(f, rate);408	if (!f)409		return -EINVAL;410 411	index = qcom_find_src_index(hw, parent_map, f->src);412	if (index < 0)413		return index;414 415	clk_flags = clk_hw_get_flags(hw);416	p = clk_hw_get_parent_by_index(hw, index);417	if (clk_flags & CLK_SET_RATE_PARENT) {418		rate = rate * f->pre_div;419		if (f->n) {420			u64 tmp = rate;421			tmp = tmp * f->n;422			do_div(tmp, f->m);423			rate = tmp;424		}425	} else {426		rate =  clk_hw_get_rate(p);427	}428	req->best_parent_hw = p;429	req->best_parent_rate = rate;430	req->rate = f->freq;431 432	return 0;433}434 435static int clk_rcg_determine_rate(struct clk_hw *hw,436				  struct clk_rate_request *req)437{438	struct clk_rcg *rcg = to_clk_rcg(hw);439 440	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req,441					rcg->s.parent_map);442}443 444static int clk_dyn_rcg_determine_rate(struct clk_hw *hw,445				      struct clk_rate_request *req)446{447	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);448	u32 reg;449	int bank;450	struct src_sel *s;451 452	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);453	bank = reg_to_bank(rcg, reg);454	s = &rcg->s[bank];455 456	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map);457}458 459static int clk_rcg_bypass_determine_rate(struct clk_hw *hw,460					 struct clk_rate_request *req)461{462	struct clk_rcg *rcg = to_clk_rcg(hw);463	const struct freq_tbl *f = rcg->freq_tbl;464	struct clk_hw *p;465	int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src);466 467	req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);468	req->best_parent_rate = clk_hw_round_rate(p, req->rate);469	req->rate = req->best_parent_rate;470 471	return 0;472}473 474static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)475{476	u32 ns, md, ctl;477	struct mn *mn = &rcg->mn;478	u32 mask = 0;479	unsigned int reset_reg;480 481	if (rcg->mn.reset_in_cc)482		reset_reg = rcg->clkr.enable_reg;483	else484		reset_reg = rcg->ns_reg;485 486	if (rcg->mn.width) {487		mask = BIT(mn->mnctr_reset_bit);488		regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, mask);489 490		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);491		md = mn_to_md(mn, f->m, f->n, md);492		regmap_write(rcg->clkr.regmap, rcg->md_reg, md);493 494		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);495		/* MN counter mode is in hw.enable_reg sometimes */496		if (rcg->clkr.enable_reg != rcg->ns_reg) {497			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl);498			ctl = mn_to_reg(mn, f->m, f->n, ctl);499			regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl);500		} else {501			ns = mn_to_reg(mn, f->m, f->n, ns);502		}503		ns = mn_to_ns(mn, f->m, f->n, ns);504	} else {505		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);506	}507 508	ns = pre_div_to_ns(&rcg->p, f->pre_div - 1, ns);509	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);510 511	regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, 0);512 513	return 0;514}515 516static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate,517			    unsigned long parent_rate)518{519	struct clk_rcg *rcg = to_clk_rcg(hw);520	const struct freq_tbl *f;521 522	f = qcom_find_freq(rcg->freq_tbl, rate);523	if (!f)524		return -EINVAL;525 526	return __clk_rcg_set_rate(rcg, f);527}528 529static int clk_rcg_set_floor_rate(struct clk_hw *hw, unsigned long rate,530				  unsigned long parent_rate)531{532	struct clk_rcg *rcg = to_clk_rcg(hw);533	const struct freq_tbl *f;534 535	f = qcom_find_freq_floor(rcg->freq_tbl, rate);536	if (!f)537		return -EINVAL;538 539	return __clk_rcg_set_rate(rcg, f);540}541 542static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,543				unsigned long parent_rate)544{545	struct clk_rcg *rcg = to_clk_rcg(hw);546 547	return __clk_rcg_set_rate(rcg, rcg->freq_tbl);548}549 550static int clk_rcg_bypass2_determine_rate(struct clk_hw *hw,551				struct clk_rate_request *req)552{553	struct clk_hw *p;554 555	p = req->best_parent_hw;556	req->best_parent_rate = clk_hw_round_rate(p, req->rate);557	req->rate = req->best_parent_rate;558 559	return 0;560}561 562static int clk_rcg_bypass2_set_rate(struct clk_hw *hw, unsigned long rate,563				unsigned long parent_rate)564{565	struct clk_rcg *rcg = to_clk_rcg(hw);566	struct freq_tbl f = { 0 };567	u32 ns, src;568	int i, ret, num_parents = clk_hw_get_num_parents(hw);569 570	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);571	if (ret)572		return ret;573 574	src = ns_to_src(&rcg->s, ns);575	f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;576 577	for (i = 0; i < num_parents; i++) {578		if (src == rcg->s.parent_map[i].cfg) {579			f.src = rcg->s.parent_map[i].src;580			return __clk_rcg_set_rate(rcg, &f);581		}582	}583 584	return -EINVAL;585}586 587static int clk_rcg_bypass2_set_rate_and_parent(struct clk_hw *hw,588		unsigned long rate, unsigned long parent_rate, u8 index)589{590	/* Read the hardware to determine parent during set_rate */591	return clk_rcg_bypass2_set_rate(hw, rate, parent_rate);592}593 594struct frac_entry {595	int num;596	int den;597};598 599static const struct frac_entry pixel_table[] = {600	{ 1, 2 },601	{ 1, 3 },602	{ 3, 16 },603	{ }604};605 606static int clk_rcg_pixel_determine_rate(struct clk_hw *hw,607		struct clk_rate_request *req)608{609	int delta = 100000;610	const struct frac_entry *frac = pixel_table;611	unsigned long request, src_rate;612 613	for (; frac->num; frac++) {614		request = (req->rate * frac->den) / frac->num;615 616		src_rate = clk_hw_round_rate(req->best_parent_hw, request);617 618		if ((src_rate < (request - delta)) ||619			(src_rate > (request + delta)))620			continue;621 622		req->best_parent_rate = src_rate;623		req->rate = (src_rate * frac->num) / frac->den;624		return 0;625	}626 627	return -EINVAL;628}629 630static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate,631				unsigned long parent_rate)632{633	struct clk_rcg *rcg = to_clk_rcg(hw);634	int delta = 100000;635	const struct frac_entry *frac = pixel_table;636	unsigned long request;637	struct freq_tbl f = { 0 };638	u32 ns, src;639	int i, ret, num_parents = clk_hw_get_num_parents(hw);640 641	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);642	if (ret)643		return ret;644 645	src = ns_to_src(&rcg->s, ns);646 647	for (i = 0; i < num_parents; i++) {648		if (src == rcg->s.parent_map[i].cfg) {649			f.src = rcg->s.parent_map[i].src;650			break;651		}652	}653 654	/* bypass the pre divider */655	f.pre_div = 1;656 657	/* let us find appropriate m/n values for this */658	for (; frac->num; frac++) {659		request = (rate * frac->den) / frac->num;660 661		if ((parent_rate < (request - delta)) ||662			(parent_rate > (request + delta)))663			continue;664 665		f.m = frac->num;666		f.n = frac->den;667 668		return __clk_rcg_set_rate(rcg, &f);669	}670 671	return -EINVAL;672}673 674static int clk_rcg_pixel_set_rate_and_parent(struct clk_hw *hw,675		unsigned long rate, unsigned long parent_rate, u8 index)676{677	return clk_rcg_pixel_set_rate(hw, rate, parent_rate);678}679 680static int clk_rcg_esc_determine_rate(struct clk_hw *hw,681		struct clk_rate_request *req)682{683	struct clk_rcg *rcg = to_clk_rcg(hw);684	int pre_div_max = BIT(rcg->p.pre_div_width);685	int div;686	unsigned long src_rate;687 688	if (req->rate == 0)689		return -EINVAL;690 691	src_rate = clk_hw_get_rate(req->best_parent_hw);692 693	div = src_rate / req->rate;694 695	if (div >= 1 && div <= pre_div_max) {696		req->best_parent_rate = src_rate;697		req->rate = src_rate / div;698		return 0;699	}700 701	return -EINVAL;702}703 704static int clk_rcg_esc_set_rate(struct clk_hw *hw, unsigned long rate,705				unsigned long parent_rate)706{707	struct clk_rcg *rcg = to_clk_rcg(hw);708	struct freq_tbl f = { 0 };709	int pre_div_max = BIT(rcg->p.pre_div_width);710	int div;711	u32 ns;712	int i, ret, num_parents = clk_hw_get_num_parents(hw);713 714	if (rate == 0)715		return -EINVAL;716 717	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);718	if (ret)719		return ret;720 721	ns = ns_to_src(&rcg->s, ns);722 723	for (i = 0; i < num_parents; i++) {724		if (ns == rcg->s.parent_map[i].cfg) {725			f.src = rcg->s.parent_map[i].src;726			break;727		}728	}729 730	div = parent_rate / rate;731 732	if (div >= 1 && div <= pre_div_max) {733		f.pre_div = div;734		return __clk_rcg_set_rate(rcg, &f);735	}736 737	return -EINVAL;738}739 740static int clk_rcg_esc_set_rate_and_parent(struct clk_hw *hw,741		unsigned long rate, unsigned long parent_rate, u8 index)742{743	return clk_rcg_esc_set_rate(hw, rate, parent_rate);744}745 746/*747 * This type of clock has a glitch-free mux that switches between the output of748 * the M/N counter and an always on clock source (XO). When clk_set_rate() is749 * called we need to make sure that we don't switch to the M/N counter if it750 * isn't clocking because the mux will get stuck and the clock will stop751 * outputting a clock. This can happen if the framework isn't aware that this752 * clock is on and so clk_set_rate() doesn't turn on the new parent. To fix753 * this we switch the mux in the enable/disable ops and reprogram the M/N754 * counter in the set_rate op. We also make sure to switch away from the M/N755 * counter in set_rate if software thinks the clock is off.756 */757static int clk_rcg_lcc_set_rate(struct clk_hw *hw, unsigned long rate,758				unsigned long parent_rate)759{760	struct clk_rcg *rcg = to_clk_rcg(hw);761	const struct freq_tbl *f;762	int ret;763	u32 gfm = BIT(10);764 765	f = qcom_find_freq(rcg->freq_tbl, rate);766	if (!f)767		return -EINVAL;768 769	/* Switch to XO to avoid glitches */770	regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, 0);771	ret = __clk_rcg_set_rate(rcg, f);772	/* Switch back to M/N if it's clocking */773	if (__clk_is_enabled(hw->clk))774		regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, gfm);775 776	return ret;777}778 779static int clk_rcg_lcc_enable(struct clk_hw *hw)780{781	struct clk_rcg *rcg = to_clk_rcg(hw);782	u32 gfm = BIT(10);783 784	/* Use M/N */785	return regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, gfm);786}787 788static void clk_rcg_lcc_disable(struct clk_hw *hw)789{790	struct clk_rcg *rcg = to_clk_rcg(hw);791	u32 gfm = BIT(10);792 793	/* Use XO */794	regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, 0);795}796 797static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate)798{799	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);800	const struct freq_tbl *f;801 802	f = qcom_find_freq(rcg->freq_tbl, rate);803	if (!f)804		return -EINVAL;805 806	return configure_bank(rcg, f);807}808 809static int clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate,810			    unsigned long parent_rate)811{812	return __clk_dyn_rcg_set_rate(hw, rate);813}814 815static int clk_dyn_rcg_set_rate_and_parent(struct clk_hw *hw,816		unsigned long rate, unsigned long parent_rate, u8 index)817{818	return __clk_dyn_rcg_set_rate(hw, rate);819}820 821const struct clk_ops clk_rcg_ops = {822	.enable = clk_enable_regmap,823	.disable = clk_disable_regmap,824	.get_parent = clk_rcg_get_parent,825	.set_parent = clk_rcg_set_parent,826	.recalc_rate = clk_rcg_recalc_rate,827	.determine_rate = clk_rcg_determine_rate,828	.set_rate = clk_rcg_set_rate,829};830EXPORT_SYMBOL_GPL(clk_rcg_ops);831 832const struct clk_ops clk_rcg_floor_ops = {833	.enable = clk_enable_regmap,834	.disable = clk_disable_regmap,835	.get_parent = clk_rcg_get_parent,836	.set_parent = clk_rcg_set_parent,837	.recalc_rate = clk_rcg_recalc_rate,838	.determine_rate = clk_rcg_determine_rate,839	.set_rate = clk_rcg_set_floor_rate,840};841EXPORT_SYMBOL_GPL(clk_rcg_floor_ops);842 843const struct clk_ops clk_rcg_bypass_ops = {844	.enable = clk_enable_regmap,845	.disable = clk_disable_regmap,846	.get_parent = clk_rcg_get_parent,847	.set_parent = clk_rcg_set_parent,848	.recalc_rate = clk_rcg_recalc_rate,849	.determine_rate = clk_rcg_bypass_determine_rate,850	.set_rate = clk_rcg_bypass_set_rate,851};852EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);853 854const struct clk_ops clk_rcg_bypass2_ops = {855	.enable = clk_enable_regmap,856	.disable = clk_disable_regmap,857	.get_parent = clk_rcg_get_parent,858	.set_parent = clk_rcg_set_parent,859	.recalc_rate = clk_rcg_recalc_rate,860	.determine_rate = clk_rcg_bypass2_determine_rate,861	.set_rate = clk_rcg_bypass2_set_rate,862	.set_rate_and_parent = clk_rcg_bypass2_set_rate_and_parent,863};864EXPORT_SYMBOL_GPL(clk_rcg_bypass2_ops);865 866const struct clk_ops clk_rcg_pixel_ops = {867	.enable = clk_enable_regmap,868	.disable = clk_disable_regmap,869	.get_parent = clk_rcg_get_parent,870	.set_parent = clk_rcg_set_parent,871	.recalc_rate = clk_rcg_recalc_rate,872	.determine_rate = clk_rcg_pixel_determine_rate,873	.set_rate = clk_rcg_pixel_set_rate,874	.set_rate_and_parent = clk_rcg_pixel_set_rate_and_parent,875};876EXPORT_SYMBOL_GPL(clk_rcg_pixel_ops);877 878const struct clk_ops clk_rcg_esc_ops = {879	.enable = clk_enable_regmap,880	.disable = clk_disable_regmap,881	.get_parent = clk_rcg_get_parent,882	.set_parent = clk_rcg_set_parent,883	.recalc_rate = clk_rcg_recalc_rate,884	.determine_rate = clk_rcg_esc_determine_rate,885	.set_rate = clk_rcg_esc_set_rate,886	.set_rate_and_parent = clk_rcg_esc_set_rate_and_parent,887};888EXPORT_SYMBOL_GPL(clk_rcg_esc_ops);889 890const struct clk_ops clk_rcg_lcc_ops = {891	.enable = clk_rcg_lcc_enable,892	.disable = clk_rcg_lcc_disable,893	.get_parent = clk_rcg_get_parent,894	.set_parent = clk_rcg_set_parent,895	.recalc_rate = clk_rcg_recalc_rate,896	.determine_rate = clk_rcg_determine_rate,897	.set_rate = clk_rcg_lcc_set_rate,898};899EXPORT_SYMBOL_GPL(clk_rcg_lcc_ops);900 901const struct clk_ops clk_dyn_rcg_ops = {902	.enable = clk_enable_regmap,903	.is_enabled = clk_is_enabled_regmap,904	.disable = clk_disable_regmap,905	.get_parent = clk_dyn_rcg_get_parent,906	.set_parent = clk_dyn_rcg_set_parent,907	.recalc_rate = clk_dyn_rcg_recalc_rate,908	.determine_rate = clk_dyn_rcg_determine_rate,909	.set_rate = clk_dyn_rcg_set_rate,910	.set_rate_and_parent = clk_dyn_rcg_set_rate_and_parent,911};912EXPORT_SYMBOL_GPL(clk_dyn_rcg_ops);913