leds: leds-qpnp: add blink functionality support for GPLEDs

Existing implementation does not support blink feature for
GPLEDs. Blink functionality is required if user wants to
produce fading effects using GPLEDs. Hence, adding blink
functionality to GPLEDs.

CRs-Fixed: 723698
Change-Id: I87886469b05cf75986e89ebc3f28d9a6a386401f
Signed-off-by: Abinaya P <abinayap@codeaurora.org>
This commit is contained in:
Abinaya P
2014-10-20 17:01:41 +05:30
parent af3ad6144a
commit 875425cd0d
2 changed files with 102 additions and 9 deletions
@@ -19,7 +19,7 @@ Required properties for each child node, WLED, Flash and RGB:
- qcom,max-current : maximum current that the LED can sustain in mA
- linux,name : name of the led that is used in led framework
Optional properties for each child node, WLED, Flash, MPP and RGB:
Optional properties for each child node, WLED, Flash, MPP, RGB and KPDBL:
- qcom,in-order-command-processing : specify if user space requests leds in order
WLED is primarily used as display backlight. Display subsystem uses
@@ -121,6 +121,7 @@ Optional properties for keypad backlight:
for vph_pwr.
- qcom,row-src-en: specify to enable row source
- qcom,always-on: specify if the module has to be always on
- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
+100 -8
View File
@@ -434,6 +434,7 @@ struct flash_config_data {
* @always_on - always on row
* @lut_params - lut parameters to be used by pwm driver
* @duty_cycles - duty cycles for lut
* @pwm_mode - pwm mode in use
*/
struct kpdbl_config_data {
struct pwm_config_data *pwm_cfg;
@@ -443,6 +444,7 @@ struct kpdbl_config_data {
bool always_on;
struct pwm_duty_cycles *duty_cycles;
struct lut_params lut_params;
u8 pwm_mode;
};
/**
@@ -1835,7 +1837,7 @@ static int qpnp_pwm_init(struct pwm_config_data *pwm_cfg,
struct spmi_device *spmi_dev,
const char *name)
{
int rc, start_idx, idx_len;
int rc, start_idx, idx_len, lut_max_size;
if (pwm_cfg->pwm_channel != -1) {
pwm_cfg->pwm_dev =
@@ -1857,14 +1859,18 @@ static int qpnp_pwm_init(struct pwm_config_data *pwm_cfg,
idx_len =
pwm_cfg->duty_cycles->num_duty_pcts;
if (idx_len >= PWM_LUT_MAX_SIZE &&
start_idx) {
if (strnstr(name, "kpdbl", sizeof("kpdbl")))
lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
else
lut_max_size = PWM_LUT_MAX_SIZE;
if (idx_len >= lut_max_size && start_idx) {
dev_err(&spmi_dev->dev,
"Wrong LUT size or index\n");
return -EINVAL;
}
if ((start_idx + idx_len) >
PWM_LUT_MAX_SIZE) {
if ((start_idx + idx_len) > lut_max_size) {
dev_err(&spmi_dev->dev,
"Exceed LUT limit\n");
return -EINVAL;
@@ -1914,6 +1920,9 @@ static ssize_t pwm_us_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pwm_us\n");
@@ -1966,6 +1975,9 @@ static ssize_t pause_lo_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause lo\n");
@@ -2018,6 +2030,9 @@ static ssize_t pause_hi_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause hi\n");
@@ -2070,6 +2085,9 @@ static ssize_t start_idx_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for start idx\n");
@@ -2123,6 +2141,9 @@ static ssize_t ramp_step_ms_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for ramp step\n");
@@ -2175,6 +2196,9 @@ static ssize_t lut_flags_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for lut flags\n");
@@ -2231,6 +2255,10 @@ static ssize_t duty_pcts_store(struct device *dev,
pwm_cfg = led->rgb_cfg->pwm_cfg;
max_duty_pcts = PWM_LUT_MAX_SIZE;
break;
case QPNP_ID_KPDBL:
pwm_cfg = led->kpdbl_cfg->pwm_cfg;
max_duty_pcts = PWM_GPLED_LUT_MAX_SIZE;
break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for duty pcts\n");
@@ -2300,12 +2328,17 @@ static void led_blink(struct qpnp_led_data *led,
pwm_cfg->blinking = true;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = LPG_MODE;
else if (led->id == QPNP_ID_KPDBL)
led->kpdbl_cfg->pwm_mode = LPG_MODE;
pwm_cfg->mode = LPG_MODE;
} else {
pwm_cfg->blinking = false;
pwm_cfg->mode = pwm_cfg->default_mode;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = pwm_cfg->default_mode;
else if (led->id == QPNP_ID_KPDBL)
led->kpdbl_cfg->pwm_mode =
pwm_cfg->default_mode;
}
pwm_free(pwm_cfg->pwm_dev);
qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
@@ -2320,6 +2353,11 @@ static void led_blink(struct qpnp_led_data *led,
if (rc < 0)
dev_err(&led->spmi_dev->dev,
"MPP set brightness failed (%d)\n", rc);
} else if (led->id == QPNP_ID_KPDBL) {
rc = qpnp_kpdbl_set(led);
if (rc < 0)
dev_err(&led->spmi_dev->dev,
"KPDBL set brightness failed (%d)\n", rc);
}
}
mutex_unlock(&led->lock);
@@ -2349,6 +2387,9 @@ static ssize_t blink_store(struct device *dev,
case QPNP_ID_RGB_BLUE:
led_blink(led, led->rgb_cfg->pwm_cfg);
break;
case QPNP_ID_KPDBL:
led_blink(led, led->kpdbl_cfg->pwm_cfg);
break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED id type for blink\n");
return -EINVAL;
@@ -3003,9 +3044,10 @@ static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
struct device_node *node)
{
struct property *prop;
int rc, i;
int rc, i, lut_max_size;
u32 val;
u8 *temp_cfg;
const char *led_label;
rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
if (!rc)
@@ -3049,9 +3091,22 @@ static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
goto bad_lpg_params;
}
rc = of_property_read_string(node, "label", &led_label);
if (rc < 0) {
dev_err(&spmi_dev->dev,
"Failure reading label, rc = %d\n", rc);
return rc;
}
if (strcmp(led_label, "kpdbl") == 0)
lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
else
lut_max_size = PWM_LUT_MAX_SIZE;
pwm_cfg->duty_cycles->duty_pcts =
devm_kzalloc(&spmi_dev->dev,
sizeof(int) * PWM_LUT_MAX_SIZE,
sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->duty_cycles->duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -3062,7 +3117,7 @@ static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
pwm_cfg->old_duty_pcts =
devm_kzalloc(&spmi_dev->dev,
sizeof(int) * PWM_LUT_MAX_SIZE,
sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->old_duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -3570,6 +3625,29 @@ static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
if (rc)
goto fail_id_check;
}
} else if (led->id == QPNP_ID_KPDBL) {
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
rc = sysfs_create_group(&led->cdev.dev->kobj,
&pwm_attr_group);
if (rc)
goto fail_id_check;
}
if (led->kpdbl_cfg->pwm_cfg->use_blink) {
rc = sysfs_create_group(&led->cdev.dev->kobj,
&blink_attr_group);
if (rc)
goto fail_id_check;
rc = sysfs_create_group(&led->cdev.dev->kobj,
&lpg_attr_group);
if (rc)
goto fail_id_check;
} else if (led->kpdbl_cfg->pwm_cfg->mode == LPG_MODE) {
rc = sysfs_create_group(&led->cdev.dev->kobj,
&lpg_attr_group);
if (rc)
goto fail_id_check;
}
}
/* configure default state */
@@ -3659,6 +3737,20 @@ static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
sysfs_remove_group(&led_array[i].cdev.dev->\
kobj, &lpg_attr_group);
break;
case QPNP_ID_KPDBL:
if (led_array[i].kpdbl_cfg->pwm_cfg->mode == PWM_MODE)
sysfs_remove_group(&led_array[i].cdev.dev->
kobj, &pwm_attr_group);
if (led_array[i].kpdbl_cfg->pwm_cfg->use_blink) {
sysfs_remove_group(&led_array[i].cdev.dev->
kobj, &blink_attr_group);
sysfs_remove_group(&led_array[i].cdev.dev->
kobj, &lpg_attr_group);
} else if (led_array[i].kpdbl_cfg->pwm_cfg->mode
== LPG_MODE)
sysfs_remove_group(&led_array[i].cdev.dev->
kobj, &lpg_attr_group);
break;
default:
dev_err(&led_array[i].spmi_dev->dev,
"Invalid LED(%d)\n",