cap11xx: add LED support
Subsystems (4)
v6 cover cap11xx: add LED support
changes from v5:
* Dropped linux,led-brightness DT property
* Removed several ifdefs to LED CLASS
* Added cap11xx_init_leds stub
Matt Ranostay (2):
dt: add cap11xx LED documentation
cap11xx: add LED support
.../devicetree/bindings/input/cap11xx.txt | 19 +++ drivers/input/keyboard/cap11xx.c | 140 ++++++++++++++++++++- 2 files changed, 156 insertions(+), 3 deletions(-)
Signature · 1 line
1.9.1
PATCH v6 2/2 cap11xx: add LED support
Several cap11xx variants have LEDs that be can be controlled, this patchset implements this functionality.
--- drivers/input/keyboard/cap11xx.c | 140 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-)
drivers/input/keyboard/cap11xx.c +137 -3
@@ -12,6 +12,7 @@#include <linux/module.h> #include <linux/interrupt.h> #include <linux/input.h> +#include <linux/leds.h> #include <linux/of_irq.h> #include <linux/regmap.h> #include <linux/i2c.h>
@@ -47,6 +48,20 @@#define CAP11XX_REG_CONFIG2 0x44#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6)#define CAP11XX_REG_SENSOR_BASE_CNT (X ) (0x50 + (X)) +#define CAP11XX_REG_LED_POLARITY 0x73 +#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74 + +#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90 +#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91 +#define CAP11XX_REG_LED_DUTY_CYCLE_3 0x92 +#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93 + +#define CAP11XX_REG_LED_DUTY_MIN_MASK (0x0f) +#define CAP11XX_REG_LED_DUTY_MIN_MASK_SHIFT (0) +#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0) +#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4) +#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15) +#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X))#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba
@@ -56,10 +71,23 @@#define CAP11XX_MANUFACTURER_ID 0x5d +#ifdef CONFIG_LEDS_CLASS +struct cap11xx_led { +struct cap11xx_priv *priv; +struct led_classdev cdev; +struct work_struct work; +u32 reg; +enum led_brightness new_brightness; +}; +#endif +struct cap11xx_priv {struct regmap *regmap;struct input_dev *idev; +struct cap11xx_led *leds; +int num_leds; +/* config */ u32 keycodes[]; };
@@ -67,6 +95,7 @@ struct cap11xx_priv {struct cap11xx_hw_model {u8 product_id;unsigned int num_channels; +unsigned int num_leds; };enum {
@@ -76,9 +105,9 @@ enum { };static const struct cap11xx_hw_model cap11xx_devices[] = { - [CAP1106 ] = { .product_id =0x55 , .num_channels =6 }, - [CAP1126 ] = { .product_id =0x53 , .num_channels =6 }, - [CAP1188 ] = { .product_id =0x50 , .num_channels =8 }, + [CAP1106 ] = { .product_id =0x55 , .num_channels =6 , .num_leds =0 }, + [CAP1126 ] = { .product_id =0x53 , .num_channels =6 , .num_leds =2 }, + [CAP1188 ] = { .product_id =0x50 , .num_channels =8 , .num_leds =8 }, };static const struct reg_default cap11xx_reg_defaults[] = {
@@ -111,6 +140,7 @@ static const struct reg_default cap11xx_reg_defaults[] = { { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 }, { CAP11XX_REG_STANDBY_THRESH, 0x40 }, { CAP11XX_REG_CONFIG2, 0x40 }, + { CAP11XX_REG_LED_POLARITY, 0x00 }, { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 }, { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 }, };
@@ -177,6 +207,13 @@ out:static int cap11xx_set_sleep (struct cap11xx_priv *priv,bool sleep) { +#ifdef CONFIG_LEDS_CLASS +/* +* DLSEEP mode will turn off all LEDS, prevent this +*/ +if (priv->num_leds) +return 0 ; +#endif return regmap_update_bits (priv->regmap,CAP11XX_REG_MAIN_CONTROL ,CAP11XX_REG_MAIN_CONTROL_DLSEEP , sleep ?CAP11XX_REG_MAIN_CONTROL_DLSEEP :0 );
@@ -196,6 +233,99 @@ static void cap11xx_input_close(struct input_dev *idev)cap11xx_set_sleep (priv, true); } +#ifdef CONFIG_LEDS_CLASS +static void cap11xx_led_work (struct work_struct *work) +{ + struct cap11xx_led *led = container_of(work, struct cap11xx_led, work); +struct cap11xx_priv *priv = led->priv; +int value = led->new_brightness; + +/* +* All LEDs share the same duty cycle as this is a HW limitation. +* Brightness levels per LED are either 0 (OFF) and 1 (ON). +*/ +regmap_update_bits (priv->regmap,CAP11XX_REG_LED_OUTPUT_CONTROL , +BIT (led->reg), value ?BIT (led->reg) :0 ); +} + +static void cap11xx_led_set (struct led_classdev *cdev, +enum led_brightness value) +{ + struct cap11xx_led *led = container_of(cdev, struct cap11xx_led, cdev); + +if (led->new_brightness == value) +return ; + + led->new_brightness = value; +schedule_work (&led->work); +} + +static int cap11xx_init_leds (struct device *dev, +struct cap11xx_priv *priv,int num_leds) +{ +struct device_node *node = dev->of_node, *child; +struct cap11xx_led *led; +int cnt =of_get_child_count (node); +int error; + +if (!num_leds || !cnt) +return 0 ; +if (cnt > num_leds) +return -EINVAL ; + + led =devm_kcalloc (dev, cnt, +sizeof (struct cap11xx_led ),GFP_KERNEL ); +if (!led) +return -ENOMEM ; + priv->leds = led; + + error =regmap_update_bits (priv->regmap, +CAP11XX_REG_LED_OUTPUT_CONTROL ,0xff ,0 ); +if (error) +return error; + error =regmap_update_bits (priv->regmap,CAP11XX_REG_LED_DUTY_CYCLE_4 , +CAP11XX_REG_LED_DUTY_MAX_MASK , +CAP11XX_REG_LED_DUTY_MAX_VALUE << +CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT ); +if (error) +return error; + +for_each_child_of_node (node, child) { +u32 reg; + + led->cdev.name = +of_get_property (child,"label" ,NULL ) ? : child->name; + led->cdev.default_trigger = +of_get_property (child,"linux,default-trigger" ,NULL ); + led->cdev.flags =0 ; + led->cdev.brightness_set = cap11xx_led_set; + led->cdev.max_brightness =1 ; + led->cdev.brightness =LED_OFF ; + + error =of_property_read_u32 (child,"reg" , ®); +if (error !=0 || reg >= num_leds) +return -EINVAL ; + led->reg = reg; + led->priv = priv; + +INIT_WORK (&led->work, cap11xx_led_work); + error =devm_led_classdev_register (dev, &led->cdev); +if (error <0 ) +return -EINVAL ; + priv->num_leds++; + led++; + }; + +return 0 ; +} +#else +static int cap11xx_init_leds (struct device *dev, +struct cap11xx_priv *priv,int num_leds) +{ +return 0 ; +} +#endif +static int cap11xx_i2c_probe (struct i2c_client *i2c_client,const struct i2c_device_id *id) {
@@ -316,6 +446,10 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, priv->idev->open = cap11xx_input_open; priv->idev->close = cap11xx_input_close; + error =cap11xx_init_leds (dev, priv, cap->num_leds); +if (error) +return error; +input_set_drvdata (priv->idev, priv);/*
Signature · 1 line
1.9.1
A message that is not in the archive (sent off-list or not yet received): 1435128654-19454-1-git-send-email-mranostay-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
PATCH v6 1/2 dt: add cap11xx LED documentation
--- Documentation/devicetree/bindings/input/cap11xx.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
Documentation/devicetree/bindings/input/cap11xx.txt +19 -0
@@ -55,5 +55,24 @@ i2c_controller { <105>, /* KEY_LEFT */ <109>, /* KEY_PAGEDOWN */ <104>; /* KEY_PAGEUP */ + + #address-cells = <1>; + #size-cells = <0>; + + usr@0 { + label = "cap11xx:green:usr0"; + reg = <0>; + }; + + usr@1 { + label = "cap11xx:green:usr1"; + reg = <1>; + }; + + alive@2 { + label = "cap11xx:green:alive"; + reg = <2>; + linux,default_trigger = "heartbeat"; + }; }; }
Signature · 6 lines
1.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Was there any more input or changes needed for this patchset?
Thanks,
Matt
Quoted 16 lines · Matt Ranostay
changes from v5:
* Dropped linux,led-brightness DT property
* Removed several ifdefs to LED CLASS
* Addedcap11xx_init_ledsstubMatt Ranostay (2):
dt: add cap11xx LED documentation
cap11xx: add LED support.../devicetree/bindings/input/cap11xx.txt | 19 +++ drivers/input/keyboard/cap11xx.c | 140 ++++++++++++++++++++- 2 files changed, 156 insertions(+), 3 deletions(-)--
1.9.1