16bdc85b48
The top-level framework flags are passed as parameter to the common clock framework (ccf) registration routines without being used. Checks of the flags setting added by the patch have been added in the ccf test. Signed-off-by: Dario Binacchi <dariobin@libero.it>
184 lines
4.4 KiB
C
184 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
|
|
* Copyright 2019 NXP
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <malloc.h>
|
|
#include <clk-uclass.h>
|
|
#include <dm/device.h>
|
|
#include <dm/devres.h>
|
|
#include <linux/clk-provider.h>
|
|
#include <clk.h>
|
|
#include <linux/err.h>
|
|
|
|
#include "clk.h"
|
|
|
|
#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
|
|
|
|
static u8 clk_composite_get_parent(struct clk *clk)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
struct clk *mux = composite->mux;
|
|
|
|
if (mux)
|
|
return clk_mux_get_parent(mux);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
const struct clk_ops *mux_ops = composite->mux_ops;
|
|
struct clk *mux = composite->mux;
|
|
|
|
if (mux && mux_ops)
|
|
return mux_ops->set_parent(mux, parent);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
static unsigned long clk_composite_recalc_rate(struct clk *clk)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
const struct clk_ops *rate_ops = composite->rate_ops;
|
|
struct clk *rate = composite->rate;
|
|
|
|
if (rate && rate_ops)
|
|
return rate_ops->get_rate(rate);
|
|
else
|
|
return clk_get_parent_rate(clk);
|
|
}
|
|
|
|
static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
const struct clk_ops *rate_ops = composite->rate_ops;
|
|
struct clk *clk_rate = composite->rate;
|
|
|
|
if (rate && rate_ops)
|
|
return rate_ops->set_rate(clk_rate, rate);
|
|
else
|
|
return clk_get_rate(clk);
|
|
}
|
|
|
|
static int clk_composite_enable(struct clk *clk)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
const struct clk_ops *gate_ops = composite->gate_ops;
|
|
struct clk *gate = composite->gate;
|
|
|
|
if (gate && gate_ops)
|
|
return gate_ops->enable(gate);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int clk_composite_disable(struct clk *clk)
|
|
{
|
|
struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
|
|
(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
|
|
const struct clk_ops *gate_ops = composite->gate_ops;
|
|
struct clk *gate = composite->gate;
|
|
|
|
if (gate && gate_ops)
|
|
return gate_ops->disable(gate);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
struct clk *clk_register_composite(struct device *dev, const char *name,
|
|
const char * const *parent_names,
|
|
int num_parents, struct clk *mux,
|
|
const struct clk_ops *mux_ops,
|
|
struct clk *rate,
|
|
const struct clk_ops *rate_ops,
|
|
struct clk *gate,
|
|
const struct clk_ops *gate_ops,
|
|
unsigned long flags)
|
|
{
|
|
struct clk *clk;
|
|
struct clk_composite *composite;
|
|
int ret;
|
|
|
|
if (!num_parents || (num_parents != 1 && !mux))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
composite = kzalloc(sizeof(*composite), GFP_KERNEL);
|
|
if (!composite)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
if (mux && mux_ops) {
|
|
composite->mux = mux;
|
|
composite->mux_ops = mux_ops;
|
|
mux->data = (ulong)composite;
|
|
}
|
|
|
|
if (rate && rate_ops) {
|
|
if (!rate_ops->get_rate) {
|
|
clk = ERR_PTR(-EINVAL);
|
|
goto err;
|
|
}
|
|
|
|
composite->rate = rate;
|
|
composite->rate_ops = rate_ops;
|
|
rate->data = (ulong)composite;
|
|
}
|
|
|
|
if (gate && gate_ops) {
|
|
if (!gate_ops->enable || !gate_ops->disable) {
|
|
clk = ERR_PTR(-EINVAL);
|
|
goto err;
|
|
}
|
|
|
|
composite->gate = gate;
|
|
composite->gate_ops = gate_ops;
|
|
gate->data = (ulong)composite;
|
|
}
|
|
|
|
clk = &composite->clk;
|
|
clk->flags = flags;
|
|
ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
|
|
parent_names[clk_composite_get_parent(clk)]);
|
|
if (ret) {
|
|
clk = ERR_PTR(ret);
|
|
goto err;
|
|
}
|
|
|
|
if (composite->mux)
|
|
composite->mux->dev = clk->dev;
|
|
if (composite->rate)
|
|
composite->rate->dev = clk->dev;
|
|
if (composite->gate)
|
|
composite->gate->dev = clk->dev;
|
|
|
|
return clk;
|
|
|
|
err:
|
|
kfree(composite);
|
|
return clk;
|
|
}
|
|
|
|
static const struct clk_ops clk_composite_ops = {
|
|
.set_parent = clk_composite_set_parent,
|
|
.get_rate = clk_composite_recalc_rate,
|
|
.set_rate = clk_composite_set_rate,
|
|
.enable = clk_composite_enable,
|
|
.disable = clk_composite_disable,
|
|
};
|
|
|
|
U_BOOT_DRIVER(clk_composite) = {
|
|
.name = UBOOT_DM_CLK_COMPOSITE,
|
|
.id = UCLASS_CLK,
|
|
.ops = &clk_composite_ops,
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
};
|