1*48b41c5eSBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0 2*48b41c5eSBenjamin Gaignard /* 3*48b41c5eSBenjamin Gaignard * Copyright (C) STMicroelectronics 2019 - All Rights Reserved 4*48b41c5eSBenjamin Gaignard * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 5*48b41c5eSBenjamin Gaignard * Pascal Paillet <p.paillet@st.com> for STMicroelectronics. 6*48b41c5eSBenjamin Gaignard */ 7*48b41c5eSBenjamin Gaignard 8*48b41c5eSBenjamin Gaignard #include <linux/clk.h> 9*48b41c5eSBenjamin Gaignard #include <linux/clockchips.h> 10*48b41c5eSBenjamin Gaignard #include <linux/interrupt.h> 11*48b41c5eSBenjamin Gaignard #include <linux/mfd/stm32-lptimer.h> 12*48b41c5eSBenjamin Gaignard #include <linux/module.h> 13*48b41c5eSBenjamin Gaignard #include <linux/of_address.h> 14*48b41c5eSBenjamin Gaignard #include <linux/of_irq.h> 15*48b41c5eSBenjamin Gaignard #include <linux/platform_device.h> 16*48b41c5eSBenjamin Gaignard #include <linux/pm_wakeirq.h> 17*48b41c5eSBenjamin Gaignard 18*48b41c5eSBenjamin Gaignard #define CFGR_PSC_OFFSET 9 19*48b41c5eSBenjamin Gaignard #define STM32_LP_RATING 1000 20*48b41c5eSBenjamin Gaignard #define STM32_TARGET_CLKRATE (32000 * HZ) 21*48b41c5eSBenjamin Gaignard #define STM32_LP_MAX_PSC 7 22*48b41c5eSBenjamin Gaignard 23*48b41c5eSBenjamin Gaignard struct stm32_lp_private { 24*48b41c5eSBenjamin Gaignard struct regmap *reg; 25*48b41c5eSBenjamin Gaignard struct clock_event_device clkevt; 26*48b41c5eSBenjamin Gaignard unsigned long period; 27*48b41c5eSBenjamin Gaignard struct device *dev; 28*48b41c5eSBenjamin Gaignard }; 29*48b41c5eSBenjamin Gaignard 30*48b41c5eSBenjamin Gaignard static struct stm32_lp_private* 31*48b41c5eSBenjamin Gaignard to_priv(struct clock_event_device *clkevt) 32*48b41c5eSBenjamin Gaignard { 33*48b41c5eSBenjamin Gaignard return container_of(clkevt, struct stm32_lp_private, clkevt); 34*48b41c5eSBenjamin Gaignard } 35*48b41c5eSBenjamin Gaignard 36*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt) 37*48b41c5eSBenjamin Gaignard { 38*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 39*48b41c5eSBenjamin Gaignard 40*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 0); 41*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_IER, 0); 42*48b41c5eSBenjamin Gaignard /* clear pending flags */ 43*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); 44*48b41c5eSBenjamin Gaignard 45*48b41c5eSBenjamin Gaignard return 0; 46*48b41c5eSBenjamin Gaignard } 47*48b41c5eSBenjamin Gaignard 48*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_timer(unsigned long evt, 49*48b41c5eSBenjamin Gaignard struct clock_event_device *clkevt, 50*48b41c5eSBenjamin Gaignard int is_periodic) 51*48b41c5eSBenjamin Gaignard { 52*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 53*48b41c5eSBenjamin Gaignard 54*48b41c5eSBenjamin Gaignard /* disable LPTIMER to be able to write into IER register*/ 55*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 0); 56*48b41c5eSBenjamin Gaignard /* enable ARR interrupt */ 57*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE); 58*48b41c5eSBenjamin Gaignard /* enable LPTIMER to be able to write into ARR register */ 59*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE); 60*48b41c5eSBenjamin Gaignard /* set next event counter */ 61*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ARR, evt); 62*48b41c5eSBenjamin Gaignard 63*48b41c5eSBenjamin Gaignard /* start counter */ 64*48b41c5eSBenjamin Gaignard if (is_periodic) 65*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 66*48b41c5eSBenjamin Gaignard STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE); 67*48b41c5eSBenjamin Gaignard else 68*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 69*48b41c5eSBenjamin Gaignard STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE); 70*48b41c5eSBenjamin Gaignard 71*48b41c5eSBenjamin Gaignard return 0; 72*48b41c5eSBenjamin Gaignard } 73*48b41c5eSBenjamin Gaignard 74*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_next_event(unsigned long evt, 75*48b41c5eSBenjamin Gaignard struct clock_event_device *clkevt) 76*48b41c5eSBenjamin Gaignard { 77*48b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(evt, clkevt, 78*48b41c5eSBenjamin Gaignard clockevent_state_periodic(clkevt)); 79*48b41c5eSBenjamin Gaignard } 80*48b41c5eSBenjamin Gaignard 81*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt) 82*48b41c5eSBenjamin Gaignard { 83*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 84*48b41c5eSBenjamin Gaignard 85*48b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(priv->period, clkevt, true); 86*48b41c5eSBenjamin Gaignard } 87*48b41c5eSBenjamin Gaignard 88*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt) 89*48b41c5eSBenjamin Gaignard { 90*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 91*48b41c5eSBenjamin Gaignard 92*48b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(priv->period, clkevt, false); 93*48b41c5eSBenjamin Gaignard } 94*48b41c5eSBenjamin Gaignard 95*48b41c5eSBenjamin Gaignard static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id) 96*48b41c5eSBenjamin Gaignard { 97*48b41c5eSBenjamin Gaignard struct clock_event_device *clkevt = (struct clock_event_device *)dev_id; 98*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 99*48b41c5eSBenjamin Gaignard 100*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); 101*48b41c5eSBenjamin Gaignard 102*48b41c5eSBenjamin Gaignard if (clkevt->event_handler) 103*48b41c5eSBenjamin Gaignard clkevt->event_handler(clkevt); 104*48b41c5eSBenjamin Gaignard 105*48b41c5eSBenjamin Gaignard return IRQ_HANDLED; 106*48b41c5eSBenjamin Gaignard } 107*48b41c5eSBenjamin Gaignard 108*48b41c5eSBenjamin Gaignard static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv, 109*48b41c5eSBenjamin Gaignard unsigned long *rate) 110*48b41c5eSBenjamin Gaignard { 111*48b41c5eSBenjamin Gaignard int i; 112*48b41c5eSBenjamin Gaignard 113*48b41c5eSBenjamin Gaignard for (i = 0; i <= STM32_LP_MAX_PSC; i++) { 114*48b41c5eSBenjamin Gaignard if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE) 115*48b41c5eSBenjamin Gaignard break; 116*48b41c5eSBenjamin Gaignard } 117*48b41c5eSBenjamin Gaignard 118*48b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET); 119*48b41c5eSBenjamin Gaignard 120*48b41c5eSBenjamin Gaignard /* Adjust rate and period given the prescaler value */ 121*48b41c5eSBenjamin Gaignard *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); 122*48b41c5eSBenjamin Gaignard priv->period = DIV_ROUND_UP(*rate, HZ); 123*48b41c5eSBenjamin Gaignard } 124*48b41c5eSBenjamin Gaignard 125*48b41c5eSBenjamin Gaignard static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, 126*48b41c5eSBenjamin Gaignard struct device_node *np, unsigned long rate) 127*48b41c5eSBenjamin Gaignard { 128*48b41c5eSBenjamin Gaignard priv->clkevt.name = np->full_name; 129*48b41c5eSBenjamin Gaignard priv->clkevt.cpumask = cpu_possible_mask; 130*48b41c5eSBenjamin Gaignard priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | 131*48b41c5eSBenjamin Gaignard CLOCK_EVT_FEAT_ONESHOT; 132*48b41c5eSBenjamin Gaignard priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown; 133*48b41c5eSBenjamin Gaignard priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic; 134*48b41c5eSBenjamin Gaignard priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; 135*48b41c5eSBenjamin Gaignard priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; 136*48b41c5eSBenjamin Gaignard priv->clkevt.rating = STM32_LP_RATING; 137*48b41c5eSBenjamin Gaignard 138*48b41c5eSBenjamin Gaignard clockevents_config_and_register(&priv->clkevt, rate, 0x1, 139*48b41c5eSBenjamin Gaignard STM32_LPTIM_MAX_ARR); 140*48b41c5eSBenjamin Gaignard } 141*48b41c5eSBenjamin Gaignard 142*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_probe(struct platform_device *pdev) 143*48b41c5eSBenjamin Gaignard { 144*48b41c5eSBenjamin Gaignard struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); 145*48b41c5eSBenjamin Gaignard struct stm32_lp_private *priv; 146*48b41c5eSBenjamin Gaignard unsigned long rate; 147*48b41c5eSBenjamin Gaignard int ret, irq; 148*48b41c5eSBenjamin Gaignard 149*48b41c5eSBenjamin Gaignard priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 150*48b41c5eSBenjamin Gaignard if (!priv) 151*48b41c5eSBenjamin Gaignard return -ENOMEM; 152*48b41c5eSBenjamin Gaignard 153*48b41c5eSBenjamin Gaignard priv->reg = ddata->regmap; 154*48b41c5eSBenjamin Gaignard ret = clk_prepare_enable(ddata->clk); 155*48b41c5eSBenjamin Gaignard if (ret) 156*48b41c5eSBenjamin Gaignard return -EINVAL; 157*48b41c5eSBenjamin Gaignard 158*48b41c5eSBenjamin Gaignard rate = clk_get_rate(ddata->clk); 159*48b41c5eSBenjamin Gaignard if (!rate) { 160*48b41c5eSBenjamin Gaignard ret = -EINVAL; 161*48b41c5eSBenjamin Gaignard goto out_clk_disable; 162*48b41c5eSBenjamin Gaignard } 163*48b41c5eSBenjamin Gaignard 164*48b41c5eSBenjamin Gaignard irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0); 165*48b41c5eSBenjamin Gaignard if (irq <= 0) { 166*48b41c5eSBenjamin Gaignard ret = irq; 167*48b41c5eSBenjamin Gaignard goto out_clk_disable; 168*48b41c5eSBenjamin Gaignard } 169*48b41c5eSBenjamin Gaignard 170*48b41c5eSBenjamin Gaignard if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { 171*48b41c5eSBenjamin Gaignard ret = device_init_wakeup(&pdev->dev, true); 172*48b41c5eSBenjamin Gaignard if (ret) 173*48b41c5eSBenjamin Gaignard goto out_clk_disable; 174*48b41c5eSBenjamin Gaignard 175*48b41c5eSBenjamin Gaignard ret = dev_pm_set_wake_irq(&pdev->dev, irq); 176*48b41c5eSBenjamin Gaignard if (ret) 177*48b41c5eSBenjamin Gaignard goto out_clk_disable; 178*48b41c5eSBenjamin Gaignard } 179*48b41c5eSBenjamin Gaignard 180*48b41c5eSBenjamin Gaignard ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler, 181*48b41c5eSBenjamin Gaignard IRQF_TIMER, pdev->name, &priv->clkevt); 182*48b41c5eSBenjamin Gaignard if (ret) 183*48b41c5eSBenjamin Gaignard goto out_clk_disable; 184*48b41c5eSBenjamin Gaignard 185*48b41c5eSBenjamin Gaignard stm32_clkevent_lp_set_prescaler(priv, &rate); 186*48b41c5eSBenjamin Gaignard 187*48b41c5eSBenjamin Gaignard stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate); 188*48b41c5eSBenjamin Gaignard 189*48b41c5eSBenjamin Gaignard priv->dev = &pdev->dev; 190*48b41c5eSBenjamin Gaignard 191*48b41c5eSBenjamin Gaignard return 0; 192*48b41c5eSBenjamin Gaignard 193*48b41c5eSBenjamin Gaignard out_clk_disable: 194*48b41c5eSBenjamin Gaignard clk_disable_unprepare(ddata->clk); 195*48b41c5eSBenjamin Gaignard return ret; 196*48b41c5eSBenjamin Gaignard } 197*48b41c5eSBenjamin Gaignard 198*48b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_remove(struct platform_device *pdev) 199*48b41c5eSBenjamin Gaignard { 200*48b41c5eSBenjamin Gaignard return -EBUSY; /* cannot unregister clockevent */ 201*48b41c5eSBenjamin Gaignard } 202*48b41c5eSBenjamin Gaignard 203*48b41c5eSBenjamin Gaignard static const struct of_device_id stm32_clkevent_lp_of_match[] = { 204*48b41c5eSBenjamin Gaignard { .compatible = "st,stm32-lptimer-timer", }, 205*48b41c5eSBenjamin Gaignard {}, 206*48b41c5eSBenjamin Gaignard }; 207*48b41c5eSBenjamin Gaignard MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match); 208*48b41c5eSBenjamin Gaignard 209*48b41c5eSBenjamin Gaignard static struct platform_driver stm32_clkevent_lp_driver = { 210*48b41c5eSBenjamin Gaignard .probe = stm32_clkevent_lp_probe, 211*48b41c5eSBenjamin Gaignard .remove = stm32_clkevent_lp_remove, 212*48b41c5eSBenjamin Gaignard .driver = { 213*48b41c5eSBenjamin Gaignard .name = "stm32-lptimer-timer", 214*48b41c5eSBenjamin Gaignard .of_match_table = of_match_ptr(stm32_clkevent_lp_of_match), 215*48b41c5eSBenjamin Gaignard }, 216*48b41c5eSBenjamin Gaignard }; 217*48b41c5eSBenjamin Gaignard module_platform_driver(stm32_clkevent_lp_driver); 218*48b41c5eSBenjamin Gaignard 219*48b41c5eSBenjamin Gaignard MODULE_ALIAS("platform:stm32-lptimer-timer"); 220*48b41c5eSBenjamin Gaignard MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver"); 221*48b41c5eSBenjamin Gaignard MODULE_LICENSE("GPL v2"); 222