xref: /linux/drivers/clocksource/timer-stm32-lp.c (revision 48b41c5e2de6c52c90efa99cfa122a5da7a7f0cd)
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