1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2dd7c7494SPaul Burton /*
3dd7c7494SPaul Burton * Copyright (C) 2016 Imagination Technologies
4dd7c7494SPaul Burton */
5dd7c7494SPaul Burton
6dd7c7494SPaul Burton #include <common.h>
7dd7c7494SPaul Burton #include <clk-uclass.h>
8dd7c7494SPaul Burton #include <dm.h>
9dd7c7494SPaul Burton #include <dt-bindings/clock/boston-clock.h>
10dd7c7494SPaul Burton #include <regmap.h>
11dd7c7494SPaul Burton #include <syscon.h>
12dd7c7494SPaul Burton
13dd7c7494SPaul Burton struct clk_boston {
14dd7c7494SPaul Burton struct regmap *regmap;
15dd7c7494SPaul Burton };
16dd7c7494SPaul Burton
17dd7c7494SPaul Burton #define BOSTON_PLAT_MMCMDIV 0x30
18dd7c7494SPaul Burton # define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0)
19dd7c7494SPaul Burton # define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8)
20dd7c7494SPaul Burton # define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16)
21dd7c7494SPaul Burton # define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24)
22dd7c7494SPaul Burton
ext_field(uint32_t val,uint32_t mask)23dd7c7494SPaul Burton static uint32_t ext_field(uint32_t val, uint32_t mask)
24dd7c7494SPaul Burton {
25dd7c7494SPaul Burton return (val & mask) >> (ffs(mask) - 1);
26dd7c7494SPaul Burton }
27dd7c7494SPaul Burton
clk_boston_get_rate(struct clk * clk)28dd7c7494SPaul Burton static ulong clk_boston_get_rate(struct clk *clk)
29dd7c7494SPaul Burton {
30dd7c7494SPaul Burton struct clk_boston *state = dev_get_platdata(clk->dev);
31dd7c7494SPaul Burton uint32_t in_rate, mul, div;
32dd7c7494SPaul Burton uint mmcmdiv;
33dd7c7494SPaul Burton int err;
34dd7c7494SPaul Burton
35dd7c7494SPaul Burton err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
36dd7c7494SPaul Burton if (err)
37dd7c7494SPaul Burton return 0;
38dd7c7494SPaul Burton
39dd7c7494SPaul Burton in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT);
40dd7c7494SPaul Burton mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
41dd7c7494SPaul Burton
42dd7c7494SPaul Burton switch (clk->id) {
43dd7c7494SPaul Burton case BOSTON_CLK_SYS:
44dd7c7494SPaul Burton div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
45dd7c7494SPaul Burton break;
46dd7c7494SPaul Burton case BOSTON_CLK_CPU:
47dd7c7494SPaul Burton div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
48dd7c7494SPaul Burton break;
49dd7c7494SPaul Burton default:
50dd7c7494SPaul Burton return 0;
51dd7c7494SPaul Burton }
52dd7c7494SPaul Burton
53dd7c7494SPaul Burton return (in_rate * mul * 1000000) / div;
54dd7c7494SPaul Burton }
55dd7c7494SPaul Burton
56dd7c7494SPaul Burton const struct clk_ops clk_boston_ops = {
57dd7c7494SPaul Burton .get_rate = clk_boston_get_rate,
58dd7c7494SPaul Burton };
59dd7c7494SPaul Burton
clk_boston_ofdata_to_platdata(struct udevice * dev)60dd7c7494SPaul Burton static int clk_boston_ofdata_to_platdata(struct udevice *dev)
61dd7c7494SPaul Burton {
62dd7c7494SPaul Burton struct clk_boston *state = dev_get_platdata(dev);
63dd7c7494SPaul Burton struct udevice *syscon;
64dd7c7494SPaul Burton int err;
65dd7c7494SPaul Burton
66dd7c7494SPaul Burton err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
67dd7c7494SPaul Burton "regmap", &syscon);
68dd7c7494SPaul Burton if (err) {
699b643e31SMasahiro Yamada pr_err("unable to find syscon device\n");
70dd7c7494SPaul Burton return err;
71dd7c7494SPaul Burton }
72dd7c7494SPaul Burton
73dd7c7494SPaul Burton state->regmap = syscon_get_regmap(syscon);
74dd7c7494SPaul Burton if (!state->regmap) {
759b643e31SMasahiro Yamada pr_err("unable to find regmap\n");
76dd7c7494SPaul Burton return -ENODEV;
77dd7c7494SPaul Burton }
78dd7c7494SPaul Burton
79dd7c7494SPaul Burton return 0;
80dd7c7494SPaul Burton }
81dd7c7494SPaul Burton
82dd7c7494SPaul Burton static const struct udevice_id clk_boston_match[] = {
83dd7c7494SPaul Burton {
84dd7c7494SPaul Burton .compatible = "img,boston-clock",
85dd7c7494SPaul Burton },
86dd7c7494SPaul Burton { /* sentinel */ }
87dd7c7494SPaul Burton };
88dd7c7494SPaul Burton
89dd7c7494SPaul Burton U_BOOT_DRIVER(clk_boston) = {
90dd7c7494SPaul Burton .name = "boston_clock",
91dd7c7494SPaul Burton .id = UCLASS_CLK,
92dd7c7494SPaul Burton .of_match = clk_boston_match,
93dd7c7494SPaul Burton .ofdata_to_platdata = clk_boston_ofdata_to_platdata,
94dd7c7494SPaul Burton .platdata_auto_alloc_size = sizeof(struct clk_boston),
95dd7c7494SPaul Burton .ops = &clk_boston_ops,
96dd7c7494SPaul Burton };
97