From 46cff32208681605f109f9d22ebc91973cd1f763 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Thu, 4 Jun 2020 20:22:36 +0800 Subject: [PATCH] leds: leds-rgb13h add pwm control Signed-off-by: Zefa Chen Change-Id: Id8800dc98543d4e082182a027f3fb25dbd30295c --- drivers/leds/leds-rgb13h.c | 80 ++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/drivers/leds/leds-rgb13h.c b/drivers/leds/leds-rgb13h.c index 546722b3ba62..e9f80562f226 100644 --- a/drivers/leds/leds-rgb13h.c +++ b/drivers/leds/leds-rgb13h.c @@ -17,6 +17,7 @@ #include #include #include +#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) @@ -38,6 +39,7 @@ struct rgb13h_led { /* maximum flash timeout */ u32 max_flash_tm; u32 intensity; + u32 intensity_torch; bool strobe_state; /* brightness cache */ u32 torch_brightness; @@ -55,6 +57,9 @@ struct rgb13h_led { u32 module_index; const char *module_facing; + struct pwm_device *pwm; + u32 pwm_period; + u32 pwm_duty; }; static struct rgb13h_led *fled_cdev_to_led(struct led_classdev_flash *fled_cdev) @@ -70,7 +75,24 @@ static struct rgb13h_led *sd_to_led(struct v4l2_subdev *subdev) static int rgb13h_set_output(struct rgb13h_led *led, bool on) { mutex_lock(&led->lock); - gpiod_direction_output(led->gpio_en, on); + if (!IS_ERR(led->gpio_en)) + gpiod_direction_output(led->gpio_en, on); + if (!IS_ERR(led->pwm)) { + if (led->led_mode == V4L2_FLASH_LED_MODE_TORCH) + led->pwm_duty = led->pwm_period - + led->intensity_torch * led->pwm_period / led->max_mm_current; + else + led->pwm_duty = led->pwm_period - + led->intensity * led->pwm_period / led->max_flash_current; + if (on) { + pwm_config(led->pwm, led->pwm_duty, led->pwm_period); + pwm_enable(led->pwm); + dev_dbg(&led->pdev->dev, "led pwm duty=%d, period=%d, polarity=%d\n", + led->pwm_duty, led->pwm_period, led->pwm->args.polarity); + } else { + pwm_disable(led->pwm); + } + } if (!on) { led->strobe_state = false; if (led->waiting) { @@ -187,7 +209,17 @@ static int rgb13h_led_parse_dt(struct rgb13h_led *led, led->gpio_en = devm_gpiod_get(dev, "enable", GPIOD_ASIS); if (IS_ERR(led->gpio_en)) { ret = PTR_ERR(led->gpio_en); - dev_err(dev, "Unable to claim enable-gpio\n"); + dev_info(dev, "Unable to claim enable-gpio\n"); + } + led->pwm = devm_pwm_get(dev, NULL); + if (IS_ERR(led->pwm)) { + ret = PTR_ERR(led->pwm); + dev_info(dev, "Unable to get pwm device\n"); + } else { + led->pwm_period = led->pwm->args.period; + } + if (IS_ERR(led->gpio_en) && IS_ERR(led->pwm)) { + dev_err(dev, "Neither enable-gpio nor pwm can be get,return error\n"); return ret; } @@ -199,6 +231,11 @@ static int rgb13h_led_parse_dt(struct rgb13h_led *led, if (ret < 0) dev_warn(dev, "led-max-microamp DT property missing\n"); + if (led->max_mm_current <= 0) { + led->max_mm_current = 20000; + dev_warn(dev, + "get led-max-microamp error value, used default value 20000\n"); + } ret = of_property_read_u32(child_node, "flash-max-microamp", &led->max_flash_current); @@ -207,6 +244,11 @@ static int rgb13h_led_parse_dt(struct rgb13h_led *led, "flash-max-microamp DT property missing\n"); return ret; } + if (led->max_flash_current <= 0) { + led->max_flash_current = 20000; + dev_warn(dev, + "get flash-max-microamp error value, used default value 20000\n"); + } ret = of_property_read_u32(child_node, "flash-max-timeout-us", &led->max_flash_tm); @@ -215,6 +257,11 @@ static int rgb13h_led_parse_dt(struct rgb13h_led *led, "flash-max-timeout-us DT property missing\n"); return ret; } + if (led->max_flash_tm <= 0) { + led->max_flash_tm = 1000000; + dev_warn(dev, + "get flash-max-timeout-us error value, used default value 1s\n"); + } *sub_node = child_node; return ret; @@ -262,9 +309,11 @@ static int rgb13h_get_ctrl(struct v4l2_ctrl *ctrl) ctrl->val = led->strobe_state; break; case V4L2_CID_FLASH_INTENSITY: - case V4L2_CID_FLASH_TORCH_INTENSITY: ctrl->val = led->intensity; break; + case V4L2_CID_FLASH_TORCH_INTENSITY: + ctrl->val = led->intensity_torch; + break; case V4L2_CID_FLASH_LED_MODE: ctrl->val = led->led_mode; break; @@ -287,7 +336,7 @@ static int rgb13h_set_ctrl(struct v4l2_ctrl *ctrl) led->led_mode = ctrl->val; rgb13h_set_output(led, LED_OFF); if (led->led_mode == V4L2_FLASH_LED_MODE_TORCH) - return rgb13h_set_output(led, !!led->intensity); + return rgb13h_set_output(led, LED_ON); break; case V4L2_CID_FLASH_STROBE_SOURCE: @@ -305,12 +354,15 @@ static int rgb13h_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_FLASH_TIMEOUT: return rgb13h_led_flash_timeout_set(&led->fled_cdev, ctrl->val); case V4L2_CID_FLASH_INTENSITY: + if (led->led_mode != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + led->intensity = ctrl->val; break; case V4L2_CID_FLASH_TORCH_INTENSITY: if (led->led_mode != V4L2_FLASH_LED_MODE_TORCH) break; - led->intensity = ctrl->val; - return rgb13h_set_output(led, !!ctrl->val); + led->intensity_torch = ctrl->val; + return rgb13h_set_output(led, LED_ON); default: dev_err(&led->pdev->dev, "ctrl 0x%x not supported\n", ctrl->id); @@ -358,18 +410,24 @@ static int rgb13h_init_controls(struct rgb13h_led *led) led->max_flash_tm); led->timeout = led->max_flash_tm; /* V4L2_CID_FLASH_INTENSITY */ - v4l2_ctrl_new_std(&led->ctrls, &rgb13h_ctrl_ops, + ctrl = v4l2_ctrl_new_std(&led->ctrls, &rgb13h_ctrl_ops, V4L2_CID_FLASH_INTENSITY, 0, led->max_flash_current, - led->max_flash_current, + 1, led->max_flash_current); + if (ctrl && IS_ERR(led->pwm)) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + led->intensity = led->max_flash_current; /* V4L2_CID_FLASH_TORCH_INTENSITY */ - v4l2_ctrl_new_std(&led->ctrls, &rgb13h_ctrl_ops, + ctrl = v4l2_ctrl_new_std(&led->ctrls, &rgb13h_ctrl_ops, V4L2_CID_FLASH_TORCH_INTENSITY, 0, led->max_mm_current, - led->max_mm_current, + 1, led->max_mm_current); - led->intensity = led->max_mm_current; + if (ctrl && IS_ERR(led->pwm)) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + led->intensity_torch = led->max_mm_current; + /* V4L2_CID_FLASH_FAULT */ ctrl = v4l2_ctrl_new_std(&led->ctrls, &rgb13h_ctrl_ops, V4L2_CID_FLASH_FAULT, 0,