^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Generic MMIO clocksource support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/clocksource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) struct clocksource_mmio {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct clocksource clksrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) return container_of(c, struct clocksource_mmio, clksrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) u64 clocksource_mmio_readl_up(struct clocksource *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return (u64)readl_relaxed(to_mmio_clksrc(c)->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) EXPORT_SYMBOL_GPL(clocksource_mmio_readl_up);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u64 clocksource_mmio_readl_down(struct clocksource *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return ~(u64)readl_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u64 clocksource_mmio_readw_up(struct clocksource *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return (u64)readw_relaxed(to_mmio_clksrc(c)->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u64 clocksource_mmio_readw_down(struct clocksource *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return ~(u64)readw_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * clocksource_mmio_init - Initialize a simple mmio based clocksource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * @base: Virtual address of the clock readout register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * @name: Name of the clocksource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @hz: Frequency of the clocksource in Hz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @rating: Rating of the clocksource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @bits: Number of valid bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @read: One of clocksource_mmio_read*() above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int clocksource_mmio_init(void __iomem *base, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long hz, int rating, unsigned bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u64 (*read)(struct clocksource *))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct clocksource_mmio *cs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (bits > 64 || bits < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) cs->reg = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) cs->clksrc.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) cs->clksrc.rating = rating;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) cs->clksrc.read = read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) cs->clksrc.mask = CLOCKSOURCE_MASK(bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return clocksource_register_hz(&cs->clksrc, hz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) EXPORT_SYMBOL_GPL(clocksource_mmio_init);