148b41c5eSBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0 248b41c5eSBenjamin Gaignard /* 348b41c5eSBenjamin Gaignard * Copyright (C) STMicroelectronics 2019 - All Rights Reserved 448b41c5eSBenjamin Gaignard * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 548b41c5eSBenjamin Gaignard * Pascal Paillet <p.paillet@st.com> for STMicroelectronics. 648b41c5eSBenjamin Gaignard */ 748b41c5eSBenjamin Gaignard 848b41c5eSBenjamin Gaignard #include <linux/clk.h> 948b41c5eSBenjamin Gaignard #include <linux/clockchips.h> 1048b41c5eSBenjamin Gaignard #include <linux/interrupt.h> 1148b41c5eSBenjamin Gaignard #include <linux/mfd/stm32-lptimer.h> 1248b41c5eSBenjamin Gaignard #include <linux/module.h> 1348b41c5eSBenjamin Gaignard #include <linux/of_address.h> 1448b41c5eSBenjamin Gaignard #include <linux/of_irq.h> 1548b41c5eSBenjamin Gaignard #include <linux/platform_device.h> 1648b41c5eSBenjamin Gaignard #include <linux/pm_wakeirq.h> 1748b41c5eSBenjamin Gaignard 1848b41c5eSBenjamin Gaignard #define CFGR_PSC_OFFSET 9 1948b41c5eSBenjamin Gaignard #define STM32_LP_RATING 1000 2048b41c5eSBenjamin Gaignard #define STM32_TARGET_CLKRATE (32000 * HZ) 2148b41c5eSBenjamin Gaignard #define STM32_LP_MAX_PSC 7 2248b41c5eSBenjamin Gaignard 2348b41c5eSBenjamin Gaignard struct stm32_lp_private { 2448b41c5eSBenjamin Gaignard struct regmap *reg; 2548b41c5eSBenjamin Gaignard struct clock_event_device clkevt; 2648b41c5eSBenjamin Gaignard unsigned long period; 2748b41c5eSBenjamin Gaignard struct device *dev; 2848b41c5eSBenjamin Gaignard }; 2948b41c5eSBenjamin Gaignard 3048b41c5eSBenjamin Gaignard static struct stm32_lp_private* 3148b41c5eSBenjamin Gaignard to_priv(struct clock_event_device *clkevt) 3248b41c5eSBenjamin Gaignard { 3348b41c5eSBenjamin Gaignard return container_of(clkevt, struct stm32_lp_private, clkevt); 3448b41c5eSBenjamin Gaignard } 3548b41c5eSBenjamin Gaignard 3648b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt) 3748b41c5eSBenjamin Gaignard { 3848b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 3948b41c5eSBenjamin Gaignard 4048b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 0); 4148b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_IER, 0); 4248b41c5eSBenjamin Gaignard /* clear pending flags */ 4348b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); 4448b41c5eSBenjamin Gaignard 4548b41c5eSBenjamin Gaignard return 0; 4648b41c5eSBenjamin Gaignard } 4748b41c5eSBenjamin Gaignard 4848b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_timer(unsigned long evt, 4948b41c5eSBenjamin Gaignard struct clock_event_device *clkevt, 5048b41c5eSBenjamin Gaignard int is_periodic) 5148b41c5eSBenjamin Gaignard { 5248b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 5348b41c5eSBenjamin Gaignard 5448b41c5eSBenjamin Gaignard /* disable LPTIMER to be able to write into IER register*/ 5548b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 0); 5648b41c5eSBenjamin Gaignard /* enable ARR interrupt */ 5748b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE); 5848b41c5eSBenjamin Gaignard /* enable LPTIMER to be able to write into ARR register */ 5948b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE); 6048b41c5eSBenjamin Gaignard /* set next event counter */ 6148b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ARR, evt); 6248b41c5eSBenjamin Gaignard 6348b41c5eSBenjamin Gaignard /* start counter */ 6448b41c5eSBenjamin Gaignard if (is_periodic) 6548b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 6648b41c5eSBenjamin Gaignard STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE); 6748b41c5eSBenjamin Gaignard else 6848b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CR, 6948b41c5eSBenjamin Gaignard STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE); 7048b41c5eSBenjamin Gaignard 7148b41c5eSBenjamin Gaignard return 0; 7248b41c5eSBenjamin Gaignard } 7348b41c5eSBenjamin Gaignard 7448b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_next_event(unsigned long evt, 7548b41c5eSBenjamin Gaignard struct clock_event_device *clkevt) 7648b41c5eSBenjamin Gaignard { 7748b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(evt, clkevt, 7848b41c5eSBenjamin Gaignard clockevent_state_periodic(clkevt)); 7948b41c5eSBenjamin Gaignard } 8048b41c5eSBenjamin Gaignard 8148b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt) 8248b41c5eSBenjamin Gaignard { 8348b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 8448b41c5eSBenjamin Gaignard 8548b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(priv->period, clkevt, true); 8648b41c5eSBenjamin Gaignard } 8748b41c5eSBenjamin Gaignard 8848b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt) 8948b41c5eSBenjamin Gaignard { 9048b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 9148b41c5eSBenjamin Gaignard 9248b41c5eSBenjamin Gaignard return stm32_clkevent_lp_set_timer(priv->period, clkevt, false); 9348b41c5eSBenjamin Gaignard } 9448b41c5eSBenjamin Gaignard 9548b41c5eSBenjamin Gaignard static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id) 9648b41c5eSBenjamin Gaignard { 9748b41c5eSBenjamin Gaignard struct clock_event_device *clkevt = (struct clock_event_device *)dev_id; 9848b41c5eSBenjamin Gaignard struct stm32_lp_private *priv = to_priv(clkevt); 9948b41c5eSBenjamin Gaignard 10048b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); 10148b41c5eSBenjamin Gaignard 10248b41c5eSBenjamin Gaignard if (clkevt->event_handler) 10348b41c5eSBenjamin Gaignard clkevt->event_handler(clkevt); 10448b41c5eSBenjamin Gaignard 10548b41c5eSBenjamin Gaignard return IRQ_HANDLED; 10648b41c5eSBenjamin Gaignard } 10748b41c5eSBenjamin Gaignard 10848b41c5eSBenjamin Gaignard static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv, 10948b41c5eSBenjamin Gaignard unsigned long *rate) 11048b41c5eSBenjamin Gaignard { 11148b41c5eSBenjamin Gaignard int i; 11248b41c5eSBenjamin Gaignard 11348b41c5eSBenjamin Gaignard for (i = 0; i <= STM32_LP_MAX_PSC; i++) { 11448b41c5eSBenjamin Gaignard if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE) 11548b41c5eSBenjamin Gaignard break; 11648b41c5eSBenjamin Gaignard } 11748b41c5eSBenjamin Gaignard 11848b41c5eSBenjamin Gaignard regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET); 11948b41c5eSBenjamin Gaignard 12048b41c5eSBenjamin Gaignard /* Adjust rate and period given the prescaler value */ 12148b41c5eSBenjamin Gaignard *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); 12248b41c5eSBenjamin Gaignard priv->period = DIV_ROUND_UP(*rate, HZ); 12348b41c5eSBenjamin Gaignard } 12448b41c5eSBenjamin Gaignard 12548b41c5eSBenjamin Gaignard static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, 12648b41c5eSBenjamin Gaignard struct device_node *np, unsigned long rate) 12748b41c5eSBenjamin Gaignard { 12848b41c5eSBenjamin Gaignard priv->clkevt.name = np->full_name; 12948b41c5eSBenjamin Gaignard priv->clkevt.cpumask = cpu_possible_mask; 13048b41c5eSBenjamin Gaignard priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | 13148b41c5eSBenjamin Gaignard CLOCK_EVT_FEAT_ONESHOT; 13248b41c5eSBenjamin Gaignard priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown; 13348b41c5eSBenjamin Gaignard priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic; 13448b41c5eSBenjamin Gaignard priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; 13548b41c5eSBenjamin Gaignard priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; 13648b41c5eSBenjamin Gaignard priv->clkevt.rating = STM32_LP_RATING; 13748b41c5eSBenjamin Gaignard 13848b41c5eSBenjamin Gaignard clockevents_config_and_register(&priv->clkevt, rate, 0x1, 13948b41c5eSBenjamin Gaignard STM32_LPTIM_MAX_ARR); 14048b41c5eSBenjamin Gaignard } 14148b41c5eSBenjamin Gaignard 14248b41c5eSBenjamin Gaignard static int stm32_clkevent_lp_probe(struct platform_device *pdev) 14348b41c5eSBenjamin Gaignard { 14448b41c5eSBenjamin Gaignard struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); 14548b41c5eSBenjamin Gaignard struct stm32_lp_private *priv; 14648b41c5eSBenjamin Gaignard unsigned long rate; 14748b41c5eSBenjamin Gaignard int ret, irq; 14848b41c5eSBenjamin Gaignard 14948b41c5eSBenjamin Gaignard priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 15048b41c5eSBenjamin Gaignard if (!priv) 15148b41c5eSBenjamin Gaignard return -ENOMEM; 15248b41c5eSBenjamin Gaignard 15348b41c5eSBenjamin Gaignard priv->reg = ddata->regmap; 15448b41c5eSBenjamin Gaignard ret = clk_prepare_enable(ddata->clk); 15548b41c5eSBenjamin Gaignard if (ret) 15648b41c5eSBenjamin Gaignard return -EINVAL; 15748b41c5eSBenjamin Gaignard 15848b41c5eSBenjamin Gaignard rate = clk_get_rate(ddata->clk); 15948b41c5eSBenjamin Gaignard if (!rate) { 16048b41c5eSBenjamin Gaignard ret = -EINVAL; 16148b41c5eSBenjamin Gaignard goto out_clk_disable; 16248b41c5eSBenjamin Gaignard } 16348b41c5eSBenjamin Gaignard 16448b41c5eSBenjamin Gaignard irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0); 16548b41c5eSBenjamin Gaignard if (irq <= 0) { 16648b41c5eSBenjamin Gaignard ret = irq; 16748b41c5eSBenjamin Gaignard goto out_clk_disable; 16848b41c5eSBenjamin Gaignard } 16948b41c5eSBenjamin Gaignard 17048b41c5eSBenjamin Gaignard if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { 17148b41c5eSBenjamin Gaignard ret = device_init_wakeup(&pdev->dev, true); 17248b41c5eSBenjamin Gaignard if (ret) 17348b41c5eSBenjamin Gaignard goto out_clk_disable; 17448b41c5eSBenjamin Gaignard 17548b41c5eSBenjamin Gaignard ret = dev_pm_set_wake_irq(&pdev->dev, irq); 17648b41c5eSBenjamin Gaignard if (ret) 17748b41c5eSBenjamin Gaignard goto out_clk_disable; 17848b41c5eSBenjamin Gaignard } 17948b41c5eSBenjamin Gaignard 18048b41c5eSBenjamin Gaignard ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler, 18148b41c5eSBenjamin Gaignard IRQF_TIMER, pdev->name, &priv->clkevt); 18248b41c5eSBenjamin Gaignard if (ret) 18348b41c5eSBenjamin Gaignard goto out_clk_disable; 18448b41c5eSBenjamin Gaignard 18548b41c5eSBenjamin Gaignard stm32_clkevent_lp_set_prescaler(priv, &rate); 18648b41c5eSBenjamin Gaignard 18748b41c5eSBenjamin Gaignard stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate); 18848b41c5eSBenjamin Gaignard 18948b41c5eSBenjamin Gaignard priv->dev = &pdev->dev; 19048b41c5eSBenjamin Gaignard 19148b41c5eSBenjamin Gaignard return 0; 19248b41c5eSBenjamin Gaignard 19348b41c5eSBenjamin Gaignard out_clk_disable: 19448b41c5eSBenjamin Gaignard clk_disable_unprepare(ddata->clk); 19548b41c5eSBenjamin Gaignard return ret; 19648b41c5eSBenjamin Gaignard } 19748b41c5eSBenjamin Gaignard 19848b41c5eSBenjamin Gaignard static const struct of_device_id stm32_clkevent_lp_of_match[] = { 19948b41c5eSBenjamin Gaignard { .compatible = "st,stm32-lptimer-timer", }, 20048b41c5eSBenjamin Gaignard {}, 20148b41c5eSBenjamin Gaignard }; 20248b41c5eSBenjamin Gaignard MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match); 20348b41c5eSBenjamin Gaignard 20448b41c5eSBenjamin Gaignard static struct platform_driver stm32_clkevent_lp_driver = { 20548b41c5eSBenjamin Gaignard .probe = stm32_clkevent_lp_probe, 20648b41c5eSBenjamin Gaignard .driver = { 20748b41c5eSBenjamin Gaignard .name = "stm32-lptimer-timer", 208*b6f228e8SKrzysztof Kozlowski .of_match_table = stm32_clkevent_lp_of_match, 209ede38f92SUwe Kleine-König .suppress_bind_attrs = true, 21048b41c5eSBenjamin Gaignard }, 21148b41c5eSBenjamin Gaignard }; 21248b41c5eSBenjamin Gaignard module_platform_driver(stm32_clkevent_lp_driver); 21348b41c5eSBenjamin Gaignard 21448b41c5eSBenjamin Gaignard MODULE_ALIAS("platform:stm32-lptimer-timer"); 21548b41c5eSBenjamin Gaignard MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver"); 21648b41c5eSBenjamin Gaignard MODULE_LICENSE("GPL v2"); 217