blob: 4bcf9117551232a20df1ff99900e5c891002d71f [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>
Simon Glasscd93d622020-05-10 11:40:13 -060012#include <linux/bitops.h>
Simon Glass1e94b462023-09-14 18:21:46 -060013#include <linux/printk.h>
Paul Burtondd7c7492016-09-08 07:47:38 +010014
15struct clk_boston {
16 struct regmap *regmap;
17};
18
19#define BOSTON_PLAT_MMCMDIV 0x30
20# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0)
21# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8)
22# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16)
23# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24)
24
25static uint32_t ext_field(uint32_t val, uint32_t mask)
26{
27 return (val & mask) >> (ffs(mask) - 1);
28}
29
30static ulong clk_boston_get_rate(struct clk *clk)
31{
Simon Glassc69cda22020-12-03 16:55:20 -070032 struct clk_boston *state = dev_get_plat(clk->dev);
Paul Burtondd7c7492016-09-08 07:47:38 +010033 uint32_t in_rate, mul, div;
34 uint mmcmdiv;
35 int err;
36
37 err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
38 if (err)
39 return 0;
40
41 in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT);
42 mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
43
44 switch (clk->id) {
45 case BOSTON_CLK_SYS:
46 div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
47 break;
48 case BOSTON_CLK_CPU:
49 div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
50 break;
51 default:
52 return 0;
53 }
54
55 return (in_rate * mul * 1000000) / div;
56}
57
58const struct clk_ops clk_boston_ops = {
59 .get_rate = clk_boston_get_rate,
60};
61
Simon Glassd1998a92020-12-03 16:55:21 -070062static int clk_boston_of_to_plat(struct udevice *dev)
Paul Burtondd7c7492016-09-08 07:47:38 +010063{
Simon Glassc69cda22020-12-03 16:55:20 -070064 struct clk_boston *state = dev_get_plat(dev);
Paul Burtondd7c7492016-09-08 07:47:38 +010065 struct udevice *syscon;
66 int err;
67
68 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
69 "regmap", &syscon);
70 if (err) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090071 pr_err("unable to find syscon device\n");
Paul Burtondd7c7492016-09-08 07:47:38 +010072 return err;
73 }
74
75 state->regmap = syscon_get_regmap(syscon);
76 if (!state->regmap) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090077 pr_err("unable to find regmap\n");
Paul Burtondd7c7492016-09-08 07:47:38 +010078 return -ENODEV;
79 }
80
81 return 0;
82}
83
84static const struct udevice_id clk_boston_match[] = {
85 {
86 .compatible = "img,boston-clock",
87 },
88 { /* sentinel */ }
89};
90
91U_BOOT_DRIVER(clk_boston) = {
92 .name = "boston_clock",
93 .id = UCLASS_CLK,
94 .of_match = clk_boston_match,
Simon Glassd1998a92020-12-03 16:55:21 -070095 .of_to_plat = clk_boston_of_to_plat,
Simon Glasscaa4daa2020-12-03 16:55:18 -070096 .plat_auto = sizeof(struct clk_boston),
Paul Burtondd7c7492016-09-08 07:47:38 +010097 .ops = &clk_boston_ops,
98};