^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Clocksource using the Low Power Timer found in the Low Power Controller (LPC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 STMicroelectronics – All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author(s): Francesco Virlinzi <francesco.virlinzi@st.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Ajit Pal Singh <ajitpal.singh@st.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/clocksource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of_address.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) #include <dt-bindings/mfd/st-lpc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Low Power Timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define LPC_LPT_LSB_OFF 0x400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define LPC_LPT_MSB_OFF 0x404
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define LPC_LPT_START_OFF 0x408
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static struct st_clksrc_ddata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) } ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static void __init st_clksrc_reset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) writel_relaxed(0, ddata.base + LPC_LPT_START_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) writel_relaxed(1, ddata.base + LPC_LPT_START_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static u64 notrace st_clksrc_sched_clock_read(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int __init st_clksrc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned long rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) st_clksrc_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) rate = clk_get_rate(ddata.clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) sched_clock_register(st_clksrc_sched_clock_read, 32, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) "clksrc-st-lpc", rate, 300, 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) clocksource_mmio_readl_up);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pr_err("clksrc-st-lpc: Failed to register clocksource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return 0;
^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) static int __init st_clksrc_setup_clk(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) clk = of_clk_get(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) pr_err("clksrc-st-lpc: Failed to get LPC clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (clk_prepare_enable(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) pr_err("clksrc-st-lpc: Failed to enable LPC clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!clk_get_rate(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) clk_disable_unprepare(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ddata.clk = clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^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) static int __init st_clksrc_of_register(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) uint32_t mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ret = of_property_read_u32(np, "st,lpc-mode", &mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) pr_err("clksrc-st-lpc: An LPC mode must be provided\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* LPC can either run as a Clocksource or in RTC or WDT mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (mode != ST_LPC_MODE_CLKSRC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ddata.base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (!ddata.base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pr_err("clksrc-st-lpc: Unable to map iomem\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ret = st_clksrc_setup_clk(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) iounmap(ddata.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ret = st_clksrc_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) clk_disable_unprepare(ddata.clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) clk_put(ddata.clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) iounmap(ddata.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) clk_get_rate(ddata.clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);