| Mike Rapoport | 342d765 | 2008-12-30 22:44:53 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * Battery charger driver for Dialog Semiconductor DA9030 | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2008 Compulab, Ltd. | 
 | 5 |  * 	Mike Rapoport <mike@compulab.co.il> | 
 | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify | 
 | 8 |  * it under the terms of the GNU General Public License version 2 as | 
 | 9 |  * published by the Free Software Foundation. | 
 | 10 |  */ | 
 | 11 |  | 
 | 12 | #include <linux/kernel.h> | 
 | 13 | #include <linux/init.h> | 
 | 14 | #include <linux/types.h> | 
 | 15 | #include <linux/device.h> | 
 | 16 | #include <linux/workqueue.h> | 
 | 17 | #include <linux/module.h> | 
 | 18 | #include <linux/platform_device.h> | 
 | 19 | #include <linux/power_supply.h> | 
 | 20 | #include <linux/mfd/da903x.h> | 
 | 21 |  | 
 | 22 | #include <linux/debugfs.h> | 
 | 23 | #include <linux/seq_file.h> | 
 | 24 |  | 
 | 25 | #define DA9030_STATUS_CHDET	(1 << 3) | 
 | 26 |  | 
 | 27 | #define DA9030_FAULT_LOG		0x0a | 
 | 28 | #define DA9030_FAULT_LOG_OVER_TEMP	(1 << 7) | 
 | 29 | #define DA9030_FAULT_LOG_VBAT_OVER	(1 << 4) | 
 | 30 |  | 
 | 31 | #define DA9030_CHARGE_CONTROL		0x28 | 
 | 32 | #define DA9030_CHRG_CHARGER_ENABLE	(1 << 7) | 
 | 33 |  | 
 | 34 | #define DA9030_ADC_MAN_CONTROL		0x30 | 
 | 35 | #define DA9030_ADC_TBATREF_ENABLE	(1 << 5) | 
 | 36 | #define DA9030_ADC_LDO_INT_ENABLE	(1 << 4) | 
 | 37 |  | 
 | 38 | #define DA9030_ADC_AUTO_CONTROL		0x31 | 
 | 39 | #define DA9030_ADC_TBAT_ENABLE		(1 << 5) | 
 | 40 | #define DA9030_ADC_VBAT_IN_TXON		(1 << 4) | 
 | 41 | #define DA9030_ADC_VCH_ENABLE		(1 << 3) | 
 | 42 | #define DA9030_ADC_ICH_ENABLE		(1 << 2) | 
 | 43 | #define DA9030_ADC_VBAT_ENABLE		(1 << 1) | 
 | 44 | #define DA9030_ADC_AUTO_SLEEP_ENABLE	(1 << 0) | 
 | 45 |  | 
 | 46 | #define DA9030_VBATMON		0x32 | 
 | 47 | #define DA9030_VBATMONTXON	0x33 | 
 | 48 | #define DA9030_TBATHIGHP	0x34 | 
 | 49 | #define DA9030_TBATHIGHN	0x35 | 
 | 50 | #define DA9030_TBATLOW		0x36 | 
 | 51 |  | 
 | 52 | #define DA9030_VBAT_RES		0x41 | 
 | 53 | #define DA9030_VBATMIN_RES	0x42 | 
 | 54 | #define DA9030_VBATMINTXON_RES	0x43 | 
 | 55 | #define DA9030_ICHMAX_RES	0x44 | 
 | 56 | #define DA9030_ICHMIN_RES	0x45 | 
 | 57 | #define DA9030_ICHAVERAGE_RES	0x46 | 
 | 58 | #define DA9030_VCHMAX_RES	0x47 | 
 | 59 | #define DA9030_VCHMIN_RES	0x48 | 
 | 60 | #define DA9030_TBAT_RES		0x49 | 
 | 61 |  | 
 | 62 | struct da9030_adc_res { | 
 | 63 | 	uint8_t vbat_res; | 
 | 64 | 	uint8_t vbatmin_res; | 
 | 65 | 	uint8_t vbatmintxon; | 
 | 66 | 	uint8_t ichmax_res; | 
 | 67 | 	uint8_t ichmin_res; | 
 | 68 | 	uint8_t ichaverage_res; | 
 | 69 | 	uint8_t vchmax_res; | 
 | 70 | 	uint8_t vchmin_res; | 
 | 71 | 	uint8_t tbat_res; | 
 | 72 | 	uint8_t adc_in4_res; | 
 | 73 | 	uint8_t adc_in5_res; | 
 | 74 | }; | 
 | 75 |  | 
 | 76 | struct da9030_battery_thresholds { | 
 | 77 | 	int tbat_low; | 
 | 78 | 	int tbat_high; | 
 | 79 | 	int tbat_restart; | 
 | 80 |  | 
 | 81 | 	int vbat_low; | 
 | 82 | 	int vbat_crit; | 
 | 83 | 	int vbat_charge_start; | 
 | 84 | 	int vbat_charge_stop; | 
 | 85 | 	int vbat_charge_restart; | 
 | 86 |  | 
 | 87 | 	int vcharge_min; | 
 | 88 | 	int vcharge_max; | 
 | 89 | }; | 
 | 90 |  | 
 | 91 | struct da9030_charger { | 
 | 92 | 	struct power_supply psy; | 
 | 93 |  | 
 | 94 | 	struct device *master; | 
 | 95 |  | 
 | 96 | 	struct da9030_adc_res adc; | 
 | 97 | 	struct delayed_work work; | 
 | 98 | 	unsigned int interval; | 
 | 99 |  | 
 | 100 | 	struct power_supply_info *battery_info; | 
 | 101 |  | 
 | 102 | 	struct da9030_battery_thresholds thresholds; | 
 | 103 |  | 
 | 104 | 	unsigned int charge_milliamp; | 
 | 105 | 	unsigned int charge_millivolt; | 
 | 106 |  | 
 | 107 | 	/* charger status */ | 
 | 108 | 	bool chdet; | 
 | 109 | 	uint8_t fault; | 
 | 110 | 	int mA; | 
 | 111 | 	int mV; | 
 | 112 | 	bool is_on; | 
 | 113 |  | 
 | 114 | 	struct notifier_block nb; | 
 | 115 |  | 
 | 116 | 	/* platform callbacks for battery low and critical events */ | 
 | 117 | 	void (*battery_low)(void); | 
 | 118 | 	void (*battery_critical)(void); | 
 | 119 |  | 
 | 120 | 	struct dentry *debug_file; | 
 | 121 | }; | 
 | 122 |  | 
 | 123 | static inline int da9030_reg_to_mV(int reg) | 
 | 124 | { | 
 | 125 | 	return ((reg * 2650) >> 8) + 2650; | 
 | 126 | } | 
 | 127 |  | 
 | 128 | static inline int da9030_millivolt_to_reg(int mV) | 
 | 129 | { | 
 | 130 | 	return ((mV - 2650) << 8) / 2650; | 
 | 131 | } | 
 | 132 |  | 
 | 133 | static inline int da9030_reg_to_mA(int reg) | 
 | 134 | { | 
 | 135 | 	return ((reg * 24000) >> 8) / 15; | 
 | 136 | } | 
 | 137 |  | 
 | 138 | #ifdef CONFIG_DEBUG_FS | 
 | 139 | static int bat_debug_show(struct seq_file *s, void *data) | 
 | 140 | { | 
 | 141 | 	struct da9030_charger *charger = s->private; | 
 | 142 |  | 
 | 143 | 	seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off"); | 
 | 144 | 	if (charger->chdet) { | 
 | 145 | 		seq_printf(s, "iset = %dmA, vset = %dmV\n", | 
 | 146 | 			   charger->mA, charger->mV); | 
 | 147 | 	} | 
 | 148 |  | 
 | 149 | 	seq_printf(s, "vbat_res = %d (%dmV)\n", | 
 | 150 | 		   charger->adc.vbat_res, | 
 | 151 | 		   da9030_reg_to_mV(charger->adc.vbat_res)); | 
 | 152 | 	seq_printf(s, "vbatmin_res = %d (%dmV)\n", | 
 | 153 | 		   charger->adc.vbatmin_res, | 
 | 154 | 		   da9030_reg_to_mV(charger->adc.vbatmin_res)); | 
 | 155 | 	seq_printf(s, "vbatmintxon = %d (%dmV)\n", | 
 | 156 | 		   charger->adc.vbatmintxon, | 
 | 157 | 		   da9030_reg_to_mV(charger->adc.vbatmintxon)); | 
 | 158 | 	seq_printf(s, "ichmax_res = %d (%dmA)\n", | 
 | 159 | 		   charger->adc.ichmax_res, | 
 | 160 | 		   da9030_reg_to_mV(charger->adc.ichmax_res)); | 
 | 161 | 	seq_printf(s, "ichmin_res = %d (%dmA)\n", | 
 | 162 | 		   charger->adc.ichmin_res, | 
 | 163 | 		   da9030_reg_to_mA(charger->adc.ichmin_res)); | 
 | 164 | 	seq_printf(s, "ichaverage_res = %d (%dmA)\n", | 
 | 165 | 		   charger->adc.ichaverage_res, | 
 | 166 | 		   da9030_reg_to_mA(charger->adc.ichaverage_res)); | 
 | 167 | 	seq_printf(s, "vchmax_res = %d (%dmV)\n", | 
 | 168 | 		   charger->adc.vchmax_res, | 
 | 169 | 		   da9030_reg_to_mA(charger->adc.vchmax_res)); | 
 | 170 | 	seq_printf(s, "vchmin_res = %d (%dmV)\n", | 
 | 171 | 		   charger->adc.vchmin_res, | 
 | 172 | 		   da9030_reg_to_mV(charger->adc.vchmin_res)); | 
 | 173 |  | 
 | 174 | 	return 0; | 
 | 175 | } | 
 | 176 |  | 
 | 177 | static int debug_open(struct inode *inode, struct file *file) | 
 | 178 | { | 
 | 179 | 	return single_open(file, bat_debug_show, inode->i_private); | 
 | 180 | } | 
 | 181 |  | 
 | 182 | static const struct file_operations bat_debug_fops = { | 
 | 183 | 	.open		= debug_open, | 
 | 184 | 	.read		= seq_read, | 
 | 185 | 	.llseek		= seq_lseek, | 
 | 186 | 	.release	= single_release, | 
 | 187 | }; | 
 | 188 |  | 
 | 189 | static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger) | 
 | 190 | { | 
 | 191 | 	charger->debug_file = debugfs_create_file("charger", 0666, 0, charger, | 
 | 192 | 						 &bat_debug_fops); | 
 | 193 | 	return charger->debug_file; | 
 | 194 | } | 
 | 195 |  | 
 | 196 | static void da9030_bat_remove_debugfs(struct da9030_charger *charger) | 
 | 197 | { | 
 | 198 | 	debugfs_remove(charger->debug_file); | 
 | 199 | } | 
 | 200 | #else | 
 | 201 | static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger) | 
 | 202 | { | 
 | 203 | 	return NULL; | 
 | 204 | } | 
 | 205 | static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger) | 
 | 206 | { | 
 | 207 | } | 
 | 208 | #endif | 
 | 209 |  | 
 | 210 | static inline void da9030_read_adc(struct da9030_charger *charger, | 
 | 211 | 				   struct da9030_adc_res *adc) | 
 | 212 | { | 
 | 213 | 	da903x_reads(charger->master, DA9030_VBAT_RES, | 
 | 214 | 		     sizeof(*adc), (uint8_t *)adc); | 
 | 215 | } | 
 | 216 |  | 
 | 217 | static void da9030_charger_update_state(struct da9030_charger *charger) | 
 | 218 | { | 
 | 219 | 	uint8_t val; | 
 | 220 |  | 
 | 221 | 	da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val); | 
 | 222 | 	charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0; | 
 | 223 | 	charger->mA = ((val >> 3) & 0xf) * 100; | 
 | 224 | 	charger->mV = (val & 0x7) * 50 + 4000; | 
 | 225 |  | 
 | 226 | 	da9030_read_adc(charger, &charger->adc); | 
 | 227 | 	da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault); | 
 | 228 | 	charger->chdet = da903x_query_status(charger->master, | 
 | 229 | 						     DA9030_STATUS_CHDET); | 
 | 230 | } | 
 | 231 |  | 
 | 232 | static void da9030_set_charge(struct da9030_charger *charger, int on) | 
 | 233 | { | 
 | 234 | 	uint8_t val; | 
 | 235 |  | 
 | 236 | 	if (on) { | 
 | 237 | 		val = DA9030_CHRG_CHARGER_ENABLE; | 
 | 238 | 		val |= (charger->charge_milliamp / 100) << 3; | 
 | 239 | 		val |= (charger->charge_millivolt - 4000) / 50; | 
 | 240 | 		charger->is_on = 1; | 
 | 241 | 	} else { | 
 | 242 | 		val = 0; | 
 | 243 | 		charger->is_on = 0; | 
 | 244 | 	} | 
 | 245 |  | 
 | 246 | 	da903x_write(charger->master, DA9030_CHARGE_CONTROL, val); | 
 | 247 | } | 
 | 248 |  | 
 | 249 | static void da9030_charger_check_state(struct da9030_charger *charger) | 
 | 250 | { | 
 | 251 | 	da9030_charger_update_state(charger); | 
 | 252 |  | 
 | 253 | 	/* we wake or boot with external power on */ | 
 | 254 | 	if (!charger->is_on) { | 
 | 255 | 		if ((charger->chdet) && | 
 | 256 | 		    (charger->adc.vbat_res < | 
 | 257 | 		     charger->thresholds.vbat_charge_start)) { | 
 | 258 | 			da9030_set_charge(charger, 1); | 
 | 259 | 		} | 
 | 260 | 	} else { | 
 | 261 | 		if (charger->adc.vbat_res >= | 
 | 262 | 		    charger->thresholds.vbat_charge_stop) { | 
 | 263 | 			da9030_set_charge(charger, 0); | 
 | 264 | 			da903x_write(charger->master, DA9030_VBATMON, | 
 | 265 | 				       charger->thresholds.vbat_charge_restart); | 
 | 266 | 		} else if (charger->adc.vbat_res > | 
 | 267 | 			   charger->thresholds.vbat_low) { | 
 | 268 | 			/* we are charging and passed LOW_THRESH, | 
 | 269 | 			   so upate DA9030 VBAT threshold | 
 | 270 | 			 */ | 
 | 271 | 			da903x_write(charger->master, DA9030_VBATMON, | 
 | 272 | 				     charger->thresholds.vbat_low); | 
 | 273 | 		} | 
 | 274 | 		if (charger->adc.vchmax_res > charger->thresholds.vcharge_max || | 
 | 275 | 		    charger->adc.vchmin_res < charger->thresholds.vcharge_min || | 
 | 276 | 		    /* Tempreture readings are negative */ | 
 | 277 | 		    charger->adc.tbat_res < charger->thresholds.tbat_high || | 
 | 278 | 		    charger->adc.tbat_res > charger->thresholds.tbat_low) { | 
 | 279 | 			/* disable charger */ | 
 | 280 | 			da9030_set_charge(charger, 0); | 
 | 281 | 		} | 
 | 282 | 	} | 
 | 283 | } | 
 | 284 |  | 
 | 285 | static void da9030_charging_monitor(struct work_struct *work) | 
 | 286 | { | 
 | 287 | 	struct da9030_charger *charger; | 
 | 288 |  | 
 | 289 | 	charger = container_of(work, struct da9030_charger, work.work); | 
 | 290 |  | 
 | 291 | 	da9030_charger_check_state(charger); | 
 | 292 |  | 
 | 293 | 	/* reschedule for the next time */ | 
 | 294 | 	schedule_delayed_work(&charger->work, charger->interval); | 
 | 295 | } | 
 | 296 |  | 
 | 297 | static enum power_supply_property da9030_battery_props[] = { | 
 | 298 | 	POWER_SUPPLY_PROP_MODEL_NAME, | 
 | 299 | 	POWER_SUPPLY_PROP_STATUS, | 
 | 300 | 	POWER_SUPPLY_PROP_HEALTH, | 
 | 301 | 	POWER_SUPPLY_PROP_TECHNOLOGY, | 
 | 302 | 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | 
 | 303 | 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 
 | 304 | 	POWER_SUPPLY_PROP_VOLTAGE_NOW, | 
 | 305 | 	POWER_SUPPLY_PROP_CURRENT_AVG, | 
 | 306 | }; | 
 | 307 |  | 
 | 308 | static void da9030_battery_check_status(struct da9030_charger *charger, | 
 | 309 | 				    union power_supply_propval *val) | 
 | 310 | { | 
 | 311 | 	if (charger->chdet) { | 
 | 312 | 		if (charger->is_on) | 
 | 313 | 			val->intval = POWER_SUPPLY_STATUS_CHARGING; | 
 | 314 | 		else | 
 | 315 | 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | 
 | 316 | 	} else { | 
 | 317 | 		val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | 
 | 318 | 	} | 
 | 319 | } | 
 | 320 |  | 
 | 321 | static void da9030_battery_check_health(struct da9030_charger *charger, | 
 | 322 | 				    union power_supply_propval *val) | 
 | 323 | { | 
 | 324 | 	if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP) | 
 | 325 | 		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | 
 | 326 | 	else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER) | 
 | 327 | 		val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | 
 | 328 | 	else | 
 | 329 | 		val->intval = POWER_SUPPLY_HEALTH_GOOD; | 
 | 330 | } | 
 | 331 |  | 
 | 332 | static int da9030_battery_get_property(struct power_supply *psy, | 
 | 333 | 				   enum power_supply_property psp, | 
 | 334 | 				   union power_supply_propval *val) | 
 | 335 | { | 
 | 336 | 	struct da9030_charger *charger; | 
 | 337 | 	charger = container_of(psy, struct da9030_charger, psy); | 
 | 338 |  | 
 | 339 | 	switch (psp) { | 
 | 340 | 	case POWER_SUPPLY_PROP_STATUS: | 
 | 341 | 		da9030_battery_check_status(charger, val); | 
 | 342 | 		break; | 
 | 343 | 	case POWER_SUPPLY_PROP_HEALTH: | 
 | 344 | 		da9030_battery_check_health(charger, val); | 
 | 345 | 		break; | 
 | 346 | 	case POWER_SUPPLY_PROP_TECHNOLOGY: | 
 | 347 | 		val->intval = charger->battery_info->technology; | 
 | 348 | 		break; | 
 | 349 | 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 
 | 350 | 		val->intval = charger->battery_info->voltage_max_design; | 
 | 351 | 		break; | 
 | 352 | 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | 
 | 353 | 		val->intval = charger->battery_info->voltage_min_design; | 
 | 354 | 		break; | 
 | 355 | 	case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 
 | 356 | 		val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000; | 
 | 357 | 		break; | 
 | 358 | 	case POWER_SUPPLY_PROP_CURRENT_AVG: | 
 | 359 | 		val->intval = | 
 | 360 | 			da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000; | 
 | 361 | 		break; | 
 | 362 | 	case POWER_SUPPLY_PROP_MODEL_NAME: | 
 | 363 | 		val->strval = charger->battery_info->name; | 
 | 364 | 		break; | 
 | 365 | 	default: | 
 | 366 | 		break; | 
 | 367 | 	} | 
 | 368 |  | 
 | 369 | 	return 0; | 
 | 370 | } | 
 | 371 |  | 
 | 372 | static void da9030_battery_vbat_event(struct da9030_charger *charger) | 
 | 373 | { | 
 | 374 | 	da9030_read_adc(charger, &charger->adc); | 
 | 375 |  | 
 | 376 | 	if (charger->is_on) | 
 | 377 | 		return; | 
 | 378 |  | 
 | 379 | 	if (charger->adc.vbat_res < charger->thresholds.vbat_low) { | 
 | 380 | 		/* set VBAT threshold for critical */ | 
 | 381 | 		da903x_write(charger->master, DA9030_VBATMON, | 
 | 382 | 			     charger->thresholds.vbat_crit); | 
 | 383 | 		if (charger->battery_low) | 
 | 384 | 			charger->battery_low(); | 
 | 385 | 	} else if (charger->adc.vbat_res < | 
 | 386 | 		   charger->thresholds.vbat_crit) { | 
 | 387 | 		/* notify the system of battery critical */ | 
 | 388 | 		if (charger->battery_critical) | 
 | 389 | 			charger->battery_critical(); | 
 | 390 | 	} | 
 | 391 | } | 
 | 392 |  | 
 | 393 | static int da9030_battery_event(struct notifier_block *nb, unsigned long event, | 
 | 394 | 				void *data) | 
 | 395 | { | 
 | 396 | 	struct da9030_charger *charger = | 
 | 397 | 		container_of(nb, struct da9030_charger, nb); | 
 | 398 | 	int status; | 
 | 399 |  | 
 | 400 | 	switch (event) { | 
 | 401 | 	case DA9030_EVENT_CHDET: | 
 | 402 | 		status = da903x_query_status(charger->master, | 
 | 403 | 					     DA9030_STATUS_CHDET); | 
 | 404 | 		da9030_set_charge(charger, status); | 
 | 405 | 		break; | 
 | 406 | 	case DA9030_EVENT_VBATMON: | 
 | 407 | 		da9030_battery_vbat_event(charger); | 
 | 408 | 		break; | 
 | 409 | 	case DA9030_EVENT_CHIOVER: | 
 | 410 | 	case DA9030_EVENT_TBAT: | 
 | 411 | 		da9030_set_charge(charger, 0); | 
 | 412 | 		break; | 
 | 413 | 	} | 
 | 414 |  | 
 | 415 | 	return 0; | 
 | 416 | } | 
 | 417 |  | 
 | 418 | static void da9030_battery_convert_thresholds(struct da9030_charger *charger, | 
 | 419 | 					      struct da9030_battery_info *pdata) | 
 | 420 | { | 
 | 421 | 	charger->thresholds.tbat_low = pdata->tbat_low; | 
 | 422 | 	charger->thresholds.tbat_high = pdata->tbat_high; | 
 | 423 | 	charger->thresholds.tbat_restart  = pdata->tbat_restart; | 
 | 424 |  | 
 | 425 | 	charger->thresholds.vbat_low = | 
 | 426 | 		da9030_millivolt_to_reg(pdata->vbat_low); | 
 | 427 | 	charger->thresholds.vbat_crit = | 
 | 428 | 		da9030_millivolt_to_reg(pdata->vbat_crit); | 
 | 429 | 	charger->thresholds.vbat_charge_start = | 
 | 430 | 		da9030_millivolt_to_reg(pdata->vbat_charge_start); | 
 | 431 | 	charger->thresholds.vbat_charge_stop = | 
 | 432 | 		da9030_millivolt_to_reg(pdata->vbat_charge_stop); | 
 | 433 | 	charger->thresholds.vbat_charge_restart = | 
 | 434 | 		da9030_millivolt_to_reg(pdata->vbat_charge_restart); | 
 | 435 |  | 
 | 436 | 	charger->thresholds.vcharge_min = | 
 | 437 | 		da9030_millivolt_to_reg(pdata->vcharge_min); | 
 | 438 | 	charger->thresholds.vcharge_max = | 
 | 439 | 		da9030_millivolt_to_reg(pdata->vcharge_max); | 
 | 440 | } | 
 | 441 |  | 
 | 442 | static void da9030_battery_setup_psy(struct da9030_charger *charger) | 
 | 443 | { | 
 | 444 | 	struct power_supply *psy = &charger->psy; | 
 | 445 | 	struct power_supply_info *info = charger->battery_info; | 
 | 446 |  | 
 | 447 | 	psy->name = info->name; | 
 | 448 | 	psy->use_for_apm = info->use_for_apm; | 
 | 449 | 	psy->type = POWER_SUPPLY_TYPE_BATTERY; | 
 | 450 | 	psy->get_property = da9030_battery_get_property; | 
 | 451 |  | 
 | 452 | 	psy->properties = da9030_battery_props; | 
 | 453 | 	psy->num_properties = ARRAY_SIZE(da9030_battery_props); | 
 | 454 | }; | 
 | 455 |  | 
 | 456 | static int da9030_battery_charger_init(struct da9030_charger *charger) | 
 | 457 | { | 
 | 458 | 	char v[5]; | 
 | 459 | 	int ret; | 
 | 460 |  | 
 | 461 | 	v[0] = v[1] = charger->thresholds.vbat_low; | 
 | 462 | 	v[2] = charger->thresholds.tbat_high; | 
 | 463 | 	v[3] = charger->thresholds.tbat_restart; | 
 | 464 | 	v[4] = charger->thresholds.tbat_low; | 
 | 465 |  | 
 | 466 | 	ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v); | 
 | 467 | 	if (ret) | 
 | 468 | 		return ret; | 
 | 469 |  | 
 | 470 | 	/* | 
 | 471 | 	 * Enable reference voltage supply for ADC from the LDO_INTERNAL | 
 | 472 | 	 * regulator. Must be set before ADC measurements can be made. | 
 | 473 | 	 */ | 
 | 474 | 	ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL, | 
 | 475 | 			   DA9030_ADC_LDO_INT_ENABLE | | 
 | 476 | 			   DA9030_ADC_TBATREF_ENABLE); | 
 | 477 | 	if (ret) | 
 | 478 | 		return ret; | 
 | 479 |  | 
 | 480 | 	/* enable auto ADC measuremnts */ | 
 | 481 | 	return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL, | 
 | 482 | 			    DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON | | 
 | 483 | 			    DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE | | 
 | 484 | 			    DA9030_ADC_VBAT_ENABLE | | 
 | 485 | 			    DA9030_ADC_AUTO_SLEEP_ENABLE); | 
 | 486 | } | 
 | 487 |  | 
 | 488 | static int da9030_battery_probe(struct platform_device *pdev) | 
 | 489 | { | 
 | 490 | 	struct da9030_charger *charger; | 
 | 491 | 	struct da9030_battery_info *pdata = pdev->dev.platform_data; | 
 | 492 | 	int ret; | 
 | 493 |  | 
 | 494 | 	if (pdata == NULL) | 
 | 495 | 		return -EINVAL; | 
 | 496 |  | 
 | 497 | 	if (pdata->charge_milliamp >= 1500 || | 
 | 498 | 	    pdata->charge_millivolt < 4000 || | 
 | 499 | 	    pdata->charge_millivolt > 4350) | 
 | 500 | 		return -EINVAL; | 
 | 501 |  | 
 | 502 | 	charger = kzalloc(sizeof(*charger), GFP_KERNEL); | 
 | 503 | 	if (charger == NULL) | 
 | 504 | 		return -ENOMEM; | 
 | 505 |  | 
 | 506 | 	charger->master = pdev->dev.parent; | 
 | 507 |  | 
 | 508 | 	/* 10 seconds between monotor runs unless platfrom defines other | 
 | 509 | 	   interval */ | 
 | 510 | 	charger->interval = msecs_to_jiffies( | 
 | 511 | 		(pdata->batmon_interval ? : 10) * 1000); | 
 | 512 |  | 
 | 513 | 	charger->charge_milliamp = pdata->charge_milliamp; | 
 | 514 | 	charger->charge_millivolt = pdata->charge_millivolt; | 
 | 515 | 	charger->battery_info = pdata->battery_info; | 
 | 516 | 	charger->battery_low = pdata->battery_low; | 
 | 517 | 	charger->battery_critical = pdata->battery_critical; | 
 | 518 |  | 
 | 519 | 	da9030_battery_convert_thresholds(charger, pdata); | 
 | 520 |  | 
 | 521 | 	ret = da9030_battery_charger_init(charger); | 
 | 522 | 	if (ret) | 
 | 523 | 		goto err_charger_init; | 
 | 524 |  | 
 | 525 | 	INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor); | 
 | 526 | 	schedule_delayed_work(&charger->work, charger->interval); | 
 | 527 |  | 
 | 528 | 	charger->nb.notifier_call = da9030_battery_event; | 
 | 529 | 	ret = da903x_register_notifier(charger->master, &charger->nb, | 
 | 530 | 				       DA9030_EVENT_CHDET | | 
 | 531 | 				       DA9030_EVENT_VBATMON | | 
 | 532 | 				       DA9030_EVENT_CHIOVER | | 
 | 533 | 				       DA9030_EVENT_TBAT); | 
 | 534 | 	if (ret) | 
 | 535 | 		goto err_notifier; | 
 | 536 |  | 
 | 537 | 	da9030_battery_setup_psy(charger); | 
 | 538 | 	ret = power_supply_register(&pdev->dev, &charger->psy); | 
 | 539 | 	if (ret) | 
 | 540 | 		goto err_ps_register; | 
 | 541 |  | 
 | 542 | 	charger->debug_file = da9030_bat_create_debugfs(charger); | 
 | 543 | 	platform_set_drvdata(pdev, charger); | 
 | 544 | 	return 0; | 
 | 545 |  | 
 | 546 | err_ps_register: | 
 | 547 | 	da903x_unregister_notifier(charger->master, &charger->nb, | 
 | 548 | 				   DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON | | 
 | 549 | 				   DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); | 
 | 550 | err_notifier: | 
 | 551 | 	cancel_delayed_work(&charger->work); | 
 | 552 |  | 
 | 553 | err_charger_init: | 
 | 554 | 	kfree(charger); | 
 | 555 |  | 
 | 556 | 	return ret; | 
 | 557 | } | 
 | 558 |  | 
 | 559 | static int da9030_battery_remove(struct platform_device *dev) | 
 | 560 | { | 
 | 561 | 	struct da9030_charger *charger = platform_get_drvdata(dev); | 
 | 562 |  | 
 | 563 | 	da9030_bat_remove_debugfs(charger); | 
 | 564 |  | 
 | 565 | 	da903x_unregister_notifier(charger->master, &charger->nb, | 
 | 566 | 				   DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON | | 
 | 567 | 				   DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); | 
 | 568 | 	cancel_delayed_work(&charger->work); | 
 | 569 | 	power_supply_unregister(&charger->psy); | 
 | 570 |  | 
 | 571 | 	kfree(charger); | 
 | 572 |  | 
 | 573 | 	return 0; | 
 | 574 | } | 
 | 575 |  | 
 | 576 | static struct platform_driver da903x_battery_driver = { | 
 | 577 | 	.driver	= { | 
 | 578 | 		.name	= "da903x-battery", | 
 | 579 | 		.owner	= THIS_MODULE, | 
 | 580 | 	}, | 
 | 581 | 	.probe = da9030_battery_probe, | 
 | 582 | 	.remove = da9030_battery_remove, | 
 | 583 | }; | 
 | 584 |  | 
 | 585 | static int da903x_battery_init(void) | 
 | 586 | { | 
 | 587 | 	return platform_driver_register(&da903x_battery_driver); | 
 | 588 | } | 
 | 589 |  | 
 | 590 | static void da903x_battery_exit(void) | 
 | 591 | { | 
 | 592 | 	platform_driver_unregister(&da903x_battery_driver); | 
 | 593 | } | 
 | 594 |  | 
 | 595 | module_init(da903x_battery_init); | 
 | 596 | module_exit(da903x_battery_exit); | 
 | 597 |  | 
 | 598 | MODULE_DESCRIPTION("DA9030 battery charger driver"); | 
 | 599 | MODULE_AUTHOR("Mike Rapoport, CompuLab"); | 
 | 600 | MODULE_LICENSE("GPL"); |