blob: 372baa9c11b5d3802ea2ca4670da554ffd19d85b [file] [log] [blame]
Tom Rini03de3052024-05-20 13:35:03 -06001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (C) Copyright 2022 - Analog Devices, Inc.
4 *
5 * Written and/or maintained by Timesys Corporation
6 *
7 * Author: Greg Malysa <greg.malysa@timesys.com>
8 *
9 * Ported from Linux: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
10 */
11
12#include <clk.h>
13#include <clk-uclass.h>
14#include <asm/io.h>
15#include <dm/device.h>
16#include <linux/compiler_types.h>
17#include <linux/err.h>
18#include <linux/kernel.h>
19
20#include "clk.h"
21
22#define ADI_CLK_PLL_GENERIC "adi_clk_pll_generic"
23
24struct clk_sc5xx_cgu_pll {
25 struct clk clk;
26 void __iomem *base;
27 u32 mask;
28 u32 max;
29 u32 m_offset;
30 u8 shift;
31 bool half_m;
32};
33
34#define to_clk_sc5xx_cgu_pll(_clk) container_of(_clk, struct clk_sc5xx_cgu_pll, clk)
35
36static unsigned long sc5xx_cgu_pll_get_rate(struct clk *clk)
37{
38 struct clk_sc5xx_cgu_pll *pll = to_clk_sc5xx_cgu_pll(dev_get_clk_ptr(clk->dev));
39 unsigned long parent_rate = clk_get_parent_rate(clk);
40
41 u32 reg = readl(pll->base);
42 u32 m = ((reg & pll->mask) >> pll->shift) + pll->m_offset;
43
44 if (m == 0)
45 m = pll->max;
46
47 if (pll->half_m)
48 return parent_rate * m * 2;
49 return parent_rate * m;
50}
51
52static const struct clk_ops clk_sc5xx_cgu_pll_ops = {
53 .get_rate = sc5xx_cgu_pll_get_rate,
54};
55
56struct clk *sc5xx_cgu_pll(const char *name, const char *parent_name,
57 void __iomem *base, u8 shift, u8 width, u32 m_offset,
58 bool half_m)
59{
60 struct clk_sc5xx_cgu_pll *pll;
61 struct clk *clk;
62 int ret;
63 char *drv_name = ADI_CLK_PLL_GENERIC;
64
65 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
66 if (!pll)
67 return ERR_PTR(-ENOMEM);
68
69 pll->base = base;
70 pll->shift = shift;
71 pll->mask = GENMASK(width - 1, 0) << shift;
72 pll->max = pll->mask + 1;
73 pll->m_offset = m_offset;
74 pll->half_m = half_m;
75
76 clk = &pll->clk;
77
78 ret = clk_register(clk, drv_name, name, parent_name);
79 if (ret) {
80 pr_err("Failed to register %s in %s: %d\n", name, __func__, ret);
81 kfree(pll);
82 return ERR_PTR(ret);
83 }
84
85 return clk;
86}
87
88U_BOOT_DRIVER(clk_adi_pll_generic) = {
89 .name = ADI_CLK_PLL_GENERIC,
90 .id = UCLASS_CLK,
91 .ops = &clk_sc5xx_cgu_pll_ops,
92 .flags = DM_FLAG_PRE_RELOC,
93};