]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/tm6000/tm6000-input.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / staging / tm6000 / tm6000-input.c
index 6022caaa739b43eadc3109eae7dedc6acbfa3b1d..21e7da40f049c2824c289b9da1e41913620fc458 100644 (file)
@@ -24,8 +24,7 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 
-#include <media/ir-core.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
 
 #include "tm6000.h"
 #include "tm6000-regs.h"
@@ -38,6 +37,10 @@ static unsigned int enable_ir = 1;
 module_param(enable_ir, int, 0644);
 MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 
+/* number of 50ms for ON-OFF-ON power led */
+/* show IR activity */
+#define PWLED_OFF 2
+
 #undef dprintk
 
 #define dprintk(fmt, arg...) \
@@ -51,8 +54,7 @@ struct tm6000_ir_poll_result {
 
 struct tm6000_IR {
        struct tm6000_core      *dev;
-       struct ir_input_dev     *input;
-       struct ir_input_state   ir;
+       struct rc_dev           *rc;
        char                    name[32];
        char                    phys[32];
 
@@ -61,13 +63,16 @@ struct tm6000_IR {
        struct delayed_work     work;
        u8                      wait:1;
        u8                      key:1;
+       u8                      pwled:1;
+       u8                      pwledcnt;
+       u16                     key_addr;
        struct urb              *int_urb;
        u8                      *urb_data;
 
        int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
 
        /* IR device properties */
-       struct ir_dev_props     props;
+       u64                     rc_type;
 };
 
 
@@ -91,26 +96,49 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
        u8 buf[10];
        int rc;
 
-       /* hack */
-       buf[0] = 0xff;
-       buf[1] = 0xff;
-       buf[2] = 0xf2;
-       buf[3] = 0x2b;
-       buf[4] = 0x20;
-       buf[5] = 0x35;
-       buf[6] = 0x60;
-       buf[7] = 0x04;
-       buf[8] = 0xc0;
-       buf[9] = 0x08;
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-               USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
-       msleep(100);
-
-       if (rc < 0) {
-               printk(KERN_INFO "IR configuration failed");
-               return rc;
+       switch (ir->rc_type) {
+       case RC_TYPE_NEC:
+               /* Setup IR decoder for NEC standard 12MHz system clock */
+               /* IR_LEADER_CNT = 0.9ms             */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
+               /* IR_PULSE_CNT = 0.7ms              */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
+               /* Remote WAKEUP = enable */
+               tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+               /* IR_WKUP_SEL = Low byte in decoded IR data */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
+               /* IR_WKU_ADD code */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
+               tm6000_flash_led(dev, 0);
+               msleep(100);
+               tm6000_flash_led(dev, 1);
+               break;
+       default:
+               /* hack */
+               buf[0] = 0xff;
+               buf[1] = 0xff;
+               buf[2] = 0xf2;
+               buf[3] = 0x2b;
+               buf[4] = 0x20;
+               buf[5] = 0x35;
+               buf[6] = 0x60;
+               buf[7] = 0x04;
+               buf[8] = 0xc0;
+               buf[9] = 0x08;
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+               msleep(100);
+
+               if (rc < 0) {
+                       printk(KERN_INFO "IR configuration failed");
+                       return rc;
+               }
+               break;
        }
+
        return 0;
 }
 
@@ -145,17 +173,28 @@ static int default_polling_getkey(struct tm6000_IR *ir,
                return 0;
 
        if (&dev->int_in) {
-               if (ir->ir.ir_type == IR_TYPE_RC5)
+               switch (ir->rc_type) {
+               case RC_TYPE_RC5:
                        poll_result->rc_data = ir->urb_data[0];
-               else
-                       poll_result->rc_data = ir->urb_data[0] | ir->urb_data[1] << 8;
+                       break;
+               case RC_TYPE_NEC:
+                       if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
+                               poll_result->rc_data = ir->urb_data[0]
+                                                       | ir->urb_data[1] << 8;
+                       }
+                       break;
+               default:
+                       poll_result->rc_data = ir->urb_data[0]
+                                       | ir->urb_data[1] << 8;
+                       break;
+               }
        } else {
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
                msleep(10);
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
                msleep(10);
 
-               if (ir->ir.ir_type == IR_TYPE_RC5) {
+               if (ir->rc_type == RC_TYPE_RC5) {
                        rc = tm6000_read_write_usb(dev, USB_DIR_IN |
                                USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                REQ_02_GET_IR_CODE, 0, 0, buf, 1);
@@ -188,6 +227,7 @@ static int default_polling_getkey(struct tm6000_IR *ir,
 
 static void tm6000_ir_handle_key(struct tm6000_IR *ir)
 {
+       struct tm6000_core *dev = ir->dev;
        int result;
        struct tm6000_ir_poll_result poll_result;
 
@@ -200,12 +240,21 @@ static void tm6000_ir_handle_key(struct tm6000_IR *ir)
 
        dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
 
-       if (ir->key) {
-               ir_input_keydown(ir->input->input_dev, &ir->ir,
-                               (u32)poll_result.rc_data);
+       if (ir->pwled) {
+               if (ir->pwledcnt >= PWLED_OFF) {
+                       ir->pwled = 0;
+                       ir->pwledcnt = 0;
+                       tm6000_flash_led(dev, 1);
+               } else
+                       ir->pwledcnt += 1;
+       }
 
-               ir_input_nokey(ir->input->input_dev, &ir->ir);
+       if (ir->key) {
+               rc_keydown(ir->rc, poll_result.rc_data, 0);
                ir->key = 0;
+               ir->pwled = 1;
+               ir->pwledcnt = 0;
+               tm6000_flash_led(dev, 0);
        }
        return;
 }
@@ -218,9 +267,9 @@ static void tm6000_ir_work(struct work_struct *work)
        schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
-static int tm6000_ir_start(void *priv)
+static int tm6000_ir_start(struct rc_dev *rc)
 {
-       struct tm6000_IR *ir = priv;
+       struct tm6000_IR *ir = rc->priv;
 
        INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
        schedule_delayed_work(&ir->work, 0);
@@ -228,30 +277,91 @@ static int tm6000_ir_start(void *priv)
        return 0;
 }
 
-static void tm6000_ir_stop(void *priv)
+static void tm6000_ir_stop(struct rc_dev *rc)
 {
-       struct tm6000_IR *ir = priv;
+       struct tm6000_IR *ir = rc->priv;
 
        cancel_delayed_work_sync(&ir->work);
 }
 
-int tm6000_ir_change_protocol(void *priv, u64 ir_type)
+int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
 {
-       struct tm6000_IR *ir = priv;
+       struct tm6000_IR *ir = rc->priv;
+
+       if (!ir)
+               return 0;
+
+       if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
+               ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
 
        ir->get_key = default_polling_getkey;
+       ir->rc_type = rc_type;
 
        tm6000_ir_config(ir);
        /* TODO */
        return 0;
 }
 
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+       int pipe, size;
+       int err = -ENOMEM;
+
+
+       if (!ir)
+               return -ENODEV;
+
+       ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+       pipe = usb_rcvintpipe(dev->udev,
+               dev->int_in.endp->desc.bEndpointAddress
+               & USB_ENDPOINT_NUMBER_MASK);
+
+       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+       dprintk("IR max size: %d\n", size);
+
+       ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+       if (ir->int_urb->transfer_buffer == NULL) {
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+       usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+               ir->int_urb->transfer_buffer, size,
+               tm6000_ir_urb_received, dev,
+               dev->int_in.endp->desc.bInterval);
+       err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+       if (err) {
+               kfree(ir->int_urb->transfer_buffer);
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+       return 0;
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!ir)
+               return;
+
+       usb_kill_urb(ir->int_urb);
+       kfree(ir->int_urb->transfer_buffer);
+       usb_free_urb(ir->int_urb);
+       ir->int_urb = NULL;
+       kfree(ir->urb_data);
+       ir->urb_data = NULL;
+}
+
 int tm6000_ir_init(struct tm6000_core *dev)
 {
        struct tm6000_IR *ir;
-       struct ir_input_dev *ir_input_dev;
+       struct rc_dev *rc;
        int err = -ENOMEM;
-       int pipe, size, rc;
 
        if (!enable_ir)
                return -ENODEV;
@@ -263,26 +373,27 @@ int tm6000_ir_init(struct tm6000_core *dev)
                return 0;
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL);
-       ir_input_dev->input_dev = input_allocate_device();
-       if (!ir || !ir_input_dev || !ir_input_dev->input_dev)
-               goto err_out_free;
+       rc = rc_allocate_device();
+       if (!ir | !rc)
+               goto out;
 
        /* record handles to ourself */
        ir->dev = dev;
        dev->ir = ir;
-
-       ir->input = ir_input_dev;
+       ir->rc = rc;
 
        /* input einrichten */
-       ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
-       ir->props.priv = ir;
-       ir->props.change_protocol = tm6000_ir_change_protocol;
-       ir->props.open = tm6000_ir_start;
-       ir->props.close = tm6000_ir_stop;
-       ir->props.driver_type = RC_DRIVER_SCANCODE;
+       rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+       rc->priv = ir;
+       rc->change_protocol = tm6000_ir_change_protocol;
+       rc->open = tm6000_ir_start;
+       rc->close = tm6000_ir_stop;
+       rc->driver_type = RC_DRIVER_SCANCODE;
 
        ir->polling = 50;
+       ir->pwled = 0;
+       ir->pwledcnt = 0;
+
 
        snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
                                                dev->name);
@@ -290,64 +401,37 @@ int tm6000_ir_init(struct tm6000_core *dev)
        usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
        strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-       tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
-       err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER);
-       if (err < 0)
-               goto err_out_free;
-
-       ir_input_dev->input_dev->name = ir->name;
-       ir_input_dev->input_dev->phys = ir->phys;
-       ir_input_dev->input_dev->id.bustype = BUS_USB;
-       ir_input_dev->input_dev->id.version = 1;
-       ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
-       ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+       tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
 
-       ir_input_dev->input_dev->dev.parent = &dev->udev->dev;
+       rc->input_name = ir->name;
+       rc->input_phys = ir->phys;
+       rc->input_id.bustype = BUS_USB;
+       rc->input_id.version = 1;
+       rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+       rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+       rc->map_name = dev->ir_codes;
+       rc->driver_name = "tm6000";
+       rc->dev.parent = &dev->udev->dev;
 
        if (&dev->int_in) {
                dprintk("IR over int\n");
 
-               ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+               err = tm6000_ir_int_start(dev);
 
-               pipe = usb_rcvintpipe(dev->udev,
-                       dev->int_in.endp->desc.bEndpointAddress
-                       & USB_ENDPOINT_NUMBER_MASK);
-
-               size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-               dprintk("IR max size: %d\n", size);
-
-               ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-               if (ir->int_urb->transfer_buffer == NULL) {
-                       usb_free_urb(ir->int_urb);
-                       goto err_out_stop;
-               }
-               dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
-               usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
-                       ir->int_urb->transfer_buffer, size,
-                       tm6000_ir_urb_received, dev,
-                       dev->int_in.endp->desc.bInterval);
-               rc = usb_submit_urb(ir->int_urb, GFP_KERNEL);
-               if (rc) {
-                       kfree(ir->int_urb->transfer_buffer);
-                       usb_free_urb(ir->int_urb);
-                       err = rc;
-                       goto err_out_stop;
-               }
-               ir->urb_data = kzalloc(size, GFP_KERNEL);
+               if (err)
+                       goto out;
        }
 
        /* ir register */
-       err = ir_input_register(ir->input->input_dev, dev->ir_codes,
-               &ir->props, "tm6000");
+       err = rc_register_device(rc);
        if (err)
-               goto err_out_stop;
+               goto out;
 
        return 0;
 
-err_out_stop:
+out:
        dev->ir = NULL;
-err_out_free:
-       kfree(ir_input_dev);
+       rc_free_device(rc);
        kfree(ir);
        return err;
 }
@@ -361,19 +445,12 @@ int tm6000_ir_fini(struct tm6000_core *dev)
        if (!ir)
                return 0;
 
-       ir_input_unregister(ir->input->input_dev);
+       rc_unregister_device(ir->rc);
 
        if (ir->int_urb) {
-               usb_kill_urb(ir->int_urb);
-               kfree(ir->int_urb->transfer_buffer);
-               usb_free_urb(ir->int_urb);
-               ir->int_urb = NULL;
-               kfree(ir->urb_data);
-               ir->urb_data = NULL;
+               tm6000_ir_int_stop(dev);
        }
 
-       kfree(ir->input);
-       ir->input = NULL;
        kfree(ir);
        dev->ir = NULL;