Ventana: KBC: Removing the KBC usage on ventana
[linux-2.6.git] / arch / arm / mach-tegra / arb_sema.c
1 /*
2  * Copyright (C) 2010, NVIDIA Corporation
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/io.h>
21 #include <linux/mutex.h>
22 #include <linux/err.h>
23 #include <linux/delay.h>
24 #include <linux/completion.h>
25
26 #include <mach/arb_sema.h>
27 #include <mach/irqs.h>
28 #include <mach/iomap.h>
29
30 #define TEGRA_RPC_MAX_SEM 32
31
32 /* arb_gnt ictrl */
33 #define ARB_CPU_INT_EN          0x4
34
35 /* arb_sema */
36 #define ARB_GRANT_STATUS        0x0
37 #define ARB_GRANT_REQUEST       0x4
38 #define ARB_GRANT_RELEASE       0x8
39 #define ARB_GRANT_PENDING       0xC
40
41 struct tegra_arb_dev {
42         void __iomem    *sema_base;
43         void __iomem    *gnt_base;
44         spinlock_t lock;
45         struct completion arb_gnt_complete[TEGRA_RPC_MAX_SEM];
46         struct mutex mutexes[TEGRA_RPC_MAX_SEM];
47         int irq;
48         int status;
49         bool suspended;
50 };
51
52 static struct tegra_arb_dev *arb;
53
54 static inline u32 arb_sema_read(u32 offset)
55 {
56         return readl(arb->sema_base + offset);
57 }
58
59 static inline void arb_sema_write(u32 value, u32 offset)
60 {
61         writel(value, arb->sema_base + offset);
62 }
63
64 static inline u32 arb_gnt_read(u32 offset)
65 {
66         return readl(arb->gnt_base + offset);
67 }
68
69 static inline void arb_gnt_write(u32 value, u32 offset)
70 {
71         writel(value, arb->gnt_base + offset);
72 }
73
74 static void request_arb_sem(enum tegra_arb_module lock)
75 {
76         unsigned long flags;
77         u32 value;
78
79         spin_lock_irqsave(&arb->lock, flags);
80
81         arb_sema_write(1 << lock, ARB_GRANT_REQUEST);
82         value = arb_gnt_read(ARB_CPU_INT_EN);
83         value |= (1 << lock);
84         arb_gnt_write(value, ARB_CPU_INT_EN);
85
86         spin_unlock_irqrestore(&arb->lock, flags);
87 }
88
89 static void cancel_arb_sem(enum tegra_arb_module lock)
90 {
91         unsigned long flags;
92         u32 value;
93
94         spin_lock_irqsave(&arb->lock, flags);
95
96         arb_sema_write(1 << lock, ARB_GRANT_RELEASE);
97         value = arb_gnt_read(ARB_CPU_INT_EN);
98         value &= ~(1 << lock);
99         arb_gnt_write(value, ARB_CPU_INT_EN);
100
101         spin_unlock_irqrestore(&arb->lock, flags);
102 }
103
104 int tegra_arb_mutex_lock_timeout(enum tegra_arb_module lock, int msecs)
105 {
106         int ret;
107
108         if (!arb)
109                 return -ENODEV;
110
111         if (arb->suspended) {
112                 pr_err("device in suspend\n");
113                 return -ETIMEDOUT;
114         }
115
116         mutex_lock(&arb->mutexes[lock]);
117         INIT_COMPLETION(arb->arb_gnt_complete[lock]);
118         request_arb_sem(lock);
119         ret = wait_for_completion_timeout(&arb->arb_gnt_complete[lock], msecs_to_jiffies(msecs));
120         if (ret == 0) {
121                 pr_err("timed out. pending:0x%x\n", arb_sema_read(ARB_GRANT_PENDING));
122                 cancel_arb_sem(lock);
123                 mutex_unlock(&arb->mutexes[lock]);
124                 return -ETIMEDOUT;
125         }
126
127         return 0;
128 }
129 EXPORT_SYMBOL(tegra_arb_mutex_lock_timeout);
130
131 int tegra_arb_mutex_unlock(enum tegra_arb_module lock)
132 {
133         if (!arb)
134                 return -ENODEV;
135
136         if (arb->suspended) {
137                 pr_err("device in suspend\n");
138                 return -ETIMEDOUT;
139         }
140
141         cancel_arb_sem(lock);
142         mutex_unlock(&arb->mutexes[lock]);
143         return 0;
144 }
145 EXPORT_SYMBOL(tegra_arb_mutex_unlock);
146
147 static irqreturn_t arb_gnt_isr(int irq, void *dev_id)
148 {
149         struct tegra_arb_dev *dev = dev_id;
150         unsigned long status;
151         u32 cpu_int_en;
152         unsigned int bit;
153         unsigned long flags;
154
155         spin_lock_irqsave(&arb->lock, flags);
156
157         status = arb_sema_read(ARB_GRANT_STATUS);
158         pr_debug("%s: 0x%lx\n", __func__, status);
159
160         /* disable the arb semaphores which were signalled */
161         cpu_int_en = arb_gnt_read(ARB_CPU_INT_EN);
162         arb_gnt_write((cpu_int_en & ~(status & cpu_int_en)),
163                 ARB_CPU_INT_EN);
164
165         status &= cpu_int_en;
166         for_each_set_bit(bit, &status, BITS_PER_LONG)
167                 complete(&dev->arb_gnt_complete[bit]);
168
169         spin_unlock_irqrestore(&arb->lock, flags);
170         return IRQ_HANDLED;
171 }
172
173 int tegra_arb_suspend(void)
174 {
175         unsigned long status = arb_sema_read(ARB_GRANT_STATUS);
176
177         if (WARN_ON(status != 0)) {
178                 pr_err("%s: suspending while holding arbitration "
179                        "semaphore: %08lx\n", __func__, status);
180         }
181         arb->suspended = true;
182
183         return status ? -EBUSY : 0;
184 }
185
186 int tegra_arb_resume(void)
187 {
188         arb->suspended = false;
189         return 0;
190 }
191
192 static int __init tegra_arb_init(void)
193 {
194         struct tegra_arb_dev *dev = NULL;
195         int err, i;
196
197         dev = kzalloc(sizeof(struct tegra_arb_dev), GFP_KERNEL);
198         if (dev == NULL) {
199                 pr_err("%s: unable to alloc data struct.\n", __func__);
200                 return -ENOMEM;
201         }
202
203         for (i = 0; i < TEGRA_RPC_MAX_SEM; i++) {
204                 mutex_init(&dev->mutexes[i]);
205                 init_completion(&dev->arb_gnt_complete[i]);
206         }
207
208         dev->sema_base = IO_ADDRESS(TEGRA_ARB_SEMA_BASE);
209         if (!dev->sema_base) {
210                 pr_err("%s: can't get arb sema_base\n", __func__);
211                 err = -ENOMEM;
212                 goto out;
213         }
214
215         dev->gnt_base = IO_ADDRESS(TEGRA_ARBGNT_ICTLR_BASE);
216         if (!dev->gnt_base) {
217                 pr_err("%s: can't ioremap gnt_base\n", __func__);
218                 err = -ENOMEM;
219                 goto out;
220         }
221
222         dev->irq = INT_GNT_1;
223         err = request_irq(dev->irq, arb_gnt_isr, 0, "rpc-arbsema", dev);
224         if (err) {
225                 pr_err("%s: request_irq(%d) failed(%d)\n", __func__,
226                         dev->irq, err);
227                 goto out;
228         }
229
230         spin_lock_init(&dev->lock);
231         arb = dev;
232
233         pr_info("%s: initialized\n", __func__);
234         return 0;
235
236 out:
237         kfree(dev);
238         pr_err("%s: initialization failed.\n", __func__);
239         return err;
240 }
241 subsys_initcall(tegra_arb_init);
242
243 MODULE_LICENSE("GPLv2");