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>
38 #include <linux/gpio.h>
40 #include <asm/uaccess.h>
41 #include <asm/mach-types.h>
44 #include <plat/board.h>
52 static int tahvo_initialized
;
53 static int tahvo_irq_pin
;
54 static int tahvo_is_betty
;
56 static struct tasklet_struct tahvo_tasklet
;
57 spinlock_t tahvo_lock
= SPIN_LOCK_UNLOCKED
;
59 static struct completion device_release
;
61 struct tahvo_irq_handler_desc
{
62 int (*func
)(unsigned long);
67 static struct tahvo_irq_handler_desc tahvo_irq_handlers
[MAX_TAHVO_IRQ_HANDLERS
];
70 * tahvo_read_reg - Read a value from a register in Tahvo
71 * @reg: the register to read from
73 * This function returns the contents of the specified register
75 int tahvo_read_reg(int reg
)
77 BUG_ON(!tahvo_initialized
);
78 return cbus_read_reg(cbus_host
, TAHVO_ID
, reg
);
82 * tahvo_write_reg - Write a value to a register in Tahvo
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 tahvo_write_reg(int reg
, u16 val
)
90 BUG_ON(!tahvo_initialized
);
91 cbus_write_reg(cbus_host
, TAHVO_ID
, reg
, val
);
95 * tahvo_set_clear_reg_bits - set and clear register bits atomically
96 * @reg: the register to write to
97 * @bits: the bits to set
99 * This function sets and clears the specified Tahvo register bits atomically
101 void tahvo_set_clear_reg_bits(int reg
, u16 set
, u16 clear
)
106 spin_lock_irqsave(&tahvo_lock
, flags
);
107 w
= tahvo_read_reg(reg
);
110 tahvo_write_reg(reg
, w
);
111 spin_unlock_irqrestore(&tahvo_lock
, flags
);
115 * Disable given TAHVO interrupt
117 void tahvo_disable_irq(int id
)
122 spin_lock_irqsave(&tahvo_lock
, flags
);
123 mask
= tahvo_read_reg(TAHVO_REG_IMR
);
125 tahvo_write_reg(TAHVO_REG_IMR
, mask
);
126 spin_unlock_irqrestore(&tahvo_lock
, flags
);
130 * Enable given TAHVO interrupt
132 void tahvo_enable_irq(int id
)
137 spin_lock_irqsave(&tahvo_lock
, flags
);
138 mask
= tahvo_read_reg(TAHVO_REG_IMR
);
140 tahvo_write_reg(TAHVO_REG_IMR
, mask
);
141 spin_unlock_irqrestore(&tahvo_lock
, flags
);
145 * Acknowledge given TAHVO interrupt
147 void tahvo_ack_irq(int id
)
149 tahvo_write_reg(TAHVO_REG_IDR
, 1 << id
);
152 static int tahvo_7bit_backlight
;
154 int tahvo_get_backlight_level(void)
158 if (tahvo_7bit_backlight
)
162 return tahvo_read_reg(TAHVO_REG_LEDPWMR
) & mask
;
165 int tahvo_get_max_backlight_level(void)
167 if (tahvo_7bit_backlight
)
173 void tahvo_set_backlight_level(int level
)
177 max_level
= tahvo_get_max_backlight_level();
178 if (level
> max_level
)
180 tahvo_write_reg(TAHVO_REG_LEDPWMR
, level
);
184 * TAHVO interrupt handler. Only schedules the tasklet.
186 static irqreturn_t
tahvo_irq_handler(int irq
, void *dev_id
)
188 tasklet_schedule(&tahvo_tasklet
);
195 static void tahvo_tasklet_handler(unsigned long data
)
197 struct tahvo_irq_handler_desc
*hnd
;
203 id
= tahvo_read_reg(TAHVO_REG_IDR
);
204 im
= ~tahvo_read_reg(TAHVO_REG_IMR
);
210 for (i
= 0; id
!= 0; i
++, id
>>= 1) {
213 hnd
= &tahvo_irq_handlers
[i
];
214 if (hnd
->func
== NULL
) {
215 /* Spurious tahvo interrupt - just ack it */
216 printk(KERN_INFO
"Spurious Tahvo interrupt "
218 tahvo_disable_irq(i
);
224 * Don't acknowledge the interrupt here
225 * It must be done explicitly
232 * Register the handler for a given TAHVO interrupt source.
234 int tahvo_request_irq(int id
, void *irq_handler
, unsigned long arg
, char *name
)
236 struct tahvo_irq_handler_desc
*hnd
;
238 if (irq_handler
== NULL
|| id
>= MAX_TAHVO_IRQ_HANDLERS
||
240 printk(KERN_ERR PFX
"Invalid arguments to %s\n",
244 hnd
= &tahvo_irq_handlers
[id
];
245 if (hnd
->func
!= NULL
) {
246 printk(KERN_ERR PFX
"IRQ %d already reserved\n", id
);
249 printk(KERN_INFO PFX
"Registering interrupt %d for device %s\n",
251 hnd
->func
= irq_handler
;
253 strlcpy(hnd
->name
, name
, sizeof(hnd
->name
));
256 tahvo_enable_irq(id
);
262 * Unregister the handler for a given TAHVO interrupt source.
264 void tahvo_free_irq(int id
)
266 struct tahvo_irq_handler_desc
*hnd
;
268 if (id
>= MAX_TAHVO_IRQ_HANDLERS
) {
269 printk(KERN_ERR PFX
"Invalid argument to %s\n",
273 hnd
= &tahvo_irq_handlers
[id
];
274 if (hnd
->func
== NULL
) {
275 printk(KERN_ERR PFX
"IRQ %d already freed\n", id
);
279 tahvo_disable_irq(id
);
284 * tahvo_probe - Probe for Tahvo ASIC
285 * @dev: the Tahvo device
287 * Probe for the Tahvo ASIC and allocate memory
288 * for its device-struct if found
290 static int __devinit
tahvo_probe(struct device
*dev
)
294 /* Prepare tasklet */
295 tasklet_init(&tahvo_tasklet
, tahvo_tasklet_handler
, 0);
297 tahvo_initialized
= 1;
299 rev
= tahvo_read_reg(TAHVO_REG_ASICR
);
301 id
= (rev
>> 8) & 0xff;
303 if ((rev
& 0xff) >= 0x50)
304 tahvo_7bit_backlight
= 1;
305 } else if (id
== 0x0b) {
307 tahvo_7bit_backlight
= 1;
309 printk(KERN_ERR
"Tahvo/Betty chip not found");
313 printk(KERN_INFO
"%s v%d.%d found\n", tahvo_is_betty
? "Betty" : "Tahvo",
314 (rev
>> 4) & 0x0f, rev
& 0x0f);
316 /* REVISIT: Pass these from board-*.c files in platform_data */
317 if (machine_is_nokia770()) {
319 } else if (machine_is_nokia_n800() || machine_is_nokia_n810() ||
320 machine_is_nokia_n810_wimax()) {
323 printk(KERN_ERR
"cbus: Unsupported board for tahvo\n");
327 if ((ret
= gpio_request(tahvo_irq_pin
, "TAHVO irq")) < 0) {
328 printk(KERN_ERR PFX
"Unable to reserve IRQ GPIO\n");
332 /* Set the pin as input */
333 gpio_direction_input(tahvo_irq_pin
);
335 /* Rising edge triggers the IRQ */
336 set_irq_type(gpio_to_irq(tahvo_irq_pin
), IRQ_TYPE_EDGE_RISING
);
338 /* Mask all TAHVO interrupts */
339 tahvo_write_reg(TAHVO_REG_IMR
, 0xffff);
341 ret
= request_irq(gpio_to_irq(tahvo_irq_pin
), tahvo_irq_handler
, 0,
344 printk(KERN_ERR PFX
"Unable to register IRQ handler\n");
345 gpio_free(tahvo_irq_pin
);
348 #ifdef CONFIG_CBUS_TAHVO_USER
349 /* Initialize user-space interface */
350 if (tahvo_user_init() < 0) {
351 printk(KERN_ERR
"Unable to initialize driver\n");
352 free_irq(gpio_to_irq(tahvo_irq_pin
), 0);
353 gpio_free(tahvo_irq_pin
);
360 static int tahvo_remove(struct device
*dev
)
362 #ifdef CONFIG_CBUS_TAHVO_USER
363 tahvo_user_cleanup();
365 /* Mask all TAHVO interrupts */
366 tahvo_write_reg(TAHVO_REG_IMR
, 0xffff);
367 free_irq(gpio_to_irq(tahvo_irq_pin
), 0);
368 gpio_free(tahvo_irq_pin
);
369 tasklet_kill(&tahvo_tasklet
);
374 static void tahvo_device_release(struct device
*dev
)
376 complete(&device_release
);
379 static struct device_driver tahvo_driver
= {
381 .bus
= &platform_bus_type
,
382 .probe
= tahvo_probe
,
383 .remove
= tahvo_remove
,
386 static struct platform_device tahvo_device
= {
390 .release
= tahvo_device_release
,
395 * tahvo_init - initialise Tahvo driver
397 * Initialise the Tahvo driver and return 0 if everything worked ok
399 static int __init
tahvo_init(void)
403 printk(KERN_INFO
"Tahvo/Betty driver initialising\n");
405 init_completion(&device_release
);
407 if ((ret
= driver_register(&tahvo_driver
)) < 0)
410 if ((ret
= platform_device_register(&tahvo_device
)) < 0) {
411 driver_unregister(&tahvo_driver
);
420 static void __exit
tahvo_exit(void)
422 platform_device_unregister(&tahvo_device
);
423 driver_unregister(&tahvo_driver
);
424 wait_for_completion(&device_release
);
427 EXPORT_SYMBOL(tahvo_request_irq
);
428 EXPORT_SYMBOL(tahvo_free_irq
);
429 EXPORT_SYMBOL(tahvo_enable_irq
);
430 EXPORT_SYMBOL(tahvo_disable_irq
);
431 EXPORT_SYMBOL(tahvo_ack_irq
);
432 EXPORT_SYMBOL(tahvo_read_reg
);
433 EXPORT_SYMBOL(tahvo_write_reg
);
434 EXPORT_SYMBOL(tahvo_get_backlight_level
);
435 EXPORT_SYMBOL(tahvo_get_max_backlight_level
);
436 EXPORT_SYMBOL(tahvo_set_backlight_level
);
438 subsys_initcall(tahvo_init
);
439 module_exit(tahvo_exit
);
441 MODULE_DESCRIPTION("Tahvo ASIC control");
442 MODULE_LICENSE("GPL");
443 MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");