summaryrefslogtreecommitdiff
path: root/drivers/leds
diff options
context:
space:
mode:
authorChun Zhang <chunz@codeaurora.org>2013-06-25 20:14:46 -0700
committerStephen Boyd <sboyd@codeaurora.org>2013-09-04 17:15:32 -0700
commitd4b8ec9dfaf88731e9f80b327adb17bb24c23e13 (patch)
tree533c8fbc6f6dfa3dbec57cefd0d8acab2f90820c /drivers/leds
parentc35c12ce0653a3177e595a631b0d12db8b536070 (diff)
leds: leds-qpnp: Enable sync boost for flash LED torch mode
Flash LED uses sync boost as power source in torch mode. Enabling sync boost when flash LED is used as torch light can make flash LED working when battery is low. Change-Id: Iab757de65087ee1a4312a5a9ec4d87c8bf3d5555 Signed-off-by: Chun Zhang <chunz@codeaurora.org>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/leds-qpnp.c236
1 files changed, 174 insertions, 62 deletions
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 4fe09a719af4..0c82e286700a 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -372,7 +372,9 @@ struct mpp_config_data {
* @torch_enable - enable flash LED torch mode
* @flash_reg_get - flash regulator attached or not
* @flash_on - flash status, on or off
+ * @torch_on - torch status, on or off
* @flash_boost_reg - boost regulator for flash
+ * @torch_boost_reg - boost regulator for torch
*/
struct flash_config_data {
u8 current_prgm;
@@ -389,7 +391,9 @@ struct flash_config_data {
bool torch_enable;
bool flash_reg_get;
bool flash_on;
+ bool torch_on;
struct regulator *flash_boost_reg;
+ struct regulator *torch_boost_reg;
};
/**
@@ -733,9 +737,40 @@ regulator_turn_off:
return 0;
}
-static int qpnp_flash_set(struct qpnp_led_data *led)
+static int qpnp_torch_regulator_operate(struct qpnp_led_data *led, bool on)
{
int rc;
+
+ if (!on)
+ goto regulator_turn_off;
+
+ if (!led->flash_cfg->torch_on) {
+ rc = regulator_enable(led->flash_cfg->torch_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Regulator enable failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->torch_on = true;
+ }
+ return 0;
+
+regulator_turn_off:
+ if (led->flash_cfg->torch_on) {
+ rc = regulator_disable(led->flash_cfg->torch_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Regulator disable failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->torch_on = false;
+ }
+ return 0;
+}
+
+static int qpnp_flash_set(struct qpnp_led_data *led)
+{
+ int rc, error;
int val = led->cdev.brightness;
if (led->flash_cfg->torch_enable)
@@ -753,13 +788,21 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
/* Set led current */
if (val > 0) {
if (led->flash_cfg->torch_enable) {
+ rc = qpnp_torch_regulator_operate(led, true);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led,
FLASH_LED_UNLOCK_SECURE(led->base),
FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -768,7 +811,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Torch reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -778,7 +821,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -789,7 +832,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_torch_set;
}
qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -799,16 +842,16 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
} else {
rc = qpnp_flash_regulator_operate(led, true);
@@ -816,7 +859,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"Flash regulator operate failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set flash safety timer */
@@ -828,7 +871,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"Safety timer reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set max current */
@@ -839,7 +882,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set clamp current */
@@ -851,7 +894,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"Clamp current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Write 0x80 to MODULE_ENABLE before writing 0xE0
@@ -864,7 +907,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -874,7 +917,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -885,7 +928,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -894,7 +937,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
}
@@ -906,7 +949,10 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"LED %d strobe reg write failed(%d)\n",
led->id, rc);
- return rc;
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
}
} else {
rc = qpnp_led_masked_write(led,
@@ -916,10 +962,38 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
dev_err(&led->spmi_dev->dev,
"LED %d strobe reg write failed(%d)\n",
led->id, rc);
- return rc;
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
}
}
} else {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_STROBE_CTRL(led->base),
+ FLASH_STROBE_MASK,
+ FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED %d flash write failed(%d)\n", led->id, rc);
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
+ }
+
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK,
+ FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
+ }
+
if (led->flash_cfg->torch_enable) {
rc = qpnp_led_masked_write(led,
FLASH_LED_UNLOCK_SECURE(led->base),
@@ -927,7 +1001,7 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -937,40 +1011,48 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
if (rc) {
dev_err(&led->spmi_dev->dev,
"Torch reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
- }
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- FLASH_STROBE_MASK,
- FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "LED %d flash write failed(%d)\n", led->id, rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MASK,
- FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_flash_regulator_operate(led, false);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Flash regulator operate failed(%d)\n", rc);
- return rc;
+ rc = qpnp_torch_regulator_operate(led, false);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
+ } else {
+ rc = qpnp_flash_regulator_operate(led, false);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
}
}
qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
return 0;
+
+error_torch_set:
+ error = qpnp_torch_regulator_operate(led, false);
+ if (error) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n", rc);
+ return error;
+ }
+ return rc;
+
+error_flash_set:
+ error = qpnp_flash_regulator_operate(led, false);
+ if (error) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n", rc);
+ return error;
+ }
+ return rc;
}
static int qpnp_kpdbl_set(struct qpnp_led_data *led)
@@ -1997,6 +2079,18 @@ static int qpnp_flash_init(struct qpnp_led_data *led)
return rc;
}
+ /* Disable flash LED module */
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ if (led->flash_cfg->torch_enable)
+ return 0;
+
/* Set headroom */
rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -2056,15 +2150,6 @@ static int qpnp_flash_init(struct qpnp_led_data *led)
return rc;
}
- /* Disable flash LED module */
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
-
led->flash_cfg->strobe_type = 0;
/* dump flash registers */
@@ -2393,7 +2478,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
"Regulator get failed(%d)\n", rc);
- return rc;
+ goto error_get_flash_reg;
}
led->flash_cfg->flash_reg_get = true;
*reg_set = true;
@@ -2412,7 +2497,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
"Regulator get failed(%d)\n", rc);
- return rc;
+ goto error_get_flash_reg;
}
led->flash_cfg->flash_reg_get = true;
*reg_set = true;
@@ -2426,16 +2511,32 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
led->flash_cfg->torch_enable =
of_property_read_bool(node, "qcom,torch-enable");
+ if (led->flash_cfg->torch_enable) {
+ led->flash_cfg->torch_boost_reg =
+ regulator_get(&led->spmi_dev->dev, "torch_boost");
+ if (IS_ERR(led->flash_cfg->torch_boost_reg)) {
+ rc = PTR_ERR(led->flash_cfg->torch_boost_reg);
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator get failed(%d)\n", rc);
+ goto error_get_torch_reg;
+ }
+ }
+
rc = of_property_read_u32(node, "qcom,current", &val);
if (!rc) {
- if (led->flash_cfg->torch_enable)
+ if (led->flash_cfg->torch_enable) {
led->flash_cfg->current_prgm = (val *
TORCH_MAX_LEVEL / led->max_current);
+ return 0;
+ }
else
led->flash_cfg->current_prgm = (val *
FLASH_MAX_LEVEL / led->max_current);
} else
- return -EINVAL;
+ if (led->flash_cfg->torch_enable)
+ goto error_get_torch_reg;
+ else
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,headroom", &val);
if (!rc)
@@ -2443,7 +2544,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
else if (rc == -EINVAL)
led->flash_cfg->headroom = HEADROOM_500mV;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,duration", &val);
if (!rc)
@@ -2451,7 +2552,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
else if (rc == -EINVAL)
led->flash_cfg->duration = FLASH_DURATION_200ms;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
if (!rc)
@@ -2460,7 +2561,7 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
else if (rc == -EINVAL)
led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,startup-dly", &val);
if (!rc)
@@ -2468,12 +2569,20 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
else if (rc == -EINVAL)
led->flash_cfg->startup_dly = DELAY_128us;
else
- return rc;
+ goto error_get_flash_reg;
led->flash_cfg->safety_timer =
of_property_read_bool(node, "qcom,safety-timer");
return 0;
+
+error_get_torch_reg:
+ regulator_put(led->flash_cfg->torch_boost_reg);
+
+error_get_flash_reg:
+ regulator_put(led->flash_cfg->flash_boost_reg);
+ return rc;
+
}
static int qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
@@ -3065,6 +3174,9 @@ static int qpnp_leds_remove(struct spmi_device *spmi)
if (led_array[i].flash_cfg->flash_reg_get)
regulator_put(led_array[i].flash_cfg-> \
flash_boost_reg);
+ if (led_array[i].flash_cfg->torch_enable)
+ regulator_put(led_array[i].flash_cfg->\
+ torch_boost_reg);
sysfs_remove_group(&led_array[i].cdev.dev->kobj,
&led_attr_group);
break;