1d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm/* 2d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * SuperH Timer Support - MTU2 3d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * 4d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * Copyright (C) 2009 Magnus Damm 5d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * 6d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * This program is free software; you can redistribute it and/or modify 7d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * it under the terms of the GNU General Public License as published by 8d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * the Free Software Foundation; either version 2 of the License 9d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * 10d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * This program is distributed in the hope that it will be useful, 11d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of 12d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * GNU General Public License for more details. 14d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * 15d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * You should have received a copy of the GNU General Public License 16d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * along with this program; if not, write to the Free Software 17d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm */ 19d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 20d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/init.h> 21d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/platform_device.h> 22d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/spinlock.h> 23d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/interrupt.h> 24d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/ioport.h> 25d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/delay.h> 26d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/io.h> 27d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/clk.h> 28d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/irq.h> 29d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/err.h> 30d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#include <linux/clockchips.h> 3146a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt#include <linux/sh_timer.h> 325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 337deeab5dc414240a341e80f41b5f00620aa9ef98Paul Gortmaker#include <linux/module.h> 3457d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki#include <linux/pm_domain.h> 35d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 36d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstruct sh_mtu2_priv { 37d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm void __iomem *mapbase; 38d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct clk *clk; 39d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct irqaction irqaction; 40d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct platform_device *pdev; 41d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long rate; 42d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long periodic; 43d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct clock_event_device ced; 44d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}; 45d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 46d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic DEFINE_SPINLOCK(sh_mtu2_lock); 47d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 48d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TSTR -1 /* shared register */ 49d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TCR 0 /* channel register */ 50d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TMDR 1 /* channel register */ 51d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TIOR 2 /* channel register */ 52d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TIER 3 /* channel register */ 53d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TSR 4 /* channel register */ 54d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TCNT 5 /* channel register */ 55d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm#define TGR 6 /* channel register */ 56d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 57d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic unsigned long mtu2_reg_offs[] = { 58d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TCR] = 0, 59d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TMDR] = 1, 60d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TIOR] = 2, 61d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TIER] = 4, 62d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TSR] = 5, 63d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TCNT] = 6, 64d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm [TGR] = 8, 65d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}; 66d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 67d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr) 68d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 6946a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 70d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm void __iomem *base = p->mapbase; 71d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long offs; 72d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 73d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (reg_nr == TSTR) 74d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ioread8(base + cfg->channel_offset); 75d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 76d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm offs = mtu2_reg_offs[reg_nr]; 77d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 78d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if ((reg_nr == TCNT) || (reg_nr == TGR)) 79d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ioread16(base + offs); 80d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm else 81d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ioread8(base + offs); 82d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 83d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 84d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr, 85d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long value) 86d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 8746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 88d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm void __iomem *base = p->mapbase; 89d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long offs; 90d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 91d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (reg_nr == TSTR) { 92d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm iowrite8(value, base + cfg->channel_offset); 93d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return; 94d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 95d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 96d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm offs = mtu2_reg_offs[reg_nr]; 97d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 98d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if ((reg_nr == TCNT) || (reg_nr == TGR)) 99d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm iowrite16(value, base + offs); 100d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm else 101d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm iowrite8(value, base + offs); 102d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 103d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 104d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start) 105d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 10646a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 107d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm unsigned long flags, value; 108d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 109d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* start stop register shared by multiple timer channels */ 110d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm spin_lock_irqsave(&sh_mtu2_lock, flags); 111d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm value = sh_mtu2_read(p, TSTR); 112d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 113d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (start) 114d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm value |= 1 << cfg->timer_bit; 115d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm else 116d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm value &= ~(1 << cfg->timer_bit); 117d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 118d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TSTR, value); 119d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm spin_unlock_irqrestore(&sh_mtu2_lock, flags); 120d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 121d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 122d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int sh_mtu2_enable(struct sh_mtu2_priv *p) 123d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 124d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm int ret; 125d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 126d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* enable clock */ 127d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ret = clk_enable(p->clk); 128d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (ret) { 129214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_err(&p->pdev->dev, "cannot enable clock\n"); 130d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ret; 131d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 132d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 133d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* make sure channel is disabled */ 134d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_start_stop_ch(p, 0); 135d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 136d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->rate = clk_get_rate(p->clk) / 64; 137d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->periodic = (p->rate + HZ/2) / HZ; 138d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 139d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* "Periodic Counter Operation" */ 140d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */ 141d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TIOR, 0); 142d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TGR, p->periodic); 143d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TCNT, 0); 144d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TMDR, 0); 145d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TIER, 0x01); 146d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 147d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* enable channel */ 148d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_start_stop_ch(p, 1); 149d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 150d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return 0; 151d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 152d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 153d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_disable(struct sh_mtu2_priv *p) 154d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 155d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* disable channel */ 156d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_start_stop_ch(p, 0); 157d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 158d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* stop clock */ 159d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm clk_disable(p->clk); 160d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 161d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 162d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) 163d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 164d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct sh_mtu2_priv *p = dev_id; 165d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 166d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* acknowledge interrupt */ 167d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_read(p, TSR); 168d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_write(p, TSR, 0xfe); 169d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 170d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* notify clockevent layer */ 171d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->ced.event_handler(&p->ced); 172d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return IRQ_HANDLED; 173d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 174d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 175d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced) 176d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 177d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return container_of(ced, struct sh_mtu2_priv, ced); 178d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 179d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 180d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_clock_event_mode(enum clock_event_mode mode, 181d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct clock_event_device *ced) 182d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 183d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced); 184d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm int disabled = 0; 185d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 186d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* deal with old setting first */ 187d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm switch (ced->mode) { 188d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm case CLOCK_EVT_MODE_PERIODIC: 189d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_disable(p); 190d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm disabled = 1; 191d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm break; 192d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm default: 193d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm break; 194d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 195d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 196d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm switch (mode) { 197d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm case CLOCK_EVT_MODE_PERIODIC: 198214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_info(&p->pdev->dev, "used for periodic clock events\n"); 199d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_enable(p); 200d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm break; 201d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm case CLOCK_EVT_MODE_UNUSED: 202d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (!disabled) 203d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_disable(p); 204d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm break; 205d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm case CLOCK_EVT_MODE_SHUTDOWN: 206d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm default: 207d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm break; 208d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 209d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 210d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 211d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, 212d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm char *name, unsigned long rating) 213d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 214d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct clock_event_device *ced = &p->ced; 215d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm int ret; 216d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 217d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm memset(ced, 0, sizeof(*ced)); 218d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 219d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ced->name = name; 220d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ced->features = CLOCK_EVT_FEAT_PERIODIC; 221d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ced->rating = rating; 222d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ced->cpumask = cpumask_of(0); 223d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ced->set_mode = sh_mtu2_clock_event_mode; 224d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 225214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_info(&p->pdev->dev, "used for clock events\n"); 226da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt clockevents_register_device(ced); 227da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt 228d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ret = setup_irq(p->irqaction.irq, &p->irqaction); 229d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (ret) { 230214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_err(&p->pdev->dev, "failed to request irq %d\n", 231214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt p->irqaction.irq); 232d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return; 233d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 234d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 235d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 236d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundtstatic int sh_mtu2_register(struct sh_mtu2_priv *p, char *name, 237d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundt unsigned long clockevent_rating) 238d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 239d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (clockevent_rating) 240d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm sh_mtu2_register_clockevent(p, name, clockevent_rating); 241d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 242d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return 0; 243d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 244d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 245d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) 246d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 24746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = pdev->dev.platform_data; 248d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct resource *res; 249d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm int irq, ret; 250d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ret = -ENXIO; 251d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 252d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm memset(p, 0, sizeof(*p)); 253d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->pdev = pdev; 254d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 255d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (!cfg) { 256d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm dev_err(&p->pdev->dev, "missing platform data\n"); 257d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm goto err0; 258d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 259d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 260d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm platform_set_drvdata(pdev, p); 261d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 262d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); 263d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (!res) { 264d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm dev_err(&p->pdev->dev, "failed to get I/O memory\n"); 265d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm goto err0; 266d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 267d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 268d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm irq = platform_get_irq(p->pdev, 0); 269d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (irq < 0) { 270d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm dev_err(&p->pdev->dev, "failed to get irq\n"); 271d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm goto err0; 272d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 273d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 274d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* map memory, let mapbase point to our channel */ 275d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->mapbase = ioremap_nocache(res->start, resource_size(res)); 276d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (p->mapbase == NULL) { 277214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_err(&p->pdev->dev, "failed to remap I/O memory\n"); 278d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm goto err0; 279d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 280d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 281d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* setup data for setup_irq() (too early for request_irq()) */ 282214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt p->irqaction.name = dev_name(&p->pdev->dev); 283d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->irqaction.handler = sh_mtu2_interrupt; 284d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->irqaction.dev_id = p; 285d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p->irqaction.irq = irq; 286fecf066c2d2fbc7e6a7e7e3a5af772a165bdd7b0Paul Mundt p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \ 287fecf066c2d2fbc7e6a7e7e3a5af772a165bdd7b0Paul Mundt IRQF_IRQPOLL | IRQF_NOBALANCING; 288d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 289d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm /* get hold of clock */ 290c2a25e819717ea34e8f682d67a3fa76f4893395bPaul Mundt p->clk = clk_get(&p->pdev->dev, "mtu2_fck"); 291d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (IS_ERR(p->clk)) { 29203ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm dev_err(&p->pdev->dev, "cannot get clock\n"); 29303ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm ret = PTR_ERR(p->clk); 29403ff858c09c81a659b2a90a08826bc0abdbb784cMagnus Damm goto err1; 295d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 296d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 297214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev), 298214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt cfg->clockevent_rating); 299d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm err1: 300d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm iounmap(p->mapbase); 301d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm err0: 302d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ret; 303d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 304d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 305d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __devinit sh_mtu2_probe(struct platform_device *pdev) 306d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 307d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm struct sh_mtu2_priv *p = platform_get_drvdata(pdev); 308d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm int ret; 30957d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki 31057d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki if (!is_early_platform_device(pdev)) 31157d13370cfaf6017c68981e66ff5b3bf20a2705cRafael J. Wysocki pm_genpd_dev_always_on(&pdev->dev, true); 312d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 313d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (p) { 314214a607a4f5bf5a14dab0304ba350cdaf3916795Paul Mundt dev_info(&pdev->dev, "kept as earlytimer\n"); 315d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return 0; 316d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 317d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 318d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm p = kmalloc(sizeof(*p), GFP_KERNEL); 319d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (p == NULL) { 320d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm dev_err(&pdev->dev, "failed to allocate driver data\n"); 321d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return -ENOMEM; 322d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 323d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 324d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm ret = sh_mtu2_setup(p, pdev); 325d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm if (ret) { 326d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm kfree(p); 327d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm platform_set_drvdata(pdev, NULL); 328d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 329d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return ret; 330d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 331d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 332d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __devexit sh_mtu2_remove(struct platform_device *pdev) 333d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 334d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return -EBUSY; /* cannot unregister clockevent */ 335d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 336d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 337d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic struct platform_driver sh_mtu2_device_driver = { 338d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm .probe = sh_mtu2_probe, 339d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm .remove = __devexit_p(sh_mtu2_remove), 340d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm .driver = { 341d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm .name = "sh_mtu2", 342d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm } 343d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm}; 344d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 345d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic int __init sh_mtu2_init(void) 346d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 347d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm return platform_driver_register(&sh_mtu2_device_driver); 348d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 349d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 350d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammstatic void __exit sh_mtu2_exit(void) 351d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm{ 352d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm platform_driver_unregister(&sh_mtu2_device_driver); 353d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm} 354d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 355d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammearly_platform_init("earlytimer", &sh_mtu2_device_driver); 356d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammmodule_init(sh_mtu2_init); 357d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Dammmodule_exit(sh_mtu2_exit); 358d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus Damm 359d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_AUTHOR("Magnus Damm"); 360d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_DESCRIPTION("SuperH MTU2 Timer Driver"); 361d5ed4c2e5ce9f5f6fd6a5a39ee1196a1f8a46eedMagnus DammMODULE_LICENSE("GPL v2"); 362