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