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