18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2013, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
118c2ecf20Sopenharmony_ci#include <linux/regmap.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/div64.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "clk-rcg.h"
168c2ecf20Sopenharmony_ci#include "common.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic u32 ns_to_src(struct src_sel *s, u32 ns)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	ns >>= s->src_sel_shift;
218c2ecf20Sopenharmony_ci	ns &= SRC_SEL_MASK;
228c2ecf20Sopenharmony_ci	return ns;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	u32 mask;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	mask = SRC_SEL_MASK;
308c2ecf20Sopenharmony_ci	mask <<= s->src_sel_shift;
318c2ecf20Sopenharmony_ci	ns &= ~mask;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	ns |= src << s->src_sel_shift;
348c2ecf20Sopenharmony_ci	return ns;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic u8 clk_rcg_get_parent(struct clk_hw *hw)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
408c2ecf20Sopenharmony_ci	int num_parents = clk_hw_get_num_parents(hw);
418c2ecf20Sopenharmony_ci	u32 ns;
428c2ecf20Sopenharmony_ci	int i, ret;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
458c2ecf20Sopenharmony_ci	if (ret)
468c2ecf20Sopenharmony_ci		goto err;
478c2ecf20Sopenharmony_ci	ns = ns_to_src(&rcg->s, ns);
488c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++)
498c2ecf20Sopenharmony_ci		if (ns == rcg->s.parent_map[i].cfg)
508c2ecf20Sopenharmony_ci			return i;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cierr:
538c2ecf20Sopenharmony_ci	pr_debug("%s: Clock %s has invalid parent, using default.\n",
548c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw));
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	bank &= BIT(rcg->mux_sel_bit);
618c2ecf20Sopenharmony_ci	return !!bank;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
678c2ecf20Sopenharmony_ci	int num_parents = clk_hw_get_num_parents(hw);
688c2ecf20Sopenharmony_ci	u32 ns, reg;
698c2ecf20Sopenharmony_ci	int bank;
708c2ecf20Sopenharmony_ci	int i, ret;
718c2ecf20Sopenharmony_ci	struct src_sel *s;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
748c2ecf20Sopenharmony_ci	if (ret)
758c2ecf20Sopenharmony_ci		goto err;
768c2ecf20Sopenharmony_ci	bank = reg_to_bank(rcg, reg);
778c2ecf20Sopenharmony_ci	s = &rcg->s[bank];
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
808c2ecf20Sopenharmony_ci	if (ret)
818c2ecf20Sopenharmony_ci		goto err;
828c2ecf20Sopenharmony_ci	ns = ns_to_src(s, ns);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++)
858c2ecf20Sopenharmony_ci		if (ns == s->parent_map[i].cfg)
868c2ecf20Sopenharmony_ci			return i;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cierr:
898c2ecf20Sopenharmony_ci	pr_debug("%s: Clock %s has invalid parent, using default.\n",
908c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw));
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int clk_rcg_set_parent(struct clk_hw *hw, u8 index)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
978c2ecf20Sopenharmony_ci	u32 ns;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
1008c2ecf20Sopenharmony_ci	ns = src_to_ns(&rcg->s, rcg->s.parent_map[index].cfg, ns);
1018c2ecf20Sopenharmony_ci	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic u32 md_to_m(struct mn *mn, u32 md)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	md >>= mn->m_val_shift;
1098c2ecf20Sopenharmony_ci	md &= BIT(mn->width) - 1;
1108c2ecf20Sopenharmony_ci	return md;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic u32 ns_to_pre_div(struct pre_div *p, u32 ns)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	ns >>= p->pre_div_shift;
1168c2ecf20Sopenharmony_ci	ns &= BIT(p->pre_div_width) - 1;
1178c2ecf20Sopenharmony_ci	return ns;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic u32 pre_div_to_ns(struct pre_div *p, u8 pre_div, u32 ns)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	u32 mask;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	mask = BIT(p->pre_div_width) - 1;
1258c2ecf20Sopenharmony_ci	mask <<= p->pre_div_shift;
1268c2ecf20Sopenharmony_ci	ns &= ~mask;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	ns |= pre_div << p->pre_div_shift;
1298c2ecf20Sopenharmony_ci	return ns;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic u32 mn_to_md(struct mn *mn, u32 m, u32 n, u32 md)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u32 mask, mask_w;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	mask_w = BIT(mn->width) - 1;
1378c2ecf20Sopenharmony_ci	mask = (mask_w << mn->m_val_shift) | mask_w;
1388c2ecf20Sopenharmony_ci	md &= ~mask;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (n) {
1418c2ecf20Sopenharmony_ci		m <<= mn->m_val_shift;
1428c2ecf20Sopenharmony_ci		md |= m;
1438c2ecf20Sopenharmony_ci		md |= ~n & mask_w;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return md;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic u32 ns_m_to_n(struct mn *mn, u32 ns, u32 m)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	ns = ~ns >> mn->n_val_shift;
1528c2ecf20Sopenharmony_ci	ns &= BIT(mn->width) - 1;
1538c2ecf20Sopenharmony_ci	return ns + m;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic u32 reg_to_mnctr_mode(struct mn *mn, u32 val)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	val >>= mn->mnctr_mode_shift;
1598c2ecf20Sopenharmony_ci	val &= MNCTR_MODE_MASK;
1608c2ecf20Sopenharmony_ci	return val;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic u32 mn_to_ns(struct mn *mn, u32 m, u32 n, u32 ns)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	u32 mask;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	mask = BIT(mn->width) - 1;
1688c2ecf20Sopenharmony_ci	mask <<= mn->n_val_shift;
1698c2ecf20Sopenharmony_ci	ns &= ~mask;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (n) {
1728c2ecf20Sopenharmony_ci		n = n - m;
1738c2ecf20Sopenharmony_ci		n = ~n;
1748c2ecf20Sopenharmony_ci		n &= BIT(mn->width) - 1;
1758c2ecf20Sopenharmony_ci		n <<= mn->n_val_shift;
1768c2ecf20Sopenharmony_ci		ns |= n;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return ns;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	u32 mask;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	mask = MNCTR_MODE_MASK << mn->mnctr_mode_shift;
1878c2ecf20Sopenharmony_ci	mask |= BIT(mn->mnctr_en_bit);
1888c2ecf20Sopenharmony_ci	val &= ~mask;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (n) {
1918c2ecf20Sopenharmony_ci		val |= BIT(mn->mnctr_en_bit);
1928c2ecf20Sopenharmony_ci		val |= MNCTR_MODE_DUAL << mn->mnctr_mode_shift;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return val;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u32 ns, md, reg;
2018c2ecf20Sopenharmony_ci	int bank, new_bank, ret, index;
2028c2ecf20Sopenharmony_ci	struct mn *mn;
2038c2ecf20Sopenharmony_ci	struct pre_div *p;
2048c2ecf20Sopenharmony_ci	struct src_sel *s;
2058c2ecf20Sopenharmony_ci	bool enabled;
2068c2ecf20Sopenharmony_ci	u32 md_reg, ns_reg;
2078c2ecf20Sopenharmony_ci	bool banked_mn = !!rcg->mn[1].width;
2088c2ecf20Sopenharmony_ci	bool banked_p = !!rcg->p[1].pre_div_width;
2098c2ecf20Sopenharmony_ci	struct clk_hw *hw = &rcg->clkr.hw;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	enabled = __clk_is_enabled(hw->clk);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
2148c2ecf20Sopenharmony_ci	if (ret)
2158c2ecf20Sopenharmony_ci		return ret;
2168c2ecf20Sopenharmony_ci	bank = reg_to_bank(rcg, reg);
2178c2ecf20Sopenharmony_ci	new_bank = enabled ? !bank : bank;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ns_reg = rcg->ns_reg[new_bank];
2208c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, ns_reg, &ns);
2218c2ecf20Sopenharmony_ci	if (ret)
2228c2ecf20Sopenharmony_ci		return ret;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (banked_mn) {
2258c2ecf20Sopenharmony_ci		mn = &rcg->mn[new_bank];
2268c2ecf20Sopenharmony_ci		md_reg = rcg->md_reg[new_bank];
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		ns |= BIT(mn->mnctr_reset_bit);
2298c2ecf20Sopenharmony_ci		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);
2308c2ecf20Sopenharmony_ci		if (ret)
2318c2ecf20Sopenharmony_ci			return ret;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		ret = regmap_read(rcg->clkr.regmap, md_reg, &md);
2348c2ecf20Sopenharmony_ci		if (ret)
2358c2ecf20Sopenharmony_ci			return ret;
2368c2ecf20Sopenharmony_ci		md = mn_to_md(mn, f->m, f->n, md);
2378c2ecf20Sopenharmony_ci		ret = regmap_write(rcg->clkr.regmap, md_reg, md);
2388c2ecf20Sopenharmony_ci		if (ret)
2398c2ecf20Sopenharmony_ci			return ret;
2408c2ecf20Sopenharmony_ci		ns = mn_to_ns(mn, f->m, f->n, ns);
2418c2ecf20Sopenharmony_ci		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);
2428c2ecf20Sopenharmony_ci		if (ret)
2438c2ecf20Sopenharmony_ci			return ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		/* Two NS registers means mode control is in NS register */
2468c2ecf20Sopenharmony_ci		if (rcg->ns_reg[0] != rcg->ns_reg[1]) {
2478c2ecf20Sopenharmony_ci			ns = mn_to_reg(mn, f->m, f->n, ns);
2488c2ecf20Sopenharmony_ci			ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);
2498c2ecf20Sopenharmony_ci			if (ret)
2508c2ecf20Sopenharmony_ci				return ret;
2518c2ecf20Sopenharmony_ci		} else {
2528c2ecf20Sopenharmony_ci			reg = mn_to_reg(mn, f->m, f->n, reg);
2538c2ecf20Sopenharmony_ci			ret = regmap_write(rcg->clkr.regmap, rcg->bank_reg,
2548c2ecf20Sopenharmony_ci					   reg);
2558c2ecf20Sopenharmony_ci			if (ret)
2568c2ecf20Sopenharmony_ci				return ret;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		ns &= ~BIT(mn->mnctr_reset_bit);
2608c2ecf20Sopenharmony_ci		ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);
2618c2ecf20Sopenharmony_ci		if (ret)
2628c2ecf20Sopenharmony_ci			return ret;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (banked_p) {
2668c2ecf20Sopenharmony_ci		p = &rcg->p[new_bank];
2678c2ecf20Sopenharmony_ci		ns = pre_div_to_ns(p, f->pre_div - 1, ns);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	s = &rcg->s[new_bank];
2718c2ecf20Sopenharmony_ci	index = qcom_find_src_index(hw, s->parent_map, f->src);
2728c2ecf20Sopenharmony_ci	if (index < 0)
2738c2ecf20Sopenharmony_ci		return index;
2748c2ecf20Sopenharmony_ci	ns = src_to_ns(s, s->parent_map[index].cfg, ns);
2758c2ecf20Sopenharmony_ci	ret = regmap_write(rcg->clkr.regmap, ns_reg, ns);
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (enabled) {
2808c2ecf20Sopenharmony_ci		ret = regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
2818c2ecf20Sopenharmony_ci		if (ret)
2828c2ecf20Sopenharmony_ci			return ret;
2838c2ecf20Sopenharmony_ci		reg ^= BIT(rcg->mux_sel_bit);
2848c2ecf20Sopenharmony_ci		ret = regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg);
2858c2ecf20Sopenharmony_ci		if (ret)
2868c2ecf20Sopenharmony_ci			return ret;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
2948c2ecf20Sopenharmony_ci	u32 ns, md, reg;
2958c2ecf20Sopenharmony_ci	int bank;
2968c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
2978c2ecf20Sopenharmony_ci	bool banked_mn = !!rcg->mn[1].width;
2988c2ecf20Sopenharmony_ci	bool banked_p = !!rcg->p[1].pre_div_width;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
3018c2ecf20Sopenharmony_ci	bank = reg_to_bank(rcg, reg);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (banked_mn) {
3068c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);
3078c2ecf20Sopenharmony_ci		f.m = md_to_m(&rcg->mn[bank], md);
3088c2ecf20Sopenharmony_ci		f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m);
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (banked_p)
3128c2ecf20Sopenharmony_ci		f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	f.src = qcom_find_src_index(hw, rcg->s[bank].parent_map, index);
3158c2ecf20Sopenharmony_ci	return configure_bank(rcg, &f);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci/*
3198c2ecf20Sopenharmony_ci * Calculate m/n:d rate
3208c2ecf20Sopenharmony_ci *
3218c2ecf20Sopenharmony_ci *          parent_rate     m
3228c2ecf20Sopenharmony_ci *   rate = ----------- x  ---
3238c2ecf20Sopenharmony_ci *            pre_div       n
3248c2ecf20Sopenharmony_ci */
3258c2ecf20Sopenharmony_cistatic unsigned long
3268c2ecf20Sopenharmony_cicalc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 pre_div)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	if (pre_div)
3298c2ecf20Sopenharmony_ci		rate /= pre_div + 1;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (mode) {
3328c2ecf20Sopenharmony_ci		u64 tmp = rate;
3338c2ecf20Sopenharmony_ci		tmp *= m;
3348c2ecf20Sopenharmony_ci		do_div(tmp, n);
3358c2ecf20Sopenharmony_ci		rate = tmp;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return rate;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic unsigned long
3428c2ecf20Sopenharmony_ciclk_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
3458c2ecf20Sopenharmony_ci	u32 pre_div, m = 0, n = 0, ns, md, mode = 0;
3468c2ecf20Sopenharmony_ci	struct mn *mn = &rcg->mn;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
3498c2ecf20Sopenharmony_ci	pre_div = ns_to_pre_div(&rcg->p, ns);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (rcg->mn.width) {
3528c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);
3538c2ecf20Sopenharmony_ci		m = md_to_m(mn, md);
3548c2ecf20Sopenharmony_ci		n = ns_m_to_n(mn, ns, m);
3558c2ecf20Sopenharmony_ci		/* MN counter mode is in hw.enable_reg sometimes */
3568c2ecf20Sopenharmony_ci		if (rcg->clkr.enable_reg != rcg->ns_reg)
3578c2ecf20Sopenharmony_ci			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &mode);
3588c2ecf20Sopenharmony_ci		else
3598c2ecf20Sopenharmony_ci			mode = ns;
3608c2ecf20Sopenharmony_ci		mode = reg_to_mnctr_mode(mn, mode);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return calc_rate(parent_rate, m, n, mode, pre_div);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic unsigned long
3678c2ecf20Sopenharmony_ciclk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
3708c2ecf20Sopenharmony_ci	u32 m, n, pre_div, ns, md, mode, reg;
3718c2ecf20Sopenharmony_ci	int bank;
3728c2ecf20Sopenharmony_ci	struct mn *mn;
3738c2ecf20Sopenharmony_ci	bool banked_p = !!rcg->p[1].pre_div_width;
3748c2ecf20Sopenharmony_ci	bool banked_mn = !!rcg->mn[1].width;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
3778c2ecf20Sopenharmony_ci	bank = reg_to_bank(rcg, reg);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns);
3808c2ecf20Sopenharmony_ci	m = n = pre_div = mode = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (banked_mn) {
3838c2ecf20Sopenharmony_ci		mn = &rcg->mn[bank];
3848c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md);
3858c2ecf20Sopenharmony_ci		m = md_to_m(mn, md);
3868c2ecf20Sopenharmony_ci		n = ns_m_to_n(mn, ns, m);
3878c2ecf20Sopenharmony_ci		/* Two NS registers means mode control is in NS register */
3888c2ecf20Sopenharmony_ci		if (rcg->ns_reg[0] != rcg->ns_reg[1])
3898c2ecf20Sopenharmony_ci			reg = ns;
3908c2ecf20Sopenharmony_ci		mode = reg_to_mnctr_mode(mn, reg);
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (banked_p)
3948c2ecf20Sopenharmony_ci		pre_div = ns_to_pre_div(&rcg->p[bank], ns);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return calc_rate(parent_rate, m, n, mode, pre_div);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
4008c2ecf20Sopenharmony_ci		struct clk_rate_request *req,
4018c2ecf20Sopenharmony_ci		const struct parent_map *parent_map)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	unsigned long clk_flags, rate = req->rate;
4048c2ecf20Sopenharmony_ci	struct clk_hw *p;
4058c2ecf20Sopenharmony_ci	int index;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	f = qcom_find_freq(f, rate);
4088c2ecf20Sopenharmony_ci	if (!f)
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	index = qcom_find_src_index(hw, parent_map, f->src);
4128c2ecf20Sopenharmony_ci	if (index < 0)
4138c2ecf20Sopenharmony_ci		return index;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	clk_flags = clk_hw_get_flags(hw);
4168c2ecf20Sopenharmony_ci	p = clk_hw_get_parent_by_index(hw, index);
4178c2ecf20Sopenharmony_ci	if (clk_flags & CLK_SET_RATE_PARENT) {
4188c2ecf20Sopenharmony_ci		rate = rate * f->pre_div;
4198c2ecf20Sopenharmony_ci		if (f->n) {
4208c2ecf20Sopenharmony_ci			u64 tmp = rate;
4218c2ecf20Sopenharmony_ci			tmp = tmp * f->n;
4228c2ecf20Sopenharmony_ci			do_div(tmp, f->m);
4238c2ecf20Sopenharmony_ci			rate = tmp;
4248c2ecf20Sopenharmony_ci		}
4258c2ecf20Sopenharmony_ci	} else {
4268c2ecf20Sopenharmony_ci		rate =  clk_hw_get_rate(p);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci	req->best_parent_hw = p;
4298c2ecf20Sopenharmony_ci	req->best_parent_rate = rate;
4308c2ecf20Sopenharmony_ci	req->rate = f->freq;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int clk_rcg_determine_rate(struct clk_hw *hw,
4368c2ecf20Sopenharmony_ci				  struct clk_rate_request *req)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req,
4418c2ecf20Sopenharmony_ci					rcg->s.parent_map);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int clk_dyn_rcg_determine_rate(struct clk_hw *hw,
4458c2ecf20Sopenharmony_ci				      struct clk_rate_request *req)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
4488c2ecf20Sopenharmony_ci	u32 reg;
4498c2ecf20Sopenharmony_ci	int bank;
4508c2ecf20Sopenharmony_ci	struct src_sel *s;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->bank_reg, &reg);
4538c2ecf20Sopenharmony_ci	bank = reg_to_bank(rcg, reg);
4548c2ecf20Sopenharmony_ci	s = &rcg->s[bank];
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int clk_rcg_bypass_determine_rate(struct clk_hw *hw,
4608c2ecf20Sopenharmony_ci					 struct clk_rate_request *req)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
4638c2ecf20Sopenharmony_ci	const struct freq_tbl *f = rcg->freq_tbl;
4648c2ecf20Sopenharmony_ci	struct clk_hw *p;
4658c2ecf20Sopenharmony_ci	int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
4688c2ecf20Sopenharmony_ci	req->best_parent_rate = clk_hw_round_rate(p, req->rate);
4698c2ecf20Sopenharmony_ci	req->rate = req->best_parent_rate;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	u32 ns, md, ctl;
4778c2ecf20Sopenharmony_ci	struct mn *mn = &rcg->mn;
4788c2ecf20Sopenharmony_ci	u32 mask = 0;
4798c2ecf20Sopenharmony_ci	unsigned int reset_reg;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (rcg->mn.reset_in_cc)
4828c2ecf20Sopenharmony_ci		reset_reg = rcg->clkr.enable_reg;
4838c2ecf20Sopenharmony_ci	else
4848c2ecf20Sopenharmony_ci		reset_reg = rcg->ns_reg;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (rcg->mn.width) {
4878c2ecf20Sopenharmony_ci		mask = BIT(mn->mnctr_reset_bit);
4888c2ecf20Sopenharmony_ci		regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, mask);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->md_reg, &md);
4918c2ecf20Sopenharmony_ci		md = mn_to_md(mn, f->m, f->n, md);
4928c2ecf20Sopenharmony_ci		regmap_write(rcg->clkr.regmap, rcg->md_reg, md);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
4958c2ecf20Sopenharmony_ci		/* MN counter mode is in hw.enable_reg sometimes */
4968c2ecf20Sopenharmony_ci		if (rcg->clkr.enable_reg != rcg->ns_reg) {
4978c2ecf20Sopenharmony_ci			regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl);
4988c2ecf20Sopenharmony_ci			ctl = mn_to_reg(mn, f->m, f->n, ctl);
4998c2ecf20Sopenharmony_ci			regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl);
5008c2ecf20Sopenharmony_ci		} else {
5018c2ecf20Sopenharmony_ci			ns = mn_to_reg(mn, f->m, f->n, ns);
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci		ns = mn_to_ns(mn, f->m, f->n, ns);
5048c2ecf20Sopenharmony_ci	} else {
5058c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	ns = pre_div_to_ns(&rcg->p, f->pre_div - 1, ns);
5098c2ecf20Sopenharmony_ci	regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, 0);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	return 0;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
5178c2ecf20Sopenharmony_ci			    unsigned long parent_rate)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
5208c2ecf20Sopenharmony_ci	const struct freq_tbl *f;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	f = qcom_find_freq(rcg->freq_tbl, rate);
5238c2ecf20Sopenharmony_ci	if (!f)
5248c2ecf20Sopenharmony_ci		return -EINVAL;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return __clk_rcg_set_rate(rcg, f);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,
5308c2ecf20Sopenharmony_ci				unsigned long parent_rate)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	return __clk_rcg_set_rate(rcg, rcg->freq_tbl);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic int clk_rcg_bypass2_determine_rate(struct clk_hw *hw,
5388c2ecf20Sopenharmony_ci				struct clk_rate_request *req)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct clk_hw *p;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	p = req->best_parent_hw;
5438c2ecf20Sopenharmony_ci	req->best_parent_rate = clk_hw_round_rate(p, req->rate);
5448c2ecf20Sopenharmony_ci	req->rate = req->best_parent_rate;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return 0;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic int clk_rcg_bypass2_set_rate(struct clk_hw *hw, unsigned long rate,
5508c2ecf20Sopenharmony_ci				unsigned long parent_rate)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
5538c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
5548c2ecf20Sopenharmony_ci	u32 ns, src;
5558c2ecf20Sopenharmony_ci	int i, ret, num_parents = clk_hw_get_num_parents(hw);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
5588c2ecf20Sopenharmony_ci	if (ret)
5598c2ecf20Sopenharmony_ci		return ret;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	src = ns_to_src(&rcg->s, ns);
5628c2ecf20Sopenharmony_ci	f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
5658c2ecf20Sopenharmony_ci		if (src == rcg->s.parent_map[i].cfg) {
5668c2ecf20Sopenharmony_ci			f.src = rcg->s.parent_map[i].src;
5678c2ecf20Sopenharmony_ci			return __clk_rcg_set_rate(rcg, &f);
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return -EINVAL;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int clk_rcg_bypass2_set_rate_and_parent(struct clk_hw *hw,
5758c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	/* Read the hardware to determine parent during set_rate */
5788c2ecf20Sopenharmony_ci	return clk_rcg_bypass2_set_rate(hw, rate, parent_rate);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistruct frac_entry {
5828c2ecf20Sopenharmony_ci	int num;
5838c2ecf20Sopenharmony_ci	int den;
5848c2ecf20Sopenharmony_ci};
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic const struct frac_entry pixel_table[] = {
5878c2ecf20Sopenharmony_ci	{ 1, 2 },
5888c2ecf20Sopenharmony_ci	{ 1, 3 },
5898c2ecf20Sopenharmony_ci	{ 3, 16 },
5908c2ecf20Sopenharmony_ci	{ }
5918c2ecf20Sopenharmony_ci};
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int clk_rcg_pixel_determine_rate(struct clk_hw *hw,
5948c2ecf20Sopenharmony_ci		struct clk_rate_request *req)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	int delta = 100000;
5978c2ecf20Sopenharmony_ci	const struct frac_entry *frac = pixel_table;
5988c2ecf20Sopenharmony_ci	unsigned long request, src_rate;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
6018c2ecf20Sopenharmony_ci		request = (req->rate * frac->den) / frac->num;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		src_rate = clk_hw_round_rate(req->best_parent_hw, request);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		if ((src_rate < (request - delta)) ||
6068c2ecf20Sopenharmony_ci			(src_rate > (request + delta)))
6078c2ecf20Sopenharmony_ci			continue;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		req->best_parent_rate = src_rate;
6108c2ecf20Sopenharmony_ci		req->rate = (src_rate * frac->num) / frac->den;
6118c2ecf20Sopenharmony_ci		return 0;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return -EINVAL;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
6188c2ecf20Sopenharmony_ci				unsigned long parent_rate)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
6218c2ecf20Sopenharmony_ci	int delta = 100000;
6228c2ecf20Sopenharmony_ci	const struct frac_entry *frac = pixel_table;
6238c2ecf20Sopenharmony_ci	unsigned long request;
6248c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
6258c2ecf20Sopenharmony_ci	u32 ns, src;
6268c2ecf20Sopenharmony_ci	int i, ret, num_parents = clk_hw_get_num_parents(hw);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
6298c2ecf20Sopenharmony_ci	if (ret)
6308c2ecf20Sopenharmony_ci		return ret;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	src = ns_to_src(&rcg->s, ns);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
6358c2ecf20Sopenharmony_ci		if (src == rcg->s.parent_map[i].cfg) {
6368c2ecf20Sopenharmony_ci			f.src = rcg->s.parent_map[i].src;
6378c2ecf20Sopenharmony_ci			break;
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	/* bypass the pre divider */
6428c2ecf20Sopenharmony_ci	f.pre_div = 1;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	/* let us find appropriate m/n values for this */
6458c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
6468c2ecf20Sopenharmony_ci		request = (rate * frac->den) / frac->num;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		if ((parent_rate < (request - delta)) ||
6498c2ecf20Sopenharmony_ci			(parent_rate > (request + delta)))
6508c2ecf20Sopenharmony_ci			continue;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		f.m = frac->num;
6538c2ecf20Sopenharmony_ci		f.n = frac->den;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		return __clk_rcg_set_rate(rcg, &f);
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return -EINVAL;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic int clk_rcg_pixel_set_rate_and_parent(struct clk_hw *hw,
6628c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	return clk_rcg_pixel_set_rate(hw, rate, parent_rate);
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic int clk_rcg_esc_determine_rate(struct clk_hw *hw,
6688c2ecf20Sopenharmony_ci		struct clk_rate_request *req)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
6718c2ecf20Sopenharmony_ci	int pre_div_max = BIT(rcg->p.pre_div_width);
6728c2ecf20Sopenharmony_ci	int div;
6738c2ecf20Sopenharmony_ci	unsigned long src_rate;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	if (req->rate == 0)
6768c2ecf20Sopenharmony_ci		return -EINVAL;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	src_rate = clk_hw_get_rate(req->best_parent_hw);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	div = src_rate / req->rate;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (div >= 1 && div <= pre_div_max) {
6838c2ecf20Sopenharmony_ci		req->best_parent_rate = src_rate;
6848c2ecf20Sopenharmony_ci		req->rate = src_rate / div;
6858c2ecf20Sopenharmony_ci		return 0;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return -EINVAL;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic int clk_rcg_esc_set_rate(struct clk_hw *hw, unsigned long rate,
6928c2ecf20Sopenharmony_ci				unsigned long parent_rate)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
6958c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
6968c2ecf20Sopenharmony_ci	int pre_div_max = BIT(rcg->p.pre_div_width);
6978c2ecf20Sopenharmony_ci	int div;
6988c2ecf20Sopenharmony_ci	u32 ns;
6998c2ecf20Sopenharmony_ci	int i, ret, num_parents = clk_hw_get_num_parents(hw);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (rate == 0)
7028c2ecf20Sopenharmony_ci		return -EINVAL;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
7058c2ecf20Sopenharmony_ci	if (ret)
7068c2ecf20Sopenharmony_ci		return ret;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	ns = ns_to_src(&rcg->s, ns);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
7118c2ecf20Sopenharmony_ci		if (ns == rcg->s.parent_map[i].cfg) {
7128c2ecf20Sopenharmony_ci			f.src = rcg->s.parent_map[i].src;
7138c2ecf20Sopenharmony_ci			break;
7148c2ecf20Sopenharmony_ci		}
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	div = parent_rate / rate;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (div >= 1 && div <= pre_div_max) {
7208c2ecf20Sopenharmony_ci		f.pre_div = div;
7218c2ecf20Sopenharmony_ci		return __clk_rcg_set_rate(rcg, &f);
7228c2ecf20Sopenharmony_ci	}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	return -EINVAL;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int clk_rcg_esc_set_rate_and_parent(struct clk_hw *hw,
7288c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	return clk_rcg_esc_set_rate(hw, rate, parent_rate);
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/*
7348c2ecf20Sopenharmony_ci * This type of clock has a glitch-free mux that switches between the output of
7358c2ecf20Sopenharmony_ci * the M/N counter and an always on clock source (XO). When clk_set_rate() is
7368c2ecf20Sopenharmony_ci * called we need to make sure that we don't switch to the M/N counter if it
7378c2ecf20Sopenharmony_ci * isn't clocking because the mux will get stuck and the clock will stop
7388c2ecf20Sopenharmony_ci * outputting a clock. This can happen if the framework isn't aware that this
7398c2ecf20Sopenharmony_ci * clock is on and so clk_set_rate() doesn't turn on the new parent. To fix
7408c2ecf20Sopenharmony_ci * this we switch the mux in the enable/disable ops and reprogram the M/N
7418c2ecf20Sopenharmony_ci * counter in the set_rate op. We also make sure to switch away from the M/N
7428c2ecf20Sopenharmony_ci * counter in set_rate if software thinks the clock is off.
7438c2ecf20Sopenharmony_ci */
7448c2ecf20Sopenharmony_cistatic int clk_rcg_lcc_set_rate(struct clk_hw *hw, unsigned long rate,
7458c2ecf20Sopenharmony_ci				unsigned long parent_rate)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
7488c2ecf20Sopenharmony_ci	const struct freq_tbl *f;
7498c2ecf20Sopenharmony_ci	int ret;
7508c2ecf20Sopenharmony_ci	u32 gfm = BIT(10);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	f = qcom_find_freq(rcg->freq_tbl, rate);
7538c2ecf20Sopenharmony_ci	if (!f)
7548c2ecf20Sopenharmony_ci		return -EINVAL;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* Switch to XO to avoid glitches */
7578c2ecf20Sopenharmony_ci	regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, 0);
7588c2ecf20Sopenharmony_ci	ret = __clk_rcg_set_rate(rcg, f);
7598c2ecf20Sopenharmony_ci	/* Switch back to M/N if it's clocking */
7608c2ecf20Sopenharmony_ci	if (__clk_is_enabled(hw->clk))
7618c2ecf20Sopenharmony_ci		regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, gfm);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	return ret;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic int clk_rcg_lcc_enable(struct clk_hw *hw)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
7698c2ecf20Sopenharmony_ci	u32 gfm = BIT(10);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	/* Use M/N */
7728c2ecf20Sopenharmony_ci	return regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, gfm);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic void clk_rcg_lcc_disable(struct clk_hw *hw)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct clk_rcg *rcg = to_clk_rcg(hw);
7788c2ecf20Sopenharmony_ci	u32 gfm = BIT(10);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/* Use XO */
7818c2ecf20Sopenharmony_ci	regmap_update_bits(rcg->clkr.regmap, rcg->ns_reg, gfm, 0);
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
7878c2ecf20Sopenharmony_ci	const struct freq_tbl *f;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	f = qcom_find_freq(rcg->freq_tbl, rate);
7908c2ecf20Sopenharmony_ci	if (!f)
7918c2ecf20Sopenharmony_ci		return -EINVAL;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return configure_bank(rcg, f);
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
7978c2ecf20Sopenharmony_ci			    unsigned long parent_rate)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	return __clk_dyn_rcg_set_rate(hw, rate);
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic int clk_dyn_rcg_set_rate_and_parent(struct clk_hw *hw,
8038c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	return __clk_dyn_rcg_set_rate(hw, rate);
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_ops = {
8098c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8108c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8118c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8128c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8138c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8148c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_determine_rate,
8158c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_set_rate,
8168c2ecf20Sopenharmony_ci};
8178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_ops);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_bypass_ops = {
8208c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8218c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8228c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8238c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8248c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8258c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_bypass_determine_rate,
8268c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_bypass_set_rate,
8278c2ecf20Sopenharmony_ci};
8288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_bypass2_ops = {
8318c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8328c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8338c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8348c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8358c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8368c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_bypass2_determine_rate,
8378c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_bypass2_set_rate,
8388c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg_bypass2_set_rate_and_parent,
8398c2ecf20Sopenharmony_ci};
8408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_bypass2_ops);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_pixel_ops = {
8438c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8448c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8458c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8468c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8478c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8488c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_pixel_determine_rate,
8498c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_pixel_set_rate,
8508c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg_pixel_set_rate_and_parent,
8518c2ecf20Sopenharmony_ci};
8528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_pixel_ops);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_esc_ops = {
8558c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8568c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8578c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8588c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8598c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8608c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_esc_determine_rate,
8618c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_esc_set_rate,
8628c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg_esc_set_rate_and_parent,
8638c2ecf20Sopenharmony_ci};
8648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_esc_ops);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg_lcc_ops = {
8678c2ecf20Sopenharmony_ci	.enable = clk_rcg_lcc_enable,
8688c2ecf20Sopenharmony_ci	.disable = clk_rcg_lcc_disable,
8698c2ecf20Sopenharmony_ci	.get_parent = clk_rcg_get_parent,
8708c2ecf20Sopenharmony_ci	.set_parent = clk_rcg_set_parent,
8718c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg_recalc_rate,
8728c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg_determine_rate,
8738c2ecf20Sopenharmony_ci	.set_rate = clk_rcg_lcc_set_rate,
8748c2ecf20Sopenharmony_ci};
8758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg_lcc_ops);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ciconst struct clk_ops clk_dyn_rcg_ops = {
8788c2ecf20Sopenharmony_ci	.enable = clk_enable_regmap,
8798c2ecf20Sopenharmony_ci	.is_enabled = clk_is_enabled_regmap,
8808c2ecf20Sopenharmony_ci	.disable = clk_disable_regmap,
8818c2ecf20Sopenharmony_ci	.get_parent = clk_dyn_rcg_get_parent,
8828c2ecf20Sopenharmony_ci	.set_parent = clk_dyn_rcg_set_parent,
8838c2ecf20Sopenharmony_ci	.recalc_rate = clk_dyn_rcg_recalc_rate,
8848c2ecf20Sopenharmony_ci	.determine_rate = clk_dyn_rcg_determine_rate,
8858c2ecf20Sopenharmony_ci	.set_rate = clk_dyn_rcg_set_rate,
8868c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_dyn_rcg_set_rate_and_parent,
8878c2ecf20Sopenharmony_ci};
8888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_dyn_rcg_ops);
889