162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Ingenic SoC CGU driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013-2015 Imagination Technologies
662306a36Sopenharmony_ci * Author: Paul Burton <paul.burton@mips.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/clk-provider.h>
1262306a36Sopenharmony_ci#include <linux/clkdev.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/iopoll.h>
1662306a36Sopenharmony_ci#include <linux/math64.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_address.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/spinlock.h>
2162306a36Sopenharmony_ci#include <linux/time.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "cgu.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define MHZ (1000 * 1000)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic inline const struct ingenic_cgu_clk_info *
2862306a36Sopenharmony_cito_clk_info(struct ingenic_clk *clk)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	return &clk->cgu->clock_info[clk->idx];
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/**
3462306a36Sopenharmony_ci * ingenic_cgu_gate_get() - get the value of clock gate register bit
3562306a36Sopenharmony_ci * @cgu: reference to the CGU whose registers should be read
3662306a36Sopenharmony_ci * @info: info struct describing the gate bit
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Retrieves the state of the clock gate bit described by info. The
3962306a36Sopenharmony_ci * caller must hold cgu->lock.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * Return: true if the gate bit is set, else false.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistatic inline bool
4462306a36Sopenharmony_ciingenic_cgu_gate_get(struct ingenic_cgu *cgu,
4562306a36Sopenharmony_ci		     const struct ingenic_cgu_gate_info *info)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return !!(readl(cgu->base + info->reg) & BIT(info->bit))
4862306a36Sopenharmony_ci		^ info->clear_to_gate;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/**
5262306a36Sopenharmony_ci * ingenic_cgu_gate_set() - set the value of clock gate register bit
5362306a36Sopenharmony_ci * @cgu: reference to the CGU whose registers should be modified
5462306a36Sopenharmony_ci * @info: info struct describing the gate bit
5562306a36Sopenharmony_ci * @val: non-zero to gate a clock, otherwise zero
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * Sets the given gate bit in order to gate or ungate a clock.
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * The caller must hold cgu->lock.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_cistatic inline void
6262306a36Sopenharmony_ciingenic_cgu_gate_set(struct ingenic_cgu *cgu,
6362306a36Sopenharmony_ci		     const struct ingenic_cgu_gate_info *info, bool val)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	u32 clkgr = readl(cgu->base + info->reg);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (val ^ info->clear_to_gate)
6862306a36Sopenharmony_ci		clkgr |= BIT(info->bit);
6962306a36Sopenharmony_ci	else
7062306a36Sopenharmony_ci		clkgr &= ~BIT(info->bit);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	writel(clkgr, cgu->base + info->reg);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*
7662306a36Sopenharmony_ci * PLL operations
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic unsigned long
8062306a36Sopenharmony_ciingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
8362306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
8462306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
8562306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info;
8662306a36Sopenharmony_ci	unsigned m, n, od, od_enc = 0;
8762306a36Sopenharmony_ci	bool bypass;
8862306a36Sopenharmony_ci	u32 ctl;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	BUG_ON(clk_info->type != CGU_CLK_PLL);
9162306a36Sopenharmony_ci	pll_info = &clk_info->pll;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	ctl = readl(cgu->base + pll_info->reg);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	m = (ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0);
9662306a36Sopenharmony_ci	m += pll_info->m_offset;
9762306a36Sopenharmony_ci	n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0);
9862306a36Sopenharmony_ci	n += pll_info->n_offset;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (pll_info->od_bits > 0) {
10162306a36Sopenharmony_ci		od_enc = ctl >> pll_info->od_shift;
10262306a36Sopenharmony_ci		od_enc &= GENMASK(pll_info->od_bits - 1, 0);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (pll_info->bypass_bit >= 0) {
10662306a36Sopenharmony_ci		ctl = readl(cgu->base + pll_info->bypass_reg);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		bypass = !!(ctl & BIT(pll_info->bypass_bit));
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		if (bypass)
11162306a36Sopenharmony_ci			return parent_rate;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	for (od = 0; od < pll_info->od_max; od++)
11562306a36Sopenharmony_ci		if (pll_info->od_encoding[od] == od_enc)
11662306a36Sopenharmony_ci			break;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* if od_max = 0, od_bits should be 0 and od is fixed to 1. */
11962306a36Sopenharmony_ci	if (pll_info->od_max == 0)
12062306a36Sopenharmony_ci		BUG_ON(pll_info->od_bits != 0);
12162306a36Sopenharmony_ci	else
12262306a36Sopenharmony_ci		BUG_ON(od == pll_info->od_max);
12362306a36Sopenharmony_ci	od++;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return div_u64((u64)parent_rate * m * pll_info->rate_multiplier,
12662306a36Sopenharmony_ci		n * od);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void
13062306a36Sopenharmony_ciingenic_pll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
13162306a36Sopenharmony_ci			unsigned long rate, unsigned long parent_rate,
13262306a36Sopenharmony_ci			unsigned int *pm, unsigned int *pn, unsigned int *pod)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	unsigned int m, n, od = 1;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/*
13762306a36Sopenharmony_ci	 * The frequency after the input divider must be between 10 and 50 MHz.
13862306a36Sopenharmony_ci	 * The highest divider yields the best resolution.
13962306a36Sopenharmony_ci	 */
14062306a36Sopenharmony_ci	n = parent_rate / (10 * MHZ);
14162306a36Sopenharmony_ci	n = min_t(unsigned int, n, 1 << pll_info->n_bits);
14262306a36Sopenharmony_ci	n = max_t(unsigned int, n, pll_info->n_offset);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	m = (rate / MHZ) * od * n / (parent_rate / MHZ);
14562306a36Sopenharmony_ci	m = min_t(unsigned int, m, 1 << pll_info->m_bits);
14662306a36Sopenharmony_ci	m = max_t(unsigned int, m, pll_info->m_offset);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	*pm = m;
14962306a36Sopenharmony_ci	*pn = n;
15062306a36Sopenharmony_ci	*pod = od;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic unsigned long
15462306a36Sopenharmony_ciingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
15562306a36Sopenharmony_ci		 unsigned long rate, unsigned long parent_rate,
15662306a36Sopenharmony_ci		 unsigned int *pm, unsigned int *pn, unsigned int *pod)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
15962306a36Sopenharmony_ci	unsigned int m, n, od;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (pll_info->calc_m_n_od)
16262306a36Sopenharmony_ci		(*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od);
16362306a36Sopenharmony_ci	else
16462306a36Sopenharmony_ci		ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (pm)
16762306a36Sopenharmony_ci		*pm = m;
16862306a36Sopenharmony_ci	if (pn)
16962306a36Sopenharmony_ci		*pn = n;
17062306a36Sopenharmony_ci	if (pod)
17162306a36Sopenharmony_ci		*pod = od;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return div_u64((u64)parent_rate * m * pll_info->rate_multiplier,
17462306a36Sopenharmony_ci		n * od);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic long
17862306a36Sopenharmony_ciingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
17962306a36Sopenharmony_ci		       unsigned long *prate)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
18262306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu,
18862306a36Sopenharmony_ci					   const struct ingenic_cgu_pll_info *pll_info)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	u32 ctl;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (pll_info->stable_bit < 0)
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return readl_poll_timeout(cgu->base + pll_info->reg, ctl,
19662306a36Sopenharmony_ci				  ctl & BIT(pll_info->stable_bit),
19762306a36Sopenharmony_ci				  0, 100 * USEC_PER_MSEC);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int
20162306a36Sopenharmony_ciingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
20262306a36Sopenharmony_ci		     unsigned long parent_rate)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
20562306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
20662306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
20762306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
20862306a36Sopenharmony_ci	unsigned long rate, flags;
20962306a36Sopenharmony_ci	unsigned int m, n, od;
21062306a36Sopenharmony_ci	int ret = 0;
21162306a36Sopenharmony_ci	u32 ctl;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
21462306a36Sopenharmony_ci			       &m, &n, &od);
21562306a36Sopenharmony_ci	if (rate != req_rate)
21662306a36Sopenharmony_ci		pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n",
21762306a36Sopenharmony_ci			clk_info->name, req_rate, rate);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	spin_lock_irqsave(&cgu->lock, flags);
22062306a36Sopenharmony_ci	ctl = readl(cgu->base + pll_info->reg);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift);
22362306a36Sopenharmony_ci	ctl |= (m - pll_info->m_offset) << pll_info->m_shift;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
22662306a36Sopenharmony_ci	ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (pll_info->od_bits > 0) {
22962306a36Sopenharmony_ci		ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
23062306a36Sopenharmony_ci		ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	writel(ctl, cgu->base + pll_info->reg);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (pll_info->set_rate_hook)
23662306a36Sopenharmony_ci		pll_info->set_rate_hook(pll_info, rate, parent_rate);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* If the PLL is enabled, verify that it's stable */
23962306a36Sopenharmony_ci	if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
24062306a36Sopenharmony_ci		ret = ingenic_pll_check_stable(cgu, pll_info);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	spin_unlock_irqrestore(&cgu->lock, flags);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return ret;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int ingenic_pll_enable(struct clk_hw *hw)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
25062306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
25162306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
25262306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
25362306a36Sopenharmony_ci	unsigned long flags;
25462306a36Sopenharmony_ci	int ret;
25562306a36Sopenharmony_ci	u32 ctl;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (pll_info->enable_bit < 0)
25862306a36Sopenharmony_ci		return 0;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	spin_lock_irqsave(&cgu->lock, flags);
26162306a36Sopenharmony_ci	if (pll_info->bypass_bit >= 0) {
26262306a36Sopenharmony_ci		ctl = readl(cgu->base + pll_info->bypass_reg);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		ctl &= ~BIT(pll_info->bypass_bit);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		writel(ctl, cgu->base + pll_info->bypass_reg);
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ctl = readl(cgu->base + pll_info->reg);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	ctl |= BIT(pll_info->enable_bit);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	writel(ctl, cgu->base + pll_info->reg);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ret = ingenic_pll_check_stable(cgu, pll_info);
27662306a36Sopenharmony_ci	spin_unlock_irqrestore(&cgu->lock, flags);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ret;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void ingenic_pll_disable(struct clk_hw *hw)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
28462306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
28562306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
28662306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
28762306a36Sopenharmony_ci	unsigned long flags;
28862306a36Sopenharmony_ci	u32 ctl;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (pll_info->enable_bit < 0)
29162306a36Sopenharmony_ci		return;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	spin_lock_irqsave(&cgu->lock, flags);
29462306a36Sopenharmony_ci	ctl = readl(cgu->base + pll_info->reg);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	ctl &= ~BIT(pll_info->enable_bit);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	writel(ctl, cgu->base + pll_info->reg);
29962306a36Sopenharmony_ci	spin_unlock_irqrestore(&cgu->lock, flags);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int ingenic_pll_is_enabled(struct clk_hw *hw)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
30562306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
30662306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
30762306a36Sopenharmony_ci	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
30862306a36Sopenharmony_ci	u32 ctl;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (pll_info->enable_bit < 0)
31162306a36Sopenharmony_ci		return true;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ctl = readl(cgu->base + pll_info->reg);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return !!(ctl & BIT(pll_info->enable_bit));
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic const struct clk_ops ingenic_pll_ops = {
31962306a36Sopenharmony_ci	.recalc_rate = ingenic_pll_recalc_rate,
32062306a36Sopenharmony_ci	.round_rate = ingenic_pll_round_rate,
32162306a36Sopenharmony_ci	.set_rate = ingenic_pll_set_rate,
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	.enable = ingenic_pll_enable,
32462306a36Sopenharmony_ci	.disable = ingenic_pll_disable,
32562306a36Sopenharmony_ci	.is_enabled = ingenic_pll_is_enabled,
32662306a36Sopenharmony_ci};
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/*
32962306a36Sopenharmony_ci * Operations for all non-PLL clocks
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic u8 ingenic_clk_get_parent(struct clk_hw *hw)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
33562306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
33662306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
33762306a36Sopenharmony_ci	u32 reg;
33862306a36Sopenharmony_ci	u8 i, hw_idx, idx = 0;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_MUX) {
34162306a36Sopenharmony_ci		reg = readl(cgu->base + clk_info->mux.reg);
34262306a36Sopenharmony_ci		hw_idx = (reg >> clk_info->mux.shift) &
34362306a36Sopenharmony_ci			 GENMASK(clk_info->mux.bits - 1, 0);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		/*
34662306a36Sopenharmony_ci		 * Convert the hardware index to the parent index by skipping
34762306a36Sopenharmony_ci		 * over any -1's in the parents array.
34862306a36Sopenharmony_ci		 */
34962306a36Sopenharmony_ci		for (i = 0; i < hw_idx; i++) {
35062306a36Sopenharmony_ci			if (clk_info->parents[i] != -1)
35162306a36Sopenharmony_ci				idx++;
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return idx;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int ingenic_clk_set_parent(struct clk_hw *hw, u8 idx)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
36162306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
36262306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
36362306a36Sopenharmony_ci	unsigned long flags;
36462306a36Sopenharmony_ci	u8 curr_idx, hw_idx, num_poss;
36562306a36Sopenharmony_ci	u32 reg, mask;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_MUX) {
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * Convert the parent index to the hardware index by adding
37062306a36Sopenharmony_ci		 * 1 for any -1 in the parents array preceding the given
37162306a36Sopenharmony_ci		 * index. That is, we want the index of idx'th entry in
37262306a36Sopenharmony_ci		 * clk_info->parents which does not equal -1.
37362306a36Sopenharmony_ci		 */
37462306a36Sopenharmony_ci		hw_idx = curr_idx = 0;
37562306a36Sopenharmony_ci		num_poss = 1 << clk_info->mux.bits;
37662306a36Sopenharmony_ci		for (; hw_idx < num_poss; hw_idx++) {
37762306a36Sopenharmony_ci			if (clk_info->parents[hw_idx] == -1)
37862306a36Sopenharmony_ci				continue;
37962306a36Sopenharmony_ci			if (curr_idx == idx)
38062306a36Sopenharmony_ci				break;
38162306a36Sopenharmony_ci			curr_idx++;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		/* idx should always be a valid parent */
38562306a36Sopenharmony_ci		BUG_ON(curr_idx != idx);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		mask = GENMASK(clk_info->mux.bits - 1, 0);
38862306a36Sopenharmony_ci		mask <<= clk_info->mux.shift;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		spin_lock_irqsave(&cgu->lock, flags);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci		/* write the register */
39362306a36Sopenharmony_ci		reg = readl(cgu->base + clk_info->mux.reg);
39462306a36Sopenharmony_ci		reg &= ~mask;
39562306a36Sopenharmony_ci		reg |= hw_idx << clk_info->mux.shift;
39662306a36Sopenharmony_ci		writel(reg, cgu->base + clk_info->mux.reg);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		spin_unlock_irqrestore(&cgu->lock, flags);
39962306a36Sopenharmony_ci		return 0;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return idx ? -EINVAL : 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic unsigned long
40662306a36Sopenharmony_ciingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
40962306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
41062306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
41162306a36Sopenharmony_ci	unsigned long rate = parent_rate;
41262306a36Sopenharmony_ci	u32 div_reg, div;
41362306a36Sopenharmony_ci	u8 parent;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_DIV) {
41662306a36Sopenharmony_ci		parent = ingenic_clk_get_parent(hw);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		if (!(clk_info->div.bypass_mask & BIT(parent))) {
41962306a36Sopenharmony_ci			div_reg = readl(cgu->base + clk_info->div.reg);
42062306a36Sopenharmony_ci			div = (div_reg >> clk_info->div.shift) &
42162306a36Sopenharmony_ci			      GENMASK(clk_info->div.bits - 1, 0);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci			if (clk_info->div.div_table)
42462306a36Sopenharmony_ci				div = clk_info->div.div_table[div];
42562306a36Sopenharmony_ci			else
42662306a36Sopenharmony_ci				div = (div + 1) * clk_info->div.div;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci			rate /= div;
42962306a36Sopenharmony_ci		}
43062306a36Sopenharmony_ci	} else if (clk_info->type & CGU_CLK_FIXDIV) {
43162306a36Sopenharmony_ci		rate /= clk_info->fixdiv.div;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return rate;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic unsigned int
43862306a36Sopenharmony_ciingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
43962306a36Sopenharmony_ci			unsigned int div)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	unsigned int i, best_i = 0, best = (unsigned int)-1;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	for (i = 0; i < (1 << clk_info->div.bits)
44462306a36Sopenharmony_ci				&& clk_info->div.div_table[i]; i++) {
44562306a36Sopenharmony_ci		if (clk_info->div.div_table[i] >= div &&
44662306a36Sopenharmony_ci		    clk_info->div.div_table[i] < best) {
44762306a36Sopenharmony_ci			best = clk_info->div.div_table[i];
44862306a36Sopenharmony_ci			best_i = i;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			if (div == best)
45162306a36Sopenharmony_ci				break;
45262306a36Sopenharmony_ci		}
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return best_i;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic unsigned
45962306a36Sopenharmony_ciingenic_clk_calc_div(struct clk_hw *hw,
46062306a36Sopenharmony_ci		     const struct ingenic_cgu_clk_info *clk_info,
46162306a36Sopenharmony_ci		     unsigned long parent_rate, unsigned long req_rate)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	unsigned int div, hw_div;
46462306a36Sopenharmony_ci	u8 parent;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	parent = ingenic_clk_get_parent(hw);
46762306a36Sopenharmony_ci	if (clk_info->div.bypass_mask & BIT(parent))
46862306a36Sopenharmony_ci		return 1;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* calculate the divide */
47162306a36Sopenharmony_ci	div = DIV_ROUND_UP(parent_rate, req_rate);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (clk_info->div.div_table) {
47462306a36Sopenharmony_ci		hw_div = ingenic_clk_calc_hw_div(clk_info, div);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		return clk_info->div.div_table[hw_div];
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Impose hardware constraints */
48062306a36Sopenharmony_ci	div = clamp_t(unsigned int, div, clk_info->div.div,
48162306a36Sopenharmony_ci		      clk_info->div.div << clk_info->div.bits);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/*
48462306a36Sopenharmony_ci	 * If the divider value itself must be divided before being written to
48562306a36Sopenharmony_ci	 * the divider register, we must ensure we don't have any bits set that
48662306a36Sopenharmony_ci	 * would be lost as a result of doing so.
48762306a36Sopenharmony_ci	 */
48862306a36Sopenharmony_ci	div = DIV_ROUND_UP(div, clk_info->div.div);
48962306a36Sopenharmony_ci	div *= clk_info->div.div;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return div;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int ingenic_clk_determine_rate(struct clk_hw *hw,
49562306a36Sopenharmony_ci				      struct clk_rate_request *req)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
49862306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
49962306a36Sopenharmony_ci	unsigned int div = 1;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_DIV)
50262306a36Sopenharmony_ci		div = ingenic_clk_calc_div(hw, clk_info, req->best_parent_rate,
50362306a36Sopenharmony_ci					   req->rate);
50462306a36Sopenharmony_ci	else if (clk_info->type & CGU_CLK_FIXDIV)
50562306a36Sopenharmony_ci		div = clk_info->fixdiv.div;
50662306a36Sopenharmony_ci	else if (clk_hw_can_set_rate_parent(hw))
50762306a36Sopenharmony_ci		req->best_parent_rate = req->rate;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	req->rate = DIV_ROUND_UP(req->best_parent_rate, div);
51062306a36Sopenharmony_ci	return 0;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic inline int ingenic_clk_check_stable(struct ingenic_cgu *cgu,
51462306a36Sopenharmony_ci					   const struct ingenic_cgu_clk_info *clk_info)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	u32 reg;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return readl_poll_timeout(cgu->base + clk_info->div.reg, reg,
51962306a36Sopenharmony_ci				  !(reg & BIT(clk_info->div.busy_bit)),
52062306a36Sopenharmony_ci				  0, 100 * USEC_PER_MSEC);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int
52462306a36Sopenharmony_ciingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
52562306a36Sopenharmony_ci		     unsigned long parent_rate)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
52862306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
52962306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
53062306a36Sopenharmony_ci	unsigned long rate, flags;
53162306a36Sopenharmony_ci	unsigned int hw_div, div;
53262306a36Sopenharmony_ci	u32 reg, mask;
53362306a36Sopenharmony_ci	int ret = 0;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_DIV) {
53662306a36Sopenharmony_ci		div = ingenic_clk_calc_div(hw, clk_info, parent_rate, req_rate);
53762306a36Sopenharmony_ci		rate = DIV_ROUND_UP(parent_rate, div);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		if (rate != req_rate)
54062306a36Sopenharmony_ci			return -EINVAL;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		if (clk_info->div.div_table)
54362306a36Sopenharmony_ci			hw_div = ingenic_clk_calc_hw_div(clk_info, div);
54462306a36Sopenharmony_ci		else
54562306a36Sopenharmony_ci			hw_div = ((div / clk_info->div.div) - 1);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		spin_lock_irqsave(&cgu->lock, flags);
54862306a36Sopenharmony_ci		reg = readl(cgu->base + clk_info->div.reg);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		/* update the divide */
55162306a36Sopenharmony_ci		mask = GENMASK(clk_info->div.bits - 1, 0);
55262306a36Sopenharmony_ci		reg &= ~(mask << clk_info->div.shift);
55362306a36Sopenharmony_ci		reg |= hw_div << clk_info->div.shift;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		/* clear the stop bit */
55662306a36Sopenharmony_ci		if (clk_info->div.stop_bit != -1)
55762306a36Sopenharmony_ci			reg &= ~BIT(clk_info->div.stop_bit);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		/* set the change enable bit */
56062306a36Sopenharmony_ci		if (clk_info->div.ce_bit != -1)
56162306a36Sopenharmony_ci			reg |= BIT(clk_info->div.ce_bit);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/* update the hardware */
56462306a36Sopenharmony_ci		writel(reg, cgu->base + clk_info->div.reg);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		/* wait for the change to take effect */
56762306a36Sopenharmony_ci		if (clk_info->div.busy_bit != -1)
56862306a36Sopenharmony_ci			ret = ingenic_clk_check_stable(cgu, clk_info);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		spin_unlock_irqrestore(&cgu->lock, flags);
57162306a36Sopenharmony_ci		return ret;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return -EINVAL;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int ingenic_clk_enable(struct clk_hw *hw)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
58062306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
58162306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
58262306a36Sopenharmony_ci	unsigned long flags;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_GATE) {
58562306a36Sopenharmony_ci		/* ungate the clock */
58662306a36Sopenharmony_ci		spin_lock_irqsave(&cgu->lock, flags);
58762306a36Sopenharmony_ci		ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
58862306a36Sopenharmony_ci		spin_unlock_irqrestore(&cgu->lock, flags);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		if (clk_info->gate.delay_us)
59162306a36Sopenharmony_ci			udelay(clk_info->gate.delay_us);
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return 0;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic void ingenic_clk_disable(struct clk_hw *hw)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
60062306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
60162306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
60262306a36Sopenharmony_ci	unsigned long flags;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_GATE) {
60562306a36Sopenharmony_ci		/* gate the clock */
60662306a36Sopenharmony_ci		spin_lock_irqsave(&cgu->lock, flags);
60762306a36Sopenharmony_ci		ingenic_cgu_gate_set(cgu, &clk_info->gate, true);
60862306a36Sopenharmony_ci		spin_unlock_irqrestore(&cgu->lock, flags);
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int ingenic_clk_is_enabled(struct clk_hw *hw)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
61562306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
61662306a36Sopenharmony_ci	struct ingenic_cgu *cgu = ingenic_clk->cgu;
61762306a36Sopenharmony_ci	int enabled = 1;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (clk_info->type & CGU_CLK_GATE)
62062306a36Sopenharmony_ci		enabled = !ingenic_cgu_gate_get(cgu, &clk_info->gate);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return enabled;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic const struct clk_ops ingenic_clk_ops = {
62662306a36Sopenharmony_ci	.get_parent = ingenic_clk_get_parent,
62762306a36Sopenharmony_ci	.set_parent = ingenic_clk_set_parent,
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	.recalc_rate = ingenic_clk_recalc_rate,
63062306a36Sopenharmony_ci	.determine_rate = ingenic_clk_determine_rate,
63162306a36Sopenharmony_ci	.set_rate = ingenic_clk_set_rate,
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	.enable = ingenic_clk_enable,
63462306a36Sopenharmony_ci	.disable = ingenic_clk_disable,
63562306a36Sopenharmony_ci	.is_enabled = ingenic_clk_is_enabled,
63662306a36Sopenharmony_ci};
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci/*
63962306a36Sopenharmony_ci * Setup functions.
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx];
64562306a36Sopenharmony_ci	struct clk_init_data clk_init;
64662306a36Sopenharmony_ci	struct ingenic_clk *ingenic_clk = NULL;
64762306a36Sopenharmony_ci	struct clk *clk, *parent;
64862306a36Sopenharmony_ci	const char *parent_names[4];
64962306a36Sopenharmony_ci	unsigned caps, i, num_possible;
65062306a36Sopenharmony_ci	int err = -EINVAL;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names));
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (clk_info->type == CGU_CLK_EXT) {
65562306a36Sopenharmony_ci		clk = of_clk_get_by_name(cgu->np, clk_info->name);
65662306a36Sopenharmony_ci		if (IS_ERR(clk)) {
65762306a36Sopenharmony_ci			pr_err("%s: no external clock '%s' provided\n",
65862306a36Sopenharmony_ci			       __func__, clk_info->name);
65962306a36Sopenharmony_ci			err = -ENODEV;
66062306a36Sopenharmony_ci			goto out;
66162306a36Sopenharmony_ci		}
66262306a36Sopenharmony_ci		err = clk_register_clkdev(clk, clk_info->name, NULL);
66362306a36Sopenharmony_ci		if (err) {
66462306a36Sopenharmony_ci			clk_put(clk);
66562306a36Sopenharmony_ci			goto out;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		cgu->clocks.clks[idx] = clk;
66862306a36Sopenharmony_ci		return 0;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (!clk_info->type) {
67262306a36Sopenharmony_ci		pr_err("%s: no clock type specified for '%s'\n", __func__,
67362306a36Sopenharmony_ci		       clk_info->name);
67462306a36Sopenharmony_ci		goto out;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	ingenic_clk = kzalloc(sizeof(*ingenic_clk), GFP_KERNEL);
67862306a36Sopenharmony_ci	if (!ingenic_clk) {
67962306a36Sopenharmony_ci		err = -ENOMEM;
68062306a36Sopenharmony_ci		goto out;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	ingenic_clk->hw.init = &clk_init;
68462306a36Sopenharmony_ci	ingenic_clk->cgu = cgu;
68562306a36Sopenharmony_ci	ingenic_clk->idx = idx;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	clk_init.name = clk_info->name;
68862306a36Sopenharmony_ci	clk_init.flags = clk_info->flags;
68962306a36Sopenharmony_ci	clk_init.parent_names = parent_names;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	caps = clk_info->type;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (caps & CGU_CLK_DIV) {
69462306a36Sopenharmony_ci		caps &= ~CGU_CLK_DIV;
69562306a36Sopenharmony_ci	} else if (!(caps & CGU_CLK_CUSTOM)) {
69662306a36Sopenharmony_ci		/* pass rate changes to the parent clock */
69762306a36Sopenharmony_ci		clk_init.flags |= CLK_SET_RATE_PARENT;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) {
70162306a36Sopenharmony_ci		clk_init.num_parents = 0;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		if (caps & CGU_CLK_MUX)
70462306a36Sopenharmony_ci			num_possible = 1 << clk_info->mux.bits;
70562306a36Sopenharmony_ci		else
70662306a36Sopenharmony_ci			num_possible = ARRAY_SIZE(clk_info->parents);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		for (i = 0; i < num_possible; i++) {
70962306a36Sopenharmony_ci			if (clk_info->parents[i] == -1)
71062306a36Sopenharmony_ci				continue;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci			parent = cgu->clocks.clks[clk_info->parents[i]];
71362306a36Sopenharmony_ci			parent_names[clk_init.num_parents] =
71462306a36Sopenharmony_ci				__clk_get_name(parent);
71562306a36Sopenharmony_ci			clk_init.num_parents++;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		BUG_ON(!clk_init.num_parents);
71962306a36Sopenharmony_ci		BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names));
72062306a36Sopenharmony_ci	} else {
72162306a36Sopenharmony_ci		BUG_ON(clk_info->parents[0] == -1);
72262306a36Sopenharmony_ci		clk_init.num_parents = 1;
72362306a36Sopenharmony_ci		parent = cgu->clocks.clks[clk_info->parents[0]];
72462306a36Sopenharmony_ci		parent_names[0] = __clk_get_name(parent);
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (caps & CGU_CLK_CUSTOM) {
72862306a36Sopenharmony_ci		clk_init.ops = clk_info->custom.clk_ops;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		caps &= ~CGU_CLK_CUSTOM;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		if (caps) {
73362306a36Sopenharmony_ci			pr_err("%s: custom clock may not be combined with type 0x%x\n",
73462306a36Sopenharmony_ci			       __func__, caps);
73562306a36Sopenharmony_ci			goto out;
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci	} else if (caps & CGU_CLK_PLL) {
73862306a36Sopenharmony_ci		clk_init.ops = &ingenic_pll_ops;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci		caps &= ~CGU_CLK_PLL;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		if (caps) {
74362306a36Sopenharmony_ci			pr_err("%s: PLL may not be combined with type 0x%x\n",
74462306a36Sopenharmony_ci			       __func__, caps);
74562306a36Sopenharmony_ci			goto out;
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci	} else {
74862306a36Sopenharmony_ci		clk_init.ops = &ingenic_clk_ops;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* nothing to do for gates or fixed dividers */
75262306a36Sopenharmony_ci	caps &= ~(CGU_CLK_GATE | CGU_CLK_FIXDIV);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (caps & CGU_CLK_MUX) {
75562306a36Sopenharmony_ci		if (!(caps & CGU_CLK_MUX_GLITCHFREE))
75662306a36Sopenharmony_ci			clk_init.flags |= CLK_SET_PARENT_GATE;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE);
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (caps) {
76262306a36Sopenharmony_ci		pr_err("%s: unknown clock type 0x%x\n", __func__, caps);
76362306a36Sopenharmony_ci		goto out;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	clk = clk_register(NULL, &ingenic_clk->hw);
76762306a36Sopenharmony_ci	if (IS_ERR(clk)) {
76862306a36Sopenharmony_ci		pr_err("%s: failed to register clock '%s'\n", __func__,
76962306a36Sopenharmony_ci		       clk_info->name);
77062306a36Sopenharmony_ci		err = PTR_ERR(clk);
77162306a36Sopenharmony_ci		goto out;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	err = clk_register_clkdev(clk, clk_info->name, NULL);
77562306a36Sopenharmony_ci	if (err)
77662306a36Sopenharmony_ci		goto out;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	cgu->clocks.clks[idx] = clk;
77962306a36Sopenharmony_ciout:
78062306a36Sopenharmony_ci	if (err)
78162306a36Sopenharmony_ci		kfree(ingenic_clk);
78262306a36Sopenharmony_ci	return err;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistruct ingenic_cgu *
78662306a36Sopenharmony_ciingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
78762306a36Sopenharmony_ci		unsigned num_clocks, struct device_node *np)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct ingenic_cgu *cgu;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	cgu = kzalloc(sizeof(*cgu), GFP_KERNEL);
79262306a36Sopenharmony_ci	if (!cgu)
79362306a36Sopenharmony_ci		goto err_out;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	cgu->base = of_iomap(np, 0);
79662306a36Sopenharmony_ci	if (!cgu->base) {
79762306a36Sopenharmony_ci		pr_err("%s: failed to map CGU registers\n", __func__);
79862306a36Sopenharmony_ci		goto err_out_free;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	cgu->np = np;
80262306a36Sopenharmony_ci	cgu->clock_info = clock_info;
80362306a36Sopenharmony_ci	cgu->clocks.clk_num = num_clocks;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	spin_lock_init(&cgu->lock);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return cgu;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cierr_out_free:
81062306a36Sopenharmony_ci	kfree(cgu);
81162306a36Sopenharmony_cierr_out:
81262306a36Sopenharmony_ci	return NULL;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ciint ingenic_cgu_register_clocks(struct ingenic_cgu *cgu)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	unsigned i;
81862306a36Sopenharmony_ci	int err;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	cgu->clocks.clks = kcalloc(cgu->clocks.clk_num, sizeof(struct clk *),
82162306a36Sopenharmony_ci				   GFP_KERNEL);
82262306a36Sopenharmony_ci	if (!cgu->clocks.clks) {
82362306a36Sopenharmony_ci		err = -ENOMEM;
82462306a36Sopenharmony_ci		goto err_out;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	for (i = 0; i < cgu->clocks.clk_num; i++) {
82862306a36Sopenharmony_ci		err = ingenic_register_clock(cgu, i);
82962306a36Sopenharmony_ci		if (err)
83062306a36Sopenharmony_ci			goto err_out_unregister;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get,
83462306a36Sopenharmony_ci				  &cgu->clocks);
83562306a36Sopenharmony_ci	if (err)
83662306a36Sopenharmony_ci		goto err_out_unregister;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cierr_out_unregister:
84162306a36Sopenharmony_ci	for (i = 0; i < cgu->clocks.clk_num; i++) {
84262306a36Sopenharmony_ci		if (!cgu->clocks.clks[i])
84362306a36Sopenharmony_ci			continue;
84462306a36Sopenharmony_ci		if (cgu->clock_info[i].type & CGU_CLK_EXT)
84562306a36Sopenharmony_ci			clk_put(cgu->clocks.clks[i]);
84662306a36Sopenharmony_ci		else
84762306a36Sopenharmony_ci			clk_unregister(cgu->clocks.clks[i]);
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci	kfree(cgu->clocks.clks);
85062306a36Sopenharmony_cierr_out:
85162306a36Sopenharmony_ci	return err;
85262306a36Sopenharmony_ci}
853