aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-01-23 09:38:15 -0500
committerLee Jones <lee.jones@linaro.org>2013-01-23 09:39:19 -0500
commit3988043b0ee1104d4cca7c57bbc23b16ea798b6f (patch)
tree416daa30f175aa7bb2710919ea06753ae7260013
parente41f39ea2a0e9ba32d6896c2cc38bfec880a0937 (diff)
pm2301: LPN mode control support
The AC charger plug-in detection while booting causes I2C read failure if AC charger is not connected. Now the LPN pin is enabled for every PM2301 register access, which solves the issue. Signed-off-by: Rupesh Kumar <rupesh.kumar@stericsson.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com> Reviewed-by: Vijaya Kumar K-1 <vijay.kilari@stericsson.com> Reviewed-by: Rabin VINCENT <rabin.vincent@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r--drivers/power/pm2301_charger.c71
-rw-r--r--drivers/power/pm2301_charger.h1
-rw-r--r--include/linux/pm2301_charger.h1
3 files changed, 71 insertions, 2 deletions
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
index 9b2e8943f944..ed48d75bb786 100644
--- a/drivers/power/pm2301_charger.c
+++ b/drivers/power/pm2301_charger.c
@@ -28,6 +28,7 @@
28#include <linux/mfd/abx500/ab8500-gpadc.h> 28#include <linux/mfd/abx500/ab8500-gpadc.h>
29#include <linux/mfd/abx500/ux500_chargalg.h> 29#include <linux/mfd/abx500/ux500_chargalg.h>
30#include <linux/pm2301_charger.h> 30#include <linux/pm2301_charger.h>
31#include <linux/gpio.h>
31 32
32#include "pm2301_charger.h" 33#include "pm2301_charger.h"
33 34
@@ -110,9 +111,35 @@ static const struct i2c_device_id pm2xxx_ident[] = {
110 { } 111 { }
111}; 112};
112 113
114static void set_lpn_pin(struct pm2xxx_charger *pm2)
115{
116 if (pm2->ac.charger_connected)
117 return;
118 gpio_set_value(pm2->lpn_pin, 1);
119
120 return;
121}
122
123static void clear_lpn_pin(struct pm2xxx_charger *pm2)
124{
125 if (pm2->ac.charger_connected)
126 return;
127 gpio_set_value(pm2->lpn_pin, 0);
128
129 return;
130}
131
113static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val) 132static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
114{ 133{
115 int ret; 134 int ret;
135 /*
136 * When AC adaptor is unplugged, the host
137 * must put LPN high to be able to
138 * communicate by I2C with PM2301
139 * and receive I2C "acknowledge" from PM2301.
140 */
141 mutex_lock(&pm2->lock);
142 set_lpn_pin(pm2);
116 143
117 ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg, 144 ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
118 1, val); 145 1, val);
@@ -120,6 +147,8 @@ static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
120 dev_err(pm2->dev, "Error reading register at 0x%x\n", reg); 147 dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
121 else 148 else
122 ret = 0; 149 ret = 0;
150 clear_lpn_pin(pm2);
151 mutex_unlock(&pm2->lock);
123 152
124 return ret; 153 return ret;
125} 154}
@@ -127,6 +156,14 @@ static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
127static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val) 156static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
128{ 157{
129 int ret; 158 int ret;
159 /*
160 * When AC adaptor is unplugged, the host
161 * must put LPN high to be able to
162 * communicate by I2C with PM2301
163 * and receive I2C "acknowledge" from PM2301.
164 */
165 mutex_lock(&pm2->lock);
166 set_lpn_pin(pm2);
130 167
131 ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg, 168 ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
132 1, &val); 169 1, &val);
@@ -134,6 +171,8 @@ static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
134 dev_err(pm2->dev, "Error writing register at 0x%x\n", reg); 171 dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
135 else 172 else
136 ret = 0; 173 ret = 0;
174 clear_lpn_pin(pm2);
175 mutex_unlock(&pm2->lock);
137 176
138 return ret; 177 return ret;
139} 178}
@@ -850,6 +889,14 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
850 889
851 pm2->bat = pl_data->battery; 890 pm2->bat = pl_data->battery;
852 891
892 /*get lpn GPIO from platform data*/
893 if (!pm2->pdata->lpn_gpio) {
894 dev_err(pm2->dev, "no lpn gpio data supplied\n");
895 ret = -EINVAL;
896 goto free_device_info;
897 }
898 pm2->lpn_pin = pm2->pdata->lpn_gpio;
899
853 if (!i2c_check_functionality(i2c_client->adapter, 900 if (!i2c_check_functionality(i2c_client->adapter,
854 I2C_FUNC_SMBUS_BYTE_DATA | 901 I2C_FUNC_SMBUS_BYTE_DATA |
855 I2C_FUNC_SMBUS_READ_WORD_DATA)) { 902 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
@@ -929,10 +976,25 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
929 goto unregister_pm2xxx_charger; 976 goto unregister_pm2xxx_charger;
930 } 977 }
931 978
979 /*Initialize lock*/
980 mutex_init(&pm2->lock);
981
932 /* 982 /*
933 * I2C Read/Write will fail, if AC adaptor is not connected. 983 * Charger detection mechanism requires pulling up the LPN pin
934 * fix the charger detection mechanism. 984 * while i2c communication if Charger is not connected
985 * LPN pin of PM2301 is GPIO60 of AB9540
935 */ 986 */
987 ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
988 if (ret < 0) {
989 dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
990 goto unregister_pm2xxx_charger;
991 }
992 ret = gpio_direction_output(pm2->lpn_pin, 0);
993 if (ret < 0) {
994 dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
995 goto free_gpio;
996 }
997
936 ret = pm2xxx_charger_detection(pm2, &val); 998 ret = pm2xxx_charger_detection(pm2, &val);
937 999
938 if ((ret == 0) && val) { 1000 if ((ret == 0) && val) {
@@ -944,6 +1006,8 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
944 1006
945 return 0; 1007 return 0;
946 1008
1009free_gpio:
1010 gpio_free(pm2->lpn_pin);
947unregister_pm2xxx_charger: 1011unregister_pm2xxx_charger:
948 /* unregister power supply */ 1012 /* unregister power supply */
949 power_supply_unregister(&pm2->ac_chg.psy); 1013 power_supply_unregister(&pm2->ac_chg.psy);
@@ -977,6 +1041,9 @@ static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
977 1041
978 power_supply_unregister(&pm2->ac_chg.psy); 1042 power_supply_unregister(&pm2->ac_chg.psy);
979 1043
1044 /*Free GPIO60*/
1045 gpio_free(pm2->lpn_pin);
1046
980 kfree(pm2); 1047 kfree(pm2);
981 1048
982 return 0; 1049 return 0;
diff --git a/drivers/power/pm2301_charger.h b/drivers/power/pm2301_charger.h
index 3531cc5a9056..e6319cdbc94f 100644
--- a/drivers/power/pm2301_charger.h
+++ b/drivers/power/pm2301_charger.h
@@ -493,6 +493,7 @@ struct pm2xxx_charger {
493 int old_vbat; 493 int old_vbat;
494 int failure_case; 494 int failure_case;
495 int failure_input_ovv; 495 int failure_input_ovv;
496 unsigned int lpn_pin;
496 struct pm2xxx_interrupts *pm2_int; 497 struct pm2xxx_interrupts *pm2_int;
497 struct ab8500_gpadc *gpadc; 498 struct ab8500_gpadc *gpadc;
498 struct regulator *regu; 499 struct regulator *regu;
diff --git a/include/linux/pm2301_charger.h b/include/linux/pm2301_charger.h
index 16bb1d34b9d5..fc3f026922ae 100644
--- a/include/linux/pm2301_charger.h
+++ b/include/linux/pm2301_charger.h
@@ -49,6 +49,7 @@ struct pm2xxx_charger_platform_data {
49 int i2c_bus; 49 int i2c_bus;
50 const char *label; 50 const char *label;
51 int irq_number; 51 int irq_number;
52 unsigned int lpn_gpio;
52 int irq_type; 53 int irq_type;
53}; 54};
54 55