leds: leds-rgb13h add pwm control

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: Id8800dc98543d4e082182a027f3fb25dbd30295c
This commit is contained in:
Zefa Chen
2020-06-04 20:22:36 +08:00
committed by Tao Huang
parent 6118bbac7b
commit 46cff32208

View File

@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/version.h>
#include <linux/pwm.h>
#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,