18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic MMIO clocksource support 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct clocksource_mmio { 118c2ecf20Sopenharmony_ci void __iomem *reg; 128c2ecf20Sopenharmony_ci struct clocksource clksrc; 138c2ecf20Sopenharmony_ci}; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci return container_of(c, struct clocksource_mmio, clksrc); 188c2ecf20Sopenharmony_ci} 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciu64 clocksource_mmio_readl_up(struct clocksource *c) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci return (u64)readl_relaxed(to_mmio_clksrc(c)->reg); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciu64 clocksource_mmio_readl_down(struct clocksource *c) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci return ~(u64)readl_relaxed(to_mmio_clksrc(c)->reg) & c->mask; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciu64 clocksource_mmio_readw_up(struct clocksource *c) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return (u64)readw_relaxed(to_mmio_clksrc(c)->reg); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciu64 clocksource_mmio_readw_down(struct clocksource *c) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci return ~(u64)readw_relaxed(to_mmio_clksrc(c)->reg) & c->mask; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * clocksource_mmio_init - Initialize a simple mmio based clocksource 428c2ecf20Sopenharmony_ci * @base: Virtual address of the clock readout register 438c2ecf20Sopenharmony_ci * @name: Name of the clocksource 448c2ecf20Sopenharmony_ci * @hz: Frequency of the clocksource in Hz 458c2ecf20Sopenharmony_ci * @rating: Rating of the clocksource 468c2ecf20Sopenharmony_ci * @bits: Number of valid bits 478c2ecf20Sopenharmony_ci * @read: One of clocksource_mmio_read*() above 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ciint __init clocksource_mmio_init(void __iomem *base, const char *name, 508c2ecf20Sopenharmony_ci unsigned long hz, int rating, unsigned bits, 518c2ecf20Sopenharmony_ci u64 (*read)(struct clocksource *)) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct clocksource_mmio *cs; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (bits > 64 || bits < 16) 568c2ecf20Sopenharmony_ci return -EINVAL; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL); 598c2ecf20Sopenharmony_ci if (!cs) 608c2ecf20Sopenharmony_ci return -ENOMEM; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci cs->reg = base; 638c2ecf20Sopenharmony_ci cs->clksrc.name = name; 648c2ecf20Sopenharmony_ci cs->clksrc.rating = rating; 658c2ecf20Sopenharmony_ci cs->clksrc.read = read; 668c2ecf20Sopenharmony_ci cs->clksrc.mask = CLOCKSOURCE_MASK(bits); 678c2ecf20Sopenharmony_ci cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return clocksource_register_hz(&cs->clksrc, hz); 708c2ecf20Sopenharmony_ci} 71