]>
Commit | Line | Data |
---|---|---|
ea45b8f2 DB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * TI clock utilities | |
4 | * | |
5 | * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it> | |
6 | */ | |
7 | ||
d678a59d | 8 | #include <common.h> |
b1aef038 | 9 | #include <dm.h> |
401d1c4f | 10 | #include <fdtdec.h> |
b1aef038 | 11 | #include <regmap.h> |
ea45b8f2 | 12 | #include <asm/io.h> |
b1aef038 | 13 | #include <dm/device_compat.h> |
ea45b8f2 DB |
14 | #include "clk.h" |
15 | ||
b1aef038 DB |
16 | #define CLK_MAX_MEMMAPS 10 |
17 | ||
18 | struct clk_iomap { | |
19 | struct regmap *regmap; | |
20 | ofnode node; | |
21 | }; | |
22 | ||
23 | static unsigned int clk_memmaps_num; | |
24 | static struct clk_iomap clk_memmaps[CLK_MAX_MEMMAPS]; | |
25 | ||
2dd2f3ea | 26 | static void clk_ti_rmw(u32 val, u32 mask, struct clk_ti_reg *reg) |
ea45b8f2 DB |
27 | { |
28 | u32 v; | |
29 | ||
2dd2f3ea | 30 | v = clk_ti_readl(reg); |
ea45b8f2 DB |
31 | v &= ~mask; |
32 | v |= val; | |
2dd2f3ea | 33 | clk_ti_writel(v, reg); |
ea45b8f2 DB |
34 | } |
35 | ||
2dd2f3ea | 36 | void clk_ti_latch(struct clk_ti_reg *reg, s8 shift) |
ea45b8f2 DB |
37 | { |
38 | u32 latch; | |
39 | ||
40 | if (shift < 0) | |
41 | return; | |
42 | ||
43 | latch = 1 << shift; | |
44 | ||
45 | clk_ti_rmw(latch, latch, reg); | |
46 | clk_ti_rmw(0, latch, reg); | |
2dd2f3ea | 47 | clk_ti_readl(reg); /* OCP barrier */ |
ea45b8f2 | 48 | } |
b1aef038 DB |
49 | |
50 | void clk_ti_writel(u32 val, struct clk_ti_reg *reg) | |
51 | { | |
52 | struct clk_iomap *io = &clk_memmaps[reg->index]; | |
53 | ||
54 | regmap_write(io->regmap, reg->offset, val); | |
55 | } | |
56 | ||
57 | u32 clk_ti_readl(struct clk_ti_reg *reg) | |
58 | { | |
59 | struct clk_iomap *io = &clk_memmaps[reg->index]; | |
60 | u32 val; | |
61 | ||
62 | regmap_read(io->regmap, reg->offset, &val); | |
63 | return val; | |
64 | } | |
65 | ||
66 | static ofnode clk_ti_get_regmap_node(struct udevice *dev) | |
67 | { | |
68 | ofnode node = dev_ofnode(dev), parent; | |
69 | ||
70 | if (!ofnode_valid(node)) | |
71 | return ofnode_null(); | |
72 | ||
73 | parent = ofnode_get_parent(node); | |
74 | if (strcmp(ofnode_get_name(parent), "clocks")) | |
75 | return ofnode_null(); | |
76 | ||
77 | return ofnode_get_parent(parent); | |
78 | } | |
79 | ||
80 | int clk_ti_get_reg_addr(struct udevice *dev, int index, struct clk_ti_reg *reg) | |
81 | { | |
82 | ofnode node; | |
83 | int i, ret; | |
84 | u32 val; | |
85 | ||
86 | ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", index, &val); | |
87 | if (ret) { | |
88 | dev_err(dev, "%s must have reg[%d]\n", ofnode_get_name(node), | |
89 | index); | |
90 | return ret; | |
91 | } | |
92 | ||
93 | /* parent = ofnode_get_parent(parent); */ | |
94 | node = clk_ti_get_regmap_node(dev); | |
95 | if (!ofnode_valid(node)) { | |
96 | dev_err(dev, "failed to get regmap node\n"); | |
97 | return -EFAULT; | |
98 | } | |
99 | ||
100 | for (i = 0; i < clk_memmaps_num; i++) { | |
101 | if (ofnode_equal(clk_memmaps[i].node, node)) | |
102 | break; | |
103 | } | |
104 | ||
105 | if (i == clk_memmaps_num) { | |
106 | if (i == CLK_MAX_MEMMAPS) | |
107 | return -ENOMEM; | |
108 | ||
109 | ret = regmap_init_mem(node, &clk_memmaps[i].regmap); | |
110 | if (ret) | |
111 | return ret; | |
112 | ||
113 | clk_memmaps[i].node = node; | |
114 | clk_memmaps_num++; | |
115 | } | |
116 | ||
117 | reg->index = i; | |
118 | reg->offset = val; | |
119 | return 0; | |
120 | } |