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 */ 81fdfcab17SShinya Kuribayashi ret = clk_prepare_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 */ 110fdfcab17SShinya Kuribayashi clk_disable_unprepare(p->clk); 111b9dbf951SMagnus Damm } 112b9dbf951SMagnus Damm 113b9dbf951SMagnus Damm static cycle_t em_sti_count(struct em_sti_priv *p) 114b9dbf951SMagnus Damm { 115b9dbf951SMagnus Damm cycle_t 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); 124b9dbf951SMagnus Damm ticks = (cycle_t)(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 131b9dbf951SMagnus Damm static cycle_t em_sti_set_next(struct em_sti_priv *p, cycle_t 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 201b9dbf951SMagnus Damm static cycle_t 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 memset(cs, 0, sizeof(*cs)); 232b9dbf951SMagnus Damm cs->name = dev_name(&p->pdev->dev); 233b9dbf951SMagnus Damm cs->rating = 200; 234b9dbf951SMagnus Damm cs->read = em_sti_clocksource_read; 235b9dbf951SMagnus Damm cs->enable = em_sti_clocksource_enable; 236b9dbf951SMagnus Damm cs->disable = em_sti_clocksource_disable; 237b9dbf951SMagnus Damm cs->suspend = em_sti_clocksource_disable; 238b9dbf951SMagnus Damm cs->resume = em_sti_clocksource_resume; 239b9dbf951SMagnus Damm cs->mask = CLOCKSOURCE_MASK(48); 240b9dbf951SMagnus Damm cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; 241b9dbf951SMagnus Damm 242b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used as clock source\n"); 243b9dbf951SMagnus Damm 244b9dbf951SMagnus Damm /* Register with dummy 1 Hz value, gets updated in ->enable() */ 245b9dbf951SMagnus Damm clocksource_register_hz(cs, 1); 246b9dbf951SMagnus Damm return 0; 247b9dbf951SMagnus Damm } 248b9dbf951SMagnus Damm 249b9dbf951SMagnus Damm static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) 250b9dbf951SMagnus Damm { 251b9dbf951SMagnus Damm return container_of(ced, struct em_sti_priv, ced); 252b9dbf951SMagnus Damm } 253b9dbf951SMagnus Damm 254*75f94061SViresh Kumar static int em_sti_clock_event_shutdown(struct clock_event_device *ced) 255*75f94061SViresh Kumar { 256*75f94061SViresh Kumar struct em_sti_priv *p = ced_to_em_sti(ced); 257*75f94061SViresh Kumar em_sti_stop(p, USER_CLOCKEVENT); 258*75f94061SViresh Kumar return 0; 259*75f94061SViresh Kumar } 260*75f94061SViresh Kumar 261*75f94061SViresh Kumar static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced) 262b9dbf951SMagnus Damm { 263b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 264b9dbf951SMagnus Damm 265b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for oneshot clock events\n"); 266b9dbf951SMagnus Damm em_sti_start(p, USER_CLOCKEVENT); 267b9dbf951SMagnus Damm clockevents_config(&p->ced, p->rate); 268*75f94061SViresh Kumar return 0; 269b9dbf951SMagnus Damm } 270b9dbf951SMagnus Damm 271b9dbf951SMagnus Damm static int em_sti_clock_event_next(unsigned long delta, 272b9dbf951SMagnus Damm struct clock_event_device *ced) 273b9dbf951SMagnus Damm { 274b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 275b9dbf951SMagnus Damm cycle_t next; 276b9dbf951SMagnus Damm int safe; 277b9dbf951SMagnus Damm 278b9dbf951SMagnus Damm next = em_sti_set_next(p, em_sti_count(p) + delta); 279b9dbf951SMagnus Damm safe = em_sti_count(p) < (next - 1); 280b9dbf951SMagnus Damm 281b9dbf951SMagnus Damm return !safe; 282b9dbf951SMagnus Damm } 283b9dbf951SMagnus Damm 284b9dbf951SMagnus Damm static void em_sti_register_clockevent(struct em_sti_priv *p) 285b9dbf951SMagnus Damm { 286b9dbf951SMagnus Damm struct clock_event_device *ced = &p->ced; 287b9dbf951SMagnus Damm 288b9dbf951SMagnus Damm memset(ced, 0, sizeof(*ced)); 289b9dbf951SMagnus Damm ced->name = dev_name(&p->pdev->dev); 290b9dbf951SMagnus Damm ced->features = CLOCK_EVT_FEAT_ONESHOT; 291b9dbf951SMagnus Damm ced->rating = 200; 2922199a557SMagnus Damm ced->cpumask = cpu_possible_mask; 293b9dbf951SMagnus Damm ced->set_next_event = em_sti_clock_event_next; 294*75f94061SViresh Kumar ced->set_state_shutdown = em_sti_clock_event_shutdown; 295*75f94061SViresh Kumar ced->set_state_oneshot = em_sti_clock_event_set_oneshot; 296b9dbf951SMagnus Damm 297b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for clock events\n"); 298b9dbf951SMagnus Damm 299*75f94061SViresh Kumar /* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */ 300b9dbf951SMagnus Damm clockevents_config_and_register(ced, 1, 2, 0xffffffff); 301b9dbf951SMagnus Damm } 302b9dbf951SMagnus Damm 3031850514bSGreg Kroah-Hartman static int em_sti_probe(struct platform_device *pdev) 304b9dbf951SMagnus Damm { 305b9dbf951SMagnus Damm struct em_sti_priv *p; 306b9dbf951SMagnus Damm struct resource *res; 3071745e696SLaurent Pinchart int irq; 308b9dbf951SMagnus Damm 3091745e696SLaurent Pinchart p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 31039dd5677SJingoo Han if (p == NULL) 3111745e696SLaurent Pinchart return -ENOMEM; 312b9dbf951SMagnus Damm 313b9dbf951SMagnus Damm p->pdev = pdev; 314b9dbf951SMagnus Damm platform_set_drvdata(pdev, p); 315b9dbf951SMagnus Damm 316b9dbf951SMagnus Damm irq = platform_get_irq(pdev, 0); 317b9dbf951SMagnus Damm if (irq < 0) { 318b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to get irq\n"); 3191745e696SLaurent Pinchart return -EINVAL; 320b9dbf951SMagnus Damm } 321b9dbf951SMagnus Damm 322b9dbf951SMagnus Damm /* map memory, let base point to the STI instance */ 3231745e696SLaurent Pinchart res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3241745e696SLaurent Pinchart p->base = devm_ioremap_resource(&pdev->dev, res); 3251745e696SLaurent Pinchart if (IS_ERR(p->base)) 3261745e696SLaurent Pinchart return PTR_ERR(p->base); 327b9dbf951SMagnus Damm 328b9dbf951SMagnus Damm /* get hold of clock */ 3291745e696SLaurent Pinchart p->clk = devm_clk_get(&pdev->dev, "sclk"); 330b9dbf951SMagnus Damm if (IS_ERR(p->clk)) { 331b9dbf951SMagnus Damm dev_err(&pdev->dev, "cannot get clock\n"); 3321745e696SLaurent Pinchart return PTR_ERR(p->clk); 333b9dbf951SMagnus Damm } 334b9dbf951SMagnus Damm 3351745e696SLaurent Pinchart if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, 336b9dbf951SMagnus Damm IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, 337b9dbf951SMagnus Damm dev_name(&pdev->dev), p)) { 338b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to request low IRQ\n"); 3391745e696SLaurent Pinchart return -ENOENT; 340b9dbf951SMagnus Damm } 341b9dbf951SMagnus Damm 342b9dbf951SMagnus Damm raw_spin_lock_init(&p->lock); 343b9dbf951SMagnus Damm em_sti_register_clockevent(p); 344b9dbf951SMagnus Damm em_sti_register_clocksource(p); 345b9dbf951SMagnus Damm return 0; 346b9dbf951SMagnus Damm } 347b9dbf951SMagnus Damm 3481850514bSGreg Kroah-Hartman static int em_sti_remove(struct platform_device *pdev) 349b9dbf951SMagnus Damm { 350b9dbf951SMagnus Damm return -EBUSY; /* cannot unregister clockevent and clocksource */ 351b9dbf951SMagnus Damm } 352b9dbf951SMagnus Damm 3531850514bSGreg Kroah-Hartman static const struct of_device_id em_sti_dt_ids[] = { 354fc0830feSMagnus Damm { .compatible = "renesas,em-sti", }, 355fc0830feSMagnus Damm {}, 356fc0830feSMagnus Damm }; 357fc0830feSMagnus Damm MODULE_DEVICE_TABLE(of, em_sti_dt_ids); 358fc0830feSMagnus Damm 359b9dbf951SMagnus Damm static struct platform_driver em_sti_device_driver = { 360b9dbf951SMagnus Damm .probe = em_sti_probe, 3611850514bSGreg Kroah-Hartman .remove = em_sti_remove, 362b9dbf951SMagnus Damm .driver = { 363b9dbf951SMagnus Damm .name = "em_sti", 364fc0830feSMagnus Damm .of_match_table = em_sti_dt_ids, 365b9dbf951SMagnus Damm } 366b9dbf951SMagnus Damm }; 367b9dbf951SMagnus Damm 36809acc3a1SSimon Horman static int __init em_sti_init(void) 36909acc3a1SSimon Horman { 37009acc3a1SSimon Horman return platform_driver_register(&em_sti_device_driver); 37109acc3a1SSimon Horman } 37209acc3a1SSimon Horman 37309acc3a1SSimon Horman static void __exit em_sti_exit(void) 37409acc3a1SSimon Horman { 37509acc3a1SSimon Horman platform_driver_unregister(&em_sti_device_driver); 37609acc3a1SSimon Horman } 37709acc3a1SSimon Horman 37809acc3a1SSimon Horman subsys_initcall(em_sti_init); 37909acc3a1SSimon Horman module_exit(em_sti_exit); 380b9dbf951SMagnus Damm 381b9dbf951SMagnus Damm MODULE_AUTHOR("Magnus Damm"); 382b9dbf951SMagnus Damm MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); 383b9dbf951SMagnus Damm MODULE_LICENSE("GPL v2"); 384