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, &regulator_probe);
 			if (rc < 0) {