1b9dbf951SMagnus Damm /* 2b9dbf951SMagnus Damm * Emma Mobile Timer Support - STI 3b9dbf951SMagnus Damm * 4b9dbf951SMagnus Damm * Copyright (C) 2012 Magnus Damm 5b9dbf951SMagnus Damm * 6b9dbf951SMagnus Damm * This program is free software; you can redistribute it and/or modify 7b9dbf951SMagnus Damm * it under the terms of the GNU General Public License as published by 8b9dbf951SMagnus Damm * the Free Software Foundation; either version 2 of the License 9b9dbf951SMagnus Damm * 10b9dbf951SMagnus Damm * This program is distributed in the hope that it will be useful, 11b9dbf951SMagnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of 12b9dbf951SMagnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13b9dbf951SMagnus Damm * GNU General Public License for more details. 14b9dbf951SMagnus Damm * 15b9dbf951SMagnus Damm * You should have received a copy of the GNU General Public License 16b9dbf951SMagnus Damm * along with this program; if not, write to the Free Software 17b9dbf951SMagnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18b9dbf951SMagnus Damm */ 19b9dbf951SMagnus Damm 20b9dbf951SMagnus Damm #include <linux/init.h> 21b9dbf951SMagnus Damm #include <linux/platform_device.h> 22b9dbf951SMagnus Damm #include <linux/spinlock.h> 23b9dbf951SMagnus Damm #include <linux/interrupt.h> 24b9dbf951SMagnus Damm #include <linux/ioport.h> 25b9dbf951SMagnus Damm #include <linux/io.h> 26b9dbf951SMagnus Damm #include <linux/clk.h> 27b9dbf951SMagnus Damm #include <linux/irq.h> 28b9dbf951SMagnus Damm #include <linux/err.h> 29b9dbf951SMagnus Damm #include <linux/delay.h> 30b9dbf951SMagnus Damm #include <linux/clocksource.h> 31b9dbf951SMagnus Damm #include <linux/clockchips.h> 32b9dbf951SMagnus Damm #include <linux/slab.h> 33b9dbf951SMagnus Damm #include <linux/module.h> 34b9dbf951SMagnus Damm 35b9dbf951SMagnus Damm enum { USER_CLOCKSOURCE, USER_CLOCKEVENT, USER_NR }; 36b9dbf951SMagnus Damm 37b9dbf951SMagnus Damm struct em_sti_priv { 38b9dbf951SMagnus Damm void __iomem *base; 39b9dbf951SMagnus Damm struct clk *clk; 40b9dbf951SMagnus Damm struct platform_device *pdev; 41b9dbf951SMagnus Damm unsigned int active[USER_NR]; 42b9dbf951SMagnus Damm unsigned long rate; 43b9dbf951SMagnus Damm raw_spinlock_t lock; 44b9dbf951SMagnus Damm struct clock_event_device ced; 45b9dbf951SMagnus Damm struct clocksource cs; 46b9dbf951SMagnus Damm }; 47b9dbf951SMagnus Damm 48b9dbf951SMagnus Damm #define STI_CONTROL 0x00 49b9dbf951SMagnus Damm #define STI_COMPA_H 0x10 50b9dbf951SMagnus Damm #define STI_COMPA_L 0x14 51b9dbf951SMagnus Damm #define STI_COMPB_H 0x18 52b9dbf951SMagnus Damm #define STI_COMPB_L 0x1c 53b9dbf951SMagnus Damm #define STI_COUNT_H 0x20 54b9dbf951SMagnus Damm #define STI_COUNT_L 0x24 55b9dbf951SMagnus Damm #define STI_COUNT_RAW_H 0x28 56b9dbf951SMagnus Damm #define STI_COUNT_RAW_L 0x2c 57b9dbf951SMagnus Damm #define STI_SET_H 0x30 58b9dbf951SMagnus Damm #define STI_SET_L 0x34 59b9dbf951SMagnus Damm #define STI_INTSTATUS 0x40 60b9dbf951SMagnus Damm #define STI_INTRAWSTATUS 0x44 61b9dbf951SMagnus Damm #define STI_INTENSET 0x48 62b9dbf951SMagnus Damm #define STI_INTENCLR 0x4c 63b9dbf951SMagnus Damm #define STI_INTFFCLR 0x50 64b9dbf951SMagnus Damm 65b9dbf951SMagnus Damm static inline unsigned long em_sti_read(struct em_sti_priv *p, int offs) 66b9dbf951SMagnus Damm { 67b9dbf951SMagnus Damm return ioread32(p->base + offs); 68b9dbf951SMagnus Damm } 69b9dbf951SMagnus Damm 70b9dbf951SMagnus Damm static inline void em_sti_write(struct em_sti_priv *p, int offs, 71b9dbf951SMagnus Damm unsigned long value) 72b9dbf951SMagnus Damm { 73b9dbf951SMagnus Damm iowrite32(value, p->base + offs); 74b9dbf951SMagnus Damm } 75b9dbf951SMagnus Damm 76b9dbf951SMagnus Damm static int em_sti_enable(struct em_sti_priv *p) 77b9dbf951SMagnus Damm { 78b9dbf951SMagnus Damm int ret; 79b9dbf951SMagnus Damm 80b9dbf951SMagnus Damm /* enable clock */ 81*3814ae09SNicolai Stange ret = clk_enable(p->clk); 82b9dbf951SMagnus Damm if (ret) { 83b9dbf951SMagnus Damm dev_err(&p->pdev->dev, "cannot enable clock\n"); 84b9dbf951SMagnus Damm return ret; 85b9dbf951SMagnus Damm } 86b9dbf951SMagnus Damm 87b9dbf951SMagnus Damm /* configure channel, periodic mode and maximum timeout */ 88b9dbf951SMagnus Damm p->rate = clk_get_rate(p->clk); 89b9dbf951SMagnus Damm 90b9dbf951SMagnus Damm /* reset the counter */ 91b9dbf951SMagnus Damm em_sti_write(p, STI_SET_H, 0x40000000); 92b9dbf951SMagnus Damm em_sti_write(p, STI_SET_L, 0x00000000); 93b9dbf951SMagnus Damm 94b9dbf951SMagnus Damm /* mask and clear pending interrupts */ 95b9dbf951SMagnus Damm em_sti_write(p, STI_INTENCLR, 3); 96b9dbf951SMagnus Damm em_sti_write(p, STI_INTFFCLR, 3); 97b9dbf951SMagnus Damm 98b9dbf951SMagnus Damm /* enable updates of counter registers */ 99b9dbf951SMagnus Damm em_sti_write(p, STI_CONTROL, 1); 100b9dbf951SMagnus Damm 101b9dbf951SMagnus Damm return 0; 102b9dbf951SMagnus Damm } 103b9dbf951SMagnus Damm 104b9dbf951SMagnus Damm static void em_sti_disable(struct em_sti_priv *p) 105b9dbf951SMagnus Damm { 106b9dbf951SMagnus Damm /* mask interrupts */ 107b9dbf951SMagnus Damm em_sti_write(p, STI_INTENCLR, 3); 108b9dbf951SMagnus Damm 109b9dbf951SMagnus Damm /* stop clock */ 110*3814ae09SNicolai Stange clk_disable(p->clk); 111b9dbf951SMagnus Damm } 112b9dbf951SMagnus Damm 113a5a1d1c2SThomas Gleixner static u64 em_sti_count(struct em_sti_priv *p) 114b9dbf951SMagnus Damm { 115a5a1d1c2SThomas Gleixner u64 ticks; 116b9dbf951SMagnus Damm unsigned long flags; 117b9dbf951SMagnus Damm 118b9dbf951SMagnus Damm /* the STI hardware buffers the 48-bit count, but to 119b9dbf951SMagnus Damm * break it out into two 32-bit access the registers 120b9dbf951SMagnus Damm * must be accessed in a certain order. 121b9dbf951SMagnus Damm * Always read STI_COUNT_H before STI_COUNT_L. 122b9dbf951SMagnus Damm */ 123b9dbf951SMagnus Damm raw_spin_lock_irqsave(&p->lock, flags); 124a5a1d1c2SThomas Gleixner ticks = (u64)(em_sti_read(p, STI_COUNT_H) & 0xffff) << 32; 125b9dbf951SMagnus Damm ticks |= em_sti_read(p, STI_COUNT_L); 126b9dbf951SMagnus Damm raw_spin_unlock_irqrestore(&p->lock, flags); 127b9dbf951SMagnus Damm 128b9dbf951SMagnus Damm return ticks; 129b9dbf951SMagnus Damm } 130b9dbf951SMagnus Damm 131a5a1d1c2SThomas Gleixner static u64 em_sti_set_next(struct em_sti_priv *p, u64 next) 132b9dbf951SMagnus Damm { 133b9dbf951SMagnus Damm unsigned long flags; 134b9dbf951SMagnus Damm 135b9dbf951SMagnus Damm raw_spin_lock_irqsave(&p->lock, flags); 136b9dbf951SMagnus Damm 137b9dbf951SMagnus Damm /* mask compare A interrupt */ 138b9dbf951SMagnus Damm em_sti_write(p, STI_INTENCLR, 1); 139b9dbf951SMagnus Damm 140b9dbf951SMagnus Damm /* update compare A value */ 141b9dbf951SMagnus Damm em_sti_write(p, STI_COMPA_H, next >> 32); 142b9dbf951SMagnus Damm em_sti_write(p, STI_COMPA_L, next & 0xffffffff); 143b9dbf951SMagnus Damm 144b9dbf951SMagnus Damm /* clear compare A interrupt source */ 145b9dbf951SMagnus Damm em_sti_write(p, STI_INTFFCLR, 1); 146b9dbf951SMagnus Damm 147b9dbf951SMagnus Damm /* unmask compare A interrupt */ 148b9dbf951SMagnus Damm em_sti_write(p, STI_INTENSET, 1); 149b9dbf951SMagnus Damm 150b9dbf951SMagnus Damm raw_spin_unlock_irqrestore(&p->lock, flags); 151b9dbf951SMagnus Damm 152b9dbf951SMagnus Damm return next; 153b9dbf951SMagnus Damm } 154b9dbf951SMagnus Damm 155b9dbf951SMagnus Damm static irqreturn_t em_sti_interrupt(int irq, void *dev_id) 156b9dbf951SMagnus Damm { 157b9dbf951SMagnus Damm struct em_sti_priv *p = dev_id; 158b9dbf951SMagnus Damm 159b9dbf951SMagnus Damm p->ced.event_handler(&p->ced); 160b9dbf951SMagnus Damm return IRQ_HANDLED; 161b9dbf951SMagnus Damm } 162b9dbf951SMagnus Damm 163b9dbf951SMagnus Damm static int em_sti_start(struct em_sti_priv *p, unsigned int user) 164b9dbf951SMagnus Damm { 165b9dbf951SMagnus Damm unsigned long flags; 166b9dbf951SMagnus Damm int used_before; 167b9dbf951SMagnus Damm int ret = 0; 168b9dbf951SMagnus Damm 169b9dbf951SMagnus Damm raw_spin_lock_irqsave(&p->lock, flags); 170b9dbf951SMagnus Damm used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; 171b9dbf951SMagnus Damm if (!used_before) 172b9dbf951SMagnus Damm ret = em_sti_enable(p); 173b9dbf951SMagnus Damm 174b9dbf951SMagnus Damm if (!ret) 175b9dbf951SMagnus Damm p->active[user] = 1; 176b9dbf951SMagnus Damm raw_spin_unlock_irqrestore(&p->lock, flags); 177b9dbf951SMagnus Damm 178b9dbf951SMagnus Damm return ret; 179b9dbf951SMagnus Damm } 180b9dbf951SMagnus Damm 181b9dbf951SMagnus Damm static void em_sti_stop(struct em_sti_priv *p, unsigned int user) 182b9dbf951SMagnus Damm { 183b9dbf951SMagnus Damm unsigned long flags; 184b9dbf951SMagnus Damm int used_before, used_after; 185b9dbf951SMagnus Damm 186b9dbf951SMagnus Damm raw_spin_lock_irqsave(&p->lock, flags); 187b9dbf951SMagnus Damm used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; 188b9dbf951SMagnus Damm p->active[user] = 0; 189b9dbf951SMagnus Damm used_after = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; 190b9dbf951SMagnus Damm 191b9dbf951SMagnus Damm if (used_before && !used_after) 192b9dbf951SMagnus Damm em_sti_disable(p); 193b9dbf951SMagnus Damm raw_spin_unlock_irqrestore(&p->lock, flags); 194b9dbf951SMagnus Damm } 195b9dbf951SMagnus Damm 196b9dbf951SMagnus Damm static struct em_sti_priv *cs_to_em_sti(struct clocksource *cs) 197b9dbf951SMagnus Damm { 198b9dbf951SMagnus Damm return container_of(cs, struct em_sti_priv, cs); 199b9dbf951SMagnus Damm } 200b9dbf951SMagnus Damm 201a5a1d1c2SThomas Gleixner static u64 em_sti_clocksource_read(struct clocksource *cs) 202b9dbf951SMagnus Damm { 203b9dbf951SMagnus Damm return em_sti_count(cs_to_em_sti(cs)); 204b9dbf951SMagnus Damm } 205b9dbf951SMagnus Damm 206b9dbf951SMagnus Damm static int em_sti_clocksource_enable(struct clocksource *cs) 207b9dbf951SMagnus Damm { 208b9dbf951SMagnus Damm int ret; 209b9dbf951SMagnus Damm struct em_sti_priv *p = cs_to_em_sti(cs); 210b9dbf951SMagnus Damm 211b9dbf951SMagnus Damm ret = em_sti_start(p, USER_CLOCKSOURCE); 212b9dbf951SMagnus Damm if (!ret) 213fba9e072SJohn Stultz __clocksource_update_freq_hz(cs, p->rate); 214b9dbf951SMagnus Damm return ret; 215b9dbf951SMagnus Damm } 216b9dbf951SMagnus Damm 217b9dbf951SMagnus Damm static void em_sti_clocksource_disable(struct clocksource *cs) 218b9dbf951SMagnus Damm { 219b9dbf951SMagnus Damm em_sti_stop(cs_to_em_sti(cs), USER_CLOCKSOURCE); 220b9dbf951SMagnus Damm } 221b9dbf951SMagnus Damm 222b9dbf951SMagnus Damm static void em_sti_clocksource_resume(struct clocksource *cs) 223b9dbf951SMagnus Damm { 224b9dbf951SMagnus Damm em_sti_clocksource_enable(cs); 225b9dbf951SMagnus Damm } 226b9dbf951SMagnus Damm 227b9dbf951SMagnus Damm static int em_sti_register_clocksource(struct em_sti_priv *p) 228b9dbf951SMagnus Damm { 229b9dbf951SMagnus Damm struct clocksource *cs = &p->cs; 230b9dbf951SMagnus Damm 231b9dbf951SMagnus Damm cs->name = dev_name(&p->pdev->dev); 232b9dbf951SMagnus Damm cs->rating = 200; 233b9dbf951SMagnus Damm cs->read = em_sti_clocksource_read; 234b9dbf951SMagnus Damm cs->enable = em_sti_clocksource_enable; 235b9dbf951SMagnus Damm cs->disable = em_sti_clocksource_disable; 236b9dbf951SMagnus Damm cs->suspend = em_sti_clocksource_disable; 237b9dbf951SMagnus Damm cs->resume = em_sti_clocksource_resume; 238b9dbf951SMagnus Damm cs->mask = CLOCKSOURCE_MASK(48); 239b9dbf951SMagnus Damm cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; 240b9dbf951SMagnus Damm 241b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used as clock source\n"); 242b9dbf951SMagnus Damm 243b9dbf951SMagnus Damm /* Register with dummy 1 Hz value, gets updated in ->enable() */ 244b9dbf951SMagnus Damm clocksource_register_hz(cs, 1); 245b9dbf951SMagnus Damm return 0; 246b9dbf951SMagnus Damm } 247b9dbf951SMagnus Damm 248b9dbf951SMagnus Damm static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) 249b9dbf951SMagnus Damm { 250b9dbf951SMagnus Damm return container_of(ced, struct em_sti_priv, ced); 251b9dbf951SMagnus Damm } 252b9dbf951SMagnus Damm 25375f94061SViresh Kumar static int em_sti_clock_event_shutdown(struct clock_event_device *ced) 25475f94061SViresh Kumar { 25575f94061SViresh Kumar struct em_sti_priv *p = ced_to_em_sti(ced); 25675f94061SViresh Kumar em_sti_stop(p, USER_CLOCKEVENT); 25775f94061SViresh Kumar return 0; 25875f94061SViresh Kumar } 25975f94061SViresh Kumar 26075f94061SViresh Kumar static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced) 261b9dbf951SMagnus Damm { 262b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 263b9dbf951SMagnus Damm 264b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for oneshot clock events\n"); 265b9dbf951SMagnus Damm em_sti_start(p, USER_CLOCKEVENT); 266b9dbf951SMagnus Damm clockevents_config(&p->ced, p->rate); 26775f94061SViresh Kumar return 0; 268b9dbf951SMagnus Damm } 269b9dbf951SMagnus Damm 270b9dbf951SMagnus Damm static int em_sti_clock_event_next(unsigned long delta, 271b9dbf951SMagnus Damm struct clock_event_device *ced) 272b9dbf951SMagnus Damm { 273b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 274a5a1d1c2SThomas Gleixner u64 next; 275b9dbf951SMagnus Damm int safe; 276b9dbf951SMagnus Damm 277b9dbf951SMagnus Damm next = em_sti_set_next(p, em_sti_count(p) + delta); 278b9dbf951SMagnus Damm safe = em_sti_count(p) < (next - 1); 279b9dbf951SMagnus Damm 280b9dbf951SMagnus Damm return !safe; 281b9dbf951SMagnus Damm } 282b9dbf951SMagnus Damm 283b9dbf951SMagnus Damm static void em_sti_register_clockevent(struct em_sti_priv *p) 284b9dbf951SMagnus Damm { 285b9dbf951SMagnus Damm struct clock_event_device *ced = &p->ced; 286b9dbf951SMagnus Damm 287b9dbf951SMagnus Damm ced->name = dev_name(&p->pdev->dev); 288b9dbf951SMagnus Damm ced->features = CLOCK_EVT_FEAT_ONESHOT; 289b9dbf951SMagnus Damm ced->rating = 200; 2902199a557SMagnus Damm ced->cpumask = cpu_possible_mask; 291b9dbf951SMagnus Damm ced->set_next_event = em_sti_clock_event_next; 29275f94061SViresh Kumar ced->set_state_shutdown = em_sti_clock_event_shutdown; 29375f94061SViresh Kumar ced->set_state_oneshot = em_sti_clock_event_set_oneshot; 294b9dbf951SMagnus Damm 295b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for clock events\n"); 296b9dbf951SMagnus Damm 29775f94061SViresh Kumar /* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */ 298b9dbf951SMagnus Damm clockevents_config_and_register(ced, 1, 2, 0xffffffff); 299b9dbf951SMagnus Damm } 300b9dbf951SMagnus Damm 3011850514bSGreg Kroah-Hartman static int em_sti_probe(struct platform_device *pdev) 302b9dbf951SMagnus Damm { 303b9dbf951SMagnus Damm struct em_sti_priv *p; 304b9dbf951SMagnus Damm struct resource *res; 3051745e696SLaurent Pinchart int irq; 306*3814ae09SNicolai Stange int ret; 307b9dbf951SMagnus Damm 3081745e696SLaurent Pinchart p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 30939dd5677SJingoo Han if (p == NULL) 3101745e696SLaurent Pinchart return -ENOMEM; 311b9dbf951SMagnus Damm 312b9dbf951SMagnus Damm p->pdev = pdev; 313b9dbf951SMagnus Damm platform_set_drvdata(pdev, p); 314b9dbf951SMagnus Damm 315b9dbf951SMagnus Damm irq = platform_get_irq(pdev, 0); 316b9dbf951SMagnus Damm if (irq < 0) { 317b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to get irq\n"); 3181745e696SLaurent Pinchart return -EINVAL; 319b9dbf951SMagnus Damm } 320b9dbf951SMagnus Damm 321b9dbf951SMagnus Damm /* map memory, let base point to the STI instance */ 3221745e696SLaurent Pinchart res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3231745e696SLaurent Pinchart p->base = devm_ioremap_resource(&pdev->dev, res); 3241745e696SLaurent Pinchart if (IS_ERR(p->base)) 3251745e696SLaurent Pinchart return PTR_ERR(p->base); 326b9dbf951SMagnus Damm 327*3814ae09SNicolai Stange if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, 328*3814ae09SNicolai Stange IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, 329*3814ae09SNicolai Stange dev_name(&pdev->dev), p)) { 330*3814ae09SNicolai Stange dev_err(&pdev->dev, "failed to request low IRQ\n"); 331*3814ae09SNicolai Stange return -ENOENT; 332*3814ae09SNicolai Stange } 333*3814ae09SNicolai Stange 334b9dbf951SMagnus Damm /* get hold of clock */ 3351745e696SLaurent Pinchart p->clk = devm_clk_get(&pdev->dev, "sclk"); 336b9dbf951SMagnus Damm if (IS_ERR(p->clk)) { 337b9dbf951SMagnus Damm dev_err(&pdev->dev, "cannot get clock\n"); 3381745e696SLaurent Pinchart return PTR_ERR(p->clk); 339b9dbf951SMagnus Damm } 340b9dbf951SMagnus Damm 341*3814ae09SNicolai Stange ret = clk_prepare(p->clk); 342*3814ae09SNicolai Stange if (ret < 0) { 343*3814ae09SNicolai Stange dev_err(&pdev->dev, "cannot prepare clock\n"); 344*3814ae09SNicolai Stange return ret; 345b9dbf951SMagnus Damm } 346b9dbf951SMagnus Damm 347b9dbf951SMagnus Damm raw_spin_lock_init(&p->lock); 348b9dbf951SMagnus Damm em_sti_register_clockevent(p); 349b9dbf951SMagnus Damm em_sti_register_clocksource(p); 350b9dbf951SMagnus Damm return 0; 351b9dbf951SMagnus Damm } 352b9dbf951SMagnus Damm 3531850514bSGreg Kroah-Hartman static int em_sti_remove(struct platform_device *pdev) 354b9dbf951SMagnus Damm { 355b9dbf951SMagnus Damm return -EBUSY; /* cannot unregister clockevent and clocksource */ 356b9dbf951SMagnus Damm } 357b9dbf951SMagnus Damm 3581850514bSGreg Kroah-Hartman static const struct of_device_id em_sti_dt_ids[] = { 359fc0830feSMagnus Damm { .compatible = "renesas,em-sti", }, 360fc0830feSMagnus Damm {}, 361fc0830feSMagnus Damm }; 362fc0830feSMagnus Damm MODULE_DEVICE_TABLE(of, em_sti_dt_ids); 363fc0830feSMagnus Damm 364b9dbf951SMagnus Damm static struct platform_driver em_sti_device_driver = { 365b9dbf951SMagnus Damm .probe = em_sti_probe, 3661850514bSGreg Kroah-Hartman .remove = em_sti_remove, 367b9dbf951SMagnus Damm .driver = { 368b9dbf951SMagnus Damm .name = "em_sti", 369fc0830feSMagnus Damm .of_match_table = em_sti_dt_ids, 370b9dbf951SMagnus Damm } 371b9dbf951SMagnus Damm }; 372b9dbf951SMagnus Damm 37309acc3a1SSimon Horman static int __init em_sti_init(void) 37409acc3a1SSimon Horman { 37509acc3a1SSimon Horman return platform_driver_register(&em_sti_device_driver); 37609acc3a1SSimon Horman } 37709acc3a1SSimon Horman 37809acc3a1SSimon Horman static void __exit em_sti_exit(void) 37909acc3a1SSimon Horman { 38009acc3a1SSimon Horman platform_driver_unregister(&em_sti_device_driver); 38109acc3a1SSimon Horman } 38209acc3a1SSimon Horman 38309acc3a1SSimon Horman subsys_initcall(em_sti_init); 38409acc3a1SSimon Horman module_exit(em_sti_exit); 385b9dbf951SMagnus Damm 386b9dbf951SMagnus Damm MODULE_AUTHOR("Magnus Damm"); 387b9dbf951SMagnus Damm MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); 388b9dbf951SMagnus Damm MODULE_LICENSE("GPL v2"); 389