xref: /linux/drivers/clk/pistachio/clk-pll.c (revision 4f4adfbf8e655914bb80daa0252c90b62fd27d78)
143049b0cSAndrew Bresticker /*
243049b0cSAndrew Bresticker  * Copyright (C) 2014 Google, Inc.
343049b0cSAndrew Bresticker  *
443049b0cSAndrew Bresticker  * This program is free software; you can redistribute it and/or modify it
543049b0cSAndrew Bresticker  * under the terms and conditions of the GNU General Public License,
643049b0cSAndrew Bresticker  * version 2, as published by the Free Software Foundation.
743049b0cSAndrew Bresticker  */
843049b0cSAndrew Bresticker 
943049b0cSAndrew Bresticker #include <linux/clk-provider.h>
1043049b0cSAndrew Bresticker #include <linux/io.h>
1143049b0cSAndrew Bresticker #include <linux/kernel.h>
1243049b0cSAndrew Bresticker #include <linux/slab.h>
1343049b0cSAndrew Bresticker 
1443049b0cSAndrew Bresticker #include "clk.h"
1543049b0cSAndrew Bresticker 
1643049b0cSAndrew Bresticker #define PLL_STATUS			0x0
1743049b0cSAndrew Bresticker #define PLL_STATUS_LOCK			BIT(0)
1843049b0cSAndrew Bresticker 
1943049b0cSAndrew Bresticker #define PLL_CTRL1			0x4
2043049b0cSAndrew Bresticker #define PLL_CTRL1_REFDIV_SHIFT		0
2143049b0cSAndrew Bresticker #define PLL_CTRL1_REFDIV_MASK		0x3f
2243049b0cSAndrew Bresticker #define PLL_CTRL1_FBDIV_SHIFT		6
2343049b0cSAndrew Bresticker #define PLL_CTRL1_FBDIV_MASK		0xfff
2443049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV1_SHIFT	18
2543049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV1_MASK	0x7
2643049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV2_SHIFT	21
2743049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV2_MASK	0x7
2843049b0cSAndrew Bresticker #define PLL_INT_CTRL1_PD		BIT(24)
2943049b0cSAndrew Bresticker #define PLL_INT_CTRL1_DSMPD		BIT(25)
3043049b0cSAndrew Bresticker #define PLL_INT_CTRL1_FOUTPOSTDIVPD	BIT(26)
3143049b0cSAndrew Bresticker #define PLL_INT_CTRL1_FOUTVCOPD		BIT(27)
3243049b0cSAndrew Bresticker 
3343049b0cSAndrew Bresticker #define PLL_CTRL2			0x8
3443049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_FRAC_SHIFT	0
3543049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_FRAC_MASK	0xffffff
3643049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV1_SHIFT	24
3743049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV1_MASK	0x7
3843049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV2_SHIFT	27
3943049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV2_MASK	0x7
4043049b0cSAndrew Bresticker #define PLL_INT_CTRL2_BYPASS		BIT(28)
4143049b0cSAndrew Bresticker 
4243049b0cSAndrew Bresticker #define PLL_CTRL3			0xc
4343049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_PD		BIT(0)
4443049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_DACPD		BIT(1)
4543049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_DSMPD		BIT(2)
4643049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUTPOSTDIVPD	BIT(3)
4743049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUT4PHASEPD	BIT(4)
4843049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUTVCOPD	BIT(5)
4943049b0cSAndrew Bresticker 
5043049b0cSAndrew Bresticker #define PLL_CTRL4			0x10
5143049b0cSAndrew Bresticker #define PLL_FRAC_CTRL4_BYPASS		BIT(28)
5243049b0cSAndrew Bresticker 
5343049b0cSAndrew Bresticker struct pistachio_clk_pll {
5443049b0cSAndrew Bresticker 	struct clk_hw hw;
5543049b0cSAndrew Bresticker 	void __iomem *base;
5643049b0cSAndrew Bresticker 	struct pistachio_pll_rate_table *rates;
5743049b0cSAndrew Bresticker 	unsigned int nr_rates;
5843049b0cSAndrew Bresticker };
5943049b0cSAndrew Bresticker 
6043049b0cSAndrew Bresticker static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg)
6143049b0cSAndrew Bresticker {
6243049b0cSAndrew Bresticker 	return readl(pll->base + reg);
6343049b0cSAndrew Bresticker }
6443049b0cSAndrew Bresticker 
6543049b0cSAndrew Bresticker static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg)
6643049b0cSAndrew Bresticker {
6743049b0cSAndrew Bresticker 	writel(val, pll->base + reg);
6843049b0cSAndrew Bresticker }
6943049b0cSAndrew Bresticker 
70*4f4adfbfSEzequiel Garcia static inline void pll_lock(struct pistachio_clk_pll *pll)
71*4f4adfbfSEzequiel Garcia {
72*4f4adfbfSEzequiel Garcia 	while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
73*4f4adfbfSEzequiel Garcia 		cpu_relax();
74*4f4adfbfSEzequiel Garcia }
75*4f4adfbfSEzequiel Garcia 
7643049b0cSAndrew Bresticker static inline u32 do_div_round_closest(u64 dividend, u32 divisor)
7743049b0cSAndrew Bresticker {
7843049b0cSAndrew Bresticker 	dividend += divisor / 2;
7943049b0cSAndrew Bresticker 	do_div(dividend, divisor);
8043049b0cSAndrew Bresticker 
8143049b0cSAndrew Bresticker 	return dividend;
8243049b0cSAndrew Bresticker }
8343049b0cSAndrew Bresticker 
8443049b0cSAndrew Bresticker static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
8543049b0cSAndrew Bresticker {
8643049b0cSAndrew Bresticker 	return container_of(hw, struct pistachio_clk_pll, hw);
8743049b0cSAndrew Bresticker }
8843049b0cSAndrew Bresticker 
8943049b0cSAndrew Bresticker static struct pistachio_pll_rate_table *
9043049b0cSAndrew Bresticker pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
9143049b0cSAndrew Bresticker 	       unsigned long fout)
9243049b0cSAndrew Bresticker {
9343049b0cSAndrew Bresticker 	unsigned int i;
9443049b0cSAndrew Bresticker 
9543049b0cSAndrew Bresticker 	for (i = 0; i < pll->nr_rates; i++) {
9643049b0cSAndrew Bresticker 		if (pll->rates[i].fref == fref && pll->rates[i].fout == fout)
9743049b0cSAndrew Bresticker 			return &pll->rates[i];
9843049b0cSAndrew Bresticker 	}
9943049b0cSAndrew Bresticker 
10043049b0cSAndrew Bresticker 	return NULL;
10143049b0cSAndrew Bresticker }
10243049b0cSAndrew Bresticker 
10343049b0cSAndrew Bresticker static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
10443049b0cSAndrew Bresticker 			   unsigned long *parent_rate)
10543049b0cSAndrew Bresticker {
10643049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
10743049b0cSAndrew Bresticker 	unsigned int i;
10843049b0cSAndrew Bresticker 
10943049b0cSAndrew Bresticker 	for (i = 0; i < pll->nr_rates; i++) {
11043049b0cSAndrew Bresticker 		if (i > 0 && pll->rates[i].fref == *parent_rate &&
11143049b0cSAndrew Bresticker 		    pll->rates[i].fout <= rate)
11243049b0cSAndrew Bresticker 			return pll->rates[i - 1].fout;
11343049b0cSAndrew Bresticker 	}
11443049b0cSAndrew Bresticker 
11543049b0cSAndrew Bresticker 	return pll->rates[0].fout;
11643049b0cSAndrew Bresticker }
11743049b0cSAndrew Bresticker 
11843049b0cSAndrew Bresticker static int pll_gf40lp_frac_enable(struct clk_hw *hw)
11943049b0cSAndrew Bresticker {
12043049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
12143049b0cSAndrew Bresticker 	u32 val;
12243049b0cSAndrew Bresticker 
12343049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL3);
12443049b0cSAndrew Bresticker 	val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD |
12543049b0cSAndrew Bresticker 		 PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
12643049b0cSAndrew Bresticker 		 PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD);
12743049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL3);
12843049b0cSAndrew Bresticker 
12943049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL4);
13043049b0cSAndrew Bresticker 	val &= ~PLL_FRAC_CTRL4_BYPASS;
13143049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL4);
13243049b0cSAndrew Bresticker 
13343049b0cSAndrew Bresticker 	return 0;
13443049b0cSAndrew Bresticker }
13543049b0cSAndrew Bresticker 
13643049b0cSAndrew Bresticker static void pll_gf40lp_frac_disable(struct clk_hw *hw)
13743049b0cSAndrew Bresticker {
13843049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
13943049b0cSAndrew Bresticker 	u32 val;
14043049b0cSAndrew Bresticker 
14143049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL3);
14243049b0cSAndrew Bresticker 	val |= PLL_FRAC_CTRL3_PD;
14343049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL3);
14443049b0cSAndrew Bresticker }
14543049b0cSAndrew Bresticker 
14643049b0cSAndrew Bresticker static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw)
14743049b0cSAndrew Bresticker {
14843049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
14943049b0cSAndrew Bresticker 
15043049b0cSAndrew Bresticker 	return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD);
15143049b0cSAndrew Bresticker }
15243049b0cSAndrew Bresticker 
15343049b0cSAndrew Bresticker static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
15443049b0cSAndrew Bresticker 				    unsigned long parent_rate)
15543049b0cSAndrew Bresticker {
15643049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
15743049b0cSAndrew Bresticker 	struct pistachio_pll_rate_table *params;
15843049b0cSAndrew Bresticker 	bool was_enabled;
15943049b0cSAndrew Bresticker 	u32 val;
16043049b0cSAndrew Bresticker 
16143049b0cSAndrew Bresticker 	params = pll_get_params(pll, parent_rate, rate);
16243049b0cSAndrew Bresticker 	if (!params)
16343049b0cSAndrew Bresticker 		return -EINVAL;
16443049b0cSAndrew Bresticker 
16543049b0cSAndrew Bresticker 	was_enabled = pll_gf40lp_frac_is_enabled(hw);
16643049b0cSAndrew Bresticker 	if (!was_enabled)
16743049b0cSAndrew Bresticker 		pll_gf40lp_frac_enable(hw);
16843049b0cSAndrew Bresticker 
16943049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
17043049b0cSAndrew Bresticker 	val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
17143049b0cSAndrew Bresticker 		 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT));
17243049b0cSAndrew Bresticker 	val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
17343049b0cSAndrew Bresticker 		(params->fbdiv << PLL_CTRL1_FBDIV_SHIFT);
17443049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL1);
17543049b0cSAndrew Bresticker 
17643049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL2);
17743049b0cSAndrew Bresticker 	val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) |
17843049b0cSAndrew Bresticker 		 (PLL_FRAC_CTRL2_POSTDIV1_MASK <<
17943049b0cSAndrew Bresticker 		  PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
18043049b0cSAndrew Bresticker 		 (PLL_FRAC_CTRL2_POSTDIV2_MASK <<
18143049b0cSAndrew Bresticker 		  PLL_FRAC_CTRL2_POSTDIV2_SHIFT));
18243049b0cSAndrew Bresticker 	val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) |
18343049b0cSAndrew Bresticker 		(params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
18443049b0cSAndrew Bresticker 		(params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
18543049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL2);
18643049b0cSAndrew Bresticker 
187*4f4adfbfSEzequiel Garcia 	pll_lock(pll);
18843049b0cSAndrew Bresticker 
18943049b0cSAndrew Bresticker 	if (!was_enabled)
19043049b0cSAndrew Bresticker 		pll_gf40lp_frac_disable(hw);
19143049b0cSAndrew Bresticker 
19243049b0cSAndrew Bresticker 	return 0;
19343049b0cSAndrew Bresticker }
19443049b0cSAndrew Bresticker 
19543049b0cSAndrew Bresticker static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
19643049b0cSAndrew Bresticker 						 unsigned long parent_rate)
19743049b0cSAndrew Bresticker {
19843049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
19943049b0cSAndrew Bresticker 	u32 val, prediv, fbdiv, frac, postdiv1, postdiv2;
20043049b0cSAndrew Bresticker 	u64 rate = parent_rate;
20143049b0cSAndrew Bresticker 
20243049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
20343049b0cSAndrew Bresticker 	prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
20443049b0cSAndrew Bresticker 	fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
20543049b0cSAndrew Bresticker 
20643049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL2);
20743049b0cSAndrew Bresticker 	postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) &
20843049b0cSAndrew Bresticker 		PLL_FRAC_CTRL2_POSTDIV1_MASK;
20943049b0cSAndrew Bresticker 	postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) &
21043049b0cSAndrew Bresticker 		PLL_FRAC_CTRL2_POSTDIV2_MASK;
21143049b0cSAndrew Bresticker 	frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
21243049b0cSAndrew Bresticker 
21343049b0cSAndrew Bresticker 	rate *= (fbdiv << 24) + frac;
21443049b0cSAndrew Bresticker 	rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
21543049b0cSAndrew Bresticker 
21643049b0cSAndrew Bresticker 	return rate;
21743049b0cSAndrew Bresticker }
21843049b0cSAndrew Bresticker 
21943049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_frac_ops = {
22043049b0cSAndrew Bresticker 	.enable = pll_gf40lp_frac_enable,
22143049b0cSAndrew Bresticker 	.disable = pll_gf40lp_frac_disable,
22243049b0cSAndrew Bresticker 	.is_enabled = pll_gf40lp_frac_is_enabled,
22343049b0cSAndrew Bresticker 	.recalc_rate = pll_gf40lp_frac_recalc_rate,
22443049b0cSAndrew Bresticker 	.round_rate = pll_round_rate,
22543049b0cSAndrew Bresticker 	.set_rate = pll_gf40lp_frac_set_rate,
22643049b0cSAndrew Bresticker };
22743049b0cSAndrew Bresticker 
22843049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_frac_fixed_ops = {
22943049b0cSAndrew Bresticker 	.enable = pll_gf40lp_frac_enable,
23043049b0cSAndrew Bresticker 	.disable = pll_gf40lp_frac_disable,
23143049b0cSAndrew Bresticker 	.is_enabled = pll_gf40lp_frac_is_enabled,
23243049b0cSAndrew Bresticker 	.recalc_rate = pll_gf40lp_frac_recalc_rate,
23343049b0cSAndrew Bresticker };
23443049b0cSAndrew Bresticker 
23543049b0cSAndrew Bresticker static int pll_gf40lp_laint_enable(struct clk_hw *hw)
23643049b0cSAndrew Bresticker {
23743049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
23843049b0cSAndrew Bresticker 	u32 val;
23943049b0cSAndrew Bresticker 
24043049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
24143049b0cSAndrew Bresticker 	val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD |
24243049b0cSAndrew Bresticker 		 PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD);
24343049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL1);
24443049b0cSAndrew Bresticker 
24543049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL2);
24643049b0cSAndrew Bresticker 	val &= ~PLL_INT_CTRL2_BYPASS;
24743049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL2);
24843049b0cSAndrew Bresticker 
24943049b0cSAndrew Bresticker 	return 0;
25043049b0cSAndrew Bresticker }
25143049b0cSAndrew Bresticker 
25243049b0cSAndrew Bresticker static void pll_gf40lp_laint_disable(struct clk_hw *hw)
25343049b0cSAndrew Bresticker {
25443049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
25543049b0cSAndrew Bresticker 	u32 val;
25643049b0cSAndrew Bresticker 
25743049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
25843049b0cSAndrew Bresticker 	val |= PLL_INT_CTRL1_PD;
25943049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL1);
26043049b0cSAndrew Bresticker }
26143049b0cSAndrew Bresticker 
26243049b0cSAndrew Bresticker static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw)
26343049b0cSAndrew Bresticker {
26443049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
26543049b0cSAndrew Bresticker 
26643049b0cSAndrew Bresticker 	return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD);
26743049b0cSAndrew Bresticker }
26843049b0cSAndrew Bresticker 
26943049b0cSAndrew Bresticker static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
27043049b0cSAndrew Bresticker 				     unsigned long parent_rate)
27143049b0cSAndrew Bresticker {
27243049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
27343049b0cSAndrew Bresticker 	struct pistachio_pll_rate_table *params;
27443049b0cSAndrew Bresticker 	bool was_enabled;
27543049b0cSAndrew Bresticker 	u32 val;
27643049b0cSAndrew Bresticker 
27743049b0cSAndrew Bresticker 	params = pll_get_params(pll, parent_rate, rate);
27843049b0cSAndrew Bresticker 	if (!params)
27943049b0cSAndrew Bresticker 		return -EINVAL;
28043049b0cSAndrew Bresticker 
28143049b0cSAndrew Bresticker 	was_enabled = pll_gf40lp_laint_is_enabled(hw);
28243049b0cSAndrew Bresticker 	if (!was_enabled)
28343049b0cSAndrew Bresticker 		pll_gf40lp_laint_enable(hw);
28443049b0cSAndrew Bresticker 
28543049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
28643049b0cSAndrew Bresticker 	val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
28743049b0cSAndrew Bresticker 		 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) |
28843049b0cSAndrew Bresticker 		 (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
28943049b0cSAndrew Bresticker 		 (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT));
29043049b0cSAndrew Bresticker 	val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
29143049b0cSAndrew Bresticker 		(params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) |
29243049b0cSAndrew Bresticker 		(params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
29343049b0cSAndrew Bresticker 		(params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT);
29443049b0cSAndrew Bresticker 	pll_writel(pll, val, PLL_CTRL1);
29543049b0cSAndrew Bresticker 
296*4f4adfbfSEzequiel Garcia 	pll_lock(pll);
29743049b0cSAndrew Bresticker 
29843049b0cSAndrew Bresticker 	if (!was_enabled)
29943049b0cSAndrew Bresticker 		pll_gf40lp_laint_disable(hw);
30043049b0cSAndrew Bresticker 
30143049b0cSAndrew Bresticker 	return 0;
30243049b0cSAndrew Bresticker }
30343049b0cSAndrew Bresticker 
30443049b0cSAndrew Bresticker static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw,
30543049b0cSAndrew Bresticker 						  unsigned long parent_rate)
30643049b0cSAndrew Bresticker {
30743049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
30843049b0cSAndrew Bresticker 	u32 val, prediv, fbdiv, postdiv1, postdiv2;
30943049b0cSAndrew Bresticker 	u64 rate = parent_rate;
31043049b0cSAndrew Bresticker 
31143049b0cSAndrew Bresticker 	val = pll_readl(pll, PLL_CTRL1);
31243049b0cSAndrew Bresticker 	prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
31343049b0cSAndrew Bresticker 	fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
31443049b0cSAndrew Bresticker 	postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) &
31543049b0cSAndrew Bresticker 		PLL_INT_CTRL1_POSTDIV1_MASK;
31643049b0cSAndrew Bresticker 	postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) &
31743049b0cSAndrew Bresticker 		PLL_INT_CTRL1_POSTDIV2_MASK;
31843049b0cSAndrew Bresticker 
31943049b0cSAndrew Bresticker 	rate *= fbdiv;
32043049b0cSAndrew Bresticker 	rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2);
32143049b0cSAndrew Bresticker 
32243049b0cSAndrew Bresticker 	return rate;
32343049b0cSAndrew Bresticker }
32443049b0cSAndrew Bresticker 
32543049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_laint_ops = {
32643049b0cSAndrew Bresticker 	.enable = pll_gf40lp_laint_enable,
32743049b0cSAndrew Bresticker 	.disable = pll_gf40lp_laint_disable,
32843049b0cSAndrew Bresticker 	.is_enabled = pll_gf40lp_laint_is_enabled,
32943049b0cSAndrew Bresticker 	.recalc_rate = pll_gf40lp_laint_recalc_rate,
33043049b0cSAndrew Bresticker 	.round_rate = pll_round_rate,
33143049b0cSAndrew Bresticker 	.set_rate = pll_gf40lp_laint_set_rate,
33243049b0cSAndrew Bresticker };
33343049b0cSAndrew Bresticker 
33443049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_laint_fixed_ops = {
33543049b0cSAndrew Bresticker 	.enable = pll_gf40lp_laint_enable,
33643049b0cSAndrew Bresticker 	.disable = pll_gf40lp_laint_disable,
33743049b0cSAndrew Bresticker 	.is_enabled = pll_gf40lp_laint_is_enabled,
33843049b0cSAndrew Bresticker 	.recalc_rate = pll_gf40lp_laint_recalc_rate,
33943049b0cSAndrew Bresticker };
34043049b0cSAndrew Bresticker 
34143049b0cSAndrew Bresticker static struct clk *pll_register(const char *name, const char *parent_name,
34243049b0cSAndrew Bresticker 				unsigned long flags, void __iomem *base,
34343049b0cSAndrew Bresticker 				enum pistachio_pll_type type,
34443049b0cSAndrew Bresticker 				struct pistachio_pll_rate_table *rates,
34543049b0cSAndrew Bresticker 				unsigned int nr_rates)
34643049b0cSAndrew Bresticker {
34743049b0cSAndrew Bresticker 	struct pistachio_clk_pll *pll;
34843049b0cSAndrew Bresticker 	struct clk_init_data init;
34943049b0cSAndrew Bresticker 	struct clk *clk;
35043049b0cSAndrew Bresticker 
35143049b0cSAndrew Bresticker 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
35243049b0cSAndrew Bresticker 	if (!pll)
35343049b0cSAndrew Bresticker 		return ERR_PTR(-ENOMEM);
35443049b0cSAndrew Bresticker 
35543049b0cSAndrew Bresticker 	init.name = name;
35643049b0cSAndrew Bresticker 	init.flags = flags | CLK_GET_RATE_NOCACHE;
35743049b0cSAndrew Bresticker 	init.parent_names = &parent_name;
35843049b0cSAndrew Bresticker 	init.num_parents = 1;
35943049b0cSAndrew Bresticker 
36043049b0cSAndrew Bresticker 	switch (type) {
36143049b0cSAndrew Bresticker 	case PLL_GF40LP_FRAC:
36243049b0cSAndrew Bresticker 		if (rates)
36343049b0cSAndrew Bresticker 			init.ops = &pll_gf40lp_frac_ops;
36443049b0cSAndrew Bresticker 		else
36543049b0cSAndrew Bresticker 			init.ops = &pll_gf40lp_frac_fixed_ops;
36643049b0cSAndrew Bresticker 		break;
36743049b0cSAndrew Bresticker 	case PLL_GF40LP_LAINT:
36843049b0cSAndrew Bresticker 		if (rates)
36943049b0cSAndrew Bresticker 			init.ops = &pll_gf40lp_laint_ops;
37043049b0cSAndrew Bresticker 		else
37143049b0cSAndrew Bresticker 			init.ops = &pll_gf40lp_laint_fixed_ops;
37243049b0cSAndrew Bresticker 		break;
37343049b0cSAndrew Bresticker 	default:
37443049b0cSAndrew Bresticker 		pr_err("Unrecognized PLL type %u\n", type);
37543049b0cSAndrew Bresticker 		kfree(pll);
37643049b0cSAndrew Bresticker 		return ERR_PTR(-EINVAL);
37743049b0cSAndrew Bresticker 	}
37843049b0cSAndrew Bresticker 
37943049b0cSAndrew Bresticker 	pll->hw.init = &init;
38043049b0cSAndrew Bresticker 	pll->base = base;
38143049b0cSAndrew Bresticker 	pll->rates = rates;
38243049b0cSAndrew Bresticker 	pll->nr_rates = nr_rates;
38343049b0cSAndrew Bresticker 
38443049b0cSAndrew Bresticker 	clk = clk_register(NULL, &pll->hw);
38543049b0cSAndrew Bresticker 	if (IS_ERR(clk))
38643049b0cSAndrew Bresticker 		kfree(pll);
38743049b0cSAndrew Bresticker 
38843049b0cSAndrew Bresticker 	return clk;
38943049b0cSAndrew Bresticker }
39043049b0cSAndrew Bresticker 
39143049b0cSAndrew Bresticker void pistachio_clk_register_pll(struct pistachio_clk_provider *p,
39243049b0cSAndrew Bresticker 				struct pistachio_pll *pll,
39343049b0cSAndrew Bresticker 				unsigned int num)
39443049b0cSAndrew Bresticker {
39543049b0cSAndrew Bresticker 	struct clk *clk;
39643049b0cSAndrew Bresticker 	unsigned int i;
39743049b0cSAndrew Bresticker 
39843049b0cSAndrew Bresticker 	for (i = 0; i < num; i++) {
39943049b0cSAndrew Bresticker 		clk = pll_register(pll[i].name, pll[i].parent,
40043049b0cSAndrew Bresticker 				   0, p->base + pll[i].reg_base,
40143049b0cSAndrew Bresticker 				   pll[i].type, pll[i].rates,
40243049b0cSAndrew Bresticker 				   pll[i].nr_rates);
40343049b0cSAndrew Bresticker 		p->clk_data.clks[pll[i].id] = clk;
40443049b0cSAndrew Bresticker 	}
40543049b0cSAndrew Bresticker }
406