mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-14 03:06:59 +02:00
In upstream devicetree, clk_boston is a child of syscon node and there is no "regmap" property for clk_boston node. Try to check parent device first to look for syscon. Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
103 lines
2.2 KiB
C
103 lines
2.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2016 Imagination Technologies
|
|
*/
|
|
|
|
#include <clk-uclass.h>
|
|
#include <dm.h>
|
|
#include <dt-bindings/clock/boston-clock.h>
|
|
#include <regmap.h>
|
|
#include <syscon.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/printk.h>
|
|
|
|
struct clk_boston {
|
|
struct regmap *regmap;
|
|
};
|
|
|
|
#define BOSTON_PLAT_MMCMDIV 0x30
|
|
# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0)
|
|
# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8)
|
|
# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16)
|
|
# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24)
|
|
|
|
static uint32_t ext_field(uint32_t val, uint32_t mask)
|
|
{
|
|
return (val & mask) >> (ffs(mask) - 1);
|
|
}
|
|
|
|
static ulong clk_boston_get_rate(struct clk *clk)
|
|
{
|
|
struct clk_boston *state = dev_get_plat(clk->dev);
|
|
uint32_t in_rate, mul, div;
|
|
uint mmcmdiv;
|
|
int err;
|
|
|
|
err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
|
|
if (err)
|
|
return 0;
|
|
|
|
in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT);
|
|
mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
|
|
|
|
switch (clk->id) {
|
|
case BOSTON_CLK_SYS:
|
|
div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
|
|
break;
|
|
case BOSTON_CLK_CPU:
|
|
div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return (in_rate * mul * 1000000) / div;
|
|
}
|
|
|
|
const struct clk_ops clk_boston_ops = {
|
|
.get_rate = clk_boston_get_rate,
|
|
};
|
|
|
|
static int clk_boston_probe(struct udevice *dev)
|
|
{
|
|
struct clk_boston *state = dev_get_plat(dev);
|
|
struct udevice *syscon;
|
|
int err;
|
|
|
|
if (dev->parent && device_get_uclass_id(dev->parent) == UCLASS_SYSCON) {
|
|
syscon = dev->parent;
|
|
} else {
|
|
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
|
|
"regmap", &syscon);
|
|
if (err) {
|
|
pr_err("unable to find syscon device\n");
|
|
return err;
|
|
}
|
|
}
|
|
|
|
state->regmap = syscon_get_regmap(syscon);
|
|
if (!state->regmap) {
|
|
pr_err("unable to find regmap\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id clk_boston_match[] = {
|
|
{
|
|
.compatible = "img,boston-clock",
|
|
},
|
|
{ /* sentinel */ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(clk_boston) = {
|
|
.name = "boston_clock",
|
|
.id = UCLASS_CLK,
|
|
.of_match = clk_boston_match,
|
|
.probe = clk_boston_probe,
|
|
.plat_auto = sizeof(struct clk_boston),
|
|
.ops = &clk_boston_ops,
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
};
|