/* * linux/drivers/mfd/ucb1x00-switches.c * * Copyright (C) 2007 Bernhard Guillon. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This driver is for the Switches of Siemens SIMpad (CL4,SL4,SLC), T-Sinus-Pad and * Swisscom WP50 devices. * * Six switches are routed to GPIO pins on the UCB1300: S3 -- S8. * * This driver is based on the 2.4 ucb1x00-switches, the 2.6 ucb1x00-assabet * and the ucb1x00-ts driver. * */ #include #include #include #include #include #include "ucb1x00.h" struct ucb1x00_switches { struct input_dev *idev; struct ucb1x00 *ucb; }; static void ucb1x00_dev_irq(int idx, void *id) { //int i; static unsigned short int last; unsigned short int this; struct ucb1x00_switches *switches = id; struct input_dev *idev = switches->idev; ucb1x00_enable(switches->ucb); this=~ucb1x00_io_read(switches->ucb); if (this==last) { return; } last=this; printk(KERN_DEBUG "switches->idev->name in ucb1x00_dev_irq: %s \n", switches->idev->name); switch (idx) { case 0: if ((this & (1<<0)) != 0) { /* for (i=0;iucb, UCB_IRQ_TSPX, UCB_FALLING); } static int ucb1x00_switches_add(struct ucb1x00_dev *dev) { struct ucb1x00_switches *switches; struct input_dev *idev; int err,i; switches = kzalloc(sizeof(struct ucb1x00_switches), GFP_KERNEL); idev = input_allocate_device(); if (!switches || !idev) { err = -ENOMEM; goto fail; } switches->ucb = dev->ucb; idev->private = switches; idev->name = "SIMpad Switches"; idev->id.product = switches->ucb->id; idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); /* this should be right but is not set_bit(148, idev->evbit); set_bit(149, idev->evbit); set_bit(103, idev->evbit); set_bit(108, idev->evbit); set_bit(105, idev->evbit); set_bit(106, idev->evbit); */ // this is -32 why the f..k? set_bit(180, idev->evbit); set_bit(181, idev->evbit); set_bit(135, idev->evbit); set_bit(140, idev->evbit); set_bit(137, idev->evbit); set_bit(138, idev->evbit); err = input_register_device(idev); if (err) goto fail; switches->idev = idev; printk(KERN_DEBUG "switches->idev->name: %s \n", switches->idev->name); dev->priv = switches; ucb1x00_enable(switches->ucb); ucb1x00_io_set_dir(switches->ucb, UCB_IO_0 | UCB_IO_1 | UCB_IO_2 | UCB_IO_3 | UCB_IO_4 | UCB_IO_5, UCB_IO_8 | UCB_IO_9); ucb1x00_disable(switches->ucb); for (i = 0; i < 6; ++i) { ucb1x00_enable_irq(switches->ucb, i, UCB_RISING | UCB_FALLING); if (ucb1x00_hook_irq(switches->ucb, i, ucb1x00_dev_irq, switches) < 0) { printk(KERN_ERR "unable to hook IRQ for " "UCB1300 SWITCH_%d\n", i); return -EBUSY; } } return 0; fail: input_free_device(idev); kfree(switches); return err; } static void ucb1x00_switches_remove(struct ucb1x00_dev *dev) { struct ucb1x00_switches *switches = dev->priv; input_unregister_device(switches->idev); /* TODO IMPLEMENT THIS PART: struct ucb1x00_ts *ts = idev->private; if (ts->rtask) kthread_stop(ts->rtask); ucb1x00_enable(ts->ucb); ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); ucb1x00_disable(ts->ucb); */ kfree(switches); } static struct ucb1x00_driver ucb1x00_switches_driver = { .add = ucb1x00_switches_add, .remove = ucb1x00_switches_remove, }; static int __init ucb1x00_switches_init(void) { return ucb1x00_register_driver(&ucb1x00_switches_driver); } static void __exit ucb1x00_switches_exit(void) { ucb1x00_unregister_driver(&ucb1x00_switches_driver); } module_init(ucb1x00_switches_init); module_exit(ucb1x00_switches_exit); MODULE_AUTHOR("Bernhard Guillon "); MODULE_DESCRIPTION("UCB1x00 Switches driver for Siemens SIMpad"); MODULE_LICENSE("GPL");