2 * Copyright (C) 2014 Intel Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Adjustable fractional divider clock implementation.
9 * Output rate = (m / n) * parent_rate.
12 #include <linux/clk-provider.h>
13 #include <linux/module.h>
14 #include <linux/device.h>
15 #include <linux/slab.h>
16 #include <linux/gcd.h>
18 #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
20 static unsigned long clk_fd_recalc_rate(struct clk_hw
*hw
,
21 unsigned long parent_rate
)
23 struct clk_fractional_divider
*fd
= to_clk_fd(hw
);
24 unsigned long flags
= 0;
29 spin_lock_irqsave(fd
->lock
, flags
);
31 val
= clk_readl(fd
->reg
);
34 spin_unlock_irqrestore(fd
->lock
, flags
);
36 m
= (val
& fd
->mmask
) >> fd
->mshift
;
37 n
= (val
& fd
->nmask
) >> fd
->nshift
;
42 ret
= (u64
)parent_rate
* m
;
48 static long clk_fd_round_rate(struct clk_hw
*hw
, unsigned long rate
,
51 struct clk_fractional_divider
*fd
= to_clk_fd(hw
);
52 unsigned maxn
= (fd
->nmask
>> fd
->nshift
) + 1;
55 if (!rate
|| rate
>= *prate
)
58 div
= gcd(*prate
, rate
);
60 while ((*prate
/ div
) > maxn
) {
68 static int clk_fd_set_rate(struct clk_hw
*hw
, unsigned long rate
,
69 unsigned long parent_rate
)
71 struct clk_fractional_divider
*fd
= to_clk_fd(hw
);
72 unsigned long flags
= 0;
77 div
= gcd(parent_rate
, rate
);
79 n
= parent_rate
/ div
;
82 spin_lock_irqsave(fd
->lock
, flags
);
84 val
= clk_readl(fd
->reg
);
85 val
&= ~(fd
->mmask
| fd
->nmask
);
86 val
|= (m
<< fd
->mshift
) | (n
<< fd
->nshift
);
87 clk_writel(val
, fd
->reg
);
90 spin_unlock_irqrestore(fd
->lock
, flags
);
95 const struct clk_ops clk_fractional_divider_ops
= {
96 .recalc_rate
= clk_fd_recalc_rate
,
97 .round_rate
= clk_fd_round_rate
,
98 .set_rate
= clk_fd_set_rate
,
100 EXPORT_SYMBOL_GPL(clk_fractional_divider_ops
);
102 struct clk
*clk_register_fractional_divider(struct device
*dev
,
103 const char *name
, const char *parent_name
, unsigned long flags
,
104 void __iomem
*reg
, u8 mshift
, u8 mwidth
, u8 nshift
, u8 nwidth
,
105 u8 clk_divider_flags
, spinlock_t
*lock
)
107 struct clk_fractional_divider
*fd
;
108 struct clk_init_data init
;
111 fd
= kzalloc(sizeof(*fd
), GFP_KERNEL
);
113 dev_err(dev
, "could not allocate fractional divider clk\n");
114 return ERR_PTR(-ENOMEM
);
118 init
.ops
= &clk_fractional_divider_ops
;
119 init
.flags
= flags
| CLK_IS_BASIC
;
120 init
.parent_names
= parent_name
? &parent_name
: NULL
;
121 init
.num_parents
= parent_name
? 1 : 0;
125 fd
->mmask
= (BIT(mwidth
) - 1) << mshift
;
127 fd
->nmask
= (BIT(nwidth
) - 1) << nshift
;
128 fd
->flags
= clk_divider_flags
;
132 clk
= clk_register(dev
, &fd
->hw
);
138 EXPORT_SYMBOL_GPL(clk_register_fractional_divider
);