1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 Microchip Technology Inc.
4 * Padmarao Begari <padmarao.begari@microchip.com>
5 */
6#include <common.h>
7#include <clk.h>
8#include <clk-uclass.h>
9#include <dm.h>
10#include <log.h>
11#include <dm/device.h>
12#include <dm/devres.h>
13#include <dm/uclass.h>
14#include <dt-bindings/clock/microchip-mpfs-clock.h>
15#include <linux/err.h>
16
17#include "mpfs_clk.h"
18
19static int mpfs_clk_probe(struct udevice *dev)
20{
21	struct clk *parent_clk = dev_get_priv(dev);
22	struct clk clk_msspll = { .id = CLK_MSSPLL };
23	void __iomem *base;
24	void __iomem *msspll_base;
25	int ret;
26
27	base = dev_read_addr_index_ptr(dev, 0);
28	if (!base)
29		return -EINVAL;
30
31	ret = clk_get_by_index(dev, 0, parent_clk);
32	if (ret)
33		return ret;
34
35	/*
36	 * The original devicetrees for mpfs messed up & defined the msspll's
37	 * output as a fixed-frequency, 600 MHz clock & used that as the input
38	 * for the clock controller node. The msspll is however not a fixed
39	 * frequency clock and later devicetrees handled this properly. Check
40	 * the devicetree & if it is one of the fixed ones, register the msspll.
41	 * Otherwise, skip registering it & pass the reference clock directly
42	 * to the cfg clock registration function.
43	 */
44	msspll_base = dev_read_addr_index_ptr(dev, 1);
45	if (msspll_base) {
46		ret = mpfs_clk_register_msspll(msspll_base, parent_clk);
47		if (ret)
48			return ret;
49
50		clk_request(dev, &clk_msspll);
51		parent_clk = &clk_msspll;
52	}
53
54	ret = mpfs_clk_register_cfgs(base, parent_clk);
55	if (ret)
56		return ret;
57
58	ret = mpfs_clk_register_periphs(base, dev);
59
60	return ret;
61}
62
63static const struct udevice_id mpfs_of_match[] = {
64	{ .compatible = "microchip,mpfs-clkcfg" },
65	{ }
66};
67
68U_BOOT_DRIVER(mpfs_clk) = {
69	.name = "mpfs_clk",
70	.id = UCLASS_CLK,
71	.of_match = mpfs_of_match,
72	.ops = &ccf_clk_ops,
73	.probe = mpfs_clk_probe,
74	.priv_auto = sizeof(struct clk),
75	.flags = DM_FLAG_PRE_RELOC,
76};
77