xref: /linux/drivers/clocksource/em_sti.c (revision 9a97b2fb070d497c683aed9fb86b7ec5245cea86)
10b712183SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b9dbf951SMagnus Damm /*
3b9dbf951SMagnus Damm  * Emma Mobile Timer Support - STI
4b9dbf951SMagnus Damm  *
5b9dbf951SMagnus Damm  *  Copyright (C) 2012 Magnus Damm
6b9dbf951SMagnus Damm  */
7b9dbf951SMagnus Damm 
8b9dbf951SMagnus Damm #include <linux/init.h>
9b9dbf951SMagnus Damm #include <linux/platform_device.h>
10b9dbf951SMagnus Damm #include <linux/spinlock.h>
11b9dbf951SMagnus Damm #include <linux/interrupt.h>
12b9dbf951SMagnus Damm #include <linux/ioport.h>
13b9dbf951SMagnus Damm #include <linux/io.h>
14b9dbf951SMagnus Damm #include <linux/clk.h>
15b9dbf951SMagnus Damm #include <linux/irq.h>
16b9dbf951SMagnus Damm #include <linux/err.h>
17b9dbf951SMagnus Damm #include <linux/delay.h>
18b9dbf951SMagnus Damm #include <linux/clocksource.h>
19b9dbf951SMagnus Damm #include <linux/clockchips.h>
20b9dbf951SMagnus Damm #include <linux/slab.h>
21b9dbf951SMagnus Damm #include <linux/module.h>
22b9dbf951SMagnus Damm 
23b9dbf951SMagnus Damm enum { USER_CLOCKSOURCE, USER_CLOCKEVENT, USER_NR };
24b9dbf951SMagnus Damm 
25b9dbf951SMagnus Damm struct em_sti_priv {
26b9dbf951SMagnus Damm 	void __iomem *base;
27b9dbf951SMagnus Damm 	struct clk *clk;
28b9dbf951SMagnus Damm 	struct platform_device *pdev;
29b9dbf951SMagnus Damm 	unsigned int active[USER_NR];
30b9dbf951SMagnus Damm 	unsigned long rate;
31b9dbf951SMagnus Damm 	raw_spinlock_t lock;
32b9dbf951SMagnus Damm 	struct clock_event_device ced;
33b9dbf951SMagnus Damm 	struct clocksource cs;
34b9dbf951SMagnus Damm };
35b9dbf951SMagnus Damm 
36b9dbf951SMagnus Damm #define STI_CONTROL 0x00
37b9dbf951SMagnus Damm #define STI_COMPA_H 0x10
38b9dbf951SMagnus Damm #define STI_COMPA_L 0x14
39b9dbf951SMagnus Damm #define STI_COMPB_H 0x18
40b9dbf951SMagnus Damm #define STI_COMPB_L 0x1c
41b9dbf951SMagnus Damm #define STI_COUNT_H 0x20
42b9dbf951SMagnus Damm #define STI_COUNT_L 0x24
43b9dbf951SMagnus Damm #define STI_COUNT_RAW_H 0x28
44b9dbf951SMagnus Damm #define STI_COUNT_RAW_L 0x2c
45b9dbf951SMagnus Damm #define STI_SET_H 0x30
46b9dbf951SMagnus Damm #define STI_SET_L 0x34
47b9dbf951SMagnus Damm #define STI_INTSTATUS 0x40
48b9dbf951SMagnus Damm #define STI_INTRAWSTATUS 0x44
49b9dbf951SMagnus Damm #define STI_INTENSET 0x48
50b9dbf951SMagnus Damm #define STI_INTENCLR 0x4c
51b9dbf951SMagnus Damm #define STI_INTFFCLR 0x50
52b9dbf951SMagnus Damm 
53b9dbf951SMagnus Damm static inline unsigned long em_sti_read(struct em_sti_priv *p, int offs)
54b9dbf951SMagnus Damm {
55b9dbf951SMagnus Damm 	return ioread32(p->base + offs);
56b9dbf951SMagnus Damm }
57b9dbf951SMagnus Damm 
58b9dbf951SMagnus Damm static inline void em_sti_write(struct em_sti_priv *p, int offs,
59b9dbf951SMagnus Damm 				unsigned long value)
60b9dbf951SMagnus Damm {
61b9dbf951SMagnus Damm 	iowrite32(value, p->base + offs);
62b9dbf951SMagnus Damm }
63b9dbf951SMagnus Damm 
64b9dbf951SMagnus Damm static int em_sti_enable(struct em_sti_priv *p)
65b9dbf951SMagnus Damm {
66b9dbf951SMagnus Damm 	int ret;
67b9dbf951SMagnus Damm 
68b9dbf951SMagnus Damm 	/* enable clock */
693814ae09SNicolai Stange 	ret = clk_enable(p->clk);
70b9dbf951SMagnus Damm 	if (ret) {
71b9dbf951SMagnus Damm 		dev_err(&p->pdev->dev, "cannot enable clock\n");
72b9dbf951SMagnus Damm 		return ret;
73b9dbf951SMagnus Damm 	}
74b9dbf951SMagnus Damm 
75b9dbf951SMagnus Damm 	/* reset the counter */
76b9dbf951SMagnus Damm 	em_sti_write(p, STI_SET_H, 0x40000000);
77b9dbf951SMagnus Damm 	em_sti_write(p, STI_SET_L, 0x00000000);
78b9dbf951SMagnus Damm 
79b9dbf951SMagnus Damm 	/* mask and clear pending interrupts */
80b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTENCLR, 3);
81b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTFFCLR, 3);
82b9dbf951SMagnus Damm 
83b9dbf951SMagnus Damm 	/* enable updates of counter registers */
84b9dbf951SMagnus Damm 	em_sti_write(p, STI_CONTROL, 1);
85b9dbf951SMagnus Damm 
86b9dbf951SMagnus Damm 	return 0;
87b9dbf951SMagnus Damm }
88b9dbf951SMagnus Damm 
89b9dbf951SMagnus Damm static void em_sti_disable(struct em_sti_priv *p)
90b9dbf951SMagnus Damm {
91b9dbf951SMagnus Damm 	/* mask interrupts */
92b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTENCLR, 3);
93b9dbf951SMagnus Damm 
94b9dbf951SMagnus Damm 	/* stop clock */
953814ae09SNicolai Stange 	clk_disable(p->clk);
96b9dbf951SMagnus Damm }
97b9dbf951SMagnus Damm 
98a5a1d1c2SThomas Gleixner static u64 em_sti_count(struct em_sti_priv *p)
99b9dbf951SMagnus Damm {
100a5a1d1c2SThomas Gleixner 	u64 ticks;
101b9dbf951SMagnus Damm 	unsigned long flags;
102b9dbf951SMagnus Damm 
103b9dbf951SMagnus Damm 	/* the STI hardware buffers the 48-bit count, but to
104b9dbf951SMagnus Damm 	 * break it out into two 32-bit access the registers
105b9dbf951SMagnus Damm 	 * must be accessed in a certain order.
106b9dbf951SMagnus Damm 	 * Always read STI_COUNT_H before STI_COUNT_L.
107b9dbf951SMagnus Damm 	 */
108b9dbf951SMagnus Damm 	raw_spin_lock_irqsave(&p->lock, flags);
109a5a1d1c2SThomas Gleixner 	ticks = (u64)(em_sti_read(p, STI_COUNT_H) & 0xffff) << 32;
110b9dbf951SMagnus Damm 	ticks |= em_sti_read(p, STI_COUNT_L);
111b9dbf951SMagnus Damm 	raw_spin_unlock_irqrestore(&p->lock, flags);
112b9dbf951SMagnus Damm 
113b9dbf951SMagnus Damm 	return ticks;
114b9dbf951SMagnus Damm }
115b9dbf951SMagnus Damm 
116a5a1d1c2SThomas Gleixner static u64 em_sti_set_next(struct em_sti_priv *p, u64 next)
117b9dbf951SMagnus Damm {
118b9dbf951SMagnus Damm 	unsigned long flags;
119b9dbf951SMagnus Damm 
120b9dbf951SMagnus Damm 	raw_spin_lock_irqsave(&p->lock, flags);
121b9dbf951SMagnus Damm 
122b9dbf951SMagnus Damm 	/* mask compare A interrupt */
123b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTENCLR, 1);
124b9dbf951SMagnus Damm 
125b9dbf951SMagnus Damm 	/* update compare A value */
126b9dbf951SMagnus Damm 	em_sti_write(p, STI_COMPA_H, next >> 32);
127b9dbf951SMagnus Damm 	em_sti_write(p, STI_COMPA_L, next & 0xffffffff);
128b9dbf951SMagnus Damm 
129b9dbf951SMagnus Damm 	/* clear compare A interrupt source */
130b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTFFCLR, 1);
131b9dbf951SMagnus Damm 
132b9dbf951SMagnus Damm 	/* unmask compare A interrupt */
133b9dbf951SMagnus Damm 	em_sti_write(p, STI_INTENSET, 1);
134b9dbf951SMagnus Damm 
135b9dbf951SMagnus Damm 	raw_spin_unlock_irqrestore(&p->lock, flags);
136b9dbf951SMagnus Damm 
137b9dbf951SMagnus Damm 	return next;
138b9dbf951SMagnus Damm }
139b9dbf951SMagnus Damm 
140b9dbf951SMagnus Damm static irqreturn_t em_sti_interrupt(int irq, void *dev_id)
141b9dbf951SMagnus Damm {
142b9dbf951SMagnus Damm 	struct em_sti_priv *p = dev_id;
143b9dbf951SMagnus Damm 
144b9dbf951SMagnus Damm 	p->ced.event_handler(&p->ced);
145b9dbf951SMagnus Damm 	return IRQ_HANDLED;
146b9dbf951SMagnus Damm }
147b9dbf951SMagnus Damm 
148b9dbf951SMagnus Damm static int em_sti_start(struct em_sti_priv *p, unsigned int user)
149b9dbf951SMagnus Damm {
150b9dbf951SMagnus Damm 	unsigned long flags;
151b9dbf951SMagnus Damm 	int used_before;
152b9dbf951SMagnus Damm 	int ret = 0;
153b9dbf951SMagnus Damm 
154b9dbf951SMagnus Damm 	raw_spin_lock_irqsave(&p->lock, flags);
155b9dbf951SMagnus Damm 	used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
156b9dbf951SMagnus Damm 	if (!used_before)
157b9dbf951SMagnus Damm 		ret = em_sti_enable(p);
158b9dbf951SMagnus Damm 
159b9dbf951SMagnus Damm 	if (!ret)
160b9dbf951SMagnus Damm 		p->active[user] = 1;
161b9dbf951SMagnus Damm 	raw_spin_unlock_irqrestore(&p->lock, flags);
162b9dbf951SMagnus Damm 
163b9dbf951SMagnus Damm 	return ret;
164b9dbf951SMagnus Damm }
165b9dbf951SMagnus Damm 
166b9dbf951SMagnus Damm static void em_sti_stop(struct em_sti_priv *p, unsigned int user)
167b9dbf951SMagnus Damm {
168b9dbf951SMagnus Damm 	unsigned long flags;
169b9dbf951SMagnus Damm 	int used_before, used_after;
170b9dbf951SMagnus Damm 
171b9dbf951SMagnus Damm 	raw_spin_lock_irqsave(&p->lock, flags);
172b9dbf951SMagnus Damm 	used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
173b9dbf951SMagnus Damm 	p->active[user] = 0;
174b9dbf951SMagnus Damm 	used_after = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT];
175b9dbf951SMagnus Damm 
176b9dbf951SMagnus Damm 	if (used_before && !used_after)
177b9dbf951SMagnus Damm 		em_sti_disable(p);
178b9dbf951SMagnus Damm 	raw_spin_unlock_irqrestore(&p->lock, flags);
179b9dbf951SMagnus Damm }
180b9dbf951SMagnus Damm 
181b9dbf951SMagnus Damm static struct em_sti_priv *cs_to_em_sti(struct clocksource *cs)
182b9dbf951SMagnus Damm {
183b9dbf951SMagnus Damm 	return container_of(cs, struct em_sti_priv, cs);
184b9dbf951SMagnus Damm }
185b9dbf951SMagnus Damm 
186a5a1d1c2SThomas Gleixner static u64 em_sti_clocksource_read(struct clocksource *cs)
187b9dbf951SMagnus Damm {
188b9dbf951SMagnus Damm 	return em_sti_count(cs_to_em_sti(cs));
189b9dbf951SMagnus Damm }
190b9dbf951SMagnus Damm 
191b9dbf951SMagnus Damm static int em_sti_clocksource_enable(struct clocksource *cs)
192b9dbf951SMagnus Damm {
193b9dbf951SMagnus Damm 	struct em_sti_priv *p = cs_to_em_sti(cs);
194b9dbf951SMagnus Damm 
1954e53aa2fSNicolai Stange 	return em_sti_start(p, USER_CLOCKSOURCE);
196b9dbf951SMagnus Damm }
197b9dbf951SMagnus Damm 
198b9dbf951SMagnus Damm static void em_sti_clocksource_disable(struct clocksource *cs)
199b9dbf951SMagnus Damm {
200b9dbf951SMagnus Damm 	em_sti_stop(cs_to_em_sti(cs), USER_CLOCKSOURCE);
201b9dbf951SMagnus Damm }
202b9dbf951SMagnus Damm 
203b9dbf951SMagnus Damm static void em_sti_clocksource_resume(struct clocksource *cs)
204b9dbf951SMagnus Damm {
205b9dbf951SMagnus Damm 	em_sti_clocksource_enable(cs);
206b9dbf951SMagnus Damm }
207b9dbf951SMagnus Damm 
208b9dbf951SMagnus Damm static int em_sti_register_clocksource(struct em_sti_priv *p)
209b9dbf951SMagnus Damm {
210b9dbf951SMagnus Damm 	struct clocksource *cs = &p->cs;
211b9dbf951SMagnus Damm 
212b9dbf951SMagnus Damm 	cs->name = dev_name(&p->pdev->dev);
213b9dbf951SMagnus Damm 	cs->rating = 200;
214b9dbf951SMagnus Damm 	cs->read = em_sti_clocksource_read;
215b9dbf951SMagnus Damm 	cs->enable = em_sti_clocksource_enable;
216b9dbf951SMagnus Damm 	cs->disable = em_sti_clocksource_disable;
217b9dbf951SMagnus Damm 	cs->suspend = em_sti_clocksource_disable;
218b9dbf951SMagnus Damm 	cs->resume = em_sti_clocksource_resume;
219b9dbf951SMagnus Damm 	cs->mask = CLOCKSOURCE_MASK(48);
220b9dbf951SMagnus Damm 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
221b9dbf951SMagnus Damm 
222b9dbf951SMagnus Damm 	dev_info(&p->pdev->dev, "used as clock source\n");
223b9dbf951SMagnus Damm 
2244e53aa2fSNicolai Stange 	clocksource_register_hz(cs, p->rate);
225b9dbf951SMagnus Damm 	return 0;
226b9dbf951SMagnus Damm }
227b9dbf951SMagnus Damm 
228b9dbf951SMagnus Damm static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced)
229b9dbf951SMagnus Damm {
230b9dbf951SMagnus Damm 	return container_of(ced, struct em_sti_priv, ced);
231b9dbf951SMagnus Damm }
232b9dbf951SMagnus Damm 
23375f94061SViresh Kumar static int em_sti_clock_event_shutdown(struct clock_event_device *ced)
23475f94061SViresh Kumar {
23575f94061SViresh Kumar 	struct em_sti_priv *p = ced_to_em_sti(ced);
23675f94061SViresh Kumar 	em_sti_stop(p, USER_CLOCKEVENT);
23775f94061SViresh Kumar 	return 0;
23875f94061SViresh Kumar }
23975f94061SViresh Kumar 
24075f94061SViresh Kumar static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced)
241b9dbf951SMagnus Damm {
242b9dbf951SMagnus Damm 	struct em_sti_priv *p = ced_to_em_sti(ced);
243b9dbf951SMagnus Damm 
244b9dbf951SMagnus Damm 	dev_info(&p->pdev->dev, "used for oneshot clock events\n");
245b9dbf951SMagnus Damm 	em_sti_start(p, USER_CLOCKEVENT);
24675f94061SViresh Kumar 	return 0;
247b9dbf951SMagnus Damm }
248b9dbf951SMagnus Damm 
249b9dbf951SMagnus Damm static int em_sti_clock_event_next(unsigned long delta,
250b9dbf951SMagnus Damm 				   struct clock_event_device *ced)
251b9dbf951SMagnus Damm {
252b9dbf951SMagnus Damm 	struct em_sti_priv *p = ced_to_em_sti(ced);
253a5a1d1c2SThomas Gleixner 	u64 next;
254b9dbf951SMagnus Damm 	int safe;
255b9dbf951SMagnus Damm 
256b9dbf951SMagnus Damm 	next = em_sti_set_next(p, em_sti_count(p) + delta);
257b9dbf951SMagnus Damm 	safe = em_sti_count(p) < (next - 1);
258b9dbf951SMagnus Damm 
259b9dbf951SMagnus Damm 	return !safe;
260b9dbf951SMagnus Damm }
261b9dbf951SMagnus Damm 
262b9dbf951SMagnus Damm static void em_sti_register_clockevent(struct em_sti_priv *p)
263b9dbf951SMagnus Damm {
264b9dbf951SMagnus Damm 	struct clock_event_device *ced = &p->ced;
265b9dbf951SMagnus Damm 
266b9dbf951SMagnus Damm 	ced->name = dev_name(&p->pdev->dev);
267b9dbf951SMagnus Damm 	ced->features = CLOCK_EVT_FEAT_ONESHOT;
268b9dbf951SMagnus Damm 	ced->rating = 200;
2692199a557SMagnus Damm 	ced->cpumask = cpu_possible_mask;
270b9dbf951SMagnus Damm 	ced->set_next_event = em_sti_clock_event_next;
27175f94061SViresh Kumar 	ced->set_state_shutdown = em_sti_clock_event_shutdown;
27275f94061SViresh Kumar 	ced->set_state_oneshot = em_sti_clock_event_set_oneshot;
273b9dbf951SMagnus Damm 
274b9dbf951SMagnus Damm 	dev_info(&p->pdev->dev, "used for clock events\n");
275b9dbf951SMagnus Damm 
2764e53aa2fSNicolai Stange 	clockevents_config_and_register(ced, p->rate, 2, 0xffffffff);
277b9dbf951SMagnus Damm }
278b9dbf951SMagnus Damm 
2791850514bSGreg Kroah-Hartman static int em_sti_probe(struct platform_device *pdev)
280b9dbf951SMagnus Damm {
281b9dbf951SMagnus Damm 	struct em_sti_priv *p;
2821745e696SLaurent Pinchart 	int irq;
2833814ae09SNicolai Stange 	int ret;
284b9dbf951SMagnus Damm 
2851745e696SLaurent Pinchart 	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
28639dd5677SJingoo Han 	if (p == NULL)
2871745e696SLaurent Pinchart 		return -ENOMEM;
288b9dbf951SMagnus Damm 
289b9dbf951SMagnus Damm 	p->pdev = pdev;
290b9dbf951SMagnus Damm 	platform_set_drvdata(pdev, p);
291b9dbf951SMagnus Damm 
292b9dbf951SMagnus Damm 	irq = platform_get_irq(pdev, 0);
2939f475d08SStephen Boyd 	if (irq < 0)
2945c23a558SGustavo A. R. Silva 		return irq;
295b9dbf951SMagnus Damm 
296b9dbf951SMagnus Damm 	/* map memory, let base point to the STI instance */
297*9a97b2fbSYangtao Li 	p->base = devm_platform_ioremap_resource(pdev, 0);
2981745e696SLaurent Pinchart 	if (IS_ERR(p->base))
2991745e696SLaurent Pinchart 		return PTR_ERR(p->base);
300b9dbf951SMagnus Damm 
3015c23a558SGustavo A. R. Silva 	ret = devm_request_irq(&pdev->dev, irq, em_sti_interrupt,
3023814ae09SNicolai Stange 			       IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
3035c23a558SGustavo A. R. Silva 			       dev_name(&pdev->dev), p);
3045c23a558SGustavo A. R. Silva 	if (ret) {
3053814ae09SNicolai Stange 		dev_err(&pdev->dev, "failed to request low IRQ\n");
3065c23a558SGustavo A. R. Silva 		return ret;
3073814ae09SNicolai Stange 	}
3083814ae09SNicolai Stange 
309b9dbf951SMagnus Damm 	/* get hold of clock */
3101745e696SLaurent Pinchart 	p->clk = devm_clk_get(&pdev->dev, "sclk");
311b9dbf951SMagnus Damm 	if (IS_ERR(p->clk)) {
312b9dbf951SMagnus Damm 		dev_err(&pdev->dev, "cannot get clock\n");
3131745e696SLaurent Pinchart 		return PTR_ERR(p->clk);
314b9dbf951SMagnus Damm 	}
315b9dbf951SMagnus Damm 
3163814ae09SNicolai Stange 	ret = clk_prepare(p->clk);
3173814ae09SNicolai Stange 	if (ret < 0) {
3183814ae09SNicolai Stange 		dev_err(&pdev->dev, "cannot prepare clock\n");
3193814ae09SNicolai Stange 		return ret;
320b9dbf951SMagnus Damm 	}
321b9dbf951SMagnus Damm 
3224e53aa2fSNicolai Stange 	ret = clk_enable(p->clk);
3234e53aa2fSNicolai Stange 	if (ret < 0) {
3244e53aa2fSNicolai Stange 		dev_err(&p->pdev->dev, "cannot enable clock\n");
3254e53aa2fSNicolai Stange 		clk_unprepare(p->clk);
3264e53aa2fSNicolai Stange 		return ret;
3274e53aa2fSNicolai Stange 	}
3284e53aa2fSNicolai Stange 	p->rate = clk_get_rate(p->clk);
3294e53aa2fSNicolai Stange 	clk_disable(p->clk);
3304e53aa2fSNicolai Stange 
331b9dbf951SMagnus Damm 	raw_spin_lock_init(&p->lock);
332b9dbf951SMagnus Damm 	em_sti_register_clockevent(p);
333b9dbf951SMagnus Damm 	em_sti_register_clocksource(p);
334b9dbf951SMagnus Damm 	return 0;
335b9dbf951SMagnus Damm }
336b9dbf951SMagnus Damm 
3371850514bSGreg Kroah-Hartman static int em_sti_remove(struct platform_device *pdev)
338b9dbf951SMagnus Damm {
339b9dbf951SMagnus Damm 	return -EBUSY; /* cannot unregister clockevent and clocksource */
340b9dbf951SMagnus Damm }
341b9dbf951SMagnus Damm 
3421850514bSGreg Kroah-Hartman static const struct of_device_id em_sti_dt_ids[] = {
343fc0830feSMagnus Damm 	{ .compatible = "renesas,em-sti", },
344fc0830feSMagnus Damm 	{},
345fc0830feSMagnus Damm };
346fc0830feSMagnus Damm MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
347fc0830feSMagnus Damm 
348b9dbf951SMagnus Damm static struct platform_driver em_sti_device_driver = {
349b9dbf951SMagnus Damm 	.probe		= em_sti_probe,
3501850514bSGreg Kroah-Hartman 	.remove		= em_sti_remove,
351b9dbf951SMagnus Damm 	.driver		= {
352b9dbf951SMagnus Damm 		.name	= "em_sti",
353fc0830feSMagnus Damm 		.of_match_table = em_sti_dt_ids,
354b9dbf951SMagnus Damm 	}
355b9dbf951SMagnus Damm };
356b9dbf951SMagnus Damm 
35709acc3a1SSimon Horman static int __init em_sti_init(void)
35809acc3a1SSimon Horman {
35909acc3a1SSimon Horman 	return platform_driver_register(&em_sti_device_driver);
36009acc3a1SSimon Horman }
36109acc3a1SSimon Horman 
36209acc3a1SSimon Horman static void __exit em_sti_exit(void)
36309acc3a1SSimon Horman {
36409acc3a1SSimon Horman 	platform_driver_unregister(&em_sti_device_driver);
36509acc3a1SSimon Horman }
36609acc3a1SSimon Horman 
36709acc3a1SSimon Horman subsys_initcall(em_sti_init);
36809acc3a1SSimon Horman module_exit(em_sti_exit);
369b9dbf951SMagnus Damm 
370b9dbf951SMagnus Damm MODULE_AUTHOR("Magnus Damm");
371b9dbf951SMagnus Damm MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver");
372b9dbf951SMagnus Damm MODULE_LICENSE("GPL v2");
373