uboot/drivers/clk/clk_boston.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2016 Imagination Technologies
   4 */
   5
   6#include <common.h>
   7#include <clk-uclass.h>
   8#include <dm.h>
   9#include <dt-bindings/clock/boston-clock.h>
  10#include <regmap.h>
  11#include <syscon.h>
  12#include <linux/bitops.h>
  13
  14struct clk_boston {
  15        struct regmap *regmap;
  16};
  17
  18#define BOSTON_PLAT_MMCMDIV             0x30
  19# define BOSTON_PLAT_MMCMDIV_CLK0DIV    (0xff << 0)
  20# define BOSTON_PLAT_MMCMDIV_INPUT      (0xff << 8)
  21# define BOSTON_PLAT_MMCMDIV_MUL        (0xff << 16)
  22# define BOSTON_PLAT_MMCMDIV_CLK1DIV    (0xff << 24)
  23
  24static uint32_t ext_field(uint32_t val, uint32_t mask)
  25{
  26        return (val & mask) >> (ffs(mask) - 1);
  27}
  28
  29static ulong clk_boston_get_rate(struct clk *clk)
  30{
  31        struct clk_boston *state = dev_get_plat(clk->dev);
  32        uint32_t in_rate, mul, div;
  33        uint mmcmdiv;
  34        int err;
  35
  36        err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
  37        if (err)
  38                return 0;
  39
  40        in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT);
  41        mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
  42
  43        switch (clk->id) {
  44        case BOSTON_CLK_SYS:
  45                div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
  46                break;
  47        case BOSTON_CLK_CPU:
  48                div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
  49                break;
  50        default:
  51                return 0;
  52        }
  53
  54        return (in_rate * mul * 1000000) / div;
  55}
  56
  57const struct clk_ops clk_boston_ops = {
  58        .get_rate = clk_boston_get_rate,
  59};
  60
  61static int clk_boston_of_to_plat(struct udevice *dev)
  62{
  63        struct clk_boston *state = dev_get_plat(dev);
  64        struct udevice *syscon;
  65        int err;
  66
  67        err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
  68                                           "regmap", &syscon);
  69        if (err) {
  70                pr_err("unable to find syscon device\n");
  71                return err;
  72        }
  73
  74        state->regmap = syscon_get_regmap(syscon);
  75        if (!state->regmap) {
  76                pr_err("unable to find regmap\n");
  77                return -ENODEV;
  78        }
  79
  80        return 0;
  81}
  82
  83static const struct udevice_id clk_boston_match[] = {
  84        {
  85                .compatible = "img,boston-clock",
  86        },
  87        { /* sentinel */ }
  88};
  89
  90U_BOOT_DRIVER(clk_boston) = {
  91        .name = "boston_clock",
  92        .id = UCLASS_CLK,
  93        .of_match = clk_boston_match,
  94        .of_to_plat = clk_boston_of_to_plat,
  95        .plat_auto      = sizeof(struct clk_boston),
  96        .ops = &clk_boston_ops,
  97};
  98