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#define LOG_CATEGORY UCLASS_CLK
   8
   9#include <common.h>
  10#include <clk.h>
  11#include <clk-uclass.h>
  12#include <log.h>
  13#include <malloc.h>
  14#include <asm/io.h>
  15#include <dm/device.h>
  16#include <dm/devres.h>
  17#include <linux/clk-provider.h>
  18#include <linux/err.h>
  19
  20#include "clk.h"
  21
  22#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
  23
  24static u8 clk_composite_get_parent(struct clk *clk)
  25{
  26        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  27                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  28        struct clk *mux = composite->mux;
  29
  30        if (mux)
  31                return clk_mux_get_parent(mux);
  32        else
  33                return 0;
  34}
  35
  36static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
  37{
  38        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  39                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  40        const struct clk_ops *mux_ops = composite->mux_ops;
  41        struct clk *mux = composite->mux;
  42
  43        if (!mux || !mux_ops)
  44                return -ENOSYS;
  45
  46        return mux_ops->set_parent(mux, parent);
  47}
  48
  49static unsigned long clk_composite_recalc_rate(struct clk *clk)
  50{
  51        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  52                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  53        const struct clk_ops *rate_ops = composite->rate_ops;
  54        struct clk *rate = composite->rate;
  55
  56        if (rate && rate_ops)
  57                return rate_ops->get_rate(rate);
  58        else
  59                return clk_get_parent_rate(clk);
  60}
  61
  62static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
  63{
  64        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  65                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  66        const struct clk_ops *rate_ops = composite->rate_ops;
  67        struct clk *clk_rate = composite->rate;
  68
  69        if (rate && rate_ops)
  70                return rate_ops->set_rate(clk_rate, rate);
  71        else
  72                return clk_get_rate(clk);
  73}
  74
  75static int clk_composite_enable(struct clk *clk)
  76{
  77        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  78                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  79        const struct clk_ops *gate_ops = composite->gate_ops;
  80        struct clk *gate = composite->gate;
  81
  82        if (gate && gate_ops)
  83                return gate_ops->enable(gate);
  84        else
  85                return 0;
  86}
  87
  88static int clk_composite_disable(struct clk *clk)
  89{
  90        struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
  91                (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
  92        const struct clk_ops *gate_ops = composite->gate_ops;
  93        struct clk *gate = composite->gate;
  94
  95        if (gate && gate_ops)
  96                return gate_ops->disable(gate);
  97        else
  98                return 0;
  99}
 100
 101struct clk *clk_register_composite(struct device *dev, const char *name,
 102                                   const char * const *parent_names,
 103                                   int num_parents, struct clk *mux,
 104                                   const struct clk_ops *mux_ops,
 105                                   struct clk *rate,
 106                                   const struct clk_ops *rate_ops,
 107                                   struct clk *gate,
 108                                   const struct clk_ops *gate_ops,
 109                                   unsigned long flags)
 110{
 111        struct clk *clk;
 112        struct clk_composite *composite;
 113        int ret;
 114
 115        if (!num_parents || (num_parents != 1 && !mux))
 116                return ERR_PTR(-EINVAL);
 117
 118        composite = kzalloc(sizeof(*composite), GFP_KERNEL);
 119        if (!composite)
 120                return ERR_PTR(-ENOMEM);
 121
 122        if (mux && mux_ops) {
 123                composite->mux = mux;
 124                composite->mux_ops = mux_ops;
 125                mux->data = (ulong)composite;
 126        }
 127
 128        if (rate && rate_ops) {
 129                if (!rate_ops->get_rate) {
 130                        clk = ERR_PTR(-EINVAL);
 131                        goto err;
 132                }
 133
 134                composite->rate = rate;
 135                composite->rate_ops = rate_ops;
 136                rate->data = (ulong)composite;
 137        }
 138
 139        if (gate && gate_ops) {
 140                if (!gate_ops->enable || !gate_ops->disable) {
 141                        clk = ERR_PTR(-EINVAL);
 142                        goto err;
 143                }
 144
 145                composite->gate = gate;
 146                composite->gate_ops = gate_ops;
 147                gate->data = (ulong)composite;
 148        }
 149
 150        clk = &composite->clk;
 151        clk->flags = flags;
 152        ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
 153                           parent_names[clk_composite_get_parent(clk)]);
 154        if (ret) {
 155                clk = ERR_PTR(ret);
 156                goto err;
 157        }
 158
 159        if (composite->mux)
 160                composite->mux->dev = clk->dev;
 161        if (composite->rate)
 162                composite->rate->dev = clk->dev;
 163        if (composite->gate)
 164                composite->gate->dev = clk->dev;
 165
 166        return clk;
 167
 168err:
 169        kfree(composite);
 170        return clk;
 171}
 172
 173static const struct clk_ops clk_composite_ops = {
 174        .set_parent = clk_composite_set_parent,
 175        .get_rate = clk_composite_recalc_rate,
 176        .set_rate = clk_composite_set_rate,
 177        .enable = clk_composite_enable,
 178        .disable = clk_composite_disable,
 179};
 180
 181U_BOOT_DRIVER(clk_composite) = {
 182        .name   = UBOOT_DM_CLK_COMPOSITE,
 183        .id     = UCLASS_CLK,
 184        .ops    = &clk_composite_ops,
 185        .flags = DM_FLAG_PRE_RELOC,
 186};
 187