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 */ 81b9dbf951SMagnus Damm 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 */ 110b9dbf951SMagnus Damm clk_disable(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) 213b9dbf951SMagnus Damm __clocksource_updatefreq_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 254b9dbf951SMagnus Damm static void em_sti_clock_event_mode(enum clock_event_mode mode, 255b9dbf951SMagnus Damm struct clock_event_device *ced) 256b9dbf951SMagnus Damm { 257b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 258b9dbf951SMagnus Damm 259b9dbf951SMagnus Damm /* deal with old setting first */ 260b9dbf951SMagnus Damm switch (ced->mode) { 261b9dbf951SMagnus Damm case CLOCK_EVT_MODE_ONESHOT: 262b9dbf951SMagnus Damm em_sti_stop(p, USER_CLOCKEVENT); 263b9dbf951SMagnus Damm break; 264b9dbf951SMagnus Damm default: 265b9dbf951SMagnus Damm break; 266b9dbf951SMagnus Damm } 267b9dbf951SMagnus Damm 268b9dbf951SMagnus Damm switch (mode) { 269b9dbf951SMagnus Damm case CLOCK_EVT_MODE_ONESHOT: 270b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for oneshot clock events\n"); 271b9dbf951SMagnus Damm em_sti_start(p, USER_CLOCKEVENT); 272b9dbf951SMagnus Damm clockevents_config(&p->ced, p->rate); 273b9dbf951SMagnus Damm break; 274b9dbf951SMagnus Damm case CLOCK_EVT_MODE_SHUTDOWN: 275b9dbf951SMagnus Damm case CLOCK_EVT_MODE_UNUSED: 276b9dbf951SMagnus Damm em_sti_stop(p, USER_CLOCKEVENT); 277b9dbf951SMagnus Damm break; 278b9dbf951SMagnus Damm default: 279b9dbf951SMagnus Damm break; 280b9dbf951SMagnus Damm } 281b9dbf951SMagnus Damm } 282b9dbf951SMagnus Damm 283b9dbf951SMagnus Damm static int em_sti_clock_event_next(unsigned long delta, 284b9dbf951SMagnus Damm struct clock_event_device *ced) 285b9dbf951SMagnus Damm { 286b9dbf951SMagnus Damm struct em_sti_priv *p = ced_to_em_sti(ced); 287b9dbf951SMagnus Damm cycle_t next; 288b9dbf951SMagnus Damm int safe; 289b9dbf951SMagnus Damm 290b9dbf951SMagnus Damm next = em_sti_set_next(p, em_sti_count(p) + delta); 291b9dbf951SMagnus Damm safe = em_sti_count(p) < (next - 1); 292b9dbf951SMagnus Damm 293b9dbf951SMagnus Damm return !safe; 294b9dbf951SMagnus Damm } 295b9dbf951SMagnus Damm 296b9dbf951SMagnus Damm static void em_sti_register_clockevent(struct em_sti_priv *p) 297b9dbf951SMagnus Damm { 298b9dbf951SMagnus Damm struct clock_event_device *ced = &p->ced; 299b9dbf951SMagnus Damm 300b9dbf951SMagnus Damm memset(ced, 0, sizeof(*ced)); 301b9dbf951SMagnus Damm ced->name = dev_name(&p->pdev->dev); 302b9dbf951SMagnus Damm ced->features = CLOCK_EVT_FEAT_ONESHOT; 303b9dbf951SMagnus Damm ced->rating = 200; 304*2199a557SMagnus Damm ced->cpumask = cpu_possible_mask; 305b9dbf951SMagnus Damm ced->set_next_event = em_sti_clock_event_next; 306b9dbf951SMagnus Damm ced->set_mode = em_sti_clock_event_mode; 307b9dbf951SMagnus Damm 308b9dbf951SMagnus Damm dev_info(&p->pdev->dev, "used for clock events\n"); 309b9dbf951SMagnus Damm 310b9dbf951SMagnus Damm /* Register with dummy 1 Hz value, gets updated in ->set_mode() */ 311b9dbf951SMagnus Damm clockevents_config_and_register(ced, 1, 2, 0xffffffff); 312b9dbf951SMagnus Damm } 313b9dbf951SMagnus Damm 3141850514bSGreg Kroah-Hartman static int em_sti_probe(struct platform_device *pdev) 315b9dbf951SMagnus Damm { 316b9dbf951SMagnus Damm struct em_sti_priv *p; 317b9dbf951SMagnus Damm struct resource *res; 3181745e696SLaurent Pinchart int irq; 319b9dbf951SMagnus Damm 3201745e696SLaurent Pinchart p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 321b9dbf951SMagnus Damm if (p == NULL) { 322b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to allocate driver data\n"); 3231745e696SLaurent Pinchart return -ENOMEM; 324b9dbf951SMagnus Damm } 325b9dbf951SMagnus Damm 326b9dbf951SMagnus Damm p->pdev = pdev; 327b9dbf951SMagnus Damm platform_set_drvdata(pdev, p); 328b9dbf951SMagnus Damm 329b9dbf951SMagnus Damm irq = platform_get_irq(pdev, 0); 330b9dbf951SMagnus Damm if (irq < 0) { 331b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to get irq\n"); 3321745e696SLaurent Pinchart return -EINVAL; 333b9dbf951SMagnus Damm } 334b9dbf951SMagnus Damm 335b9dbf951SMagnus Damm /* map memory, let base point to the STI instance */ 3361745e696SLaurent Pinchart res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3371745e696SLaurent Pinchart p->base = devm_ioremap_resource(&pdev->dev, res); 3381745e696SLaurent Pinchart if (IS_ERR(p->base)) 3391745e696SLaurent Pinchart return PTR_ERR(p->base); 340b9dbf951SMagnus Damm 341b9dbf951SMagnus Damm /* get hold of clock */ 3421745e696SLaurent Pinchart p->clk = devm_clk_get(&pdev->dev, "sclk"); 343b9dbf951SMagnus Damm if (IS_ERR(p->clk)) { 344b9dbf951SMagnus Damm dev_err(&pdev->dev, "cannot get clock\n"); 3451745e696SLaurent Pinchart return PTR_ERR(p->clk); 346b9dbf951SMagnus Damm } 347b9dbf951SMagnus Damm 3481745e696SLaurent Pinchart if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, 349b9dbf951SMagnus Damm IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, 350b9dbf951SMagnus Damm dev_name(&pdev->dev), p)) { 351b9dbf951SMagnus Damm dev_err(&pdev->dev, "failed to request low IRQ\n"); 3521745e696SLaurent Pinchart return -ENOENT; 353b9dbf951SMagnus Damm } 354b9dbf951SMagnus Damm 355b9dbf951SMagnus Damm raw_spin_lock_init(&p->lock); 356b9dbf951SMagnus Damm em_sti_register_clockevent(p); 357b9dbf951SMagnus Damm em_sti_register_clocksource(p); 358b9dbf951SMagnus Damm return 0; 359b9dbf951SMagnus Damm } 360b9dbf951SMagnus Damm 3611850514bSGreg Kroah-Hartman static int em_sti_remove(struct platform_device *pdev) 362b9dbf951SMagnus Damm { 363b9dbf951SMagnus Damm return -EBUSY; /* cannot unregister clockevent and clocksource */ 364b9dbf951SMagnus Damm } 365b9dbf951SMagnus Damm 3661850514bSGreg Kroah-Hartman static const struct of_device_id em_sti_dt_ids[] = { 367fc0830feSMagnus Damm { .compatible = "renesas,em-sti", }, 368fc0830feSMagnus Damm {}, 369fc0830feSMagnus Damm }; 370fc0830feSMagnus Damm MODULE_DEVICE_TABLE(of, em_sti_dt_ids); 371fc0830feSMagnus Damm 372b9dbf951SMagnus Damm static struct platform_driver em_sti_device_driver = { 373b9dbf951SMagnus Damm .probe = em_sti_probe, 3741850514bSGreg Kroah-Hartman .remove = em_sti_remove, 375b9dbf951SMagnus Damm .driver = { 376b9dbf951SMagnus Damm .name = "em_sti", 377fc0830feSMagnus Damm .of_match_table = em_sti_dt_ids, 378b9dbf951SMagnus Damm } 379b9dbf951SMagnus Damm }; 380b9dbf951SMagnus Damm 38109acc3a1SSimon Horman static int __init em_sti_init(void) 38209acc3a1SSimon Horman { 38309acc3a1SSimon Horman return platform_driver_register(&em_sti_device_driver); 38409acc3a1SSimon Horman } 38509acc3a1SSimon Horman 38609acc3a1SSimon Horman static void __exit em_sti_exit(void) 38709acc3a1SSimon Horman { 38809acc3a1SSimon Horman platform_driver_unregister(&em_sti_device_driver); 38909acc3a1SSimon Horman } 39009acc3a1SSimon Horman 39109acc3a1SSimon Horman subsys_initcall(em_sti_init); 39209acc3a1SSimon Horman module_exit(em_sti_exit); 393b9dbf951SMagnus Damm 394b9dbf951SMagnus Damm MODULE_AUTHOR("Magnus Damm"); 395b9dbf951SMagnus Damm MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); 396b9dbf951SMagnus Damm MODULE_LICENSE("GPL v2"); 397