~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/bcm63xx/timer.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * This file is subject to the terms and conditions of the GNU General Public
  3  * License.  See the file "COPYING" in the main directory of this archive
  4  * for more details.
  5  *
  6  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  7  */
  8 
  9 #include <linux/kernel.h>
 10 #include <linux/err.h>
 11 #include <linux/init.h>
 12 #include <linux/export.h>
 13 #include <linux/spinlock.h>
 14 #include <linux/interrupt.h>
 15 #include <linux/clk.h>
 16 #include <bcm63xx_cpu.h>
 17 #include <bcm63xx_io.h>
 18 #include <bcm63xx_timer.h>
 19 #include <bcm63xx_regs.h>
 20 
 21 static DEFINE_RAW_SPINLOCK(timer_reg_lock);
 22 static DEFINE_RAW_SPINLOCK(timer_data_lock);
 23 static struct clk *periph_clk;
 24 
 25 static struct timer_data {
 26         void    (*cb)(void *);
 27         void    *data;
 28 } timer_data[BCM63XX_TIMER_COUNT];
 29 
 30 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 31 {
 32         u32 stat;
 33         int i;
 34 
 35         raw_spin_lock(&timer_reg_lock);
 36         stat = bcm_timer_readl(TIMER_IRQSTAT_REG);
 37         bcm_timer_writel(stat, TIMER_IRQSTAT_REG);
 38         raw_spin_unlock(&timer_reg_lock);
 39 
 40         for (i = 0; i < BCM63XX_TIMER_COUNT; i++) {
 41                 if (!(stat & TIMER_IRQSTAT_TIMER_CAUSE(i)))
 42                         continue;
 43 
 44                 raw_spin_lock(&timer_data_lock);
 45                 if (!timer_data[i].cb) {
 46                         raw_spin_unlock(&timer_data_lock);
 47                         continue;
 48                 }
 49 
 50                 timer_data[i].cb(timer_data[i].data);
 51                 raw_spin_unlock(&timer_data_lock);
 52         }
 53 
 54         return IRQ_HANDLED;
 55 }
 56 
 57 int bcm63xx_timer_enable(int id)
 58 {
 59         u32 reg;
 60         unsigned long flags;
 61 
 62         if (id >= BCM63XX_TIMER_COUNT)
 63                 return -EINVAL;
 64 
 65         raw_spin_lock_irqsave(&timer_reg_lock, flags);
 66 
 67         reg = bcm_timer_readl(TIMER_CTLx_REG(id));
 68         reg |= TIMER_CTL_ENABLE_MASK;
 69         bcm_timer_writel(reg, TIMER_CTLx_REG(id));
 70 
 71         reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
 72         reg |= TIMER_IRQSTAT_TIMER_IR_EN(id);
 73         bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
 74 
 75         raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
 76         return 0;
 77 }
 78 
 79 EXPORT_SYMBOL(bcm63xx_timer_enable);
 80 
 81 int bcm63xx_timer_disable(int id)
 82 {
 83         u32 reg;
 84         unsigned long flags;
 85 
 86         if (id >= BCM63XX_TIMER_COUNT)
 87                 return -EINVAL;
 88 
 89         raw_spin_lock_irqsave(&timer_reg_lock, flags);
 90 
 91         reg = bcm_timer_readl(TIMER_CTLx_REG(id));
 92         reg &= ~TIMER_CTL_ENABLE_MASK;
 93         bcm_timer_writel(reg, TIMER_CTLx_REG(id));
 94 
 95         reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
 96         reg &= ~TIMER_IRQSTAT_TIMER_IR_EN(id);
 97         bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
 98 
 99         raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
100         return 0;
101 }
102 
103 EXPORT_SYMBOL(bcm63xx_timer_disable);
104 
105 int bcm63xx_timer_register(int id, void (*callback)(void *data), void *data)
106 {
107         unsigned long flags;
108         int ret;
109 
110         if (id >= BCM63XX_TIMER_COUNT || !callback)
111                 return -EINVAL;
112 
113         ret = 0;
114         raw_spin_lock_irqsave(&timer_data_lock, flags);
115         if (timer_data[id].cb) {
116                 ret = -EBUSY;
117                 goto out;
118         }
119 
120         timer_data[id].cb = callback;
121         timer_data[id].data = data;
122 
123 out:
124         raw_spin_unlock_irqrestore(&timer_data_lock, flags);
125         return ret;
126 }
127 
128 EXPORT_SYMBOL(bcm63xx_timer_register);
129 
130 void bcm63xx_timer_unregister(int id)
131 {
132         unsigned long flags;
133 
134         if (id >= BCM63XX_TIMER_COUNT)
135                 return;
136 
137         raw_spin_lock_irqsave(&timer_data_lock, flags);
138         timer_data[id].cb = NULL;
139         raw_spin_unlock_irqrestore(&timer_data_lock, flags);
140 }
141 
142 EXPORT_SYMBOL(bcm63xx_timer_unregister);
143 
144 unsigned int bcm63xx_timer_countdown(unsigned int countdown_us)
145 {
146         return (clk_get_rate(periph_clk) / (1000 * 1000)) * countdown_us;
147 }
148 
149 EXPORT_SYMBOL(bcm63xx_timer_countdown);
150 
151 int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us)
152 {
153         u32 reg, countdown;
154         unsigned long flags;
155 
156         if (id >= BCM63XX_TIMER_COUNT)
157                 return -EINVAL;
158 
159         countdown = bcm63xx_timer_countdown(countdown_us);
160         if (countdown & ~TIMER_CTL_COUNTDOWN_MASK)
161                 return -EINVAL;
162 
163         raw_spin_lock_irqsave(&timer_reg_lock, flags);
164         reg = bcm_timer_readl(TIMER_CTLx_REG(id));
165 
166         if (monotonic)
167                 reg &= ~TIMER_CTL_MONOTONIC_MASK;
168         else
169                 reg |= TIMER_CTL_MONOTONIC_MASK;
170 
171         reg &= ~TIMER_CTL_COUNTDOWN_MASK;
172         reg |= countdown;
173         bcm_timer_writel(reg, TIMER_CTLx_REG(id));
174 
175         raw_spin_unlock_irqrestore(&timer_reg_lock, flags);
176         return 0;
177 }
178 
179 EXPORT_SYMBOL(bcm63xx_timer_set);
180 
181 static int bcm63xx_timer_init(void)
182 {
183         int ret, irq;
184         u32 reg;
185 
186         reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
187         reg &= ~TIMER_IRQSTAT_TIMER0_IR_EN;
188         reg &= ~TIMER_IRQSTAT_TIMER1_IR_EN;
189         reg &= ~TIMER_IRQSTAT_TIMER2_IR_EN;
190         bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
191 
192         periph_clk = clk_get(NULL, "periph");
193         if (IS_ERR(periph_clk))
194                 return -ENODEV;
195 
196         irq = bcm63xx_get_irq_number(IRQ_TIMER);
197         ret = request_irq(irq, timer_interrupt, 0, "bcm63xx_timer", NULL);
198         if (ret) {
199                 pr_err("%s: failed to register irq\n", __func__);
200                 return ret;
201         }
202 
203         return 0;
204 }
205 
206 arch_initcall(bcm63xx_timer_init);
207 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php