[media] em28xx: add support for illumination button and LED
authorFrank Schaefer <fschaefer.oss@googlemail.com>
Sun, 1 Dec 2013 21:06:56 +0000 (18:06 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Tue, 10 Dec 2013 18:20:26 +0000 (16:20 -0200)
The SpeedLink VAD Laplace webcam is equipped with an illumination button and
an illumination LED. When the button is pressed, the driver must toggle the
LED state via the corresponding GPO port.

Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/usb/em28xx/em28xx-core.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx.h

index 4a8179aafc4d0310925260150a5e621a9a233b2f..fc82540352788ae115559e27aba05b4d0afde9af 100644 (file)
@@ -225,6 +225,25 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
 }
 EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
 
+/*
+ * em28xx_toggle_reg_bits()
+ * toggles/inverts the bits (specified by bitmask) of a register
+ */
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask)
+{
+       int oldval;
+       u8 newval;
+
+       oldval = em28xx_read_reg(dev, reg);
+       if (oldval < 0)
+               return oldval;
+
+       newval = (~oldval & bitmask) | (oldval & ~bitmask);
+
+       return em28xx_write_reg(dev, reg, newval);
+}
+EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
+
 /*
  * em28xx_is_ac97_ready()
  * Checks if ac97 is ready
index ebc538730e07b38d3a39903bf98b03e6de8bf8d0..e0acc92f0dfd30fb6903ca88058d3caf4cb4d43c 100644 (file)
@@ -480,6 +480,7 @@ static void em28xx_query_buttons(struct work_struct *work)
        u8 i, j;
        int regval;
        bool is_pressed, was_pressed;
+       const struct em28xx_led *led;
 
        /* Poll and evaluate all addresses */
        for (i = 0; i < dev->num_button_polling_addresses; i++) {
@@ -524,6 +525,15 @@ static void em28xx_query_buttons(struct work_struct *work)
                                input_report_key(dev->sbutton_input_dev,
                                                 EM28XX_SNAPSHOT_KEY, 0);
                                break;
+                       case EM28XX_BUTTON_ILLUMINATION:
+                               led = em28xx_find_led(dev,
+                                                     EM28XX_LED_ILLUMINATION);
+                               /* Switch illumination LED on/off */
+                               if (led)
+                                       em28xx_toggle_reg_bits(dev,
+                                                              led->gpio_reg,
+                                                              led->gpio_mask);
+                               break;
                        default:
                                WARN_ONCE(1, "BUG: unhandled button role.");
                        }
@@ -600,10 +610,17 @@ static void em28xx_init_buttons(struct em28xx *dev)
                        WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
                        addr_new = 0;
                }
-               /* Register input device (if needed) */
+               /* Button role specific checks and actions */
                if (button->role == EM28XX_BUTTON_SNAPSHOT) {
+                       /* Register input device */
                        if (em28xx_register_snapshot_button(dev) < 0)
                                addr_new = 0;
+               } else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
+                       /* Check sanity */
+                       if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
+                               em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n");
+                               addr_new = 0;
+                       }
                }
                /* Add read address to list of polling addresses */
                if (addr_new) {
index f60f236a245f9ce6dcb2e4e6c58e8d5b8c089b8c..43e29683eb6afd051794c440a7a57499b90b1335 100644 (file)
@@ -379,6 +379,7 @@ enum em28xx_adecoder {
 
 enum em28xx_led_role {
        EM28XX_LED_ANALOG_CAPTURING = 0,
+       EM28XX_LED_ILLUMINATION,
        EM28XX_NUM_LED_ROLES, /* must be the last */
 };
 
@@ -391,6 +392,7 @@ struct em28xx_led {
 
 enum em28xx_button_role {
        EM28XX_BUTTON_SNAPSHOT = 0,
+       EM28XX_BUTTON_ILLUMINATION,
        EM28XX_NUM_BUTTON_ROLES, /* must be the last */
 };
 
@@ -709,6 +711,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
 int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
 int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
                                 u8 bitmask);
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
 
 int em28xx_read_ac97(struct em28xx *dev, u8 reg);
 int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);