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);