1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
5 * Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
9 #include <linux/clockchips.h>
10 #include <linux/interrupt.h>
11 #include <linux/mfd/stm32-lptimer.h>
12 #include <linux/module.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_wakeirq.h>
18 #define CFGR_PSC_OFFSET 9
19 #define STM32_LP_RATING 1000
20 #define STM32_TARGET_CLKRATE (32000 * HZ)
21 #define STM32_LP_MAX_PSC 7
23 struct stm32_lp_private
{
25 struct clock_event_device clkevt
;
30 static struct stm32_lp_private
*
31 to_priv(struct clock_event_device
*clkevt
)
33 return container_of(clkevt
, struct stm32_lp_private
, clkevt
);
36 static int stm32_clkevent_lp_shutdown(struct clock_event_device
*clkevt
)
38 struct stm32_lp_private
*priv
= to_priv(clkevt
);
40 regmap_write(priv
->reg
, STM32_LPTIM_CR
, 0);
41 regmap_write(priv
->reg
, STM32_LPTIM_IER
, 0);
42 /* clear pending flags */
43 regmap_write(priv
->reg
, STM32_LPTIM_ICR
, STM32_LPTIM_ARRMCF
);
48 static int stm32_clkevent_lp_set_timer(unsigned long evt
,
49 struct clock_event_device
*clkevt
,
52 struct stm32_lp_private
*priv
= to_priv(clkevt
);
54 /* disable LPTIMER to be able to write into IER register*/
55 regmap_write(priv
->reg
, STM32_LPTIM_CR
, 0);
56 /* enable ARR interrupt */
57 regmap_write(priv
->reg
, STM32_LPTIM_IER
, STM32_LPTIM_ARRMIE
);
58 /* enable LPTIMER to be able to write into ARR register */
59 regmap_write(priv
->reg
, STM32_LPTIM_CR
, STM32_LPTIM_ENABLE
);
60 /* set next event counter */
61 regmap_write(priv
->reg
, STM32_LPTIM_ARR
, evt
);
65 regmap_write(priv
->reg
, STM32_LPTIM_CR
,
66 STM32_LPTIM_CNTSTRT
| STM32_LPTIM_ENABLE
);
68 regmap_write(priv
->reg
, STM32_LPTIM_CR
,
69 STM32_LPTIM_SNGSTRT
| STM32_LPTIM_ENABLE
);
74 static int stm32_clkevent_lp_set_next_event(unsigned long evt
,
75 struct clock_event_device
*clkevt
)
77 return stm32_clkevent_lp_set_timer(evt
, clkevt
,
78 clockevent_state_periodic(clkevt
));
81 static int stm32_clkevent_lp_set_periodic(struct clock_event_device
*clkevt
)
83 struct stm32_lp_private
*priv
= to_priv(clkevt
);
85 return stm32_clkevent_lp_set_timer(priv
->period
, clkevt
, true);
88 static int stm32_clkevent_lp_set_oneshot(struct clock_event_device
*clkevt
)
90 struct stm32_lp_private
*priv
= to_priv(clkevt
);
92 return stm32_clkevent_lp_set_timer(priv
->period
, clkevt
, false);
95 static irqreturn_t
stm32_clkevent_lp_irq_handler(int irq
, void *dev_id
)
97 struct clock_event_device
*clkevt
= (struct clock_event_device
*)dev_id
;
98 struct stm32_lp_private
*priv
= to_priv(clkevt
);
100 regmap_write(priv
->reg
, STM32_LPTIM_ICR
, STM32_LPTIM_ARRMCF
);
102 if (clkevt
->event_handler
)
103 clkevt
->event_handler(clkevt
);
108 static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private
*priv
,
113 for (i
= 0; i
<= STM32_LP_MAX_PSC
; i
++) {
114 if (DIV_ROUND_CLOSEST(*rate
, 1 << i
) < STM32_TARGET_CLKRATE
)
118 regmap_write(priv
->reg
, STM32_LPTIM_CFGR
, i
<< CFGR_PSC_OFFSET
);
120 /* Adjust rate and period given the prescaler value */
121 *rate
= DIV_ROUND_CLOSEST(*rate
, (1 << i
));
122 priv
->period
= DIV_ROUND_UP(*rate
, HZ
);
125 static void stm32_clkevent_lp_init(struct stm32_lp_private
*priv
,
126 struct device_node
*np
, unsigned long rate
)
128 priv
->clkevt
.name
= np
->full_name
;
129 priv
->clkevt
.cpumask
= cpu_possible_mask
;
130 priv
->clkevt
.features
= CLOCK_EVT_FEAT_PERIODIC
|
131 CLOCK_EVT_FEAT_ONESHOT
;
132 priv
->clkevt
.set_state_shutdown
= stm32_clkevent_lp_shutdown
;
133 priv
->clkevt
.set_state_periodic
= stm32_clkevent_lp_set_periodic
;
134 priv
->clkevt
.set_state_oneshot
= stm32_clkevent_lp_set_oneshot
;
135 priv
->clkevt
.set_next_event
= stm32_clkevent_lp_set_next_event
;
136 priv
->clkevt
.rating
= STM32_LP_RATING
;
138 clockevents_config_and_register(&priv
->clkevt
, rate
, 0x1,
139 STM32_LPTIM_MAX_ARR
);
142 static int stm32_clkevent_lp_probe(struct platform_device
*pdev
)
144 struct stm32_lptimer
*ddata
= dev_get_drvdata(pdev
->dev
.parent
);
145 struct stm32_lp_private
*priv
;
149 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
153 priv
->reg
= ddata
->regmap
;
154 ret
= clk_prepare_enable(ddata
->clk
);
158 rate
= clk_get_rate(ddata
->clk
);
161 goto out_clk_disable
;
164 irq
= platform_get_irq(to_platform_device(pdev
->dev
.parent
), 0);
167 goto out_clk_disable
;
170 if (of_property_read_bool(pdev
->dev
.parent
->of_node
, "wakeup-source")) {
171 ret
= device_init_wakeup(&pdev
->dev
, true);
173 goto out_clk_disable
;
175 ret
= dev_pm_set_wake_irq(&pdev
->dev
, irq
);
177 goto out_clk_disable
;
180 ret
= devm_request_irq(&pdev
->dev
, irq
, stm32_clkevent_lp_irq_handler
,
181 IRQF_TIMER
, pdev
->name
, &priv
->clkevt
);
183 goto out_clk_disable
;
185 stm32_clkevent_lp_set_prescaler(priv
, &rate
);
187 stm32_clkevent_lp_init(priv
, pdev
->dev
.parent
->of_node
, rate
);
189 priv
->dev
= &pdev
->dev
;
194 clk_disable_unprepare(ddata
->clk
);
198 static int stm32_clkevent_lp_remove(struct platform_device
*pdev
)
200 return -EBUSY
; /* cannot unregister clockevent */
203 static const struct of_device_id stm32_clkevent_lp_of_match
[] = {
204 { .compatible
= "st,stm32-lptimer-timer", },
207 MODULE_DEVICE_TABLE(of
, stm32_clkevent_lp_of_match
);
209 static struct platform_driver stm32_clkevent_lp_driver
= {
210 .probe
= stm32_clkevent_lp_probe
,
211 .remove
= stm32_clkevent_lp_remove
,
213 .name
= "stm32-lptimer-timer",
214 .of_match_table
= of_match_ptr(stm32_clkevent_lp_of_match
),
217 module_platform_driver(stm32_clkevent_lp_driver
);
219 MODULE_ALIAS("platform:stm32-lptimer-timer");
220 MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
221 MODULE_LICENSE("GPL v2");