^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * 64-bit Periodic Interval Timer driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clockchips.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/sched_clock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define MCHP_PIT64B_CR 0x00 /* Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define MCHP_PIT64B_CR_START BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MCHP_PIT64B_CR_SWRST BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MCHP_PIT64B_MR 0x04 /* Mode Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MCHP_PIT64B_MR_CONT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MCHP_PIT64B_MR_ONE_SHOT (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MCHP_PIT64B_MR_SGCLK BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define MCHP_PIT64B_MR_PRES GENMASK(11, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define MCHP_PIT64B_IER 0x10 /* Interrupt Enable Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define MCHP_PIT64B_IER_PERIOD BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MCHP_PIT64B_ISR 0x1C /* Interrupt Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define MCHP_PIT64B_PRES_MAX 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define MCHP_PIT64B_LSBMASK GENMASK_ULL(31, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define MCHP_PIT64B_PRES_TO_MODE(p) (MCHP_PIT64B_MR_PRES & ((p) << 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define MCHP_PIT64B_MODE_TO_PRES(m) ((MCHP_PIT64B_MR_PRES & (m)) >> 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define MCHP_PIT64B_DEF_CS_FREQ 5000000UL /* 5 MHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define MCHP_PIT64B_DEF_CE_FREQ 32768 /* 32 KHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define MCHP_PIT64B_NAME "pit64b"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * struct mchp_pit64b_timer - PIT64B timer data structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * @base: base address of PIT64B hardware block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * @pclk: PIT64B's peripheral clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * @gclk: PIT64B's generic clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * @mode: precomputed value for mode register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct mchp_pit64b_timer {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct clk *pclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct clk *gclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u32 mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * mchp_pit64b_clkevt - PIT64B clockevent data structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @timer: PIT64B timer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @clkevt: clockevent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct mchp_pit64b_clkevt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct mchp_pit64b_timer timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct clock_event_device clkevt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define to_mchp_pit64b_timer(x) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ((struct mchp_pit64b_timer *)container_of(x,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct mchp_pit64b_clkevt, clkevt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Base address for clocksource timer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void __iomem *mchp_pit64b_cs_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Default cycles for clockevent timer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static u64 mchp_pit64b_ce_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static inline u64 mchp_pit64b_cnt_read(void __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 low, high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) raw_local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * When using a 64 bit period TLSB must be read first, followed by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * read of TMSB. This sequence generates an atomic read of the 64 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * timer value whatever the lapse of time between the accesses.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) low = readl_relaxed(base + MCHP_PIT64B_TLSBR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) high = readl_relaxed(base + MCHP_PIT64B_TMSBR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) raw_local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return (((u64)high << 32) | low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static inline void mchp_pit64b_reset(struct mchp_pit64b_timer *timer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u64 cycles, u32 mode, u32 irqs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 low, high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) low = cycles & MCHP_PIT64B_LSBMASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) high = cycles >> 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) writel_relaxed(mode | timer->mode, timer->base + MCHP_PIT64B_MR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) writel_relaxed(high, timer->base + MCHP_PIT64B_MSB_PR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) writel_relaxed(low, timer->base + MCHP_PIT64B_LSB_PR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) writel_relaxed(irqs, timer->base + MCHP_PIT64B_IER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) writel_relaxed(MCHP_PIT64B_CR_START, timer->base + MCHP_PIT64B_CR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static u64 mchp_pit64b_clksrc_read(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return mchp_pit64b_cnt_read(mchp_pit64b_cs_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static u64 notrace mchp_pit64b_sched_read_clk(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return mchp_pit64b_cnt_read(mchp_pit64b_cs_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) MCHP_PIT64B_IER_PERIOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct clock_event_device *cedev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) MCHP_PIT64B_IER_PERIOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (timer->mode & MCHP_PIT64B_MR_SGCLK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) clk_disable_unprepare(timer->gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) clk_disable_unprepare(timer->pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) clk_prepare_enable(timer->pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (timer->mode & MCHP_PIT64B_MR_SGCLK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) clk_prepare_enable(timer->gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct mchp_pit64b_clkevt *irq_data = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* Need to clear the interrupt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) readl_relaxed(irq_data->timer.base + MCHP_PIT64B_ISR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) irq_data->clkevt.event_handler(&irq_data->clkevt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u32 max_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) for (*pres = 0; *pres < MCHP_PIT64B_PRES_MAX; (*pres)++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) tmp = clk_rate / (*pres + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (tmp <= max_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* Use the bigest prescaler if we didn't match one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (*pres == MCHP_PIT64B_PRES_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) *pres = MCHP_PIT64B_PRES_MAX - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * runtime; this includes prescaler and SGCLK bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * could be changed via clock APIs. The chosen clock (pclk or gclk) could be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * divided by the internal PIT64B's divider.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * This function, first tries to use GCLK by requesting the desired rate from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * PMC and then using the internal PIT64B prescaler, if any, to reach the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * requested rate. If PCLK/GCLK < 3 (condition requested by PIT64B hardware)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * then the function falls back on using PCLK as clock source for PIT64B timer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * choosing the highest prescaler in case it doesn't locate one to match the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * requested frequency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * Below is presented the PIT64B block in relation with PMC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * PIT64B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * PMC +------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * +----+ | +-----+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * | |-->gclk -->|-->| | +---------+ +-----+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * | | | | MUX |--->| Divider |->|timer| |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * | |-->pclk -->|-->| | +---------+ +-----+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * +----+ | +-----+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * | ^ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * | sel |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * +------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * Where:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * - gclk rate <= pclk rate/3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * - gclk rate could be requested from PMC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * - pclk rate is fixed (cannot be requested from PMC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) unsigned long max_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) unsigned long pclk_rate, diff = 0, best_diff = ULONG_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) long gclk_round = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u32 pres, best_pres = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) pclk_rate = clk_get_rate(timer->pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!pclk_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) timer->mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Try using GCLK. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) gclk_round = clk_round_rate(timer->gclk, max_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (gclk_round < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) goto pclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (pclk_rate / gclk_round < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto pclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) mchp_pit64b_pres_compute(&pres, gclk_round, max_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) best_diff = abs(gclk_round / (pres + 1) - max_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) best_pres = pres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (!best_diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) timer->mode |= MCHP_PIT64B_MR_SGCLK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) clk_set_rate(timer->gclk, gclk_round);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) pclk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* Check if requested rate could be obtained using PCLK. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) mchp_pit64b_pres_compute(&pres, pclk_rate, max_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) diff = abs(pclk_rate / (pres + 1) - max_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (best_diff > diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* Use PCLK. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) best_pres = pres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* Use GCLK. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) timer->mode |= MCHP_PIT64B_MR_SGCLK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) clk_set_rate(timer->gclk, gclk_round);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) timer->mode |= MCHP_PIT64B_PRES_TO_MODE(best_pres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) timer->mode & MCHP_PIT64B_MR_SGCLK ? "gclk" : "pclk", best_pres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) timer->mode & MCHP_PIT64B_MR_SGCLK ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) gclk_round / (best_pres + 1) : pclk_rate / (best_pres + 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) u32 clk_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) mchp_pit64b_cs_base = timer->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) ret = clocksource_mmio_init(timer->base, MCHP_PIT64B_NAME, clk_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 210, 64, mchp_pit64b_clksrc_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Stop timer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) writel_relaxed(MCHP_PIT64B_CR_SWRST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) timer->base + MCHP_PIT64B_CR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) sched_clock_register(mchp_pit64b_sched_read_clk, 64, clk_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) u32 clk_rate, u32 irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct mchp_pit64b_clkevt *ce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) ce = kzalloc(sizeof(*ce), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (!ce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) mchp_pit64b_ce_cycles = DIV_ROUND_CLOSEST(clk_rate, HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ce->timer.base = timer->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ce->timer.pclk = timer->pclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ce->timer.gclk = timer->gclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ce->timer.mode = timer->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ce->clkevt.name = MCHP_PIT64B_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ce->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) ce->clkevt.rating = 150;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ce->clkevt.set_state_shutdown = mchp_pit64b_clkevt_shutdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) ce->clkevt.set_state_periodic = mchp_pit64b_clkevt_set_periodic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) ce->clkevt.set_next_event = mchp_pit64b_clkevt_set_next_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) ce->clkevt.suspend = mchp_pit64b_clkevt_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) ce->clkevt.resume = mchp_pit64b_clkevt_resume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ce->clkevt.cpumask = cpumask_of(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ce->clkevt.irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) ret = request_irq(irq, mchp_pit64b_interrupt, IRQF_TIMER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) "pit64b_tick", ce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) kfree(ce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) clockevents_config_and_register(&ce->clkevt, clk_rate, 1, ULONG_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) bool clkevt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) u32 freq = clkevt ? MCHP_PIT64B_DEF_CE_FREQ : MCHP_PIT64B_DEF_CS_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct mchp_pit64b_timer timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) unsigned long clk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) u32 irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) /* Parse DT node. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) timer.pclk = of_clk_get_by_name(node, "pclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (IS_ERR(timer.pclk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return PTR_ERR(timer.pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) timer.gclk = of_clk_get_by_name(node, "gclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (IS_ERR(timer.gclk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return PTR_ERR(timer.gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) timer.base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (!timer.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (clkevt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) irq = irq_of_parse_and_map(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) goto io_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* Initialize mode (prescaler + SGCK bit). To be used at runtime. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = mchp_pit64b_init_mode(&timer, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) goto irq_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) ret = clk_prepare_enable(timer.pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) goto irq_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (timer.mode & MCHP_PIT64B_MR_SGCLK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) ret = clk_prepare_enable(timer.gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) goto pclk_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) clk_rate = clk_get_rate(timer.gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) clk_rate = clk_get_rate(timer.pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) clk_rate = clk_rate / (MCHP_PIT64B_MODE_TO_PRES(timer.mode) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (clkevt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ret = mchp_pit64b_init_clkevt(&timer, clk_rate, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) ret = mchp_pit64b_init_clksrc(&timer, clk_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) goto gclk_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) gclk_unprepare:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (timer.mode & MCHP_PIT64B_MR_SGCLK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) clk_disable_unprepare(timer.gclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) pclk_unprepare:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) clk_disable_unprepare(timer.pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) irq_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) irq_dispose_mapping(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) io_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) iounmap(timer.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) static int __init mchp_pit64b_dt_init(struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static int inits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) switch (inits++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) /* 1st request, register clockevent. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return mchp_pit64b_dt_init_timer(node, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /* 2nd request, register clocksource. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return mchp_pit64b_dt_init_timer(node, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) /* The rest, don't care. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) TIMER_OF_DECLARE(mchp_pit64b, "microchip,sam9x60-pit64b", mchp_pit64b_dt_init);