xref: /openbmc/u-boot/drivers/clk/clk_boston.c (revision e8f80a5a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016 Imagination Technologies
4  */
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 
13 struct 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 
ext_field(uint32_t val,uint32_t mask)23 static uint32_t ext_field(uint32_t val, uint32_t mask)
24 {
25 	return (val & mask) >> (ffs(mask) - 1);
26 }
27 
clk_boston_get_rate(struct clk * clk)28 static 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 
56 const struct clk_ops clk_boston_ops = {
57 	.get_rate = clk_boston_get_rate,
58 };
59 
clk_boston_ofdata_to_platdata(struct udevice * dev)60 static 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) {
69 		pr_err("unable to find syscon device\n");
70 		return err;
71 	}
72 
73 	state->regmap = syscon_get_regmap(syscon);
74 	if (!state->regmap) {
75 		pr_err("unable to find regmap\n");
76 		return -ENODEV;
77 	}
78 
79 	return 0;
80 }
81 
82 static const struct udevice_id clk_boston_match[] = {
83 	{
84 		.compatible = "img,boston-clock",
85 	},
86 	{ /* sentinel */ }
87 };
88 
89 U_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 };
97