uboot/drivers/timer/mchp-pit64b-timer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * 64-bit Periodic Interval Timer driver
   4 *
   5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
   6 *
   7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
   8 */
   9
  10#include <common.h>
  11#include <clk.h>
  12#include <dm.h>
  13#include <timer.h>
  14#include <asm/io.h>
  15
  16#define MCHP_PIT64B_CR                  0x00    /* Control Register */
  17#define         MCHP_PIT64B_CR_START    BIT(0)
  18#define         MCHP_PIT64B_CR_SWRST    BIT(8)
  19#define MCHP_PIT64B_MR                  0x04    /* Mode Register */
  20#define         MCHP_PIT64B_MR_CONT     BIT(0)
  21#define MCHP_PIT64B_LSB_PR              0x08    /* LSB Period Register */
  22#define MCHP_PIT64B_MSB_PR              0x0C    /* MSB Period Register */
  23#define MCHP_PIT64B_TLSBR               0x20    /* Timer LSB Register */
  24#define MCHP_PIT64B_TMSBR               0x24    /* Timer MSB Register */
  25
  26struct mchp_pit64b_priv {
  27        void __iomem *base;
  28};
  29
  30static u64 mchp_pit64b_get_count(struct udevice *dev)
  31{
  32        struct mchp_pit64b_priv *priv = dev_get_priv(dev);
  33
  34        u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR);
  35        u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR);
  36
  37        return ((u64)msb << 32) | lsb;
  38}
  39
  40static int mchp_pit64b_probe(struct udevice *dev)
  41{
  42        struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  43        struct mchp_pit64b_priv *priv = dev_get_priv(dev);
  44        struct clk clk;
  45        ulong rate;
  46        int ret;
  47
  48        priv->base = dev_read_addr_ptr(dev);
  49        if (IS_ERR(priv->base))
  50                return PTR_ERR(priv->base);
  51
  52        ret = clk_get_by_index(dev, 0, &clk);
  53        if (ret)
  54                return ret;
  55
  56        ret = clk_enable(&clk);
  57        if (ret)
  58                return ret;
  59
  60        rate = clk_get_rate(&clk);
  61        if (!rate) {
  62                clk_disable(&clk);
  63                return -ENOTSUPP;
  64        }
  65
  66        /* Reset the timer in case it was used by previous bootloaders. */
  67        writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR);
  68
  69        /*
  70         * Use highest prescaller (for a peripheral clock running at 200MHz
  71         * this will lead to the timer running at 12.5MHz) and continuous mode.
  72         */
  73        writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR);
  74        uc_priv->clock_rate = rate / 16;
  75
  76        /*
  77         * Simulate free running counter by setting max values to period
  78         * registers.
  79         */
  80        writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR);
  81        writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR);
  82
  83        /* Start the timer. */
  84        writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR);
  85
  86        return 0;
  87}
  88
  89static const struct timer_ops mchp_pit64b_ops = {
  90        .get_count = mchp_pit64b_get_count,
  91};
  92
  93static const struct udevice_id mchp_pit64b_ids[] = {
  94        { .compatible = "microchip,sam9x60-pit64b", },
  95        { .compatible = "microchip,sama7g5-pit64b", },
  96        { }
  97};
  98
  99U_BOOT_DRIVER(mchp_pit64b) = {
 100        .name   = "mchp-pit64b",
 101        .id     = UCLASS_TIMER,
 102        .of_match = mchp_pit64b_ids,
 103        .priv_auto      = sizeof(struct mchp_pit64b_priv),
 104        .probe  = mchp_pit64b_probe,
 105        .ops    = &mchp_pit64b_ops,
 106        .flags  = DM_FLAG_PRE_RELOC,
 107};
 108