uboot/drivers/clk/clk-composite.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2013 NVIDIA CORPORATION.  All rights reserved.
   4 * Copyright 2019 NXP
   5 */
   6
   7#include <common.h>
   8#include <asm/io.h>
   9#include <malloc.h>
  10#include <clk-uclass.h>
  11#include <dm/device.h>
  12#include <linux/clk-provider.h>
  13#include <clk.h>
  14
  15#include "clk.h"
  16
  17#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
  18
  19static u8 clk_composite_get_parent(struct clk *clk)
  20{
  21        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  22                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  23        struct clk *mux = composite->mux;
  24
  25        return clk_mux_get_parent(mux);
  26}
  27
  28static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
  29{
  30        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  31                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  32        const struct clk_ops *mux_ops = composite->mux_ops;
  33        struct clk *mux = composite->mux;
  34
  35        return mux_ops->set_parent(mux, parent);
  36}
  37
  38static unsigned long clk_composite_recalc_rate(struct clk *clk)
  39{
  40        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  41                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  42        const struct clk_ops *rate_ops = composite->rate_ops;
  43        struct clk *rate = composite->rate;
  44
  45        return rate_ops->get_rate(rate);
  46}
  47
  48static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
  49{
  50        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  51                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  52        const struct clk_ops *rate_ops = composite->rate_ops;
  53        struct clk *clk_rate = composite->rate;
  54
  55        return rate_ops->set_rate(clk_rate, rate);
  56}
  57
  58static int clk_composite_enable(struct clk *clk)
  59{
  60        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  61                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  62        const struct clk_ops *gate_ops = composite->gate_ops;
  63        struct clk *gate = composite->gate;
  64
  65        return gate_ops->enable(gate);
  66}
  67
  68static int clk_composite_disable(struct clk *clk)
  69{
  70        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  71                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  72        const struct clk_ops *gate_ops = composite->gate_ops;
  73        struct clk *gate = composite->gate;
  74
  75        gate_ops->disable(gate);
  76
  77        return 0;
  78}
  79
  80struct clk_ops clk_composite_ops = {
  81        /* This will be set according to clk_register_composite */
  82};
  83
  84struct clk *clk_register_composite(struct device *dev, const char *name,
  85                                   const char * const *parent_names,
  86                                   int num_parents, struct clk *mux,
  87                                   const struct clk_ops *mux_ops,
  88                                   struct clk *rate,
  89                                   const struct clk_ops *rate_ops,
  90                                   struct clk *gate,
  91                                   const struct clk_ops *gate_ops,
  92                                   unsigned long flags)
  93{
  94        struct clk *clk;
  95        struct clk_composite *composite;
  96        int ret;
  97        struct clk_ops *composite_ops = &clk_composite_ops;
  98
  99        composite = kzalloc(sizeof(*composite), GFP_KERNEL);
 100        if (!composite)
 101                return ERR_PTR(-ENOMEM);
 102
 103        if (mux && mux_ops) {
 104                composite->mux = mux;
 105                composite->mux_ops = mux_ops;
 106                if (mux_ops->set_parent)
 107                        composite_ops->set_parent = clk_composite_set_parent;
 108                mux->data = (ulong)composite;
 109        }
 110
 111        if (rate && rate_ops) {
 112                if (!rate_ops->get_rate) {
 113                        clk = ERR_PTR(-EINVAL);
 114                        goto err;
 115                }
 116                composite_ops->get_rate = clk_composite_recalc_rate;
 117
 118                /* .set_rate requires either .round_rate or .determine_rate */
 119                if (rate_ops->set_rate)
 120                        composite_ops->set_rate = clk_composite_set_rate;
 121
 122                composite->rate = rate;
 123                composite->rate_ops = rate_ops;
 124                rate->data = (ulong)composite;
 125        }
 126
 127        if (gate && gate_ops) {
 128                if (!gate_ops->enable || !gate_ops->disable) {
 129                        clk = ERR_PTR(-EINVAL);
 130                        goto err;
 131                }
 132
 133                composite->gate = gate;
 134                composite->gate_ops = gate_ops;
 135                composite_ops->enable = clk_composite_enable;
 136                composite_ops->disable = clk_composite_disable;
 137                gate->data = (ulong)composite;
 138        }
 139
 140        clk = &composite->clk;
 141        ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
 142                           parent_names[clk_composite_get_parent(clk)]);
 143        if (ret) {
 144                clk = ERR_PTR(ret);
 145                goto err;
 146        }
 147
 148        return clk;
 149
 150err:
 151        kfree(composite);
 152        return clk;
 153}
 154
 155U_BOOT_DRIVER(clk_composite) = {
 156        .name   = UBOOT_DM_CLK_COMPOSITE,
 157        .id     = UCLASS_CLK,
 158        .ops    = &clk_composite_ops,
 159        .flags = DM_FLAG_PRE_RELOC,
 160};
 161