OMAP3: PM: CPUfreq support for OMAP3EVM board
[linux-ginger.git] / drivers / cbus / retu.c
blob39493fb0980ffeac134ace968f4a82a7bac042c1
1 /**
2 * drivers/cbus/retu.c
4 * Support functions for Retu ASIC
6 * Copyright (C) 2004, 2005 Nokia Corporation
8 * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
9 * David Weinehall <david.weinehall@nokia.com>, and
10 * Mikko Ylinen <mikko.k.ylinen@nokia.com>
12 * This file is subject to the terms and conditions of the GNU General
13 * Public License. See the file "COPYING" in the main directory of this
14 * archive for more details.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <linux/module.h>
27 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/device.h>
32 #include <linux/miscdevice.h>
33 #include <linux/poll.h>
34 #include <linux/fs.h>
35 #include <linux/irq.h>
36 #include <linux/interrupt.h>
37 #include <linux/platform_device.h>
38 #include <linux/gpio.h>
40 #include <asm/uaccess.h>
41 #include <asm/mach-types.h>
43 #include <plat/mux.h>
44 #include <plat/board.h>
46 #include "cbus.h"
47 #include "retu.h"
49 #define RETU_ID 0x01
50 #define PFX "retu: "
52 static int retu_initialized;
53 static int retu_irq_pin;
54 static int retu_is_vilma;
56 static struct tasklet_struct retu_tasklet;
57 spinlock_t retu_lock = SPIN_LOCK_UNLOCKED;
59 static struct completion device_release;
61 struct retu_irq_handler_desc {
62 int (*func)(unsigned long);
63 unsigned long arg;
64 char name[8];
67 static struct retu_irq_handler_desc retu_irq_handlers[MAX_RETU_IRQ_HANDLERS];
69 /**
70 * retu_read_reg - Read a value from a register in Retu
71 * @reg: the register to read from
73 * This function returns the contents of the specified register
75 int retu_read_reg(int reg)
77 BUG_ON(!retu_initialized);
78 return cbus_read_reg(cbus_host, RETU_ID, reg);
81 /**
82 * retu_write_reg - Write a value to a register in Retu
83 * @reg: the register to write to
84 * @reg: the value to write to the register
86 * This function writes a value to the specified register
88 void retu_write_reg(int reg, u16 val)
90 BUG_ON(!retu_initialized);
91 cbus_write_reg(cbus_host, RETU_ID, reg, val);
94 void retu_set_clear_reg_bits(int reg, u16 set, u16 clear)
96 unsigned long flags;
97 u16 w;
99 spin_lock_irqsave(&retu_lock, flags);
100 w = retu_read_reg(reg);
101 w &= ~clear;
102 w |= set;
103 retu_write_reg(reg, w);
104 spin_unlock_irqrestore(&retu_lock, flags);
107 #define ADC_MAX_CHAN_NUMBER 13
109 int retu_read_adc(int channel)
111 unsigned long flags;
112 int res;
114 if (channel < 0 || channel > ADC_MAX_CHAN_NUMBER)
115 return -EINVAL;
117 spin_lock_irqsave(&retu_lock, flags);
119 if ((channel == 8) && retu_is_vilma) {
120 int scr = retu_read_reg(RETU_REG_ADCSCR);
121 int ch = (retu_read_reg(RETU_REG_ADCR) >> 10) & 0xf;
122 if (((scr & 0xff) != 0) && (ch != 8))
123 retu_write_reg (RETU_REG_ADCSCR, (scr & ~0xff));
126 /* Select the channel and read result */
127 retu_write_reg(RETU_REG_ADCR, channel << 10);
128 res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
130 if (retu_is_vilma)
131 retu_write_reg(RETU_REG_ADCR, (1 << 13));
133 /* Unlock retu */
134 spin_unlock_irqrestore(&retu_lock, flags);
136 return res;
140 static u16 retu_disable_bogus_irqs(u16 mask)
142 int i;
144 for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
145 if (mask & (1 << i))
146 continue;
147 if (retu_irq_handlers[i].func != NULL)
148 continue;
149 /* an IRQ was enabled but we don't have a handler for it */
150 printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
151 mask |= (1 << i);
153 return mask;
157 * Disable given RETU interrupt
159 void retu_disable_irq(int id)
161 unsigned long flags;
162 u16 mask;
164 spin_lock_irqsave(&retu_lock, flags);
165 mask = retu_read_reg(RETU_REG_IMR);
166 mask |= 1 << id;
167 mask = retu_disable_bogus_irqs(mask);
168 retu_write_reg(RETU_REG_IMR, mask);
169 spin_unlock_irqrestore(&retu_lock, flags);
173 * Enable given RETU interrupt
175 void retu_enable_irq(int id)
177 unsigned long flags;
178 u16 mask;
180 if (id == 3) {
181 printk("Enabling Retu IRQ %d\n", id);
182 dump_stack();
184 spin_lock_irqsave(&retu_lock, flags);
185 mask = retu_read_reg(RETU_REG_IMR);
186 mask &= ~(1 << id);
187 mask = retu_disable_bogus_irqs(mask);
188 retu_write_reg(RETU_REG_IMR, mask);
189 spin_unlock_irqrestore(&retu_lock, flags);
193 * Acknowledge given RETU interrupt
195 void retu_ack_irq(int id)
197 retu_write_reg(RETU_REG_IDR, 1 << id);
201 * RETU interrupt handler. Only schedules the tasklet.
203 static irqreturn_t retu_irq_handler(int irq, void *dev_id)
205 tasklet_schedule(&retu_tasklet);
206 return IRQ_HANDLED;
210 * Tasklet handler
212 static void retu_tasklet_handler(unsigned long data)
214 struct retu_irq_handler_desc *hnd;
215 u16 id;
216 u16 im;
217 int i;
219 for (;;) {
220 id = retu_read_reg(RETU_REG_IDR);
221 im = ~retu_read_reg(RETU_REG_IMR);
222 id &= im;
224 if (!id)
225 break;
227 for (i = 0; id != 0; i++, id >>= 1) {
228 if (!(id & 1))
229 continue;
230 hnd = &retu_irq_handlers[i];
231 if (hnd->func == NULL) {
232 /* Spurious retu interrupt - disable and ack it */
233 printk(KERN_INFO "Spurious Retu interrupt "
234 "(id %d)\n", i);
235 retu_disable_irq(i);
236 retu_ack_irq(i);
237 continue;
239 hnd->func(hnd->arg);
241 * Don't acknowledge the interrupt here
242 * It must be done explicitly
249 * Register the handler for a given RETU interrupt source.
251 int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
253 struct retu_irq_handler_desc *hnd;
255 if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
256 name == NULL) {
257 printk(KERN_ERR PFX "Invalid arguments to %s\n",
258 __FUNCTION__);
259 return -EINVAL;
261 hnd = &retu_irq_handlers[id];
262 if (hnd->func != NULL) {
263 printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
264 return -EBUSY;
266 printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
267 id, name);
268 hnd->func = irq_handler;
269 hnd->arg = arg;
270 strlcpy(hnd->name, name, sizeof(hnd->name));
272 retu_ack_irq(id);
273 retu_enable_irq(id);
275 return 0;
279 * Unregister the handler for a given RETU interrupt source.
281 void retu_free_irq(int id)
283 struct retu_irq_handler_desc *hnd;
285 if (id >= MAX_RETU_IRQ_HANDLERS) {
286 printk(KERN_ERR PFX "Invalid argument to %s\n",
287 __FUNCTION__);
288 return;
290 hnd = &retu_irq_handlers[id];
291 if (hnd->func == NULL) {
292 printk(KERN_ERR PFX "IRQ %d already freed\n", id);
293 return;
296 retu_disable_irq(id);
297 hnd->func = NULL;
301 * retu_power_off - Shut down power to system
303 * This function puts the system in power off state
305 static void retu_power_off(void)
307 /* Ignore power button state */
308 retu_write_reg(RETU_REG_CC1, retu_read_reg(RETU_REG_CC1) | 2);
309 /* Expire watchdog immediately */
310 retu_write_reg(RETU_REG_WATCHDOG, 0);
311 /* Wait for poweroff*/
312 for (;;);
316 * retu_probe - Probe for Retu ASIC
317 * @dev: the Retu device
319 * Probe for the Retu ASIC and allocate memory
320 * for its device-struct if found
322 static int __devinit retu_probe(struct device *dev)
324 int rev, ret;
326 /* Prepare tasklet */
327 tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
329 /* REVISIT: Pass these from board-*.c files in platform_data */
330 if (machine_is_nokia770()) {
331 retu_irq_pin = 62;
332 } else if (machine_is_nokia_n800() || machine_is_nokia_n810() ||
333 machine_is_nokia_n810_wimax()) {
334 retu_irq_pin = 108;
335 } else {
336 printk(KERN_ERR "cbus: Unsupported board for tahvo\n");
337 return -ENODEV;
340 if ((ret = gpio_request(retu_irq_pin, "RETU irq")) < 0) {
341 printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
342 return ret;
345 /* Set the pin as input */
346 gpio_direction_input(retu_irq_pin);
348 /* Rising edge triggers the IRQ */
349 set_irq_type(gpio_to_irq(retu_irq_pin), IRQ_TYPE_EDGE_RISING);
351 retu_initialized = 1;
353 rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
354 if (rev & (1 << 7))
355 retu_is_vilma = 1;
357 printk(KERN_INFO "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
358 (rev >> 4) & 0x07, rev & 0x0f);
360 /* Mask all RETU interrupts */
361 retu_write_reg(RETU_REG_IMR, 0xffff);
363 ret = request_irq(gpio_to_irq(retu_irq_pin), retu_irq_handler, 0,
364 "retu", 0);
365 if (ret < 0) {
366 printk(KERN_ERR PFX "Unable to register IRQ handler\n");
367 gpio_free(retu_irq_pin);
368 return ret;
370 set_irq_wake(gpio_to_irq(retu_irq_pin), 1);
372 /* Register power off function */
373 pm_power_off = retu_power_off;
375 #ifdef CONFIG_CBUS_RETU_USER
376 /* Initialize user-space interface */
377 if (retu_user_init() < 0) {
378 printk(KERN_ERR "Unable to initialize driver\n");
379 free_irq(gpio_to_irq(retu_irq_pin), 0);
380 gpio_free(retu_irq_pin);
381 return ret;
383 #endif
385 return 0;
388 static int retu_remove(struct device *dev)
390 #ifdef CONFIG_CBUS_RETU_USER
391 retu_user_cleanup();
392 #endif
393 /* Mask all RETU interrupts */
394 retu_write_reg(RETU_REG_IMR, 0xffff);
395 free_irq(gpio_to_irq(retu_irq_pin), 0);
396 gpio_free(retu_irq_pin);
397 tasklet_kill(&retu_tasklet);
399 return 0;
402 static void retu_device_release(struct device *dev)
404 complete(&device_release);
407 static struct device_driver retu_driver = {
408 .name = "retu",
409 .bus = &platform_bus_type,
410 .probe = retu_probe,
411 .remove = retu_remove,
414 static struct platform_device retu_device = {
415 .name = "retu",
416 .id = -1,
417 .dev = {
418 .release = retu_device_release,
423 * retu_init - initialise Retu driver
425 * Initialise the Retu driver and return 0 if everything worked ok
427 static int __init retu_init(void)
429 int ret = 0;
431 printk(KERN_INFO "Retu/Vilma driver initialising\n");
433 init_completion(&device_release);
435 if ((ret = driver_register(&retu_driver)) < 0)
436 return ret;
438 if ((ret = platform_device_register(&retu_device)) < 0) {
439 driver_unregister(&retu_driver);
440 return ret;
442 return 0;
446 * Cleanup
448 static void __exit retu_exit(void)
450 platform_device_unregister(&retu_device);
451 driver_unregister(&retu_driver);
452 wait_for_completion(&device_release);
455 EXPORT_SYMBOL(retu_request_irq);
456 EXPORT_SYMBOL(retu_free_irq);
457 EXPORT_SYMBOL(retu_enable_irq);
458 EXPORT_SYMBOL(retu_disable_irq);
459 EXPORT_SYMBOL(retu_ack_irq);
460 EXPORT_SYMBOL(retu_read_reg);
461 EXPORT_SYMBOL(retu_write_reg);
463 subsys_initcall(retu_init);
464 module_exit(retu_exit);
466 MODULE_DESCRIPTION("Retu ASIC control");
467 MODULE_LICENSE("GPL");
468 MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");