]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/clk/uniphier/clk-uniphier-core.c
dm: Rename dev_addr..() functions
[people/ms/u-boot.git] / drivers / clk / uniphier / clk-uniphier-core.c
CommitLineData
48264d9b 1/*
4e3d8406
MY
2 * Copyright (C) 2016 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
48264d9b
MY
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
805dc44c 9#include <clk-uclass.h>
9d922450 10#include <dm.h>
48264d9b
MY
11#include <linux/bitops.h>
12#include <linux/io.h>
45a3b1fd 13#include <linux/sizes.h>
48264d9b
MY
14
15#include "clk-uniphier.h"
16
102e3187
MY
17/**
18 * struct uniphier_clk_priv - private data for UniPhier clock driver
19 *
20 * @base: base address of the clock provider
805dc44c 21 * @data: SoC specific data
102e3187
MY
22 */
23struct uniphier_clk_priv {
24 void __iomem *base;
805dc44c 25 const struct uniphier_clk_data *data;
102e3187
MY
26};
27
805dc44c 28static int uniphier_clk_enable(struct clk *clk)
102e3187 29{
805dc44c
MY
30 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
31 unsigned long id = clk->id;
32 const struct uniphier_clk_gate_data *p;
102e3187 33
805dc44c
MY
34 for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) {
35 u32 val;
102e3187 36
805dc44c
MY
37 if (p->id != id)
38 continue;
102e3187 39
805dc44c
MY
40 val = readl(priv->base + p->reg);
41 val |= BIT(p->bit);
42 writel(val, priv->base + p->reg);
102e3187 43
805dc44c
MY
44 return 0;
45 }
46
47 dev_err(priv->dev, "clk_id=%lu was not handled\n", id);
48 return -EINVAL;
102e3187
MY
49}
50
805dc44c
MY
51static const struct uniphier_clk_mux_data *
52uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id)
48264d9b 53{
805dc44c 54 const struct uniphier_clk_mux_data *p;
48264d9b 55
805dc44c
MY
56 for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) {
57 if (p->id == id)
58 return p;
48264d9b
MY
59 }
60
805dc44c 61 return NULL;
48264d9b
MY
62}
63
135aa950 64static ulong uniphier_clk_get_rate(struct clk *clk)
48264d9b 65{
135aa950 66 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
805dc44c
MY
67 const struct uniphier_clk_mux_data *mux;
68 u32 val;
48264d9b
MY
69 int i;
70
805dc44c
MY
71 mux = uniphier_clk_get_mux_data(priv, clk->id);
72 if (!mux)
73 return 0;
48264d9b 74
805dc44c
MY
75 if (!mux->nr_muxs) /* fixed-rate */
76 return mux->rates[0];
77
78 val = readl(priv->base + mux->reg);
48264d9b 79
805dc44c
MY
80 for (i = 0; i < mux->nr_muxs; i++)
81 if ((mux->masks[i] & val) == mux->vals[i])
82 return mux->rates[i];
48264d9b 83
805dc44c 84 return -EINVAL;
48264d9b
MY
85}
86
135aa950 87static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
48264d9b 88{
135aa950 89 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
805dc44c
MY
90 const struct uniphier_clk_mux_data *mux;
91 u32 val;
92 int i, best_rate_id = -1;
48264d9b 93 ulong best_rate = 0;
48264d9b 94
805dc44c
MY
95 mux = uniphier_clk_get_mux_data(priv, clk->id);
96 if (!mux)
97 return 0;
48264d9b 98
805dc44c
MY
99 if (!mux->nr_muxs) /* fixed-rate */
100 return mux->rates[0];
48264d9b 101
805dc44c
MY
102 /* first, decide the best match rate */
103 for (i = 0; i < mux->nr_muxs; i++) {
104 if (mux->rates[i] > best_rate && mux->rates[i] <= rate) {
105 best_rate = mux->rates[i];
106 best_rate_id = i;
107 }
48264d9b
MY
108 }
109
805dc44c
MY
110 if (best_rate_id < 0)
111 return -EINVAL;
112
113 val = readl(priv->base + mux->reg);
114 val &= ~mux->masks[best_rate_id];
115 val |= mux->vals[best_rate_id];
116 writel(val, priv->base + mux->reg);
48264d9b
MY
117
118 debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
119 rate, best_rate);
120
48264d9b
MY
121 return best_rate;
122}
123
124const struct clk_ops uniphier_clk_ops = {
125 .enable = uniphier_clk_enable,
135aa950
SW
126 .get_rate = uniphier_clk_get_rate,
127 .set_rate = uniphier_clk_set_rate,
48264d9b
MY
128};
129
805dc44c
MY
130static int uniphier_clk_probe(struct udevice *dev)
131{
132 struct uniphier_clk_priv *priv = dev_get_priv(dev);
133 fdt_addr_t addr;
134
a821c4af 135 addr = devfdt_get_addr(dev->parent);
805dc44c
MY
136 if (addr == FDT_ADDR_T_NONE)
137 return -EINVAL;
138
139 priv->base = devm_ioremap(dev, addr, SZ_4K);
140 if (!priv->base)
141 return -ENOMEM;
142
143 priv->data = (void *)dev_get_driver_data(dev);
144
145 return 0;
146}
147
102e3187
MY
148static const struct udevice_id uniphier_clk_match[] = {
149 {
6dc5b6b1 150 .compatible = "socionext,uniphier-sld3-mio-clock",
102e3187
MY
151 .data = (ulong)&uniphier_mio_clk_data,
152 },
153 {
6dc5b6b1 154 .compatible = "socionext,uniphier-ld4-mio-clock",
102e3187
MY
155 .data = (ulong)&uniphier_mio_clk_data,
156 },
157 {
6dc5b6b1 158 .compatible = "socionext,uniphier-pro4-mio-clock",
102e3187
MY
159 .data = (ulong)&uniphier_mio_clk_data,
160 },
161 {
6dc5b6b1 162 .compatible = "socionext,uniphier-sld8-mio-clock",
102e3187
MY
163 .data = (ulong)&uniphier_mio_clk_data,
164 },
165 {
4c642e68 166 .compatible = "socionext,uniphier-pro5-sd-clock",
102e3187
MY
167 .data = (ulong)&uniphier_mio_clk_data,
168 },
169 {
4c642e68 170 .compatible = "socionext,uniphier-pxs2-sd-clock",
102e3187
MY
171 .data = (ulong)&uniphier_mio_clk_data,
172 },
173 {
6dc5b6b1 174 .compatible = "socionext,uniphier-ld11-mio-clock",
102e3187
MY
175 .data = (ulong)&uniphier_mio_clk_data,
176 },
177 {
4c642e68 178 .compatible = "socionext,uniphier-ld20-sd-clock",
102e3187
MY
179 .data = (ulong)&uniphier_mio_clk_data,
180 },
181 { /* sentinel */ }
182};
48264d9b 183
102e3187
MY
184U_BOOT_DRIVER(uniphier_clk) = {
185 .name = "uniphier-clk",
186 .id = UCLASS_CLK,
187 .of_match = uniphier_clk_match,
188 .probe = uniphier_clk_probe,
189 .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
190 .ops = &uniphier_clk_ops,
191};