clk: use clk_dev_binded
[oweals/u-boot.git] / drivers / clk / clk-mux.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 DENX Software Engineering
4  * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5  *
6  * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
7  * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
8  * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
9  *
10  * Simple multiplexer clock implementation
11  */
12
13 /*
14  * U-Boot CCF porting node:
15  *
16  * The Linux kernel - as of tag: 5.0-rc3 is using also the imx_clk_fixup_mux()
17  * version of CCF mux. It is used on e.g. imx6q to provide fixes (like
18  * imx_cscmr1_fixup) for broken HW.
19  *
20  * At least for IMX6Q (but NOT IMX6QP) it is important when we set the parent
21  * clock.
22  */
23
24 #include <common.h>
25 #include <asm/io.h>
26 #include <malloc.h>
27 #include <clk-uclass.h>
28 #include <dm/device.h>
29 #include <linux/clk-provider.h>
30 #include <clk.h>
31 #include "clk.h"
32
33 #define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux"
34
35 int clk_mux_val_to_index(struct clk *clk, u32 *table, unsigned int flags,
36                          unsigned int val)
37 {
38         struct clk_mux *mux = to_clk_mux(clk_dev_binded(clk) ?
39                         dev_get_clk_ptr(clk->dev) : clk);
40         int num_parents = mux->num_parents;
41
42         if (table) {
43                 int i;
44
45                 for (i = 0; i < num_parents; i++)
46                         if (table[i] == val)
47                                 return i;
48                 return -EINVAL;
49         }
50
51         if (val && (flags & CLK_MUX_INDEX_BIT))
52                 val = ffs(val) - 1;
53
54         if (val && (flags & CLK_MUX_INDEX_ONE))
55                 val--;
56
57         if (val >= num_parents)
58                 return -EINVAL;
59
60         return val;
61 }
62
63 static u8 clk_mux_get_parent(struct clk *clk)
64 {
65         struct clk_mux *mux = to_clk_mux(clk_dev_binded(clk) ?
66                         dev_get_clk_ptr(clk->dev) : clk);
67         u32 val;
68
69 #if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
70         val = mux->io_mux_val;
71 #else
72         val = readl(mux->reg);
73 #endif
74         val >>= mux->shift;
75         val &= mux->mask;
76
77         return clk_mux_val_to_index(clk, mux->table, mux->flags, val);
78 }
79
80 const struct clk_ops clk_mux_ops = {
81                 .get_rate = clk_generic_get_rate,
82 };
83
84 struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
85                 const char * const *parent_names, u8 num_parents,
86                 unsigned long flags,
87                 void __iomem *reg, u8 shift, u32 mask,
88                 u8 clk_mux_flags, u32 *table)
89 {
90         struct clk_mux *mux;
91         struct clk *clk;
92         u8 width = 0;
93         int ret;
94
95         if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
96                 width = fls(mask) - ffs(mask) + 1;
97                 if (width + shift > 16) {
98                         pr_err("mux value exceeds LOWORD field\n");
99                         return ERR_PTR(-EINVAL);
100                 }
101         }
102
103         /* allocate the mux */
104         mux = kzalloc(sizeof(*mux), GFP_KERNEL);
105         if (!mux)
106                 return ERR_PTR(-ENOMEM);
107
108         /* U-boot specific assignments */
109         mux->parent_names = parent_names;
110         mux->num_parents = num_parents;
111
112         /* struct clk_mux assignments */
113         mux->reg = reg;
114         mux->shift = shift;
115         mux->mask = mask;
116         mux->flags = clk_mux_flags;
117         mux->table = table;
118 #if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
119         mux->io_mux_val = *(u32 *)reg;
120 #endif
121
122         clk = &mux->clk;
123
124         /*
125          * Read the current mux setup - so we assign correct parent.
126          *
127          * Changing parent would require changing internals of udevice struct
128          * for the corresponding clock (to do that define .set_parent() method.
129          */
130         ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name,
131                            parent_names[clk_mux_get_parent(clk)]);
132         if (ret) {
133                 kfree(mux);
134                 return ERR_PTR(ret);
135         }
136
137         return clk;
138 }
139
140 struct clk *clk_register_mux_table(struct device *dev, const char *name,
141                 const char * const *parent_names, u8 num_parents,
142                 unsigned long flags,
143                 void __iomem *reg, u8 shift, u32 mask,
144                 u8 clk_mux_flags, u32 *table)
145 {
146         struct clk *clk;
147
148         clk = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
149                                        flags, reg, shift, mask, clk_mux_flags,
150                                        table);
151         if (IS_ERR(clk))
152                 return ERR_CAST(clk);
153         return clk;
154 }
155
156 struct clk *clk_register_mux(struct device *dev, const char *name,
157                 const char * const *parent_names, u8 num_parents,
158                 unsigned long flags,
159                 void __iomem *reg, u8 shift, u8 width,
160                 u8 clk_mux_flags)
161 {
162         u32 mask = BIT(width) - 1;
163
164         return clk_register_mux_table(dev, name, parent_names, num_parents,
165                                       flags, reg, shift, mask, clk_mux_flags,
166                                       NULL);
167 }
168
169 U_BOOT_DRIVER(ccf_clk_mux) = {
170         .name   = UBOOT_DM_CLK_CCF_MUX,
171         .id     = UCLASS_CLK,
172         .ops    = &clk_mux_ops,
173         .flags = DM_FLAG_PRE_RELOC,
174 };