linux/drivers/clocksource/sh_tmu.c
<<
>>
Prefs
   1/*
   2 * SuperH Timer Support - TMU
   3 *
   4 *  Copyright (C) 2009 Magnus Damm
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/platform_device.h>
  22#include <linux/spinlock.h>
  23#include <linux/interrupt.h>
  24#include <linux/ioport.h>
  25#include <linux/delay.h>
  26#include <linux/io.h>
  27#include <linux/clk.h>
  28#include <linux/irq.h>
  29#include <linux/err.h>
  30#include <linux/clocksource.h>
  31#include <linux/clockchips.h>
  32#include <linux/sh_timer.h>
  33#include <linux/slab.h>
  34#include <linux/module.h>
  35#include <linux/pm_domain.h>
  36
  37struct sh_tmu_priv {
  38        void __iomem *mapbase;
  39        struct clk *clk;
  40        struct irqaction irqaction;
  41        struct platform_device *pdev;
  42        unsigned long rate;
  43        unsigned long periodic;
  44        struct clock_event_device ced;
  45        struct clocksource cs;
  46};
  47
  48static DEFINE_RAW_SPINLOCK(sh_tmu_lock);
  49
  50#define TSTR -1 /* shared register */
  51#define TCOR  0 /* channel register */
  52#define TCNT 1 /* channel register */
  53#define TCR 2 /* channel register */
  54
  55static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr)
  56{
  57        struct sh_timer_config *cfg = p->pdev->dev.platform_data;
  58        void __iomem *base = p->mapbase;
  59        unsigned long offs;
  60
  61        if (reg_nr == TSTR)
  62                return ioread8(base - cfg->channel_offset);
  63
  64        offs = reg_nr << 2;
  65
  66        if (reg_nr == TCR)
  67                return ioread16(base + offs);
  68        else
  69                return ioread32(base + offs);
  70}
  71
  72static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr,
  73                                unsigned long value)
  74{
  75        struct sh_timer_config *cfg = p->pdev->dev.platform_data;
  76        void __iomem *base = p->mapbase;
  77        unsigned long offs;
  78
  79        if (reg_nr == TSTR) {
  80                iowrite8(value, base - cfg->channel_offset);
  81                return;
  82        }
  83
  84        offs = reg_nr << 2;
  85
  86        if (reg_nr == TCR)
  87                iowrite16(value, base + offs);
  88        else
  89                iowrite32(value, base + offs);
  90}
  91
  92static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
  93{
  94        struct sh_timer_config *cfg = p->pdev->dev.platform_data;
  95        unsigned long flags, value;
  96
  97        /* start stop register shared by multiple timer channels */
  98        raw_spin_lock_irqsave(&sh_tmu_lock, flags);
  99        value = sh_tmu_read(p, TSTR);
 100
 101        if (start)
 102                value |= 1 << cfg->timer_bit;
 103        else
 104                value &= ~(1 << cfg->timer_bit);
 105
 106        sh_tmu_write(p, TSTR, value);
 107        raw_spin_unlock_irqrestore(&sh_tmu_lock, flags);
 108}
 109
 110static int sh_tmu_enable(struct sh_tmu_priv *p)
 111{
 112        int ret;
 113
 114        /* enable clock */
 115        ret = clk_enable(p->clk);
 116        if (ret) {
 117                dev_err(&p->pdev->dev, "cannot enable clock\n");
 118                return ret;
 119        }
 120
 121        /* make sure channel is disabled */
 122        sh_tmu_start_stop_ch(p, 0);
 123
 124        /* maximum timeout */
 125        sh_tmu_write(p, TCOR, 0xffffffff);
 126        sh_tmu_write(p, TCNT, 0xffffffff);
 127
 128        /* configure channel to parent clock / 4, irq off */
 129        p->rate = clk_get_rate(p->clk) / 4;
 130        sh_tmu_write(p, TCR, 0x0000);
 131
 132        /* enable channel */
 133        sh_tmu_start_stop_ch(p, 1);
 134
 135        return 0;
 136}
 137
 138static void sh_tmu_disable(struct sh_tmu_priv *p)
 139{
 140        /* disable channel */
 141        sh_tmu_start_stop_ch(p, 0);
 142
 143        /* disable interrupts in TMU block */
 144        sh_tmu_write(p, TCR, 0x0000);
 145
 146        /* stop clock */
 147        clk_disable(p->clk);
 148}
 149
 150static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
 151                            int periodic)
 152{
 153        /* stop timer */
 154        sh_tmu_start_stop_ch(p, 0);
 155
 156        /* acknowledge interrupt */
 157        sh_tmu_read(p, TCR);
 158
 159        /* enable interrupt */
 160        sh_tmu_write(p, TCR, 0x0020);
 161
 162        /* reload delta value in case of periodic timer */
 163        if (periodic)
 164                sh_tmu_write(p, TCOR, delta);
 165        else
 166                sh_tmu_write(p, TCOR, 0xffffffff);
 167
 168        sh_tmu_write(p, TCNT, delta);
 169
 170        /* start timer */
 171        sh_tmu_start_stop_ch(p, 1);
 172}
 173
 174static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)
 175{
 176        struct sh_tmu_priv *p = dev_id;
 177
 178        /* disable or acknowledge interrupt */
 179        if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
 180                sh_tmu_write(p, TCR, 0x0000);
 181        else
 182                sh_tmu_write(p, TCR, 0x0020);
 183
 184        /* notify clockevent layer */
 185        p->ced.event_handler(&p->ced);
 186        return IRQ_HANDLED;
 187}
 188
 189static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs)
 190{
 191        return container_of(cs, struct sh_tmu_priv, cs);
 192}
 193
 194static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
 195{
 196        struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
 197
 198        return sh_tmu_read(p, TCNT) ^ 0xffffffff;
 199}
 200
 201static int sh_tmu_clocksource_enable(struct clocksource *cs)
 202{
 203        struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
 204        int ret;
 205
 206        ret = sh_tmu_enable(p);
 207        if (!ret)
 208                __clocksource_updatefreq_hz(cs, p->rate);
 209        return ret;
 210}
 211
 212static void sh_tmu_clocksource_disable(struct clocksource *cs)
 213{
 214        sh_tmu_disable(cs_to_sh_tmu(cs));
 215}
 216
 217static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
 218                                       char *name, unsigned long rating)
 219{
 220        struct clocksource *cs = &p->cs;
 221
 222        cs->name = name;
 223        cs->rating = rating;
 224        cs->read = sh_tmu_clocksource_read;
 225        cs->enable = sh_tmu_clocksource_enable;
 226        cs->disable = sh_tmu_clocksource_disable;
 227        cs->mask = CLOCKSOURCE_MASK(32);
 228        cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 229
 230        dev_info(&p->pdev->dev, "used as clock source\n");
 231
 232        /* Register with dummy 1 Hz value, gets updated in ->enable() */
 233        clocksource_register_hz(cs, 1);
 234        return 0;
 235}
 236
 237static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced)
 238{
 239        return container_of(ced, struct sh_tmu_priv, ced);
 240}
 241
 242static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic)
 243{
 244        struct clock_event_device *ced = &p->ced;
 245
 246        sh_tmu_enable(p);
 247
 248        clockevents_config(ced, p->rate);
 249
 250        if (periodic) {
 251                p->periodic = (p->rate + HZ/2) / HZ;
 252                sh_tmu_set_next(p, p->periodic, 1);
 253        }
 254}
 255
 256static void sh_tmu_clock_event_mode(enum clock_event_mode mode,
 257                                    struct clock_event_device *ced)
 258{
 259        struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
 260        int disabled = 0;
 261
 262        /* deal with old setting first */
 263        switch (ced->mode) {
 264        case CLOCK_EVT_MODE_PERIODIC:
 265        case CLOCK_EVT_MODE_ONESHOT:
 266                sh_tmu_disable(p);
 267                disabled = 1;
 268                break;
 269        default:
 270                break;
 271        }
 272
 273        switch (mode) {
 274        case CLOCK_EVT_MODE_PERIODIC:
 275                dev_info(&p->pdev->dev, "used for periodic clock events\n");
 276                sh_tmu_clock_event_start(p, 1);
 277                break;
 278        case CLOCK_EVT_MODE_ONESHOT:
 279                dev_info(&p->pdev->dev, "used for oneshot clock events\n");
 280                sh_tmu_clock_event_start(p, 0);
 281                break;
 282        case CLOCK_EVT_MODE_UNUSED:
 283                if (!disabled)
 284                        sh_tmu_disable(p);
 285                break;
 286        case CLOCK_EVT_MODE_SHUTDOWN:
 287        default:
 288                break;
 289        }
 290}
 291
 292static int sh_tmu_clock_event_next(unsigned long delta,
 293                                   struct clock_event_device *ced)
 294{
 295        struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
 296
 297        BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
 298
 299        /* program new delta value */
 300        sh_tmu_set_next(p, delta, 0);
 301        return 0;
 302}
 303
 304static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
 305                                       char *name, unsigned long rating)
 306{
 307        struct clock_event_device *ced = &p->ced;
 308        int ret;
 309
 310        memset(ced, 0, sizeof(*ced));
 311
 312        ced->name = name;
 313        ced->features = CLOCK_EVT_FEAT_PERIODIC;
 314        ced->features |= CLOCK_EVT_FEAT_ONESHOT;
 315        ced->rating = rating;
 316        ced->cpumask = cpumask_of(0);
 317        ced->set_next_event = sh_tmu_clock_event_next;
 318        ced->set_mode = sh_tmu_clock_event_mode;
 319
 320        dev_info(&p->pdev->dev, "used for clock events\n");
 321
 322        clockevents_config_and_register(ced, 1, 0x300, 0xffffffff);
 323
 324        ret = setup_irq(p->irqaction.irq, &p->irqaction);
 325        if (ret) {
 326                dev_err(&p->pdev->dev, "failed to request irq %d\n",
 327                        p->irqaction.irq);
 328                return;
 329        }
 330}
 331
 332static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
 333                    unsigned long clockevent_rating,
 334                    unsigned long clocksource_rating)
 335{
 336        if (clockevent_rating)
 337                sh_tmu_register_clockevent(p, name, clockevent_rating);
 338        else if (clocksource_rating)
 339                sh_tmu_register_clocksource(p, name, clocksource_rating);
 340
 341        return 0;
 342}
 343
 344static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
 345{
 346        struct sh_timer_config *cfg = pdev->dev.platform_data;
 347        struct resource *res;
 348        int irq, ret;
 349        ret = -ENXIO;
 350
 351        memset(p, 0, sizeof(*p));
 352        p->pdev = pdev;
 353
 354        if (!cfg) {
 355                dev_err(&p->pdev->dev, "missing platform data\n");
 356                goto err0;
 357        }
 358
 359        platform_set_drvdata(pdev, p);
 360
 361        res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
 362        if (!res) {
 363                dev_err(&p->pdev->dev, "failed to get I/O memory\n");
 364                goto err0;
 365        }
 366
 367        irq = platform_get_irq(p->pdev, 0);
 368        if (irq < 0) {
 369                dev_err(&p->pdev->dev, "failed to get irq\n");
 370                goto err0;
 371        }
 372
 373        /* map memory, let mapbase point to our channel */
 374        p->mapbase = ioremap_nocache(res->start, resource_size(res));
 375        if (p->mapbase == NULL) {
 376                dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
 377                goto err0;
 378        }
 379
 380        /* setup data for setup_irq() (too early for request_irq()) */
 381        p->irqaction.name = dev_name(&p->pdev->dev);
 382        p->irqaction.handler = sh_tmu_interrupt;
 383        p->irqaction.dev_id = p;
 384        p->irqaction.irq = irq;
 385        p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
 386                             IRQF_IRQPOLL  | IRQF_NOBALANCING;
 387
 388        /* get hold of clock */
 389        p->clk = clk_get(&p->pdev->dev, "tmu_fck");
 390        if (IS_ERR(p->clk)) {
 391                dev_err(&p->pdev->dev, "cannot get clock\n");
 392                ret = PTR_ERR(p->clk);
 393                goto err1;
 394        }
 395
 396        return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
 397                               cfg->clockevent_rating,
 398                               cfg->clocksource_rating);
 399 err1:
 400        iounmap(p->mapbase);
 401 err0:
 402        return ret;
 403}
 404
 405static int __devinit sh_tmu_probe(struct platform_device *pdev)
 406{
 407        struct sh_tmu_priv *p = platform_get_drvdata(pdev);
 408        int ret;
 409
 410        if (!is_early_platform_device(pdev))
 411                pm_genpd_dev_always_on(&pdev->dev, true);
 412
 413        if (p) {
 414                dev_info(&pdev->dev, "kept as earlytimer\n");
 415                return 0;
 416        }
 417
 418        p = kmalloc(sizeof(*p), GFP_KERNEL);
 419        if (p == NULL) {
 420                dev_err(&pdev->dev, "failed to allocate driver data\n");
 421                return -ENOMEM;
 422        }
 423
 424        ret = sh_tmu_setup(p, pdev);
 425        if (ret) {
 426                kfree(p);
 427                platform_set_drvdata(pdev, NULL);
 428        }
 429        return ret;
 430}
 431
 432static int __devexit sh_tmu_remove(struct platform_device *pdev)
 433{
 434        return -EBUSY; /* cannot unregister clockevent and clocksource */
 435}
 436
 437static struct platform_driver sh_tmu_device_driver = {
 438        .probe          = sh_tmu_probe,
 439        .remove         = __devexit_p(sh_tmu_remove),
 440        .driver         = {
 441                .name   = "sh_tmu",
 442        }
 443};
 444
 445static int __init sh_tmu_init(void)
 446{
 447        return platform_driver_register(&sh_tmu_device_driver);
 448}
 449
 450static void __exit sh_tmu_exit(void)
 451{
 452        platform_driver_unregister(&sh_tmu_device_driver);
 453}
 454
 455early_platform_init("earlytimer", &sh_tmu_device_driver);
 456module_init(sh_tmu_init);
 457module_exit(sh_tmu_exit);
 458
 459MODULE_AUTHOR("Magnus Damm");
 460MODULE_DESCRIPTION("SuperH TMU Timer Driver");
 461MODULE_LICENSE("GPL v2");
 462
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.