uboot/drivers/clk/at91/clk-system.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * System clock support for AT91 architectures.
   4 *
   5 * Copyright (C) Microchip Technology Inc. and its subsidiaries
   6 *
   7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
   8 *
   9 * Based on drivers/clk/at91/clk-system.c from Linux.
  10 */
  11#include <asm/processor.h>
  12#include <common.h>
  13#include <clk-uclass.h>
  14#include <dm.h>
  15#include <linux/io.h>
  16#include <linux/clk-provider.h>
  17#include <linux/clk/at91_pmc.h>
  18
  19#include "pmc.h"
  20
  21#define UBOOT_DM_CLK_AT91_SYSTEM                "at91-system-clk"
  22
  23#define SYSTEM_MAX_ID           31
  24
  25struct clk_system {
  26        void __iomem *base;
  27        struct clk clk;
  28        u8 id;
  29};
  30
  31#define to_clk_system(_c) container_of(_c, struct clk_system, clk)
  32
  33static inline int is_pck(int id)
  34{
  35        return (id >= 8) && (id <= 15);
  36}
  37
  38static inline bool clk_system_ready(void __iomem *base, int id)
  39{
  40        unsigned int status;
  41
  42        pmc_read(base, AT91_PMC_SR, &status);
  43
  44        return !!(status & (1 << id));
  45}
  46
  47static int clk_system_enable(struct clk *clk)
  48{
  49        struct clk_system *sys = to_clk_system(clk);
  50
  51        pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id);
  52
  53        if (!is_pck(sys->id))
  54                return 0;
  55
  56        while (!clk_system_ready(sys->base, sys->id)) {
  57                debug("waiting for pck%u\n", sys->id);
  58                cpu_relax();
  59        }
  60
  61        return 0;
  62}
  63
  64static int clk_system_disable(struct clk *clk)
  65{
  66        struct clk_system *sys = to_clk_system(clk);
  67
  68        pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id);
  69
  70        return 0;
  71}
  72
  73static const struct clk_ops system_ops = {
  74        .enable = clk_system_enable,
  75        .disable = clk_system_disable,
  76        .get_rate = clk_generic_get_rate,
  77};
  78
  79struct clk *at91_clk_register_system(void __iomem *base, const char *name,
  80                                     const char *parent_name, u8 id)
  81{
  82        struct clk_system *sys;
  83        struct clk *clk;
  84        int ret;
  85
  86        if (!base || !name || !parent_name || id > SYSTEM_MAX_ID)
  87                return ERR_PTR(-EINVAL);
  88
  89        sys = kzalloc(sizeof(*sys), GFP_KERNEL);
  90        if (!sys)
  91                return ERR_PTR(-ENOMEM);
  92
  93        sys->id = id;
  94        sys->base = base;
  95
  96        clk = &sys->clk;
  97        clk->flags = CLK_GET_RATE_NOCACHE;
  98        ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name);
  99        if (ret) {
 100                kfree(sys);
 101                clk = ERR_PTR(ret);
 102        }
 103
 104        return clk;
 105}
 106
 107U_BOOT_DRIVER(at91_system_clk) = {
 108        .name = UBOOT_DM_CLK_AT91_SYSTEM,
 109        .id = UCLASS_CLK,
 110        .ops = &system_ops,
 111        .flags = DM_FLAG_PRE_RELOC,
 112};
 113