4 * Copyright (C) 2014 Atmel
6 * Alexandre Belloni <alexandre.belloni@free-electrons.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
15 #include <linux/clk-provider.h>
16 #include <linux/clkdev.h>
17 #include <linux/clk/at91_pmc.h>
18 #include <linux/delay.h>
20 #include <linux/of_address.h>
21 #include <linux/of_irq.h>
23 #include <linux/interrupt.h>
24 #include <linux/irq.h>
25 #include <linux/sched.h>
26 #include <linux/wait.h>
30 #define H32MX_MAX_FREQ 90000000
32 struct clk_sama5d4_h32mx
{
37 #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
39 static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw
*hw
,
40 unsigned long parent_rate
)
42 struct clk_sama5d4_h32mx
*h32mxclk
= to_clk_sama5d4_h32mx(hw
);
44 if (pmc_read(h32mxclk
->pmc
, AT91_PMC_MCKR
) & AT91_PMC_H32MXDIV
)
45 return parent_rate
/ 2;
47 if (parent_rate
> H32MX_MAX_FREQ
)
48 pr_warn("H32MX clock is too fast\n");
52 static long clk_sama5d4_h32mx_round_rate(struct clk_hw
*hw
, unsigned long rate
,
53 unsigned long *parent_rate
)
57 if (rate
> *parent_rate
)
59 div
= *parent_rate
/ 2;
63 if (rate
- div
< *parent_rate
- rate
)
69 static int clk_sama5d4_h32mx_set_rate(struct clk_hw
*hw
, unsigned long rate
,
70 unsigned long parent_rate
)
72 struct clk_sama5d4_h32mx
*h32mxclk
= to_clk_sama5d4_h32mx(hw
);
73 struct at91_pmc
*pmc
= h32mxclk
->pmc
;
76 if (parent_rate
!= rate
&& (parent_rate
/ 2) != rate
)
80 tmp
= pmc_read(pmc
, AT91_PMC_MCKR
) & ~AT91_PMC_H32MXDIV
;
81 if ((parent_rate
/ 2) == rate
)
82 tmp
|= AT91_PMC_H32MXDIV
;
83 pmc_write(pmc
, AT91_PMC_MCKR
, tmp
);
89 static const struct clk_ops h32mx_ops
= {
90 .recalc_rate
= clk_sama5d4_h32mx_recalc_rate
,
91 .round_rate
= clk_sama5d4_h32mx_round_rate
,
92 .set_rate
= clk_sama5d4_h32mx_set_rate
,
95 void __init
of_sama5d4_clk_h32mx_setup(struct device_node
*np
,
98 struct clk_sama5d4_h32mx
*h32mxclk
;
99 struct clk_init_data init
;
100 const char *parent_name
;
103 h32mxclk
= kzalloc(sizeof(*h32mxclk
), GFP_KERNEL
);
107 parent_name
= of_clk_get_parent_name(np
, 0);
109 init
.name
= np
->name
;
110 init
.ops
= &h32mx_ops
;
111 init
.parent_names
= parent_name
? &parent_name
: NULL
;
112 init
.num_parents
= parent_name
? 1 : 0;
113 init
.flags
= CLK_SET_RATE_GATE
;
115 h32mxclk
->hw
.init
= &init
;
118 clk
= clk_register(NULL
, &h32mxclk
->hw
);
122 of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);