power: smb349: fix possible bug in start/stop_charging

gpio_set_value_cansleep should not be used in a function
that may be called from an interrupt context.

Fix this by using the gpio_set_value() function rather
than the cansleep one in the SMB349 driver.

Change-Id: I6aaa845da8373a3a16ba2f9971fbf9b3a1f22bb4
Signed-off-by: David Keitel <dkeitel@codeaurora.org>
diff --git a/drivers/power/smb349.c b/drivers/power/smb349.c
index 4c07285..2784cc3 100644
--- a/drivers/power/smb349.c
+++ b/drivers/power/smb349.c
@@ -86,11 +86,11 @@
 
 	int			en_n_gpio;
 	int			chg_susp_gpio;
-	struct dentry			*dent;
-	spinlock_t			lock;
-	struct work_struct			hwinit_work;
+	struct dentry		*dent;
+	spinlock_t		lock;
 
-	struct power_supply			dc_psy;
+	struct work_struct	chg_work;
+	struct power_supply	dc_psy;
 };
 
 struct chg_ma_limit_entry {
@@ -445,16 +445,17 @@
 static int smb349_stop_charging(struct smb349_struct *smb349_chg)
 {
 	unsigned long flags;
-
-	if (smb349_chg->charging)
-		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 0);
+	int rc = 0;
 
 	spin_lock_irqsave(&smb349_chg->lock, flags);
 	pr_debug("stop charging %d\n", smb349_chg->charging);
 	smb349_chg->charging = 0;
 	spin_unlock_irqrestore(&smb349_chg->lock, flags);
-	power_supply_changed(&smb349_chg->dc_psy);
-	return 0;
+
+	if (smb349_chg->charging)
+		rc = schedule_work(&smb349_chg->chg_work);
+
+	return rc;
 }
 
 static int smb349_start_charging(struct smb349_struct *smb349_chg)
@@ -463,21 +464,14 @@
 	int rc;
 
 	rc = 0;
-	if (!smb349_chg->charging) {
-		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 1);
-		/*
-		 * Write non-default values, charger chip reloads from
-		 * non-volatile memory if it was in suspend mode
-		 *
-		 */
-		rc = schedule_work(&smb349_chg->hwinit_work);
-	}
-
 	spin_lock_irqsave(&smb349_chg->lock, flags);
 	pr_debug("start charging %d\n", smb349_chg->charging);
 	smb349_chg->charging = 1;
 	spin_unlock_irqrestore(&smb349_chg->lock, flags);
-	power_supply_changed(&smb349_chg->dc_psy);
+
+	if (!smb349_chg->charging)
+		rc = schedule_work(&smb349_chg->chg_work);
+
 	return rc;
 }
 
@@ -522,15 +516,25 @@
 	return 0;
 }
 
-static void hwinit_worker(struct work_struct *work)
+static void chg_worker(struct work_struct *work)
 {
-	int ret;
 	struct smb349_struct *smb349_chg = container_of(work,
-				struct smb349_struct, hwinit_work);
+				struct smb349_struct, chg_work);
+	int ret = 0;
 
-	ret = smb349_hwinit(smb349_chg);
+	gpio_set_value_cansleep(smb349_chg->en_n_gpio, smb349_chg->charging);
+
+	/*
+	 * Write non-default values, charger chip reloads from
+	 * non-volatile memory if it was in suspend mode
+	 *
+	 */
+	if (smb349_chg->charging)
+		ret = smb349_hwinit(smb349_chg);
 	if (ret)
 		pr_err("Failed to re-initilaze registers\n");
+
+	power_supply_changed(&smb349_chg->dc_psy);
 }
 
 static int __devinit smb349_init_ext_chg(struct smb349_struct *smb349_chg)
@@ -614,7 +618,7 @@
 	the_smb349_chg = smb349_chg;
 
 	create_debugfs_entries(smb349_chg);
-	INIT_WORK(&smb349_chg->hwinit_work, hwinit_worker);
+	INIT_WORK(&smb349_chg->chg_work, chg_worker);
 
 	pr_info("OK connector present = %d\n", smb349_chg->present);
 	return 0;
@@ -634,7 +638,7 @@
 	const struct smb349_platform_data *pdata;
 	struct smb349_struct *smb349_chg = i2c_get_clientdata(client);
 
-	flush_work(&smb349_chg->hwinit_work);
+	flush_work(&smb349_chg->chg_work);
 	pdata = client->dev.platform_data;
 	power_supply_unregister(&smb349_chg->dc_psy);
 	gpio_free(pdata->en_n_gpio);