xref: /openbmc/linux/drivers/clk/sunxi-ng/ccu_frac.c (revision 89a3dfb787072438f72de95ff3fe7b58213e08c1)
1*89a3dfb7SMaxime Ripard /*
2*89a3dfb7SMaxime Ripard  * Copyright (C) 2016 Maxime Ripard
3*89a3dfb7SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
4*89a3dfb7SMaxime Ripard  *
5*89a3dfb7SMaxime Ripard  * This program is free software; you can redistribute it and/or
6*89a3dfb7SMaxime Ripard  * modify it under the terms of the GNU General Public License as
7*89a3dfb7SMaxime Ripard  * published by the Free Software Foundation; either version 2 of
8*89a3dfb7SMaxime Ripard  * the License, or (at your option) any later version.
9*89a3dfb7SMaxime Ripard  */
10*89a3dfb7SMaxime Ripard 
11*89a3dfb7SMaxime Ripard #include <linux/clk-provider.h>
12*89a3dfb7SMaxime Ripard #include <linux/spinlock.h>
13*89a3dfb7SMaxime Ripard 
14*89a3dfb7SMaxime Ripard #include "ccu_frac.h"
15*89a3dfb7SMaxime Ripard 
16*89a3dfb7SMaxime Ripard bool ccu_frac_helper_is_enabled(struct ccu_common *common,
17*89a3dfb7SMaxime Ripard 				struct _ccu_frac *cf)
18*89a3dfb7SMaxime Ripard {
19*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
20*89a3dfb7SMaxime Ripard 		return false;
21*89a3dfb7SMaxime Ripard 
22*89a3dfb7SMaxime Ripard 	return !(readl(common->base + common->reg) & cf->enable);
23*89a3dfb7SMaxime Ripard }
24*89a3dfb7SMaxime Ripard 
25*89a3dfb7SMaxime Ripard void ccu_frac_helper_enable(struct ccu_common *common,
26*89a3dfb7SMaxime Ripard 			    struct _ccu_frac *cf)
27*89a3dfb7SMaxime Ripard {
28*89a3dfb7SMaxime Ripard 	unsigned long flags;
29*89a3dfb7SMaxime Ripard 	u32 reg;
30*89a3dfb7SMaxime Ripard 
31*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
32*89a3dfb7SMaxime Ripard 		return;
33*89a3dfb7SMaxime Ripard 
34*89a3dfb7SMaxime Ripard 	spin_lock_irqsave(common->lock, flags);
35*89a3dfb7SMaxime Ripard 	reg = readl(common->base + common->reg);
36*89a3dfb7SMaxime Ripard 	writel(reg & ~cf->enable, common->base + common->reg);
37*89a3dfb7SMaxime Ripard 	spin_unlock_irqrestore(common->lock, flags);
38*89a3dfb7SMaxime Ripard }
39*89a3dfb7SMaxime Ripard 
40*89a3dfb7SMaxime Ripard void ccu_frac_helper_disable(struct ccu_common *common,
41*89a3dfb7SMaxime Ripard 			     struct _ccu_frac *cf)
42*89a3dfb7SMaxime Ripard {
43*89a3dfb7SMaxime Ripard 	unsigned long flags;
44*89a3dfb7SMaxime Ripard 	u32 reg;
45*89a3dfb7SMaxime Ripard 
46*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
47*89a3dfb7SMaxime Ripard 		return;
48*89a3dfb7SMaxime Ripard 
49*89a3dfb7SMaxime Ripard 	spin_lock_irqsave(common->lock, flags);
50*89a3dfb7SMaxime Ripard 	reg = readl(common->base + common->reg);
51*89a3dfb7SMaxime Ripard 	writel(reg | cf->enable, common->base + common->reg);
52*89a3dfb7SMaxime Ripard 	spin_unlock_irqrestore(common->lock, flags);
53*89a3dfb7SMaxime Ripard }
54*89a3dfb7SMaxime Ripard 
55*89a3dfb7SMaxime Ripard bool ccu_frac_helper_has_rate(struct ccu_common *common,
56*89a3dfb7SMaxime Ripard 			      struct _ccu_frac *cf,
57*89a3dfb7SMaxime Ripard 			      unsigned long rate)
58*89a3dfb7SMaxime Ripard {
59*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
60*89a3dfb7SMaxime Ripard 		return false;
61*89a3dfb7SMaxime Ripard 
62*89a3dfb7SMaxime Ripard 	return (cf->rates[0] == rate) || (cf->rates[1] == rate);
63*89a3dfb7SMaxime Ripard }
64*89a3dfb7SMaxime Ripard 
65*89a3dfb7SMaxime Ripard unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
66*89a3dfb7SMaxime Ripard 					struct _ccu_frac *cf)
67*89a3dfb7SMaxime Ripard {
68*89a3dfb7SMaxime Ripard 	u32 reg;
69*89a3dfb7SMaxime Ripard 
70*89a3dfb7SMaxime Ripard 	printk("%s: Read fractional\n", clk_hw_get_name(&common->hw));
71*89a3dfb7SMaxime Ripard 
72*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
73*89a3dfb7SMaxime Ripard 		return 0;
74*89a3dfb7SMaxime Ripard 
75*89a3dfb7SMaxime Ripard 	printk("%s: clock is fractional (rates %lu and %lu)\n",
76*89a3dfb7SMaxime Ripard 	       clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
77*89a3dfb7SMaxime Ripard 
78*89a3dfb7SMaxime Ripard 	reg = readl(common->base + common->reg);
79*89a3dfb7SMaxime Ripard 
80*89a3dfb7SMaxime Ripard 	printk("%s: clock reg is 0x%x (select is 0x%x)\n",
81*89a3dfb7SMaxime Ripard 	       clk_hw_get_name(&common->hw), reg, cf->select);
82*89a3dfb7SMaxime Ripard 
83*89a3dfb7SMaxime Ripard 	return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
84*89a3dfb7SMaxime Ripard }
85*89a3dfb7SMaxime Ripard 
86*89a3dfb7SMaxime Ripard int ccu_frac_helper_set_rate(struct ccu_common *common,
87*89a3dfb7SMaxime Ripard 			     struct _ccu_frac *cf,
88*89a3dfb7SMaxime Ripard 			     unsigned long rate)
89*89a3dfb7SMaxime Ripard {
90*89a3dfb7SMaxime Ripard 	unsigned long flags;
91*89a3dfb7SMaxime Ripard 	u32 reg, sel;
92*89a3dfb7SMaxime Ripard 
93*89a3dfb7SMaxime Ripard 	if (!(common->features & CCU_FEATURE_FRACTIONAL))
94*89a3dfb7SMaxime Ripard 		return -EINVAL;
95*89a3dfb7SMaxime Ripard 
96*89a3dfb7SMaxime Ripard 	if (cf->rates[0] == rate)
97*89a3dfb7SMaxime Ripard 		sel = 0;
98*89a3dfb7SMaxime Ripard 	else if (cf->rates[1] == rate)
99*89a3dfb7SMaxime Ripard 		sel = cf->select;
100*89a3dfb7SMaxime Ripard 	else
101*89a3dfb7SMaxime Ripard 		return -EINVAL;
102*89a3dfb7SMaxime Ripard 
103*89a3dfb7SMaxime Ripard 	spin_lock_irqsave(common->lock, flags);
104*89a3dfb7SMaxime Ripard 	reg = readl(common->base + common->reg);
105*89a3dfb7SMaxime Ripard 	reg &= ~cf->select;
106*89a3dfb7SMaxime Ripard 	writel(reg | sel, common->base + common->reg);
107*89a3dfb7SMaxime Ripard 	spin_unlock_irqrestore(common->lock, flags);
108*89a3dfb7SMaxime Ripard 
109*89a3dfb7SMaxime Ripard 	return 0;
110*89a3dfb7SMaxime Ripard }
111