leds: leds-qpnp: Enable flash torch mode on single LED PMIC
Flash LED torch mode is not supported from hardware perspective
on PMIC with single flash LED module. Enabling torch mode on such
PMIC chips requires detection of PMIC peripheral subtype and
use flash mode with a lower current to implement torch.
Change-Id: I77228068c2c0ec4a0ed5614f4a991a3bce5db013
Signed-off-by: Chun Zhang <chunz@codeaurora.org>
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index a1453ae..a90b8f0 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -95,6 +95,7 @@
#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
#define FLASH_LED_TORCH(base) (base + 0xE4)
#define FLASH_FAULT_DETECT(base) (base + 0x51)
+#define FLASH_PERIPHERAL_SUBTYPE(base) (base + 0x05)
#define FLASH_MAX_LEVEL 0x4F
#define TORCH_MAX_LEVEL 0x0F
@@ -144,6 +145,9 @@
#define FLASH_UNLOCK_SECURE 0xA5
#define FLASH_SECURE_MASK 0xFF
+#define FLASH_SUBTYPE_DUAL 0x01
+#define FLASH_SUBTYPE_SINGLE 0x02
+
#define LED_TRIGGER_DEFAULT "none"
#define RGB_LED_SRC_SEL(base) (base + 0x45)
@@ -366,6 +370,7 @@
* @trigger_flash - trigger flash
* @startup_dly - startup delay for flash
* @strobe_type - select between sw and hw strobe
+ * @peripheral_subtype - module peripheral subtype
* @current_addr - address to write for current
* @second_addr - address of secondary flash to be written
* @safety_timer - enable safety timer or watchdog timer
@@ -385,6 +390,7 @@
u8 trigger_flash;
u8 startup_dly;
u8 strobe_type;
+ u8 peripheral_subtype;
u16 current_addr;
u16 second_addr;
bool safety_timer;
@@ -788,12 +794,40 @@
/* 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,
+ if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_DUAL) {
+ rc = qpnp_torch_regulator_operate(led, true);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
"Torch regulator operate failed(%d)\n",
rc);
- return rc;
+ return rc;
+ }
+ } else if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_SINGLE) {
+ rc = qpnp_flash_regulator_operate(led, true);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n",
+ rc);
+ goto error_flash_set;
+ }
+
+ /*
+ * Write 0x80 to MODULE_ENABLE before writing
+ * 0xE0 in order to avoid a hardware bug caused
+ * by register value going from 0x00 to 0xE0.
+ */
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK,
+ FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
}
rc = qpnp_led_masked_write(led,
@@ -802,7 +836,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- goto error_torch_set;
+ goto error_reg_write;
}
rc = qpnp_led_masked_write(led,
@@ -811,7 +845,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Torch reg write failed(%d)\n", rc);
- goto error_torch_set;
+ goto error_reg_write;
}
rc = qpnp_led_masked_write(led,
@@ -821,7 +855,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
- goto error_torch_set;
+ goto error_reg_write;
}
rc = qpnp_led_masked_write(led,
@@ -832,7 +866,7 @@
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
rc);
- goto error_torch_set;
+ goto error_reg_write;
}
qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -842,16 +876,31 @@
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
rc);
- goto error_torch_set;
+ goto error_reg_write;
}
- rc = qpnp_led_masked_write(led,
- FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- goto error_torch_set;
+ if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_DUAL) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n",
+ rc);
+ goto error_torch_set;
+ }
+ } else if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_SINGLE) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n",
+ rc);
+ goto error_flash_set;
+ }
}
} else {
rc = qpnp_flash_regulator_operate(led, true);
@@ -897,9 +946,10 @@
goto error_flash_set;
}
- /* Write 0x80 to MODULE_ENABLE before writing 0xE0
- * in order to avoid reg value goes from 0x00 to
- * 0xE0. This causes a hardware bug.
+ /*
+ * Write 0x80 to MODULE_ENABLE before writing
+ * 0xE0 in order to avoid a hardware bug caused
+ * by register value going from 0x00 to 0xE0.
*/
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
@@ -1014,12 +1064,24 @@
goto error_torch_set;
}
- rc = qpnp_torch_regulator_operate(led, false);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Torch regulator operate failed(%d)\n",
- rc);
- return rc;
+ if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_DUAL) {
+ 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 if (led->flash_cfg->peripheral_subtype ==
+ FLASH_SUBTYPE_SINGLE) {
+ rc = qpnp_flash_regulator_operate(led, false);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
}
} else {
rc = qpnp_flash_regulator_operate(led, false);
@@ -1036,6 +1098,10 @@
return 0;
+error_reg_write:
+ if (led->flash_cfg->peripheral_subtype == FLASH_SUBTYPE_SINGLE)
+ goto error_flash_set;
+
error_torch_set:
error = qpnp_torch_regulator_operate(led, false);
if (error) {
@@ -2465,6 +2531,15 @@
return -ENOMEM;
}
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ FLASH_PERIPHERAL_SUBTYPE(led->base),
+ &led->flash_cfg->peripheral_subtype, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read from addr=%x, rc(%d)\n",
+ FLASH_PERIPHERAL_SUBTYPE(led->base), rc);
+ }
+
if (led->id == QPNP_ID_FLASH1_LED0) {
led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
@@ -2473,7 +2548,7 @@
if (!*reg_set) {
led->flash_cfg->flash_boost_reg =
regulator_get(&led->spmi_dev->dev,
- "flash_boost");
+ "flash-boost");
if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
@@ -2492,7 +2567,7 @@
if (!*reg_set) {
led->flash_cfg->flash_boost_reg =
regulator_get(&led->spmi_dev->dev,
- "flash_boost");
+ "flash-boost");
if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
@@ -2512,13 +2587,17 @@
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;
+ if (of_find_property(of_get_parent(node), "torch-boost-supply",
+ NULL)) {
+ 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;
+ }
}
}
@@ -3018,7 +3097,7 @@
}
} else if (strncmp(led_label, "flash", sizeof("flash"))
== 0) {
- if (!of_find_property(node, "flash_boost-supply", NULL))
+ if (!of_find_property(node, "flash-boost-supply", NULL))
regulator_probe = true;
rc = qpnp_get_config_flash(led, temp, ®ulator_probe);
if (rc < 0) {