uboot/drivers/clk/clk_vexpress_osc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Arm Ltd
   4 * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
   5 *
   6 */
   7#define DEBUG
   8#include <common.h>
   9#include <clk-uclass.h>
  10#include <dm.h>
  11#include <dm/lists.h>
  12#include <errno.h>
  13#include <misc.h>
  14
  15#define CLK_FUNCTION            BIT(20)
  16
  17struct vexpress_osc_clk_priv {
  18        u8 osc;
  19        ulong rate_min;
  20        ulong rate_max;
  21};
  22
  23static ulong vexpress_osc_clk_get_rate(struct clk *clk)
  24{
  25        int err;
  26        u32 data;
  27        struct udevice *vexpress_cfg = dev_get_parent(clk->dev);
  28        struct vexpress_osc_clk_priv *priv = dev_get_priv(clk->dev);
  29
  30        data = CLK_FUNCTION | priv->osc;
  31        err = misc_read(vexpress_cfg, 0, &data, sizeof(data));
  32        if (err < 0)
  33                return err;
  34
  35        return data;
  36}
  37
  38#ifndef CONFIG_SPL_BUILD
  39static ulong vexpress_osc_clk_set_rate(struct clk *clk, ulong rate)
  40{
  41        int err;
  42        u32 buffer[2];
  43        struct udevice *vexpress_cfg = dev_get_parent(clk->dev);
  44        struct vexpress_osc_clk_priv *priv = dev_get_priv(clk->dev);
  45
  46        if (rate < priv->rate_min || rate > priv->rate_max)
  47                return -EINVAL;
  48
  49        /*
  50         * we are sending the parent the info about the oscillator
  51         * and the value we want to set
  52         */
  53        buffer[0] = CLK_FUNCTION | priv->osc;
  54        buffer[1] = rate;
  55        err = misc_write(vexpress_cfg, 0, buffer, 2 * sizeof(u32));
  56        if (err < 0)
  57                return err;
  58
  59        return rate;
  60}
  61#endif
  62
  63static struct clk_ops vexpress_osc_clk_ops = {
  64        .get_rate = vexpress_osc_clk_get_rate,
  65#ifndef CONFIG_SPL_BUILD
  66        .set_rate = vexpress_osc_clk_set_rate,
  67#endif
  68};
  69
  70static int vexpress_osc_clk_probe(struct udevice *dev)
  71{
  72        struct vexpress_osc_clk_priv *priv = dev_get_priv(dev);
  73        u32 values[2];
  74        int err;
  75
  76        err = dev_read_u32_array(dev, "freq-range", values, 2);
  77        if (err)
  78                return err;
  79        priv->rate_min = values[0];
  80        priv->rate_max = values[1];
  81
  82        err = dev_read_u32_array(dev, "arm,vexpress-sysreg,func", values, 2);
  83        if (err)
  84                return err;
  85
  86        if (values[0] != 1) {
  87                dev_err(dev, "Invalid VExpress function for clock, must be '1'");
  88                return -EINVAL;
  89        }
  90        priv->osc = values[1];
  91        debug("clk \"%s%d\", min freq %luHz, max freq %luHz\n", dev->name,
  92              priv->osc, priv->rate_min, priv->rate_max);
  93
  94        return 0;
  95}
  96
  97static const struct udevice_id vexpress_osc_clk_ids[] = {
  98        { .compatible = "arm,vexpress-osc", },
  99        {}
 100};
 101
 102U_BOOT_DRIVER(vexpress_osc_clk) = {
 103        .name = "vexpress_osc_clk",
 104        .id = UCLASS_CLK,
 105        .of_match = vexpress_osc_clk_ids,
 106        .ops = &vexpress_osc_clk_ops,
 107        .priv_auto_alloc_size = sizeof(struct vexpress_osc_clk_priv),
 108        .probe = vexpress_osc_clk_probe,
 109};
 110