diff options
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/leds-qpnp.c | 236 |
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; |