Re: [PATCH v5] input: qt2160: Add support for LEDs.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jan 04, 2013 at 04:45:05PM +0100, javier Martin wrote:
> Hi Dmitry.
> 
> On 25 October 2012 11:53, Javier Martin <javier.martin@xxxxxxxxxxxxxxxxx> wrote:
> > Outputs x8..x0 of the qt2160 can have leds attached to it.
> > This patch handles those outputs using the generic LED
> > framework.
> >
> > The PWM controls available in the chip are used to achieve
> > different levels of brightness.
> >
> > Signed-off-by: Javier Martin <javier.martin@xxxxxxxxxxxxxxxxx>
> > ---
> >  drivers/input/keyboard/qt2160.c |  142 ++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 140 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
> > index 73ea4b0..eefa2dd 100644
> > --- a/drivers/input/keyboard/qt2160.c
> > +++ b/drivers/input/keyboard/qt2160.c
> > @@ -20,6 +20,7 @@
> >
> >  #include <linux/kernel.h>
> >  #include <linux/init.h>
> > +#include <linux/leds.h>
> >  #include <linux/module.h>
> >  #include <linux/slab.h>
> >  #include <linux/jiffies.h>
> > @@ -39,6 +40,11 @@
> >  #define QT2160_CMD_GPIOS      6
> >  #define QT2160_CMD_SUBVER     7
> >  #define QT2160_CMD_CALIBRATE  10
> > +#define QT2160_CMD_DRIVE_X    70
> > +#define QT2160_CMD_PWMEN_X    74
> > +#define QT2160_CMD_PWM_DUTY   76
> > +
> > +#define QT2160_NUM_LEDS_X      8
> >
> >  #define QT2160_CYCLE_INTERVAL  (2*HZ)
> >
> > @@ -49,6 +55,17 @@ static unsigned char qt2160_key2code[] = {
> >         KEY_C, KEY_D, KEY_E, KEY_F,
> >  };
> >
> > +#ifdef CONFIG_LEDS_CLASS
> > +struct qt2160_led {
> > +       struct qt2160_data *qt2160;
> > +       struct led_classdev cdev;
> > +       struct work_struct work;
> > +       char name[32];
> > +       int id;
> > +       enum led_brightness new_brightness;
> > +};
> > +#endif
> > +
> >  struct qt2160_data {
> >         struct i2c_client *client;
> >         struct input_dev *input;
> > @@ -56,8 +73,61 @@ struct qt2160_data {
> >         spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
> >         unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
> >         u16 key_matrix;
> > +#ifdef CONFIG_LEDS_CLASS
> > +       struct qt2160_led leds[QT2160_NUM_LEDS_X];
> > +       struct mutex led_lock;
> > +#endif
> >  };
> >
> > +static int qt2160_read(struct i2c_client *client, u8 reg);
> > +static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
> > +
> > +#ifdef CONFIG_LEDS_CLASS
> > +
> > +static void qt2160_led_work(struct work_struct *work)
> > +{
> > +       struct qt2160_led *led = container_of(work, struct qt2160_led, work);
> > +       struct qt2160_data *qt2160 = led->qt2160;
> > +       struct i2c_client *client = qt2160->client;
> > +       int value = led->new_brightness;
> > +       u32 drive, pwmen;
> > +
> > +       mutex_lock(&qt2160->led_lock);
> > +
> > +       drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
> > +       pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
> > +       if (value != LED_OFF) {
> > +               drive |= (1 << led->id);
> > +               pwmen |= (1 << led->id);
> > +
> > +       } else {
> > +               drive &= ~(1 << led->id);
> > +               pwmen &= ~(1 << led->id);
> > +       }
> > +       qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
> > +       qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
> > +
> > +       /*
> > +        * Changing this register will change the brightness
> > +        * of every LED in the qt2160. It's a HW limitation.
> > +        */
> > +       if (value != LED_OFF)
> > +               qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
> > +
> > +       mutex_unlock(&qt2160->led_lock);
> > +}
> > +
> > +static void qt2160_led_set(struct led_classdev *cdev,
> > +                          enum led_brightness value)
> > +{
> > +       struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
> > +
> > +       led->new_brightness = value;
> > +       schedule_work(&led->work);
> > +}
> > +
> > +#endif /* CONFIG_LEDS_CLASS */
> > +
> >  static int qt2160_read_block(struct i2c_client *client,
> >                              u8 inireg, u8 *buffer, unsigned int count)
> >  {
> > @@ -184,7 +254,7 @@ static void qt2160_worker(struct work_struct *work)
> >         qt2160_schedule_read(qt2160);
> >  }
> >
> > -static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
> > +static int qt2160_read(struct i2c_client *client, u8 reg)
> >  {
> >         int ret;
> >
> > @@ -205,7 +275,7 @@ static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
> >         return ret;
> >  }
> >
> > -static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data)
> > +static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
> >  {
> >         int ret;
> >
> > @@ -217,6 +287,63 @@ static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data)
> >         return ret;
> >  }
> >
> > +#ifdef CONFIG_LEDS_CLASS
> > +
> > +static int __devinit qt2160_register_leds(struct qt2160_data *qt2160)
> > +{
> > +       struct i2c_client *client = qt2160->client;
> > +       int ret;
> > +       int i;
> > +
> > +       mutex_init(&qt2160->led_lock);
> > +
> > +       for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
> > +               struct qt2160_led *led = &qt2160->leds[i];
> > +
> > +               snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
> > +               led->cdev.name = led->name;
> > +               led->cdev.brightness_set = qt2160_led_set;
> > +               led->cdev.brightness = LED_OFF;
> > +               led->id = i;
> > +               led->qt2160 = qt2160;
> > +
> > +               INIT_WORK(&led->work, qt2160_led_work);
> > +
> > +               ret = led_classdev_register(&client->dev, &led->cdev);
> > +               if (ret < 0)
> > +                       return ret;
> > +       }
> > +
> > +       /* Tur off LEDs */
> > +       qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
> > +       qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
> > +       qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
> > +
> > +       return 0;
> > +}
> > +
> > +static void __devinit qt2160_unregister_leds(struct qt2160_data *qt2160)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
> > +               cancel_work_sync(&qt2160->leds[i].work);
> > +               led_classdev_unregister(&qt2160->leds[i].cdev);
> > +       }
> > +}
> > +
> > +#else
> > +
> > +static int __devinit qt2160_register_leds(struct qt2160_data *qt2160)
> > +{
> > +       return 0;
> > +}
> > +
> > +static void __devinit qt2160_unregister_leds(struct qt2160_data *qt2160)
> > +{
> > +}
> > +
> > +#endif
> >
> >  static bool __devinit qt2160_identify(struct i2c_client *client)
> >  {
> > @@ -249,6 +376,7 @@ static bool __devinit qt2160_identify(struct i2c_client *client)
> >         return true;
> >  }
> >
> > +
> >  static int __devinit qt2160_probe(struct i2c_client *client,
> >                                   const struct i2c_device_id *id)
> >  {
> > @@ -325,8 +453,16 @@ static int __devinit qt2160_probe(struct i2c_client *client,
> >         i2c_set_clientdata(client, qt2160);
> >         qt2160_schedule_read(qt2160);
> >
> > +       error = qt2160_register_leds(qt2160);
> > +       if (error) {
> > +               dev_err(&client->dev, "Failed to register leds\n");
> > +               goto err_unreg_input;
> > +       }
> > +
> >         return 0;
> >
> > +err_unreg_input:
> > +       input_unregister_device(input);
> >  err_free_irq:
> >         if (client->irq)
> >                 free_irq(client->irq, qt2160);
> > @@ -340,6 +476,8 @@ static int __devexit qt2160_remove(struct i2c_client *client)
> >  {
> >         struct qt2160_data *qt2160 = i2c_get_clientdata(client);
> >
> > +       qt2160_unregister_leds(qt2160);
> > +
> >         /* Release IRQ so no queue will be scheduled */
> >         if (client->irq)
> >                 free_irq(client->irq, qt2160);
> > --
> > 1.7.9.5
> >
> 
> Could you please apply this patch and the previous one?
> 
> [PATCH v2 1/2] input: qt2160: Fix I2C write function.

This one was already in.

> [PATCH v5] input: qt2160: Add support for LEDs.

This one I just applied removing __devinit markings (some of them should
have been __devexit BTW) and making sure that cancel work is called
after unregisterting led device, otherwise it is racy.

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux