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