123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // 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,
- };
|