blob: 28cd151288190c9d2abcebfe977c12c6df72d416 [file] [log] [blame]
Dario Binacchid2841572020-12-30 00:06:35 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * TI clock utilities
4 *
5 * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
6 */
7
Dario Binacchi6dfe4262021-05-01 17:05:22 +02008#include <dm.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <fdtdec.h>
Dario Binacchi6dfe4262021-05-01 17:05:22 +020010#include <regmap.h>
Dario Binacchid2841572020-12-30 00:06:35 +010011#include <asm/io.h>
Dario Binacchi6dfe4262021-05-01 17:05:22 +020012#include <dm/device_compat.h>
Dario Binacchid2841572020-12-30 00:06:35 +010013#include "clk.h"
14
Dario Binacchi6dfe4262021-05-01 17:05:22 +020015#define CLK_MAX_MEMMAPS 10
16
17struct clk_iomap {
18 struct regmap *regmap;
19 ofnode node;
20};
21
22static unsigned int clk_memmaps_num;
23static struct clk_iomap clk_memmaps[CLK_MAX_MEMMAPS];
24
Dario Binacchiac7c7052021-05-01 17:05:23 +020025static void clk_ti_rmw(u32 val, u32 mask, struct clk_ti_reg *reg)
Dario Binacchid2841572020-12-30 00:06:35 +010026{
27 u32 v;
28
Dario Binacchiac7c7052021-05-01 17:05:23 +020029 v = clk_ti_readl(reg);
Dario Binacchid2841572020-12-30 00:06:35 +010030 v &= ~mask;
31 v |= val;
Dario Binacchiac7c7052021-05-01 17:05:23 +020032 clk_ti_writel(v, reg);
Dario Binacchid2841572020-12-30 00:06:35 +010033}
34
Dario Binacchiac7c7052021-05-01 17:05:23 +020035void clk_ti_latch(struct clk_ti_reg *reg, s8 shift)
Dario Binacchid2841572020-12-30 00:06:35 +010036{
37 u32 latch;
38
39 if (shift < 0)
40 return;
41
42 latch = 1 << shift;
43
44 clk_ti_rmw(latch, latch, reg);
45 clk_ti_rmw(0, latch, reg);
Dario Binacchiac7c7052021-05-01 17:05:23 +020046 clk_ti_readl(reg); /* OCP barrier */
Dario Binacchid2841572020-12-30 00:06:35 +010047}
Dario Binacchi6dfe4262021-05-01 17:05:22 +020048
49void clk_ti_writel(u32 val, struct clk_ti_reg *reg)
50{
51 struct clk_iomap *io = &clk_memmaps[reg->index];
52
53 regmap_write(io->regmap, reg->offset, val);
54}
55
56u32 clk_ti_readl(struct clk_ti_reg *reg)
57{
58 struct clk_iomap *io = &clk_memmaps[reg->index];
59 u32 val;
60
61 regmap_read(io->regmap, reg->offset, &val);
62 return val;
63}
64
65static ofnode clk_ti_get_regmap_node(struct udevice *dev)
66{
67 ofnode node = dev_ofnode(dev), parent;
68
69 if (!ofnode_valid(node))
70 return ofnode_null();
71
72 parent = ofnode_get_parent(node);
73 if (strcmp(ofnode_get_name(parent), "clocks"))
74 return ofnode_null();
75
76 return ofnode_get_parent(parent);
77}
78
79int clk_ti_get_reg_addr(struct udevice *dev, int index, struct clk_ti_reg *reg)
80{
81 ofnode node;
82 int i, ret;
83 u32 val;
84
85 ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", index, &val);
86 if (ret) {
87 dev_err(dev, "%s must have reg[%d]\n", ofnode_get_name(node),
88 index);
89 return ret;
90 }
91
92 /* parent = ofnode_get_parent(parent); */
93 node = clk_ti_get_regmap_node(dev);
94 if (!ofnode_valid(node)) {
95 dev_err(dev, "failed to get regmap node\n");
96 return -EFAULT;
97 }
98
99 for (i = 0; i < clk_memmaps_num; i++) {
100 if (ofnode_equal(clk_memmaps[i].node, node))
101 break;
102 }
103
104 if (i == clk_memmaps_num) {
105 if (i == CLK_MAX_MEMMAPS)
106 return -ENOMEM;
107
108 ret = regmap_init_mem(node, &clk_memmaps[i].regmap);
109 if (ret)
110 return ret;
111
112 clk_memmaps[i].node = node;
113 clk_memmaps_num++;
114 }
115
116 reg->index = i;
117 reg->offset = val;
118 return 0;
119}