forked from rubenslte/android_kernel_samsung_msm8226
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:
@@ -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
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user