From 6ddb3d0c90d9423ed84b4cd3213d73d54ad386ba Mon Sep 17 00:00:00 2001 From: Jun Yan Date: Mon, 22 Jun 2026 22:07:35 -0700 Subject: Input: cap11xx - refactor code for better CAP1114 support. Extend cap11xx_hw_model structure to support CAP1114 with different register offsets and hardware characteristics: - led_output_control_reg_base: different address on CAP1114 - sensor_input_reg_base: different address on CAP1114 - num_sensor_thresholds: separate value from num_channels for CAP1114 - has_repeat_en: repeat enable support, disabled by default on CAP1114 Include linux/bits.h, update the register operations related to LEDs. Signed-off-by: Jun Yan Link: https://patch.msgid.link/20260617150318.753148-8-jerrysteve1101@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/cap11xx.c | 95 ++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 23 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 1db4a9090705..16edabcf6f2d 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -5,6 +5,7 @@ * (c) 2014 Daniel Mack */ +#include #include #include #include @@ -22,6 +23,7 @@ #define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0) #define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4) #define CAP11XX_REG_SENSOR_INPUT 0x03 +#define CAP1114_REG_BUTTON_STATUS2 0x04 #define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X)) #define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f #define CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK 0x70 @@ -36,7 +38,6 @@ #define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93 #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_PRODUCT_ID 0xfd @@ -77,10 +78,14 @@ struct cap11xx_priv { struct cap11xx_hw_model { u8 product_id; + u8 led_output_control_reg_base; + u8 sensor_input_reg_base; unsigned int num_channels; unsigned int num_leds; + unsigned int num_sensor_thresholds; bool has_gain; bool has_irq_config; + bool has_repeat_en; bool has_sensitivity_control; bool has_signal_guard; }; @@ -103,6 +108,7 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg) switch (reg) { case CAP11XX_REG_MAIN_CONTROL: case CAP11XX_REG_SENSOR_INPUT: + case CAP1114_REG_BUTTON_STATUS2: case CAP11XX_REG_SENOR_DELTA(0): case CAP11XX_REG_SENOR_DELTA(1): case CAP11XX_REG_SENOR_DELTA(2): @@ -211,8 +217,8 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) } if (!of_property_read_u32_array(node, "microchip,input-threshold", - priv->thresholds, priv->model->num_channels)) { - for (i = 0; i < priv->model->num_channels; i++) { + priv->thresholds, priv->model->num_sensor_thresholds)) { + for (i = 0; i < priv->model->num_sensor_thresholds; i++) { if (priv->thresholds[i] > 127) { dev_err(dev, "Invalid input-threshold value %u\n", priv->thresholds[i]); @@ -286,10 +292,12 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) of_property_read_u32_array(node, "linux,keycodes", priv->keycodes, priv->model->num_channels); - /* Disable autorepeat. The Linux input system has its own handling. */ - error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); - if (error) - return error; + if (priv->model->has_repeat_en) { + /* Disable autorepeat. The Linux input system has its own handling. */ + error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); + if (error) + return error; + } return 0; } @@ -308,7 +316,7 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data) if (ret < 0) goto out; - ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status); + ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base, &status); if (ret < 0) goto out; @@ -361,10 +369,16 @@ static int cap11xx_led_set(struct led_classdev *cdev, * limitation. Brightness levels per LED are either * 0 (OFF) and 1 (ON). */ - return regmap_update_bits(priv->regmap, - CAP11XX_REG_LED_OUTPUT_CONTROL, - BIT(led->reg), - value ? BIT(led->reg) : 0); + if (led->reg >= 8) + return regmap_update_bits(priv->regmap, + priv->model->led_output_control_reg_base + 1, + BIT(led->reg - 8), + value ? BIT(led->reg - 8) : 0); + else + return regmap_update_bits(priv->regmap, + priv->model->led_output_control_reg_base, + BIT(led->reg), + value ? BIT(led->reg) : 0); } static int cap11xx_init_leds(struct device *dev, @@ -374,6 +388,7 @@ static int cap11xx_init_leds(struct device *dev, struct cap11xx_led *led; int cnt = of_get_child_count(node); int error; + u32 duty_val; if (!num_leds || !cnt) return 0; @@ -387,15 +402,26 @@ static int cap11xx_init_leds(struct device *dev, priv->leds = led; + /* Set all LEDs to off */ error = regmap_update_bits(priv->regmap, - CAP11XX_REG_LED_OUTPUT_CONTROL, 0xff, 0); + priv->model->led_output_control_reg_base, + GENMASK(min(num_leds, 8) - 1, 0), 0); if (error) return error; + if (num_leds > 8) { + error = regmap_update_bits(priv->regmap, + priv->model->led_output_control_reg_base + 1, + GENMASK(num_leds - 8 - 1, 0), 0); + if (error) + return error; + } + + duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK, + CAP11XX_REG_LED_DUTY_MAX_VALUE); + 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); + CAP11XX_REG_LED_DUTY_MAX_MASK, duty_val); if (error) return error; @@ -561,41 +587,64 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client) } static const struct cap11xx_hw_model cap1106_model = { - .product_id = 0x55, .num_channels = 6, .num_leds = 0, + .product_id = 0x55, + .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, .has_gain = true, .has_irq_config = true, + .has_repeat_en = true, }; static const struct cap11xx_hw_model cap1126_model = { - .product_id = 0x53, .num_channels = 6, .num_leds = 2, + .product_id = 0x53, + .num_channels = 6, .num_leds = 2, .num_sensor_thresholds = 6, + .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, .has_gain = true, .has_irq_config = true, + .has_repeat_en = true, }; static const struct cap11xx_hw_model cap1188_model = { - .product_id = 0x50, .num_channels = 8, .num_leds = 8, + .product_id = 0x50, + .num_channels = 8, .num_leds = 8, .num_sensor_thresholds = 8, + .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, .has_gain = true, .has_irq_config = true, + .has_repeat_en = true, }; static const struct cap11xx_hw_model cap1203_model = { - .product_id = 0x6d, .num_channels = 3, .num_leds = 0, + .product_id = 0x6d, + .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, + .has_repeat_en = true, }; static const struct cap11xx_hw_model cap1206_model = { - .product_id = 0x67, .num_channels = 6, .num_leds = 0, + .product_id = 0x67, + .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, + .has_repeat_en = true, }; static const struct cap11xx_hw_model cap1293_model = { - .product_id = 0x6f, .num_channels = 3, .num_leds = 0, + .product_id = 0x6f, + .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, .has_gain = true, + .has_repeat_en = true, .has_sensitivity_control = true, .has_signal_guard = true, }; static const struct cap11xx_hw_model cap1298_model = { - .product_id = 0x71, .num_channels = 8, .num_leds = 0, + .product_id = 0x71, + .num_channels = 8, .num_leds = 0, .num_sensor_thresholds = 8, + .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, .has_gain = true, + .has_repeat_en = true, .has_sensitivity_control = true, .has_signal_guard = true, }; -- cgit v1.2.3