4 * Support functions for Tahvo 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>
35 #include <linux/irq.h>
36 #include <linux/interrupt.h>
37 #include <linux/platform_device.h>
39 #include <asm/uaccess.h>
41 #include <asm/arch/mux.h>
42 #include <asm/arch/gpio.h>
43 #include <asm/arch/board.h>
51 static int tahvo_initialized;
52 static int tahvo_irq_pin;
53 static int tahvo_is_betty;
55 static struct tasklet_struct tahvo_tasklet;
56 spinlock_t tahvo_lock = SPIN_LOCK_UNLOCKED;
58 static struct completion device_release;
60 struct tahvo_irq_handler_desc {
61 int (*func)(unsigned long);
66 static struct tahvo_irq_handler_desc tahvo_irq_handlers[MAX_TAHVO_IRQ_HANDLERS];
69 * tahvo_read_reg - Read a value from a register in Tahvo
70 * @reg: the register to read from
72 * This function returns the contents of the specified register
74 int tahvo_read_reg(int reg)
76 BUG_ON(!tahvo_initialized);
77 return cbus_read_reg(cbus_host, TAHVO_ID, reg);
81 * tahvo_write_reg - Write a value to a register in Tahvo
82 * @reg: the register to write to
83 * @reg: the value to write to the register
85 * This function writes a value to the specified register
87 void tahvo_write_reg(int reg, u16 val)
89 BUG_ON(!tahvo_initialized);
90 cbus_write_reg(cbus_host, TAHVO_ID, reg, val);
94 * tahvo_set_clear_reg_bits - set and clear register bits atomically
95 * @reg: the register to write to
96 * @bits: the bits to set
98 * This function sets and clears the specified Tahvo register bits atomically
100 void tahvo_set_clear_reg_bits(int reg, u16 set, u16 clear)
105 spin_lock_irqsave(&tahvo_lock, flags);
106 w = tahvo_read_reg(reg);
109 tahvo_write_reg(reg, w);
110 spin_unlock_irqrestore(&tahvo_lock, flags);
114 * Disable given TAHVO interrupt
116 void tahvo_disable_irq(int id)
121 spin_lock_irqsave(&tahvo_lock, flags);
122 mask = tahvo_read_reg(TAHVO_REG_IMR);
124 tahvo_write_reg(TAHVO_REG_IMR, mask);
125 spin_unlock_irqrestore(&tahvo_lock, flags);
129 * Enable given TAHVO interrupt
131 void tahvo_enable_irq(int id)
136 spin_lock_irqsave(&tahvo_lock, flags);
137 mask = tahvo_read_reg(TAHVO_REG_IMR);
139 tahvo_write_reg(TAHVO_REG_IMR, mask);
140 spin_unlock_irqrestore(&tahvo_lock, flags);
144 * Acknowledge given TAHVO interrupt
146 void tahvo_ack_irq(int id)
148 tahvo_write_reg(TAHVO_REG_IDR, 1 << id);
151 static int tahvo_7bit_backlight;
153 int tahvo_get_backlight_level(void)
157 if (tahvo_7bit_backlight)
161 return tahvo_read_reg(TAHVO_REG_LEDPWMR) & mask;
164 int tahvo_get_max_backlight_level(void)
166 if (tahvo_7bit_backlight)
172 void tahvo_set_backlight_level(int level)
176 max_level = tahvo_get_max_backlight_level();
177 if (level > max_level)
179 tahvo_write_reg(TAHVO_REG_LEDPWMR, level);
183 * TAHVO interrupt handler. Only schedules the tasklet.
185 static irqreturn_t tahvo_irq_handler(int irq, void *dev_id)
187 tasklet_schedule(&tahvo_tasklet);
194 static void tahvo_tasklet_handler(unsigned long data)
196 struct tahvo_irq_handler_desc *hnd;
202 id = tahvo_read_reg(TAHVO_REG_IDR);
203 im = ~tahvo_read_reg(TAHVO_REG_IMR);
209 for (i = 0; id != 0; i++, id >>= 1) {
212 hnd = &tahvo_irq_handlers[i];
213 if (hnd->func == NULL) {
214 /* Spurious tahvo interrupt - just ack it */
215 printk(KERN_INFO "Spurious Tahvo interrupt "
217 tahvo_disable_irq(i);
223 * Don't acknowledge the interrupt here
224 * It must be done explicitly
231 * Register the handler for a given TAHVO interrupt source.
233 int tahvo_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
235 struct tahvo_irq_handler_desc *hnd;
237 if (irq_handler == NULL || id >= MAX_TAHVO_IRQ_HANDLERS ||
239 printk(KERN_ERR PFX "Invalid arguments to %s\n",
243 hnd = &tahvo_irq_handlers[id];
244 if (hnd->func != NULL) {
245 printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
248 printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
250 hnd->func = irq_handler;
252 strlcpy(hnd->name, name, sizeof(hnd->name));
255 tahvo_enable_irq(id);
261 * Unregister the handler for a given TAHVO interrupt source.
263 void tahvo_free_irq(int id)
265 struct tahvo_irq_handler_desc *hnd;
267 if (id >= MAX_TAHVO_IRQ_HANDLERS) {
268 printk(KERN_ERR PFX "Invalid argument to %s\n",
272 hnd = &tahvo_irq_handlers[id];
273 if (hnd->func == NULL) {
274 printk(KERN_ERR PFX "IRQ %d already freed\n", id);
278 tahvo_disable_irq(id);
283 * tahvo_probe - Probe for Tahvo ASIC
284 * @dev: the Tahvo device
286 * Probe for the Tahvo ASIC and allocate memory
287 * for its device-struct if found
289 static int __devinit tahvo_probe(struct device *dev)
291 const struct omap_em_asic_bb5_config * em_asic_config;
294 /* Prepare tasklet */
295 tasklet_init(&tahvo_tasklet, tahvo_tasklet_handler, 0);
297 em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
298 struct omap_em_asic_bb5_config);
299 if (em_asic_config == NULL) {
300 printk(KERN_ERR PFX "Unable to retrieve config data\n");
304 tahvo_initialized = 1;
306 rev = tahvo_read_reg(TAHVO_REG_ASICR);
308 id = (rev >> 8) & 0xff;
310 if ((rev & 0xff) >= 0x50)
311 tahvo_7bit_backlight = 1;
312 } else if (id == 0x0b) {
314 tahvo_7bit_backlight = 1;
316 printk(KERN_ERR "Tahvo/Betty chip not found");
320 printk(KERN_INFO "%s v%d.%d found\n", tahvo_is_betty ? "Betty" : "Tahvo",
321 (rev >> 4) & 0x0f, rev & 0x0f);
323 tahvo_irq_pin = em_asic_config->tahvo_irq_gpio;
325 if ((ret = omap_request_gpio(tahvo_irq_pin)) < 0) {
326 printk(KERN_ERR PFX "Unable to reserve IRQ GPIO\n");
330 /* Set the pin as input */
331 omap_set_gpio_direction(tahvo_irq_pin, 1);
333 /* Rising edge triggers the IRQ */
334 set_irq_type(OMAP_GPIO_IRQ(tahvo_irq_pin), IRQT_RISING);
336 /* Mask all TAHVO interrupts */
337 tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
339 ret = request_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), tahvo_irq_handler, 0,
342 printk(KERN_ERR PFX "Unable to register IRQ handler\n");
343 omap_free_gpio(tahvo_irq_pin);
346 #ifdef CONFIG_CBUS_TAHVO_USER
347 /* Initialize user-space interface */
348 if (tahvo_user_init() < 0) {
349 printk(KERN_ERR "Unable to initialize driver\n");
350 free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
351 omap_free_gpio(tahvo_irq_pin);
358 static int tahvo_remove(struct device *dev)
360 #ifdef CONFIG_CBUS_TAHVO_USER
361 tahvo_user_cleanup();
363 /* Mask all TAHVO interrupts */
364 tahvo_write_reg(TAHVO_REG_IMR, 0xffff);
365 free_irq(OMAP_GPIO_IRQ(tahvo_irq_pin), 0);
366 omap_free_gpio(tahvo_irq_pin);
367 tasklet_kill(&tahvo_tasklet);
372 static void tahvo_device_release(struct device *dev)
374 complete(&device_release);
377 static struct device_driver tahvo_driver = {
379 .bus = &platform_bus_type,
380 .probe = tahvo_probe,
381 .remove = tahvo_remove,
384 static struct platform_device tahvo_device = {
388 .release = tahvo_device_release,
393 * tahvo_init - initialise Tahvo driver
395 * Initialise the Tahvo driver and return 0 if everything worked ok
397 static int __init tahvo_init(void)
401 printk(KERN_INFO "Tahvo/Betty driver initialising\n");
403 init_completion(&device_release);
405 if ((ret = driver_register(&tahvo_driver)) < 0)
408 if ((ret = platform_device_register(&tahvo_device)) < 0) {
409 driver_unregister(&tahvo_driver);
418 static void __exit tahvo_exit(void)
420 platform_device_unregister(&tahvo_device);
421 driver_unregister(&tahvo_driver);
422 wait_for_completion(&device_release);
425 EXPORT_SYMBOL(tahvo_request_irq);
426 EXPORT_SYMBOL(tahvo_free_irq);
427 EXPORT_SYMBOL(tahvo_enable_irq);
428 EXPORT_SYMBOL(tahvo_disable_irq);
429 EXPORT_SYMBOL(tahvo_ack_irq);
430 EXPORT_SYMBOL(tahvo_read_reg);
431 EXPORT_SYMBOL(tahvo_write_reg);
432 EXPORT_SYMBOL(tahvo_get_backlight_level);
433 EXPORT_SYMBOL(tahvo_get_max_backlight_level);
434 EXPORT_SYMBOL(tahvo_set_backlight_level);
436 subsys_initcall(tahvo_init);
437 module_exit(tahvo_exit);
439 MODULE_DESCRIPTION("Tahvo ASIC control");
440 MODULE_LICENSE("GPL");
441 MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");