2 * Copyright (C) 2016 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5 * SPDX-License-Identifier: GPL-2.0+
9 #include <linux/bitops.h>
11 #include <linux/sizes.h>
12 #include <clk-uclass.h>
13 #include <dm/device.h>
15 #include "clk-uniphier.h"
17 static int uniphier_clk_enable(struct clk
*clk
)
19 struct uniphier_clk_priv
*priv
= dev_get_priv(clk
->dev
);
20 const struct uniphier_clk_gate_data
*gate
= priv
->socdata
->gate
;
21 unsigned int nr_gate
= priv
->socdata
->nr_gate
;
26 for (i
= 0; i
< nr_gate
; i
++) {
27 if (gate
[i
].index
!= clk
->id
)
30 reg
= priv
->base
+ gate
[i
].reg
;
32 data
= gate
[i
].data
& mask
;
37 debug("%s: %p: %08x\n", __func__
, reg
, tmp
);
44 static ulong
uniphier_clk_get_rate(struct clk
*clk
)
46 struct uniphier_clk_priv
*priv
= dev_get_priv(clk
->dev
);
47 const struct uniphier_clk_rate_data
*rdata
= priv
->socdata
->rate
;
48 unsigned int nr_rdata
= priv
->socdata
->nr_rate
;
51 ulong matched_rate
= 0;
54 for (i
= 0; i
< nr_rdata
; i
++) {
55 if (rdata
[i
].index
!= clk
->id
)
58 if (rdata
[i
].reg
== UNIPHIER_CLK_RATE_IS_FIXED
)
61 reg
= priv
->base
+ rdata
[i
].reg
;
63 data
= rdata
[i
].data
& mask
;
64 if ((readl(reg
) & mask
) == data
) {
65 if (matched_rate
&& rdata
[i
].rate
!= matched_rate
) {
66 printf("failed to get clk rate for insane register values\n");
69 matched_rate
= rdata
[i
].rate
;
73 debug("%s: rate = %lu\n", __func__
, matched_rate
);
78 static ulong
uniphier_clk_set_rate(struct clk
*clk
, ulong rate
)
80 struct uniphier_clk_priv
*priv
= dev_get_priv(clk
->dev
);
81 const struct uniphier_clk_rate_data
*rdata
= priv
->socdata
->rate
;
82 unsigned int nr_rdata
= priv
->socdata
->nr_rate
;
88 /* first, decide the best match rate */
89 for (i
= 0; i
< nr_rdata
; i
++) {
90 if (rdata
[i
].index
!= clk
->id
)
93 if (rdata
[i
].reg
== UNIPHIER_CLK_RATE_IS_FIXED
)
96 if (rdata
[i
].rate
> best_rate
&& rdata
[i
].rate
<= rate
)
97 best_rate
= rdata
[i
].rate
;
103 debug("%s: requested rate = %lu, set rate = %lu\n", __func__
,
106 /* second, really set registers */
107 for (i
= 0; i
< nr_rdata
; i
++) {
108 if (rdata
[i
].index
!= clk
->id
|| rdata
[i
].rate
!= best_rate
)
111 reg
= priv
->base
+ rdata
[i
].reg
;
112 mask
= rdata
[i
].mask
;
113 data
= rdata
[i
].data
& mask
;
118 debug("%s: %p: %08x\n", __func__
, reg
, tmp
);
125 const struct clk_ops uniphier_clk_ops
= {
126 .enable
= uniphier_clk_enable
,
127 .get_rate
= uniphier_clk_get_rate
,
128 .set_rate
= uniphier_clk_set_rate
,
131 int uniphier_clk_probe(struct udevice
*dev
)
133 struct uniphier_clk_priv
*priv
= dev_get_priv(dev
);
136 addr
= dev_get_addr(dev
);
137 if (addr
== FDT_ADDR_T_NONE
)
140 priv
->base
= devm_ioremap(dev
, addr
, SZ_4K
);
144 priv
->socdata
= (void *)dev_get_driver_data(dev
);