mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	Highlights:
- Power supply notifier - Several drivers gained DT support - Added Maxim 14577 driver - Change of maintainer -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJS3bUsAAoJEBTbcu2+gGW4uC8QAJFPpPqnEjz9NnFjbngyTswc +Wq5kusHpdgIXCqx9+H26pm2NTyIm4uAcVn2XjYIvdKZbDvygNzMr8gPYpwWapJz 1K6ED1sZROhbvSKx0ADuGHz05Kwl78Kx6Qa+YtesGaKMaTxbJySWqh81zmYvN5Sq SoSqWC866bJwL4BVFIi7qZzHuD4czMP+iI8nrDKm1OFpj94y6DzC+BNxruYRCieI k+EEjTR6sKfQ0XFNxhyWSxxZtcxexVNvck7wsMleUUGysWHFjIu8HF01o9v58mt9 o/Tr8ZAHx8h0vPVtFF4ugnc+LZHwodqlcoFj1Q+5w3AsGYZUVMOIv2wY7gQZnRTj UcDXC06fG1ODMuBc1IUZy4j1ABAk+xoNW7zylMdtpgNDTpYdF5Mfy/yuD1eu5wzT SZyRpuCfoXEP1MDt+lcgBwakb4nh4HFgnzxbKWNwzKSsbJ/ZOHja5k4xe+aQ8yQX VmifBL8WUSYj97UQVy44/9DxSI7hE4GN7oXBKN2G/an5inqceePNDl89dymywBi1 NpWGX7a2NcQpdP+EpwLPuMU/J8SC5rzPWgMttpablrFSY0NQYJhmL3AdEcROP5gf cclLaT+UKgSTxOdAN4b8PIlMmffhJjvfBdxMsBaxe8PtLkRaXyXRcBkH/eDEsk7S Jj+gZOgLoThqJSK/IbB3 =QMHd -----END PGP SIGNATURE----- Merge tag 'for-v3.14' of git://git.infradead.org/battery-2.6 Pull battery updates from Dmitry Eremin-Solenikov: "I'm picking up power supply maintainership from Anton Vorontov. Could you please pull battery-2.6 git tree changes prepared for the v3.14 release. Highlights: - Power supply notifier - Several drivers gained DT support - Added Maxim 14577 driver - Change of maintainer" * tag 'for-v3.14' of git://git.infradead.org/battery-2.6: MAINTAINERS: Pick up power supply maintainership max17042_battery: Add IRQF_ONESHOT flag to use default irq handler gpio-charger: Support wakeup events power_supply: Add charger support for Maxim 14577 dt: Binding documentation for isp1704 charger isp1704_charger: Add DT support charger-manager: of_cm_parse_desc() should be static bq2415x_charger: Add DT support power_supply: Add power_supply_get_by_phandle bq2415x_charger: Use power_supply notifier for automode power: reset: Add as3722 power-off driver mfd: AS3722: Add dt node properties for system power controller charger-manager: Support deivce tree in charger manager driver charger-manager: Modify the way of checking battery's temperature power_supply: Add power_supply notifier
This commit is contained in:
		
						commit
						03d11a0e45
					
				
					 20 changed files with 1043 additions and 132 deletions
				
			
		|  | @ -112,6 +112,15 @@ Following are properties of regulator subnode. | ||||||
| 		ams,enable-tracking: Enable tracking with SD1, only supported | 		ams,enable-tracking: Enable tracking with SD1, only supported | ||||||
| 			by LDO3. | 			by LDO3. | ||||||
| 
 | 
 | ||||||
|  | Power-off: | ||||||
|  | ========= | ||||||
|  | AS3722 supports the system power off by turning off all its rail. This | ||||||
|  | is provided through pm_power_off. | ||||||
|  | The device node should have the following properties to enable this | ||||||
|  | functionality | ||||||
|  | ams,system-power-controller: Boolean, to enable the power off functionality | ||||||
|  |         through this device. | ||||||
|  | 
 | ||||||
| Example: | Example: | ||||||
| -------- | -------- | ||||||
| #include <dt-bindings/mfd/as3722.h> | #include <dt-bindings/mfd/as3722.h> | ||||||
|  | @ -120,6 +129,8 @@ ams3722 { | ||||||
| 	compatible = "ams,as3722"; | 	compatible = "ams,as3722"; | ||||||
| 	reg = <0x48>; | 	reg = <0x48>; | ||||||
| 
 | 
 | ||||||
|  | 	ams,system-power-controller; | ||||||
|  | 
 | ||||||
| 	interrupt-parent = <&intc>; | 	interrupt-parent = <&intc>; | ||||||
| 	interrupt-controller; | 	interrupt-controller; | ||||||
| 	#interrupt-cells = <2>; | 	#interrupt-cells = <2>; | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								Documentation/devicetree/bindings/power/isp1704.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Documentation/devicetree/bindings/power/isp1704.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | Binding for NXP ISP1704 USB Charger Detection | ||||||
|  | 
 | ||||||
|  | Required properties: | ||||||
|  | - compatible: Should contain one of the following: | ||||||
|  |  * "nxp,isp1704" | ||||||
|  | - nxp,enable-gpio: Should contain a phandle + gpio-specifier | ||||||
|  |   to the GPIO pin connected to the chip's enable pin. | ||||||
|  | - usb-phy: Should contain a phandle to the USB PHY | ||||||
|  |   the ISP1704 is connected to. | ||||||
|  | 
 | ||||||
|  | Example: | ||||||
|  | 
 | ||||||
|  | isp1704 { | ||||||
|  | 	compatible = "nxp,isp1704"; | ||||||
|  | 	nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_LOW>; | ||||||
|  | 	usb-phy = <&usb2_phy>; | ||||||
|  | }; | ||||||
|  | @ -0,0 +1,81 @@ | ||||||
|  | charger-manager bindings | ||||||
|  | ~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  | 
 | ||||||
|  | Required properties : | ||||||
|  |  - compatible : "charger-manager" | ||||||
|  |  - <>-supply : for regulator consumer | ||||||
|  |  - cm-num-chargers : number of chargers | ||||||
|  |  - cm-chargers : name of chargers | ||||||
|  |  - cm-fuel-gauge : name of battery fuel gauge | ||||||
|  |  - subnode <regulator> : | ||||||
|  | 	- cm-regulator-name : name of charger regulator | ||||||
|  | 	- subnode <cable> : | ||||||
|  | 		- cm-cable-name : name of charger cable | ||||||
|  | 		- cm-cable-extcon : name of extcon dev | ||||||
|  | (optional)	- cm-cable-min : minimum current of cable | ||||||
|  | (optional)	- cm-cable-max : maximum current of cable | ||||||
|  | 
 | ||||||
|  | Optional properties : | ||||||
|  |  - cm-name : charger manager's name (default : "battery") | ||||||
|  |  - cm-poll-mode : polling mode (enum polling_modes) | ||||||
|  |  - cm-poll-interval : polling interval | ||||||
|  |  - cm-battery-stat : battery status (enum data_source) | ||||||
|  |  - cm-fullbatt-* : data for full battery checking | ||||||
|  |  - cm-thermal-zone : name of external thermometer's thermal zone | ||||||
|  |  - cm-battery-* : threshold battery temperature for charging | ||||||
|  | 	-cold : critical cold temperature of battery for charging | ||||||
|  | 	-cold-in-minus : flag that cold temerature is in minus degree | ||||||
|  | 	-hot : critical hot temperature of battery for charging | ||||||
|  | 	-temp-diff : temperature difference to allow recharging | ||||||
|  |  - cm-dis/charging-max = limits of charging duration | ||||||
|  | 
 | ||||||
|  | Example : | ||||||
|  | 	charger-manager@0 { | ||||||
|  | 		compatible = "charger-manager"; | ||||||
|  | 		chg-reg-supply = <&charger_regulator>; | ||||||
|  | 
 | ||||||
|  | 		cm-name = "battery"; | ||||||
|  | 		/* Always polling ON : 30s */ | ||||||
|  | 		cm-poll-mode = <1>; | ||||||
|  | 		cm-poll-interval = <30000>; | ||||||
|  | 
 | ||||||
|  | 		cm-fullbatt-vchkdrop-ms = <30000>; | ||||||
|  | 		cm-fullbatt-vchkdrop-volt = <150000>; | ||||||
|  | 		cm-fullbatt-soc = <100>; | ||||||
|  | 
 | ||||||
|  | 		cm-battery-stat = <3>; | ||||||
|  | 
 | ||||||
|  | 		cm-num-chargers = <3>; | ||||||
|  | 		cm-chargers = "charger0", "charger1", "charger2"; | ||||||
|  | 
 | ||||||
|  | 		cm-fuel-gauge = "fuelgauge0"; | ||||||
|  | 
 | ||||||
|  | 		cm-thermal-zone = "thermal_zone.1" | ||||||
|  | 		/* in deci centigrade */ | ||||||
|  | 		cm-battery-cold = <50>; | ||||||
|  | 		cm-battery-cold-in-minus; | ||||||
|  | 		cm-battery-hot = <800>; | ||||||
|  | 		cm-battery-temp-diff = <100>; | ||||||
|  | 
 | ||||||
|  | 		/* Allow charging for 5hr */ | ||||||
|  | 		cm-charging-max = <18000000>; | ||||||
|  | 		/* Allow discharging for 2hr */ | ||||||
|  | 		cm-discharging-max = <7200000>; | ||||||
|  | 
 | ||||||
|  | 		regulator@0 { | ||||||
|  | 			cm-regulator-name = "chg-reg"; | ||||||
|  | 			cable@0 { | ||||||
|  | 				cm-cable-name = "USB"; | ||||||
|  | 				cm-cable-extcon = "extcon-dev.0"; | ||||||
|  | 				cm-cable-min = <475000>; | ||||||
|  | 				cm-cable-max = <500000>; | ||||||
|  | 			}; | ||||||
|  | 			cable@1 { | ||||||
|  | 				cm-cable-name = "TA"; | ||||||
|  | 				cm-cable-extcon = "extcon-dev.0"; | ||||||
|  | 				cm-cable-min = <650000>; | ||||||
|  | 				cm-cable-max = <675000>; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 	}; | ||||||
|  | @ -6712,7 +6712,7 @@ F:	include/linux/timer* | ||||||
| F:	kernel/*timer* | F:	kernel/*timer* | ||||||
| 
 | 
 | ||||||
| POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS | POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS | ||||||
| M:	Anton Vorontsov <anton@enomsg.org> | M:	Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||||||
| M:	David Woodhouse <dwmw2@infradead.org> | M:	David Woodhouse <dwmw2@infradead.org> | ||||||
| T:	git git://git.infradead.org/battery-2.6.git | T:	git git://git.infradead.org/battery-2.6.git | ||||||
| S:	Maintained | S:	Maintained | ||||||
|  |  | ||||||
|  | @ -317,6 +317,13 @@ config CHARGER_MANAGER | ||||||
|           runtime and in suspend-to-RAM by waking up the system periodically |           runtime and in suspend-to-RAM by waking up the system periodically | ||||||
|           with help of suspend_again support. |           with help of suspend_again support. | ||||||
| 
 | 
 | ||||||
|  | config CHARGER_MAX14577 | ||||||
|  | 	tristate "Maxim MAX14577 MUIC battery charger driver" | ||||||
|  | 	depends on MFD_MAX14577 | ||||||
|  | 	help | ||||||
|  | 	  Say Y to enable support for the battery charger control sysfs and | ||||||
|  | 	  platform data of MAX14577 MUICs. | ||||||
|  | 
 | ||||||
| config CHARGER_MAX8997 | config CHARGER_MAX8997 | ||||||
| 	tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" | 	tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" | ||||||
| 	depends on MFD_MAX8997 && REGULATOR_MAX8997 | 	depends on MFD_MAX8997 && REGULATOR_MAX8997 | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ obj-$(CONFIG_CHARGER_LP8727)	+= lp8727_charger.o | ||||||
| obj-$(CONFIG_CHARGER_LP8788)	+= lp8788-charger.o | obj-$(CONFIG_CHARGER_LP8788)	+= lp8788-charger.o | ||||||
| obj-$(CONFIG_CHARGER_GPIO)	+= gpio-charger.o | obj-$(CONFIG_CHARGER_GPIO)	+= gpio-charger.o | ||||||
| obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o | obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o | ||||||
|  | obj-$(CONFIG_CHARGER_MAX14577)	+= max14577_charger.o | ||||||
| obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o | obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o | ||||||
| obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o | obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o | ||||||
| obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o | obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*
 | /*
 | ||||||
|  * bq2415x charger driver |  * bq2415x charger driver | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2011-2012  Pali Rohár <pali.rohar@gmail.com> |  * Copyright (C) 2011-2013  Pali Rohár <pali.rohar@gmail.com> | ||||||
|  * |  * | ||||||
|  * This program is free software; you can redistribute it and/or modify |  * This program is free software; you can redistribute it and/or modify | ||||||
|  * it under the terms of the GNU General Public License as published by |  * it under the terms of the GNU General Public License as published by | ||||||
|  | @ -170,6 +170,8 @@ struct bq2415x_device { | ||||||
| 	struct bq2415x_platform_data init_data; | 	struct bq2415x_platform_data init_data; | ||||||
| 	struct power_supply charger; | 	struct power_supply charger; | ||||||
| 	struct delayed_work work; | 	struct delayed_work work; | ||||||
|  | 	struct power_supply *notify_psy; | ||||||
|  | 	struct notifier_block nb; | ||||||
| 	enum bq2415x_mode reported_mode;/* mode reported by hook function */ | 	enum bq2415x_mode reported_mode;/* mode reported by hook function */ | ||||||
| 	enum bq2415x_mode mode;		/* current configured mode */ | 	enum bq2415x_mode mode;		/* current configured mode */ | ||||||
| 	enum bq2415x_chip chip; | 	enum bq2415x_chip chip; | ||||||
|  | @ -795,24 +797,53 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode) | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* hook function called by other driver which set reported mode */ | static int bq2415x_notifier_call(struct notifier_block *nb, | ||||||
| static void bq2415x_hook_function(enum bq2415x_mode mode, void *data) | 		unsigned long val, void *v) | ||||||
| { | { | ||||||
| 	struct bq2415x_device *bq = data; | 	struct bq2415x_device *bq = | ||||||
|  | 		container_of(nb, struct bq2415x_device, nb); | ||||||
|  | 	struct power_supply *psy = v; | ||||||
|  | 	enum bq2415x_mode mode; | ||||||
|  | 	union power_supply_propval prop; | ||||||
|  | 	int ret; | ||||||
|  | 	int mA; | ||||||
| 
 | 
 | ||||||
| 	if (!bq) | 	if (val != PSY_EVENT_PROP_CHANGED) | ||||||
| 		return; | 		return NOTIFY_OK; | ||||||
|  | 
 | ||||||
|  | 	if (psy != bq->notify_psy) | ||||||
|  | 		return NOTIFY_OK; | ||||||
|  | 
 | ||||||
|  | 	dev_dbg(bq->dev, "notifier call was called\n"); | ||||||
|  | 
 | ||||||
|  | 	ret = psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop); | ||||||
|  | 	if (ret != 0) | ||||||
|  | 		return NOTIFY_OK; | ||||||
|  | 
 | ||||||
|  | 	mA = prop.intval; | ||||||
|  | 
 | ||||||
|  | 	if (mA == 0) | ||||||
|  | 		mode = BQ2415X_MODE_OFF; | ||||||
|  | 	else if (mA < 500) | ||||||
|  | 		mode = BQ2415X_MODE_NONE; | ||||||
|  | 	else if (mA < 1800) | ||||||
|  | 		mode = BQ2415X_MODE_HOST_CHARGER; | ||||||
|  | 	else | ||||||
|  | 		mode = BQ2415X_MODE_DEDICATED_CHARGER; | ||||||
|  | 
 | ||||||
|  | 	if (bq->reported_mode == mode) | ||||||
|  | 		return NOTIFY_OK; | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(bq->dev, "hook function was called\n"); |  | ||||||
| 	bq->reported_mode = mode; | 	bq->reported_mode = mode; | ||||||
| 
 | 
 | ||||||
| 	/* if automode is not enabled do not tell about reported_mode */ | 	/* if automode is not enabled do not tell about reported_mode */ | ||||||
| 	if (bq->automode < 1) | 	if (bq->automode < 1) | ||||||
| 		return; | 		return NOTIFY_OK; | ||||||
| 
 | 
 | ||||||
| 	sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); | 	sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); | ||||||
| 	bq2415x_set_mode(bq, bq->reported_mode); | 	bq2415x_set_mode(bq, bq->reported_mode); | ||||||
| 
 | 
 | ||||||
|  | 	return NOTIFY_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**** timer functions ****/ | /**** timer functions ****/ | ||||||
|  | @ -1512,9 +1543,11 @@ static int bq2415x_probe(struct i2c_client *client, | ||||||
| 	int num; | 	int num; | ||||||
| 	char *name; | 	char *name; | ||||||
| 	struct bq2415x_device *bq; | 	struct bq2415x_device *bq; | ||||||
|  | 	struct device_node *np = client->dev.of_node; | ||||||
|  | 	struct bq2415x_platform_data *pdata = client->dev.platform_data; | ||||||
| 
 | 
 | ||||||
| 	if (!client->dev.platform_data) { | 	if (!np && !pdata) { | ||||||
| 		dev_err(&client->dev, "platform data not set\n"); | 		dev_err(&client->dev, "platform data missing\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1539,6 +1572,17 @@ static int bq2415x_probe(struct i2c_client *client, | ||||||
| 		goto error_2; | 		goto error_2; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (np) { | ||||||
|  | 		bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection"); | ||||||
|  | 
 | ||||||
|  | 		if (!bq->notify_psy) | ||||||
|  | 			return -EPROBE_DEFER; | ||||||
|  | 	} | ||||||
|  | 	else if (pdata->notify_device) | ||||||
|  | 		bq->notify_psy = power_supply_get_by_name(pdata->notify_device); | ||||||
|  | 	else | ||||||
|  | 		bq->notify_psy = NULL; | ||||||
|  | 
 | ||||||
| 	i2c_set_clientdata(client, bq); | 	i2c_set_clientdata(client, bq); | ||||||
| 
 | 
 | ||||||
| 	bq->id = num; | 	bq->id = num; | ||||||
|  | @ -1550,8 +1594,34 @@ static int bq2415x_probe(struct i2c_client *client, | ||||||
| 	bq->autotimer = 0; | 	bq->autotimer = 0; | ||||||
| 	bq->automode = 0; | 	bq->automode = 0; | ||||||
| 
 | 
 | ||||||
| 	memcpy(&bq->init_data, client->dev.platform_data, | 	if (np) { | ||||||
| 			sizeof(bq->init_data)); | 		ret = of_property_read_u32(np, "ti,current-limit", | ||||||
|  | 				&bq->init_data.current_limit); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = of_property_read_u32(np, "ti,weak-battery-voltage", | ||||||
|  | 				&bq->init_data.weak_battery_voltage); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = of_property_read_u32(np, "ti,battery-regulation-voltage", | ||||||
|  | 				&bq->init_data.battery_regulation_voltage); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = of_property_read_u32(np, "ti,charge-current", | ||||||
|  | 				&bq->init_data.charge_current); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = of_property_read_u32(np, "ti,termination-current", | ||||||
|  | 				&bq->init_data.termination_current); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = of_property_read_u32(np, "ti,resistor-sense", | ||||||
|  | 				&bq->init_data.resistor_sense); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 	} else { | ||||||
|  | 		memcpy(&bq->init_data, pdata, sizeof(bq->init_data)); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	bq2415x_reset_chip(bq); | 	bq2415x_reset_chip(bq); | ||||||
| 
 | 
 | ||||||
|  | @ -1573,16 +1643,20 @@ static int bq2415x_probe(struct i2c_client *client, | ||||||
| 		goto error_4; | 		goto error_4; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (bq->init_data.set_mode_hook) { | 	if (bq->notify_psy) { | ||||||
| 		if (bq->init_data.set_mode_hook( | 		bq->nb.notifier_call = bq2415x_notifier_call; | ||||||
| 				bq2415x_hook_function, bq)) { | 		ret = power_supply_reg_notifier(&bq->nb); | ||||||
| 			bq->automode = 1; | 		if (ret) { | ||||||
| 			bq2415x_set_mode(bq, bq->reported_mode); | 			dev_err(bq->dev, "failed to reg notifier: %d\n", ret); | ||||||
| 			dev_info(bq->dev, "automode enabled\n"); | 			goto error_5; | ||||||
| 		} else { |  | ||||||
| 			bq->automode = -1; |  | ||||||
| 			dev_info(bq->dev, "automode failed\n"); |  | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Query for initial reported_mode and set it */ | ||||||
|  | 		bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED, bq->notify_psy); | ||||||
|  | 		bq2415x_set_mode(bq, bq->reported_mode); | ||||||
|  | 
 | ||||||
|  | 		bq->automode = 1; | ||||||
|  | 		dev_info(bq->dev, "automode enabled\n"); | ||||||
| 	} else { | 	} else { | ||||||
| 		bq->automode = -1; | 		bq->automode = -1; | ||||||
| 		dev_info(bq->dev, "automode not supported\n"); | 		dev_info(bq->dev, "automode not supported\n"); | ||||||
|  | @ -1594,6 +1668,7 @@ static int bq2415x_probe(struct i2c_client *client, | ||||||
| 	dev_info(bq->dev, "driver registered\n"); | 	dev_info(bq->dev, "driver registered\n"); | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
|  | error_5: | ||||||
| error_4: | error_4: | ||||||
| 	bq2415x_sysfs_exit(bq); | 	bq2415x_sysfs_exit(bq); | ||||||
| error_3: | error_3: | ||||||
|  | @ -1614,8 +1689,8 @@ static int bq2415x_remove(struct i2c_client *client) | ||||||
| { | { | ||||||
| 	struct bq2415x_device *bq = i2c_get_clientdata(client); | 	struct bq2415x_device *bq = i2c_get_clientdata(client); | ||||||
| 
 | 
 | ||||||
| 	if (bq->init_data.set_mode_hook) | 	if (bq->notify_psy) | ||||||
| 		bq->init_data.set_mode_hook(NULL, NULL); | 		power_supply_unreg_notifier(&bq->nb); | ||||||
| 
 | 
 | ||||||
| 	bq2415x_sysfs_exit(bq); | 	bq2415x_sysfs_exit(bq); | ||||||
| 	bq2415x_power_supply_exit(bq); | 	bq2415x_power_supply_exit(bq); | ||||||
|  |  | ||||||
|  | @ -25,12 +25,23 @@ | ||||||
| #include <linux/power/charger-manager.h> | #include <linux/power/charger-manager.h> | ||||||
| #include <linux/regulator/consumer.h> | #include <linux/regulator/consumer.h> | ||||||
| #include <linux/sysfs.h> | #include <linux/sysfs.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/thermal.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Default termperature threshold for charging. | ||||||
|  |  * Every temperature units are in tenth of centigrade. | ||||||
|  |  */ | ||||||
|  | #define CM_DEFAULT_RECHARGE_TEMP_DIFF	50 | ||||||
|  | #define CM_DEFAULT_CHARGE_TEMP_MAX	500 | ||||||
| 
 | 
 | ||||||
| static const char * const default_event_names[] = { | static const char * const default_event_names[] = { | ||||||
| 	[CM_EVENT_UNKNOWN] = "Unknown", | 	[CM_EVENT_UNKNOWN] = "Unknown", | ||||||
| 	[CM_EVENT_BATT_FULL] = "Battery Full", | 	[CM_EVENT_BATT_FULL] = "Battery Full", | ||||||
| 	[CM_EVENT_BATT_IN] = "Battery Inserted", | 	[CM_EVENT_BATT_IN] = "Battery Inserted", | ||||||
| 	[CM_EVENT_BATT_OUT] = "Battery Pulled Out", | 	[CM_EVENT_BATT_OUT] = "Battery Pulled Out", | ||||||
|  | 	[CM_EVENT_BATT_OVERHEAT] = "Battery Overheat", | ||||||
|  | 	[CM_EVENT_BATT_COLD] = "Battery Cold", | ||||||
| 	[CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", | 	[CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", | ||||||
| 	[CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", | 	[CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", | ||||||
| 	[CM_EVENT_OTHERS] = "Other battery events" | 	[CM_EVENT_OTHERS] = "Other battery events" | ||||||
|  | @ -518,7 +529,7 @@ static int check_charging_duration(struct charger_manager *cm) | ||||||
| 		duration = curr - cm->charging_start_time; | 		duration = curr - cm->charging_start_time; | ||||||
| 
 | 
 | ||||||
| 		if (duration > desc->charging_max_duration_ms) { | 		if (duration > desc->charging_max_duration_ms) { | ||||||
| 			dev_info(cm->dev, "Charging duration exceed %lldms\n", | 			dev_info(cm->dev, "Charging duration exceed %ums\n", | ||||||
| 				 desc->charging_max_duration_ms); | 				 desc->charging_max_duration_ms); | ||||||
| 			uevent_notify(cm, "Discharging"); | 			uevent_notify(cm, "Discharging"); | ||||||
| 			try_charger_enable(cm, false); | 			try_charger_enable(cm, false); | ||||||
|  | @ -529,7 +540,7 @@ static int check_charging_duration(struct charger_manager *cm) | ||||||
| 
 | 
 | ||||||
| 		if (duration > desc->charging_max_duration_ms && | 		if (duration > desc->charging_max_duration_ms && | ||||||
| 				is_ext_pwr_online(cm)) { | 				is_ext_pwr_online(cm)) { | ||||||
| 			dev_info(cm->dev, "Discharging duration exceed %lldms\n", | 			dev_info(cm->dev, "Discharging duration exceed %ums\n", | ||||||
| 				 desc->discharging_max_duration_ms); | 				 desc->discharging_max_duration_ms); | ||||||
| 			uevent_notify(cm, "Recharging"); | 			uevent_notify(cm, "Recharging"); | ||||||
| 			try_charger_enable(cm, true); | 			try_charger_enable(cm, true); | ||||||
|  | @ -540,6 +551,60 @@ static int check_charging_duration(struct charger_manager *cm) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int cm_get_battery_temperature(struct charger_manager *cm, | ||||||
|  | 					int *temp) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!cm->desc->measure_battery_temp) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_THERMAL | ||||||
|  | 	ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); | ||||||
|  | 	if (!ret) | ||||||
|  | 		/* Calibrate temperature unit */ | ||||||
|  | 		*temp /= 100; | ||||||
|  | #else | ||||||
|  | 	ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||||||
|  | 				POWER_SUPPLY_PROP_TEMP, | ||||||
|  | 				(union power_supply_propval *)temp); | ||||||
|  | #endif | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int cm_check_thermal_status(struct charger_manager *cm) | ||||||
|  | { | ||||||
|  | 	struct charger_desc *desc = cm->desc; | ||||||
|  | 	int temp, upper_limit, lower_limit; | ||||||
|  | 	int ret = 0; | ||||||
|  | 
 | ||||||
|  | 	ret = cm_get_battery_temperature(cm, &temp); | ||||||
|  | 	if (ret) { | ||||||
|  | 		/* FIXME:
 | ||||||
|  | 		 * No information of battery temperature might | ||||||
|  | 		 * occur hazadous result. We have to handle it | ||||||
|  | 		 * depending on battery type. | ||||||
|  | 		 */ | ||||||
|  | 		dev_err(cm->dev, "Failed to get battery temperature\n"); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	upper_limit = desc->temp_max; | ||||||
|  | 	lower_limit = desc->temp_min; | ||||||
|  | 
 | ||||||
|  | 	if (cm->emergency_stop) { | ||||||
|  | 		upper_limit -= desc->temp_diff; | ||||||
|  | 		lower_limit += desc->temp_diff; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (temp > upper_limit) | ||||||
|  | 		ret = CM_EVENT_BATT_OVERHEAT; | ||||||
|  | 	else if (temp < lower_limit) | ||||||
|  | 		ret = CM_EVENT_BATT_COLD; | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * _cm_monitor - Monitor the temperature and return true for exceptions. |  * _cm_monitor - Monitor the temperature and return true for exceptions. | ||||||
|  * @cm: the Charger Manager representing the battery. |  * @cm: the Charger Manager representing the battery. | ||||||
|  | @ -549,28 +614,22 @@ static int check_charging_duration(struct charger_manager *cm) | ||||||
|  */ |  */ | ||||||
| static bool _cm_monitor(struct charger_manager *cm) | static bool _cm_monitor(struct charger_manager *cm) | ||||||
| { | { | ||||||
| 	struct charger_desc *desc = cm->desc; | 	int temp_alrt; | ||||||
| 	int temp = desc->temperature_out_of_range(&cm->last_temp_mC); |  | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", | 	temp_alrt = cm_check_thermal_status(cm); | ||||||
| 		cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); |  | ||||||
| 
 | 
 | ||||||
| 	/* It has been stopped already */ | 	/* It has been stopped already */ | ||||||
| 	if (temp && cm->emergency_stop) | 	if (temp_alrt && cm->emergency_stop) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Check temperature whether overheat or cold. | 	 * Check temperature whether overheat or cold. | ||||||
| 	 * If temperature is out of range normal state, stop charging. | 	 * If temperature is out of range normal state, stop charging. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (temp) { | 	if (temp_alrt) { | ||||||
| 		cm->emergency_stop = temp; | 		cm->emergency_stop = temp_alrt; | ||||||
| 		if (!try_charger_enable(cm, false)) { | 		if (!try_charger_enable(cm, false)) | ||||||
| 			if (temp > 0) | 			uevent_notify(cm, default_event_names[temp_alrt]); | ||||||
| 				uevent_notify(cm, "OVERHEAT"); |  | ||||||
| 			else |  | ||||||
| 				uevent_notify(cm, "COLD"); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Check whole charging duration and discharing duration | 	 * Check whole charging duration and discharing duration | ||||||
|  | @ -802,21 +861,8 @@ static int charger_get_property(struct power_supply *psy, | ||||||
| 				POWER_SUPPLY_PROP_CURRENT_NOW, val); | 				POWER_SUPPLY_PROP_CURRENT_NOW, val); | ||||||
| 		break; | 		break; | ||||||
| 	case POWER_SUPPLY_PROP_TEMP: | 	case POWER_SUPPLY_PROP_TEMP: | ||||||
| 		/* in thenth of centigrade */ |  | ||||||
| 		if (cm->last_temp_mC == INT_MIN) |  | ||||||
| 			desc->temperature_out_of_range(&cm->last_temp_mC); |  | ||||||
| 		val->intval = cm->last_temp_mC / 100; |  | ||||||
| 		if (!desc->measure_battery_temp) |  | ||||||
| 			ret = -ENODEV; |  | ||||||
| 		break; |  | ||||||
| 	case POWER_SUPPLY_PROP_TEMP_AMBIENT: | 	case POWER_SUPPLY_PROP_TEMP_AMBIENT: | ||||||
| 		/* in thenth of centigrade */ | 		return cm_get_battery_temperature(cm, &val->intval); | ||||||
| 		if (cm->last_temp_mC == INT_MIN) |  | ||||||
| 			desc->temperature_out_of_range(&cm->last_temp_mC); |  | ||||||
| 		val->intval = cm->last_temp_mC / 100; |  | ||||||
| 		if (desc->measure_battery_temp) |  | ||||||
| 			ret = -ENODEV; |  | ||||||
| 		break; |  | ||||||
| 	case POWER_SUPPLY_PROP_CAPACITY: | 	case POWER_SUPPLY_PROP_CAPACITY: | ||||||
| 		if (!cm->fuel_gauge) { | 		if (!cm->fuel_gauge) { | ||||||
| 			ret = -ENODEV; | 			ret = -ENODEV; | ||||||
|  | @ -1439,9 +1485,183 @@ err: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int cm_init_thermal_data(struct charger_manager *cm) | ||||||
|  | { | ||||||
|  | 	struct charger_desc *desc = cm->desc; | ||||||
|  | 	union power_supply_propval val; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	/* Verify whether fuel gauge provides battery temperature */ | ||||||
|  | 	ret = cm->fuel_gauge->get_property(cm->fuel_gauge, | ||||||
|  | 					POWER_SUPPLY_PROP_TEMP, &val); | ||||||
|  | 
 | ||||||
|  | 	if (!ret) { | ||||||
|  | 		cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||||||
|  | 				POWER_SUPPLY_PROP_TEMP; | ||||||
|  | 		cm->charger_psy.num_properties++; | ||||||
|  | 		cm->desc->measure_battery_temp = true; | ||||||
|  | 	} | ||||||
|  | #ifdef CONFIG_THERMAL | ||||||
|  | 	cm->tzd_batt = cm->fuel_gauge->tzd; | ||||||
|  | 
 | ||||||
|  | 	if (ret && desc->thermal_zone) { | ||||||
|  | 		cm->tzd_batt = | ||||||
|  | 			thermal_zone_get_zone_by_name(desc->thermal_zone); | ||||||
|  | 		if (IS_ERR(cm->tzd_batt)) | ||||||
|  | 			return PTR_ERR(cm->tzd_batt); | ||||||
|  | 
 | ||||||
|  | 		/* Use external thermometer */ | ||||||
|  | 		cm->charger_psy.properties[cm->charger_psy.num_properties] = | ||||||
|  | 				POWER_SUPPLY_PROP_TEMP_AMBIENT; | ||||||
|  | 		cm->charger_psy.num_properties++; | ||||||
|  | 		cm->desc->measure_battery_temp = true; | ||||||
|  | 		ret = 0; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 	if (cm->desc->measure_battery_temp) { | ||||||
|  | 		/* NOTICE : Default allowable minimum charge temperature is 0 */ | ||||||
|  | 		if (!desc->temp_max) | ||||||
|  | 			desc->temp_max = CM_DEFAULT_CHARGE_TEMP_MAX; | ||||||
|  | 		if (!desc->temp_diff) | ||||||
|  | 			desc->temp_diff = CM_DEFAULT_RECHARGE_TEMP_DIFF; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct of_device_id charger_manager_match[] = { | ||||||
|  | 	{ | ||||||
|  | 		.compatible = "charger-manager", | ||||||
|  | 	}, | ||||||
|  | 	{}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct charger_desc *of_cm_parse_desc(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct charger_desc *desc; | ||||||
|  | 	struct device_node *np = dev->of_node; | ||||||
|  | 	u32 poll_mode = CM_POLL_DISABLE; | ||||||
|  | 	u32 battery_stat = CM_NO_BATTERY; | ||||||
|  | 	int num_chgs = 0; | ||||||
|  | 
 | ||||||
|  | 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | ||||||
|  | 	if (!desc) | ||||||
|  | 		return ERR_PTR(-ENOMEM); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_string(np, "cm-name", &desc->psy_name); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-poll-mode", &poll_mode); | ||||||
|  | 	desc->polling_mode = poll_mode; | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-poll-interval", | ||||||
|  | 				&desc->polling_interval_ms); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", | ||||||
|  | 					&desc->fullbatt_vchkdrop_ms); | ||||||
|  | 	of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt", | ||||||
|  | 					&desc->fullbatt_vchkdrop_uV); | ||||||
|  | 	of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV); | ||||||
|  | 	of_property_read_u32(np, "cm-fullbatt-soc", &desc->fullbatt_soc); | ||||||
|  | 	of_property_read_u32(np, "cm-fullbatt-capacity", | ||||||
|  | 					&desc->fullbatt_full_capacity); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-battery-stat", &battery_stat); | ||||||
|  | 	desc->battery_present = battery_stat; | ||||||
|  | 
 | ||||||
|  | 	/* chargers */ | ||||||
|  | 	of_property_read_u32(np, "cm-num-chargers", &num_chgs); | ||||||
|  | 	if (num_chgs) { | ||||||
|  | 		/* Allocate empty bin at the tail of array */ | ||||||
|  | 		desc->psy_charger_stat = devm_kzalloc(dev, sizeof(char *) | ||||||
|  | 						* (num_chgs + 1), GFP_KERNEL); | ||||||
|  | 		if (desc->psy_charger_stat) { | ||||||
|  | 			int i; | ||||||
|  | 			for (i = 0; i < num_chgs; i++) | ||||||
|  | 				of_property_read_string_index(np, "cm-chargers", | ||||||
|  | 						i, &desc->psy_charger_stat[i]); | ||||||
|  | 		} else { | ||||||
|  | 			return ERR_PTR(-ENOMEM); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_string(np, "cm-thermal-zone", &desc->thermal_zone); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-battery-cold", &desc->temp_min); | ||||||
|  | 	if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) | ||||||
|  | 		desc->temp_min *= -1; | ||||||
|  | 	of_property_read_u32(np, "cm-battery-hot", &desc->temp_max); | ||||||
|  | 	of_property_read_u32(np, "cm-battery-temp-diff", &desc->temp_diff); | ||||||
|  | 
 | ||||||
|  | 	of_property_read_u32(np, "cm-charging-max", | ||||||
|  | 				&desc->charging_max_duration_ms); | ||||||
|  | 	of_property_read_u32(np, "cm-discharging-max", | ||||||
|  | 				&desc->discharging_max_duration_ms); | ||||||
|  | 
 | ||||||
|  | 	/* battery charger regualtors */ | ||||||
|  | 	desc->num_charger_regulators = of_get_child_count(np); | ||||||
|  | 	if (desc->num_charger_regulators) { | ||||||
|  | 		struct charger_regulator *chg_regs; | ||||||
|  | 		struct device_node *child; | ||||||
|  | 
 | ||||||
|  | 		chg_regs = devm_kzalloc(dev, sizeof(*chg_regs) | ||||||
|  | 					* desc->num_charger_regulators, | ||||||
|  | 					GFP_KERNEL); | ||||||
|  | 		if (!chg_regs) | ||||||
|  | 			return ERR_PTR(-ENOMEM); | ||||||
|  | 
 | ||||||
|  | 		desc->charger_regulators = chg_regs; | ||||||
|  | 
 | ||||||
|  | 		for_each_child_of_node(np, child) { | ||||||
|  | 			struct charger_cable *cables; | ||||||
|  | 			struct device_node *_child; | ||||||
|  | 
 | ||||||
|  | 			of_property_read_string(child, "cm-regulator-name", | ||||||
|  | 					&chg_regs->regulator_name); | ||||||
|  | 
 | ||||||
|  | 			/* charger cables */ | ||||||
|  | 			chg_regs->num_cables = of_get_child_count(child); | ||||||
|  | 			if (chg_regs->num_cables) { | ||||||
|  | 				cables = devm_kzalloc(dev, sizeof(*cables) | ||||||
|  | 						* chg_regs->num_cables, | ||||||
|  | 						GFP_KERNEL); | ||||||
|  | 				if (!cables) | ||||||
|  | 					return ERR_PTR(-ENOMEM); | ||||||
|  | 
 | ||||||
|  | 				chg_regs->cables = cables; | ||||||
|  | 
 | ||||||
|  | 				for_each_child_of_node(child, _child) { | ||||||
|  | 					of_property_read_string(_child, | ||||||
|  | 					"cm-cable-name", &cables->name); | ||||||
|  | 					of_property_read_string(_child, | ||||||
|  | 					"cm-cable-extcon", | ||||||
|  | 					&cables->extcon_name); | ||||||
|  | 					of_property_read_u32(_child, | ||||||
|  | 					"cm-cable-min", | ||||||
|  | 					&cables->min_uA); | ||||||
|  | 					of_property_read_u32(_child, | ||||||
|  | 					"cm-cable-max", | ||||||
|  | 					&cables->max_uA); | ||||||
|  | 					cables++; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			chg_regs++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return desc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	if (pdev->dev.of_node) | ||||||
|  | 		return of_cm_parse_desc(&pdev->dev); | ||||||
|  | 	return (struct charger_desc *)dev_get_platdata(&pdev->dev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int charger_manager_probe(struct platform_device *pdev) | static int charger_manager_probe(struct platform_device *pdev) | ||||||
| { | { | ||||||
| 	struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 	struct charger_desc *desc = cm_get_drv_data(pdev); | ||||||
| 	struct charger_manager *cm; | 	struct charger_manager *cm; | ||||||
| 	int ret = 0, i = 0; | 	int ret = 0, i = 0; | ||||||
| 	int j = 0; | 	int j = 0; | ||||||
|  | @ -1470,7 +1690,6 @@ static int charger_manager_probe(struct platform_device *pdev) | ||||||
| 	/* Basic Values. Unspecified are Null or 0 */ | 	/* Basic Values. Unspecified are Null or 0 */ | ||||||
| 	cm->dev = &pdev->dev; | 	cm->dev = &pdev->dev; | ||||||
| 	cm->desc = desc; | 	cm->desc = desc; | ||||||
| 	cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * The following two do not need to be errors. | 	 * The following two do not need to be errors. | ||||||
|  | @ -1533,11 +1752,6 @@ static int charger_manager_probe(struct platform_device *pdev) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!desc->temperature_out_of_range) { |  | ||||||
| 		dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!desc->charging_max_duration_ms || | 	if (!desc->charging_max_duration_ms || | ||||||
| 			!desc->discharging_max_duration_ms) { | 			!desc->discharging_max_duration_ms) { | ||||||
| 		dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); | 		dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); | ||||||
|  | @ -1583,14 +1797,10 @@ static int charger_manager_probe(struct platform_device *pdev) | ||||||
| 		cm->charger_psy.num_properties++; | 		cm->charger_psy.num_properties++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (desc->measure_battery_temp) { | 	ret = cm_init_thermal_data(cm); | ||||||
| 		cm->charger_psy.properties[cm->charger_psy.num_properties] = | 	if (ret) { | ||||||
| 				POWER_SUPPLY_PROP_TEMP; | 		dev_err(&pdev->dev, "Failed to initialize thermal data\n"); | ||||||
| 		cm->charger_psy.num_properties++; | 		cm->desc->measure_battery_temp = false; | ||||||
| 	} else { |  | ||||||
| 		cm->charger_psy.properties[cm->charger_psy.num_properties] = |  | ||||||
| 				POWER_SUPPLY_PROP_TEMP_AMBIENT; |  | ||||||
| 		cm->charger_psy.num_properties++; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); | 	INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); | ||||||
|  | @ -1808,6 +2018,7 @@ static struct platform_driver charger_manager_driver = { | ||||||
| 		.name = "charger-manager", | 		.name = "charger-manager", | ||||||
| 		.owner = THIS_MODULE, | 		.owner = THIS_MODULE, | ||||||
| 		.pm = &charger_manager_pm, | 		.pm = &charger_manager_pm, | ||||||
|  | 		.of_match_table = charger_manager_match, | ||||||
| 	}, | 	}, | ||||||
| 	.probe = charger_manager_probe, | 	.probe = charger_manager_probe, | ||||||
| 	.remove = charger_manager_remove, | 	.remove = charger_manager_remove, | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| struct gpio_charger { | struct gpio_charger { | ||||||
| 	const struct gpio_charger_platform_data *pdata; | 	const struct gpio_charger_platform_data *pdata; | ||||||
| 	unsigned int irq; | 	unsigned int irq; | ||||||
|  | 	bool wakeup_enabled; | ||||||
| 
 | 
 | ||||||
| 	struct power_supply charger; | 	struct power_supply charger; | ||||||
| }; | }; | ||||||
|  | @ -136,6 +137,8 @@ static int gpio_charger_probe(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	platform_set_drvdata(pdev, gpio_charger); | 	platform_set_drvdata(pdev, gpio_charger); | ||||||
| 
 | 
 | ||||||
|  | 	device_init_wakeup(&pdev->dev, 1); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err_gpio_free: | err_gpio_free: | ||||||
|  | @ -159,18 +162,32 @@ static int gpio_charger_remove(struct platform_device *pdev) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_PM_SLEEP | #ifdef CONFIG_PM_SLEEP | ||||||
|  | static int gpio_charger_suspend(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct gpio_charger *gpio_charger = dev_get_drvdata(dev); | ||||||
|  | 
 | ||||||
|  | 	if (device_may_wakeup(dev)) | ||||||
|  | 		gpio_charger->wakeup_enabled = | ||||||
|  | 			enable_irq_wake(gpio_charger->irq); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int gpio_charger_resume(struct device *dev) | static int gpio_charger_resume(struct device *dev) | ||||||
| { | { | ||||||
| 	struct platform_device *pdev = to_platform_device(dev); | 	struct platform_device *pdev = to_platform_device(dev); | ||||||
| 	struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | 	struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | ||||||
| 
 | 
 | ||||||
|  | 	if (gpio_charger->wakeup_enabled) | ||||||
|  | 		disable_irq_wake(gpio_charger->irq); | ||||||
| 	power_supply_changed(&gpio_charger->charger); | 	power_supply_changed(&gpio_charger->charger); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); | static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, | ||||||
|  | 		gpio_charger_suspend, gpio_charger_resume); | ||||||
| 
 | 
 | ||||||
| static struct platform_driver gpio_charger_driver = { | static struct platform_driver gpio_charger_driver = { | ||||||
| 	.probe = gpio_charger_probe, | 	.probe = gpio_charger_probe, | ||||||
|  |  | ||||||
|  | @ -29,6 +29,8 @@ | ||||||
| #include <linux/platform_device.h> | #include <linux/platform_device.h> | ||||||
| #include <linux/power_supply.h> | #include <linux/power_supply.h> | ||||||
| #include <linux/delay.h> | #include <linux/delay.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/of_gpio.h> | ||||||
| 
 | 
 | ||||||
| #include <linux/usb/otg.h> | #include <linux/usb/otg.h> | ||||||
| #include <linux/usb/ulpi.h> | #include <linux/usb/ulpi.h> | ||||||
|  | @ -88,6 +90,8 @@ static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) | ||||||
| 
 | 
 | ||||||
| 	if (board && board->set_power) | 	if (board && board->set_power) | ||||||
| 		board->set_power(on); | 		board->set_power(on); | ||||||
|  | 	else if (board) | ||||||
|  | 		gpio_set_value(board->enable_gpio, on); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -400,12 +404,47 @@ static int isp1704_charger_probe(struct platform_device *pdev) | ||||||
| 	struct isp1704_charger	*isp; | 	struct isp1704_charger	*isp; | ||||||
| 	int			ret = -ENODEV; | 	int			ret = -ENODEV; | ||||||
| 
 | 
 | ||||||
|  | 	struct isp1704_charger_data *pdata = dev_get_platdata(&pdev->dev); | ||||||
|  | 	struct device_node *np = pdev->dev.of_node; | ||||||
|  | 
 | ||||||
|  | 	if (np) { | ||||||
|  | 		int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0); | ||||||
|  | 
 | ||||||
|  | 		if (gpio < 0) | ||||||
|  | 			return gpio; | ||||||
|  | 
 | ||||||
|  | 		pdata = devm_kzalloc(&pdev->dev, | ||||||
|  | 			sizeof(struct isp1704_charger_data), GFP_KERNEL); | ||||||
|  | 		pdata->enable_gpio = gpio; | ||||||
|  | 
 | ||||||
|  | 		dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio); | ||||||
|  | 
 | ||||||
|  | 		ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio, | ||||||
|  | 					GPIOF_OUT_INIT_HIGH, "isp1704_reset"); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto fail0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!pdata) { | ||||||
|  | 		dev_err(&pdev->dev, "missing platform data!\n"); | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); | 	isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); | ||||||
| 	if (!isp) | 	if (!isp) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	isp->phy = usb_get_phy(USB_PHY_TYPE_USB2); | 	if (np) | ||||||
| 	if (IS_ERR_OR_NULL(isp->phy)) | 		isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); | ||||||
|  | 	else | ||||||
|  | 		isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | ||||||
|  | 
 | ||||||
|  | 	if (IS_ERR(isp->phy)) { | ||||||
|  | 		ret = PTR_ERR(isp->phy); | ||||||
|  | 		goto fail0; | ||||||
|  | 	} | ||||||
|  | 	if (!isp->phy) | ||||||
| 		goto fail0; | 		goto fail0; | ||||||
| 
 | 
 | ||||||
| 	isp->dev = &pdev->dev; | 	isp->dev = &pdev->dev; | ||||||
|  | @ -464,7 +503,6 @@ fail2: | ||||||
| 	power_supply_unregister(&isp->psy); | 	power_supply_unregister(&isp->psy); | ||||||
| fail1: | fail1: | ||||||
| 	isp1704_charger_set_power(isp, 0); | 	isp1704_charger_set_power(isp, 0); | ||||||
| 	usb_put_phy(isp->phy); |  | ||||||
| fail0: | fail0: | ||||||
| 	dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); | 	dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); | ||||||
| 
 | 
 | ||||||
|  | @ -477,15 +515,23 @@ static int isp1704_charger_remove(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	usb_unregister_notifier(isp->phy, &isp->nb); | 	usb_unregister_notifier(isp->phy, &isp->nb); | ||||||
| 	power_supply_unregister(&isp->psy); | 	power_supply_unregister(&isp->psy); | ||||||
| 	usb_put_phy(isp->phy); |  | ||||||
| 	isp1704_charger_set_power(isp, 0); | 	isp1704_charger_set_power(isp, 0); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | static const struct of_device_id omap_isp1704_of_match[] = { | ||||||
|  | 	{ .compatible = "nxp,isp1704", }, | ||||||
|  | 	{}, | ||||||
|  | }; | ||||||
|  | MODULE_DEVICE_TABLE(of, omap_isp1704_of_match); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static struct platform_driver isp1704_charger_driver = { | static struct platform_driver isp1704_charger_driver = { | ||||||
| 	.driver = { | 	.driver = { | ||||||
| 		.name = "isp1704_charger", | 		.name = "isp1704_charger", | ||||||
|  | 		.of_match_table = of_match_ptr(omap_isp1704_of_match), | ||||||
| 	}, | 	}, | ||||||
| 	.probe = isp1704_charger_probe, | 	.probe = isp1704_charger_probe, | ||||||
| 	.remove = isp1704_charger_remove, | 	.remove = isp1704_charger_remove, | ||||||
|  |  | ||||||
							
								
								
									
										311
									
								
								drivers/power/max14577_charger.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								drivers/power/max14577_charger.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,311 @@ | ||||||
|  | /*
 | ||||||
|  |  * Battery charger driver for the Maxim 14577 | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2013 Samsung Electronics | ||||||
|  |  * Krzysztof Kozlowski <k.kozlowski@samsung.com> | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation; either version 2 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/platform_device.h> | ||||||
|  | #include <linux/power_supply.h> | ||||||
|  | #include <linux/mfd/max14577-private.h> | ||||||
|  | 
 | ||||||
|  | struct max14577_charger { | ||||||
|  | 	struct device *dev; | ||||||
|  | 	struct max14577	*max14577; | ||||||
|  | 	struct power_supply	charger; | ||||||
|  | 
 | ||||||
|  | 	unsigned int	charging_state; | ||||||
|  | 	unsigned int	battery_state; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int max14577_get_charger_state(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	struct regmap *rmap = chg->max14577->regmap; | ||||||
|  | 	int state = POWER_SUPPLY_STATUS_DISCHARGING; | ||||||
|  | 	u8 reg_data; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Charging occurs only if: | ||||||
|  | 	 *  - CHGCTRL2/MBCHOSTEN == 1 | ||||||
|  | 	 *  - STATUS2/CGMBC == 1 | ||||||
|  | 	 * | ||||||
|  | 	 * TODO: | ||||||
|  | 	 *  - handle FULL after Top-off timer (EOC register may be off | ||||||
|  | 	 *    and the charger won't be charging although MBCHOSTEN is on) | ||||||
|  | 	 *  - handle properly dead-battery charging (respect timer) | ||||||
|  | 	 *  - handle timers (fast-charge and prequal) /MBCCHGERR/ | ||||||
|  | 	 */ | ||||||
|  | 	max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, ®_data); | ||||||
|  | 	if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) | ||||||
|  | 		goto state_set; | ||||||
|  | 
 | ||||||
|  | 	max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, ®_data); | ||||||
|  | 	if (reg_data & STATUS3_CGMBC_MASK) { | ||||||
|  | 		/* Charger or USB-cable is connected */ | ||||||
|  | 		if (reg_data & STATUS3_EOC_MASK) | ||||||
|  | 			state = POWER_SUPPLY_STATUS_FULL; | ||||||
|  | 		else | ||||||
|  | 			state = POWER_SUPPLY_STATUS_CHARGING; | ||||||
|  | 		goto state_set; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | state_set: | ||||||
|  | 	chg->charging_state = state; | ||||||
|  | 	return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Supported charge types: | ||||||
|  |  *  - POWER_SUPPLY_CHARGE_TYPE_NONE | ||||||
|  |  *  - POWER_SUPPLY_CHARGE_TYPE_FAST | ||||||
|  |  */ | ||||||
|  | static int max14577_get_charge_type(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * TODO: CHARGE_TYPE_TRICKLE (VCHGR_RC or EOC)? | ||||||
|  | 	 * As spec says: | ||||||
|  | 	 * [after reaching EOC interrupt] | ||||||
|  | 	 * "When the battery is fully charged, the 30-minute (typ) | ||||||
|  | 	 *  top-off timer starts. The device continues to trickle | ||||||
|  | 	 *  charge the battery until the top-off timer runs out." | ||||||
|  | 	 */ | ||||||
|  | 	if (max14577_get_charger_state(chg) == POWER_SUPPLY_STATUS_CHARGING) | ||||||
|  | 		return POWER_SUPPLY_CHARGE_TYPE_FAST; | ||||||
|  | 	return POWER_SUPPLY_CHARGE_TYPE_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int max14577_get_online(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	struct regmap *rmap = chg->max14577->regmap; | ||||||
|  | 	u8 reg_data; | ||||||
|  | 
 | ||||||
|  | 	max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, ®_data); | ||||||
|  | 	reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); | ||||||
|  | 	switch (reg_data) { | ||||||
|  | 	case MAX14577_CHARGER_TYPE_USB: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_DEDICATED_CHG: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_SPECIAL_500MA: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_SPECIAL_1A: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_DEAD_BATTERY: | ||||||
|  | 		return 1; | ||||||
|  | 	case MAX14577_CHARGER_TYPE_NONE: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: | ||||||
|  | 	case MAX14577_CHARGER_TYPE_RESERVED: | ||||||
|  | 	default: | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Supported health statuses: | ||||||
|  |  *  - POWER_SUPPLY_HEALTH_DEAD | ||||||
|  |  *  - POWER_SUPPLY_HEALTH_OVERVOLTAGE | ||||||
|  |  *  - POWER_SUPPLY_HEALTH_GOOD | ||||||
|  |  */ | ||||||
|  | static int max14577_get_battery_health(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	struct regmap *rmap = chg->max14577->regmap; | ||||||
|  | 	int state = POWER_SUPPLY_HEALTH_GOOD; | ||||||
|  | 	u8 reg_data; | ||||||
|  | 
 | ||||||
|  | 	max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, ®_data); | ||||||
|  | 	reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); | ||||||
|  | 	if (reg_data == MAX14577_CHARGER_TYPE_DEAD_BATTERY) { | ||||||
|  | 		state = POWER_SUPPLY_HEALTH_DEAD; | ||||||
|  | 		goto state_set; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, ®_data); | ||||||
|  | 	if (reg_data & STATUS3_OVP_MASK) { | ||||||
|  | 		state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | ||||||
|  | 		goto state_set; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | state_set: | ||||||
|  | 	chg->battery_state = state; | ||||||
|  | 	return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Always returns 1. | ||||||
|  |  * The max14577 chip doesn't report any status of battery presence. | ||||||
|  |  * Lets assume that it will always be used with some battery. | ||||||
|  |  */ | ||||||
|  | static int max14577_get_present(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Sets charger registers to proper and safe default values. | ||||||
|  |  * Some of these values are equal to defaults in MAX14577E | ||||||
|  |  * data sheet but there are minor differences. | ||||||
|  |  */ | ||||||
|  | static void max14577_charger_reg_init(struct max14577_charger *chg) | ||||||
|  | { | ||||||
|  | 	struct regmap *rmap = chg->max14577->regmap; | ||||||
|  | 	u8 reg_data; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Charger-Type Manual Detection, default off (set CHGTYPMAN to 0) | ||||||
|  | 	 * Charger-Detection Enable, default on (set CHGDETEN to 1) | ||||||
|  | 	 * Combined mask of CHGDETEN and CHGTYPMAN will zero the CHGTYPMAN bit | ||||||
|  | 	 */ | ||||||
|  | 	reg_data = 0x1 << CDETCTRL1_CHGDETEN_SHIFT; | ||||||
|  | 	max14577_update_reg(rmap, MAX14577_REG_CDETCTRL1, | ||||||
|  | 			CDETCTRL1_CHGDETEN_MASK | CDETCTRL1_CHGTYPMAN_MASK, | ||||||
|  | 			reg_data); | ||||||
|  | 
 | ||||||
|  | 	/* Battery Fast-Charge Timer, from SM-V700: 6hrs */ | ||||||
|  | 	reg_data = 0x3 << CHGCTRL1_TCHW_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL1, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Wall-Adapter Rapid Charge, default on | ||||||
|  | 	 * Battery-Charger, default on | ||||||
|  | 	 */ | ||||||
|  | 	reg_data = 0x1 << CHGCTRL2_VCHGR_RC_SHIFT; | ||||||
|  | 	reg_data |= 0x1 << CHGCTRL2_MBCHOSTEN_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL2, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/* Battery-Charger Constant Voltage (CV) Mode, from SM-V700: 4.35V */ | ||||||
|  | 	reg_data = 0xf << CHGCTRL3_MBCCVWRC_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL3, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Fast Battery-Charge Current Low, default 200-950mA | ||||||
|  | 	 * Fast Battery-Charge Current High, from SM-V700: 450mA | ||||||
|  | 	 */ | ||||||
|  | 	reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; | ||||||
|  | 	reg_data |= 0x5 << CHGCTRL4_MBCICHWRCH_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL4, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/* End-of-Charge Current, from SM-V700: 50mA */ | ||||||
|  | 	reg_data = 0x0 << CHGCTRL5_EOCS_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL5, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/* Auto Charging Stop, default off */ | ||||||
|  | 	reg_data = 0x0 << CHGCTRL6_AUTOSTOP_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL6, reg_data); | ||||||
|  | 
 | ||||||
|  | 	/* Overvoltage-Protection Threshold, from SM-V700: 6.5V */ | ||||||
|  | 	reg_data = 0x2 << CHGCTRL7_OTPCGHCVS_SHIFT; | ||||||
|  | 	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL7, reg_data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Support property from charger */ | ||||||
|  | static enum power_supply_property max14577_charger_props[] = { | ||||||
|  | 	POWER_SUPPLY_PROP_STATUS, | ||||||
|  | 	POWER_SUPPLY_PROP_CHARGE_TYPE, | ||||||
|  | 	POWER_SUPPLY_PROP_HEALTH, | ||||||
|  | 	POWER_SUPPLY_PROP_PRESENT, | ||||||
|  | 	POWER_SUPPLY_PROP_ONLINE, | ||||||
|  | 	POWER_SUPPLY_PROP_MODEL_NAME, | ||||||
|  | 	POWER_SUPPLY_PROP_MANUFACTURER, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const char *model_name = "MAX14577"; | ||||||
|  | static const char *manufacturer = "Maxim Integrated"; | ||||||
|  | 
 | ||||||
|  | static int max14577_charger_get_property(struct power_supply *psy, | ||||||
|  | 			    enum power_supply_property psp, | ||||||
|  | 			    union power_supply_propval *val) | ||||||
|  | { | ||||||
|  | 	struct max14577_charger *chg = container_of(psy, | ||||||
|  | 						  struct max14577_charger, | ||||||
|  | 						  charger); | ||||||
|  | 	int ret = 0; | ||||||
|  | 
 | ||||||
|  | 	switch (psp) { | ||||||
|  | 	case POWER_SUPPLY_PROP_STATUS: | ||||||
|  | 		val->intval = max14577_get_charger_state(chg); | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||||||
|  | 		val->intval = max14577_get_charge_type(chg); | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_HEALTH: | ||||||
|  | 		val->intval = max14577_get_battery_health(chg); | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_PRESENT: | ||||||
|  | 		val->intval = max14577_get_present(chg); | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_ONLINE: | ||||||
|  | 		val->intval = max14577_get_online(chg); | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_MODEL_NAME: | ||||||
|  | 		val->strval = model_name; | ||||||
|  | 		break; | ||||||
|  | 	case POWER_SUPPLY_PROP_MANUFACTURER: | ||||||
|  | 		val->strval = manufacturer; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int max14577_charger_probe(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	struct max14577_charger *chg; | ||||||
|  | 	struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); | ||||||
|  | 	if (!chg) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	platform_set_drvdata(pdev, chg); | ||||||
|  | 	chg->dev = &pdev->dev; | ||||||
|  | 	chg->max14577 = max14577; | ||||||
|  | 
 | ||||||
|  | 	max14577_charger_reg_init(chg); | ||||||
|  | 
 | ||||||
|  | 	chg->charger.name = "max14577-charger", | ||||||
|  | 	chg->charger.type = POWER_SUPPLY_TYPE_BATTERY, | ||||||
|  | 	chg->charger.properties = max14577_charger_props, | ||||||
|  | 	chg->charger.num_properties = ARRAY_SIZE(max14577_charger_props), | ||||||
|  | 	chg->charger.get_property = max14577_charger_get_property, | ||||||
|  | 
 | ||||||
|  | 	ret = power_supply_register(&pdev->dev, &chg->charger); | ||||||
|  | 	if (ret) { | ||||||
|  | 		dev_err(&pdev->dev, "failed: power supply register\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int max14577_charger_remove(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	struct max14577_charger *chg = platform_get_drvdata(pdev); | ||||||
|  | 
 | ||||||
|  | 	power_supply_unregister(&chg->charger); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct platform_driver max14577_charger_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.owner	= THIS_MODULE, | ||||||
|  | 		.name	= "max14577-charger", | ||||||
|  | 	}, | ||||||
|  | 	.probe		= max14577_charger_probe, | ||||||
|  | 	.remove		= max14577_charger_remove, | ||||||
|  | }; | ||||||
|  | module_platform_driver(max14577_charger_driver); | ||||||
|  | 
 | ||||||
|  | MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); | ||||||
|  | MODULE_DESCRIPTION("MAXIM 14577 charger driver"); | ||||||
|  | MODULE_LICENSE("GPL"); | ||||||
|  | @ -741,9 +741,9 @@ static int max17042_probe(struct i2c_client *client, | ||||||
| 
 | 
 | ||||||
| 	if (client->irq) { | 	if (client->irq) { | ||||||
| 		ret = request_threaded_irq(client->irq, NULL, | 		ret = request_threaded_irq(client->irq, NULL, | ||||||
| 						max17042_thread_handler, | 					max17042_thread_handler, | ||||||
| 						IRQF_TRIGGER_FALLING, | 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||||||
| 						chip->battery.name, chip); | 					chip->battery.name, chip); | ||||||
| 		if (!ret) { | 		if (!ret) { | ||||||
| 			regmap_read(chip->regmap, MAX17042_CONFIG, &val); | 			regmap_read(chip->regmap, MAX17042_CONFIG, &val); | ||||||
| 			val |= CONFIG_ALRT_BIT_ENBL; | 			val |= CONFIG_ALRT_BIT_ENBL; | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/device.h> | #include <linux/device.h> | ||||||
|  | #include <linux/notifier.h> | ||||||
| #include <linux/err.h> | #include <linux/err.h> | ||||||
| #include <linux/power_supply.h> | #include <linux/power_supply.h> | ||||||
| #include <linux/thermal.h> | #include <linux/thermal.h> | ||||||
|  | @ -24,6 +25,9 @@ | ||||||
| struct class *power_supply_class; | struct class *power_supply_class; | ||||||
| EXPORT_SYMBOL_GPL(power_supply_class); | EXPORT_SYMBOL_GPL(power_supply_class); | ||||||
| 
 | 
 | ||||||
|  | ATOMIC_NOTIFIER_HEAD(power_supply_notifier); | ||||||
|  | EXPORT_SYMBOL_GPL(power_supply_notifier); | ||||||
|  | 
 | ||||||
| static struct device_type power_supply_dev_type; | static struct device_type power_supply_dev_type; | ||||||
| 
 | 
 | ||||||
| static bool __power_supply_is_supplied_by(struct power_supply *supplier, | static bool __power_supply_is_supplied_by(struct power_supply *supplier, | ||||||
|  | @ -80,6 +84,8 @@ static void power_supply_changed_work(struct work_struct *work) | ||||||
| 		class_for_each_device(power_supply_class, NULL, psy, | 		class_for_each_device(power_supply_class, NULL, psy, | ||||||
| 				      __power_supply_changed_work); | 				      __power_supply_changed_work); | ||||||
| 		power_supply_update_leds(psy); | 		power_supply_update_leds(psy); | ||||||
|  | 		atomic_notifier_call_chain(&power_supply_notifier, | ||||||
|  | 				PSY_EVENT_PROP_CHANGED, psy); | ||||||
| 		kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); | 		kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); | ||||||
| 		spin_lock_irqsave(&psy->changed_lock, flags); | 		spin_lock_irqsave(&psy->changed_lock, flags); | ||||||
| 	} | 	} | ||||||
|  | @ -335,6 +341,32 @@ struct power_supply *power_supply_get_by_name(const char *name) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(power_supply_get_by_name); | EXPORT_SYMBOL_GPL(power_supply_get_by_name); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | static int power_supply_match_device_node(struct device *dev, const void *data) | ||||||
|  | { | ||||||
|  | 	return dev->parent && dev->parent->of_node == data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct power_supply *power_supply_get_by_phandle(struct device_node *np, | ||||||
|  | 							const char *property) | ||||||
|  | { | ||||||
|  | 	struct device_node *power_supply_np; | ||||||
|  | 	struct device *dev; | ||||||
|  | 
 | ||||||
|  | 	power_supply_np = of_parse_phandle(np, property, 0); | ||||||
|  | 	if (!power_supply_np) | ||||||
|  | 		return ERR_PTR(-ENODEV); | ||||||
|  | 
 | ||||||
|  | 	dev = class_find_device(power_supply_class, NULL, power_supply_np, | ||||||
|  | 						power_supply_match_device_node); | ||||||
|  | 
 | ||||||
|  | 	of_node_put(power_supply_np); | ||||||
|  | 
 | ||||||
|  | 	return dev ? dev_get_drvdata(dev) : NULL; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
|  | 
 | ||||||
| int power_supply_powers(struct power_supply *psy, struct device *dev) | int power_supply_powers(struct power_supply *psy, struct device *dev) | ||||||
| { | { | ||||||
| 	return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); | 	return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); | ||||||
|  | @ -347,6 +379,18 @@ static void power_supply_dev_release(struct device *dev) | ||||||
| 	kfree(dev); | 	kfree(dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int power_supply_reg_notifier(struct notifier_block *nb) | ||||||
|  | { | ||||||
|  | 	return atomic_notifier_chain_register(&power_supply_notifier, nb); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(power_supply_reg_notifier); | ||||||
|  | 
 | ||||||
|  | void power_supply_unreg_notifier(struct notifier_block *nb) | ||||||
|  | { | ||||||
|  | 	atomic_notifier_chain_unregister(&power_supply_notifier, nb); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_THERMAL | #ifdef CONFIG_THERMAL | ||||||
| static int power_supply_read_temp(struct thermal_zone_device *tzd, | static int power_supply_read_temp(struct thermal_zone_device *tzd, | ||||||
| 		unsigned long *temp) | 		unsigned long *temp) | ||||||
|  |  | ||||||
|  | @ -6,6 +6,12 @@ menuconfig POWER_RESET | ||||||
| 
 | 
 | ||||||
| 	  Say Y here to enable board reset and power off | 	  Say Y here to enable board reset and power off | ||||||
| 
 | 
 | ||||||
|  | config POWER_RESET_AS3722 | ||||||
|  | 	bool "ams AS3722 power-off driver" | ||||||
|  | 	depends on MFD_AS3722 && POWER_RESET | ||||||
|  | 	help | ||||||
|  | 	  This driver supports turning off board via a ams AS3722 power-off. | ||||||
|  | 
 | ||||||
| config POWER_RESET_GPIO | config POWER_RESET_GPIO | ||||||
| 	bool "GPIO power-off driver" | 	bool "GPIO power-off driver" | ||||||
| 	depends on OF_GPIO && POWER_RESET | 	depends on OF_GPIO && POWER_RESET | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o | ||||||
| obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o | obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o | ||||||
| obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o | obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o | ||||||
| obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o | obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o | ||||||
|  |  | ||||||
							
								
								
									
										96
									
								
								drivers/power/reset/as3722-poweroff.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								drivers/power/reset/as3722-poweroff.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | ||||||
|  | /*
 | ||||||
|  |  * Power off driver for ams AS3722 device. | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Author: Laxman Dewangan <ldewangan@nvidia.com> | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or modify it | ||||||
|  |  * under the terms and conditions of the GNU General Public License, | ||||||
|  |  * version 2, as published by the Free Software Foundation. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope it will be useful, but WITHOUT | ||||||
|  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||||
|  |  * more details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/mfd/as3722.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/of_device.h> | ||||||
|  | #include <linux/platform_device.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | 
 | ||||||
|  | struct as3722_poweroff { | ||||||
|  | 	struct device *dev; | ||||||
|  | 	struct as3722 *as3722; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct as3722_poweroff *as3722_pm_poweroff; | ||||||
|  | 
 | ||||||
|  | static void as3722_pm_power_off(void) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!as3722_pm_poweroff) { | ||||||
|  | 		pr_err("AS3722 poweroff is not initialised\n"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ret = as3722_update_bits(as3722_pm_poweroff->as3722, | ||||||
|  | 		AS3722_RESET_CONTROL_REG, AS3722_POWER_OFF, AS3722_POWER_OFF); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		dev_err(as3722_pm_poweroff->dev, | ||||||
|  | 			"RESET_CONTROL_REG update failed, %d\n", ret); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int as3722_poweroff_probe(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	struct as3722_poweroff *as3722_poweroff; | ||||||
|  | 	struct device_node *np = pdev->dev.parent->of_node; | ||||||
|  | 
 | ||||||
|  | 	if (!np) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (!of_property_read_bool(np, "ams,system-power-controller")) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	as3722_poweroff = devm_kzalloc(&pdev->dev, sizeof(*as3722_poweroff), | ||||||
|  | 				GFP_KERNEL); | ||||||
|  | 	if (!as3722_poweroff) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	as3722_poweroff->as3722 = dev_get_drvdata(pdev->dev.parent); | ||||||
|  | 	as3722_poweroff->dev = &pdev->dev; | ||||||
|  | 	as3722_pm_poweroff = as3722_poweroff; | ||||||
|  | 	if (!pm_power_off) | ||||||
|  | 		pm_power_off = as3722_pm_power_off; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int as3722_poweroff_remove(struct platform_device *pdev) | ||||||
|  | { | ||||||
|  | 	if (pm_power_off == as3722_pm_power_off) | ||||||
|  | 		pm_power_off = NULL; | ||||||
|  | 	as3722_pm_poweroff = NULL; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct platform_driver as3722_poweroff_driver = { | ||||||
|  | 	.driver = { | ||||||
|  | 		.name = "as3722-power-off", | ||||||
|  | 		.owner = THIS_MODULE, | ||||||
|  | 	}, | ||||||
|  | 	.probe = as3722_poweroff_probe, | ||||||
|  | 	.remove = as3722_poweroff_remove, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module_platform_driver(as3722_poweroff_driver); | ||||||
|  | 
 | ||||||
|  | MODULE_DESCRIPTION("Power off driver for ams AS3722 PMIC Device"); | ||||||
|  | MODULE_ALIAS("platform:as3722-power-off"); | ||||||
|  | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*
 | /*
 | ||||||
|  * bq2415x charger driver |  * bq2415x charger driver | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2011-2012  Pali Rohár <pali.rohar@gmail.com> |  * Copyright (C) 2011-2013  Pali Rohár <pali.rohar@gmail.com> | ||||||
|  * |  * | ||||||
|  * This program is free software; you can redistribute it and/or modify |  * This program is free software; you can redistribute it and/or modify | ||||||
|  * it under the terms of the GNU General Public License as published by |  * it under the terms of the GNU General Public License as published by | ||||||
|  | @ -31,46 +31,9 @@ | ||||||
|  * termination current. It it is less or equal to zero, configuring charge |  * termination current. It it is less or equal to zero, configuring charge | ||||||
|  * and termination current will not be possible. |  * and termination current will not be possible. | ||||||
|  * |  * | ||||||
|  * Function set_mode_hook is needed for automode (setting correct current |  * For automode support is needed to provide name of power supply device | ||||||
|  * limit when charger is connected/disconnected or setting boost mode). |  * in value notify_device. Device driver must immediately report property | ||||||
|  * When is NULL, automode function is disabled. When is not NULL, it must |  * POWER_SUPPLY_PROP_CURRENT_MAX when current changed. | ||||||
|  * have this prototype: |  | ||||||
|  * |  | ||||||
|  *    int (*set_mode_hook)( |  | ||||||
|  *      void (*hook)(enum bq2415x_mode mode, void *data), |  | ||||||
|  *      void *data) |  | ||||||
|  * |  | ||||||
|  * hook is hook function (see below) and data is pointer to driver private |  | ||||||
|  * data |  | ||||||
|  * |  | ||||||
|  * bq2415x driver will call it as: |  | ||||||
|  * |  | ||||||
|  *    platform_data->set_mode_hook(bq2415x_hook_function, bq2415x_device); |  | ||||||
|  * |  | ||||||
|  * Board/platform function set_mode_hook return non zero value when hook |  | ||||||
|  * function was successful registered. Platform code should call that hook |  | ||||||
|  * function (which get from pointer, with data) every time when charger |  | ||||||
|  * was connected/disconnected or require to enable boost mode. bq2415x |  | ||||||
|  * driver then will set correct current limit, enable/disable charger or |  | ||||||
|  * boost mode. |  | ||||||
|  * |  | ||||||
|  * Hook function has this prototype: |  | ||||||
|  * |  | ||||||
|  *    void hook(enum bq2415x_mode mode, void *data); |  | ||||||
|  * |  | ||||||
|  * mode is bq2415x mode (charger or boost) |  | ||||||
|  * data is pointer to driver private data (which get from |  | ||||||
|  * set_charger_type_hook) |  | ||||||
|  * |  | ||||||
|  * When bq driver is being unloaded, it call function: |  | ||||||
|  * |  | ||||||
|  *    platform_data->set_mode_hook(NULL, NULL); |  | ||||||
|  * |  | ||||||
|  * (hook function and driver private data are NULL) |  | ||||||
|  * |  | ||||||
|  * After that board/platform code must not call driver hook function! It |  | ||||||
|  * is possible that pointer to hook function will not be valid and calling |  | ||||||
|  * will cause undefined result. |  | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /* Supported modes with maximal current limit */ | /* Supported modes with maximal current limit */ | ||||||
|  | @ -89,8 +52,7 @@ struct bq2415x_platform_data { | ||||||
| 	int charge_current;		/* mA */ | 	int charge_current;		/* mA */ | ||||||
| 	int termination_current;	/* mA */ | 	int termination_current;	/* mA */ | ||||||
| 	int resistor_sense;		/* m ohm */ | 	int resistor_sense;		/* m ohm */ | ||||||
| 	int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data), | 	const char *notify_device;	/* name */ | ||||||
| 			     void *data); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -37,6 +37,8 @@ enum cm_event_types { | ||||||
| 	CM_EVENT_BATT_FULL, | 	CM_EVENT_BATT_FULL, | ||||||
| 	CM_EVENT_BATT_IN, | 	CM_EVENT_BATT_IN, | ||||||
| 	CM_EVENT_BATT_OUT, | 	CM_EVENT_BATT_OUT, | ||||||
|  | 	CM_EVENT_BATT_OVERHEAT, | ||||||
|  | 	CM_EVENT_BATT_COLD, | ||||||
| 	CM_EVENT_EXT_PWR_IN_OUT, | 	CM_EVENT_EXT_PWR_IN_OUT, | ||||||
| 	CM_EVENT_CHG_START_STOP, | 	CM_EVENT_CHG_START_STOP, | ||||||
| 	CM_EVENT_OTHERS, | 	CM_EVENT_OTHERS, | ||||||
|  | @ -173,11 +175,10 @@ struct charger_regulator { | ||||||
|  * @num_charger_regulator: the number of entries in charger_regulators |  * @num_charger_regulator: the number of entries in charger_regulators | ||||||
|  * @charger_regulators: array of charger regulators |  * @charger_regulators: array of charger regulators | ||||||
|  * @psy_fuel_gauge: the name of power-supply for fuel gauge |  * @psy_fuel_gauge: the name of power-supply for fuel gauge | ||||||
|  * @temperature_out_of_range: |  * @thermal_zone : the name of thermal zone for battery | ||||||
|  *	Determine whether the status is overheat or cold or normal. |  * @temp_min : Minimum battery temperature for charging. | ||||||
|  *	return_value > 0: overheat |  * @temp_max : Maximum battery temperature for charging. | ||||||
|  *	return_value == 0: normal |  * @temp_diff : Temperature diffential to restart charging. | ||||||
|  *	return_value < 0: cold |  | ||||||
|  * @measure_battery_temp: |  * @measure_battery_temp: | ||||||
|  *	true: measure battery temperature |  *	true: measure battery temperature | ||||||
|  *	false: measure ambient temperature |  *	false: measure ambient temperature | ||||||
|  | @ -190,7 +191,7 @@ struct charger_regulator { | ||||||
|  *	max_duration_ms', cm start charging. |  *	max_duration_ms', cm start charging. | ||||||
|  */ |  */ | ||||||
| struct charger_desc { | struct charger_desc { | ||||||
| 	char *psy_name; | 	const char *psy_name; | ||||||
| 
 | 
 | ||||||
| 	enum polling_modes polling_mode; | 	enum polling_modes polling_mode; | ||||||
| 	unsigned int polling_interval_ms; | 	unsigned int polling_interval_ms; | ||||||
|  | @ -203,18 +204,23 @@ struct charger_desc { | ||||||
| 
 | 
 | ||||||
| 	enum data_source battery_present; | 	enum data_source battery_present; | ||||||
| 
 | 
 | ||||||
| 	char **psy_charger_stat; | 	const char **psy_charger_stat; | ||||||
| 
 | 
 | ||||||
| 	int num_charger_regulators; | 	int num_charger_regulators; | ||||||
| 	struct charger_regulator *charger_regulators; | 	struct charger_regulator *charger_regulators; | ||||||
| 
 | 
 | ||||||
| 	char *psy_fuel_gauge; | 	const char *psy_fuel_gauge; | ||||||
|  | 
 | ||||||
|  | 	const char *thermal_zone; | ||||||
|  | 
 | ||||||
|  | 	int temp_min; | ||||||
|  | 	int temp_max; | ||||||
|  | 	int temp_diff; | ||||||
| 
 | 
 | ||||||
| 	int (*temperature_out_of_range)(int *mC); |  | ||||||
| 	bool measure_battery_temp; | 	bool measure_battery_temp; | ||||||
| 
 | 
 | ||||||
| 	u64 charging_max_duration_ms; | 	u32 charging_max_duration_ms; | ||||||
| 	u64 discharging_max_duration_ms; | 	u32 discharging_max_duration_ms; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define PSY_NAME_MAX	30 | #define PSY_NAME_MAX	30 | ||||||
|  | @ -226,13 +232,13 @@ struct charger_desc { | ||||||
|  * @desc: instance of charger_desc |  * @desc: instance of charger_desc | ||||||
|  * @fuel_gauge: power_supply for fuel gauge |  * @fuel_gauge: power_supply for fuel gauge | ||||||
|  * @charger_stat: array of power_supply for chargers |  * @charger_stat: array of power_supply for chargers | ||||||
|  |  * @tzd_batt : thermal zone device for battery | ||||||
|  * @charger_enabled: the state of charger |  * @charger_enabled: the state of charger | ||||||
|  * @fullbatt_vchk_jiffies_at: |  * @fullbatt_vchk_jiffies_at: | ||||||
|  *	jiffies at the time full battery check will occur. |  *	jiffies at the time full battery check will occur. | ||||||
|  * @fullbatt_vchk_work: work queue for full battery check |  * @fullbatt_vchk_work: work queue for full battery check | ||||||
|  * @emergency_stop: |  * @emergency_stop: | ||||||
|  *	When setting true, stop charging |  *	When setting true, stop charging | ||||||
|  * @last_temp_mC: the measured temperature in milli-Celsius |  | ||||||
|  * @psy_name_buf: the name of power-supply-class for charger manager |  * @psy_name_buf: the name of power-supply-class for charger manager | ||||||
|  * @charger_psy: power_supply for charger manager |  * @charger_psy: power_supply for charger manager | ||||||
|  * @status_save_ext_pwr_inserted: |  * @status_save_ext_pwr_inserted: | ||||||
|  | @ -250,13 +256,15 @@ struct charger_manager { | ||||||
| 	struct power_supply *fuel_gauge; | 	struct power_supply *fuel_gauge; | ||||||
| 	struct power_supply **charger_stat; | 	struct power_supply **charger_stat; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_THERMAL | ||||||
|  | 	struct thermal_zone_device *tzd_batt; | ||||||
|  | #endif | ||||||
| 	bool charger_enabled; | 	bool charger_enabled; | ||||||
| 
 | 
 | ||||||
| 	unsigned long fullbatt_vchk_jiffies_at; | 	unsigned long fullbatt_vchk_jiffies_at; | ||||||
| 	struct delayed_work fullbatt_vchk_work; | 	struct delayed_work fullbatt_vchk_work; | ||||||
| 
 | 
 | ||||||
| 	int emergency_stop; | 	int emergency_stop; | ||||||
| 	int last_temp_mC; |  | ||||||
| 
 | 
 | ||||||
| 	char psy_name_buf[PSY_NAME_MAX + 1]; | 	char psy_name_buf[PSY_NAME_MAX + 1]; | ||||||
| 	struct power_supply charger_psy; | 	struct power_supply charger_psy; | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ | ||||||
| 
 | 
 | ||||||
| struct isp1704_charger_data { | struct isp1704_charger_data { | ||||||
| 	void		(*set_power)(bool on); | 	void		(*set_power)(bool on); | ||||||
|  | 	int		enable_gpio; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| #include <linux/workqueue.h> | #include <linux/workqueue.h> | ||||||
| #include <linux/leds.h> | #include <linux/leds.h> | ||||||
| #include <linux/spinlock.h> | #include <linux/spinlock.h> | ||||||
|  | #include <linux/notifier.h> | ||||||
| 
 | 
 | ||||||
| struct device; | struct device; | ||||||
| 
 | 
 | ||||||
|  | @ -158,6 +159,10 @@ enum power_supply_type { | ||||||
| 	POWER_SUPPLY_TYPE_USB_ACA,	/* Accessory Charger Adapters */ | 	POWER_SUPPLY_TYPE_USB_ACA,	/* Accessory Charger Adapters */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum power_supply_notifier_events { | ||||||
|  | 	PSY_EVENT_PROP_CHANGED, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| union power_supply_propval { | union power_supply_propval { | ||||||
| 	int intval; | 	int intval; | ||||||
| 	const char *strval; | 	const char *strval; | ||||||
|  | @ -235,7 +240,18 @@ struct power_supply_info { | ||||||
| 	int use_for_apm; | 	int use_for_apm; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | extern struct atomic_notifier_head power_supply_notifier; | ||||||
|  | extern int power_supply_reg_notifier(struct notifier_block *nb); | ||||||
|  | extern void power_supply_unreg_notifier(struct notifier_block *nb); | ||||||
| extern struct power_supply *power_supply_get_by_name(const char *name); | extern struct power_supply *power_supply_get_by_name(const char *name); | ||||||
|  | #ifdef CONFIG_OF | ||||||
|  | extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, | ||||||
|  | 							const char *property); | ||||||
|  | #else /* !CONFIG_OF */ | ||||||
|  | static inline struct power_supply * | ||||||
|  | power_supply_get_by_phandle(struct device_node *np, const char *property) | ||||||
|  | { return NULL; } | ||||||
|  | #endif /* CONFIG_OF */ | ||||||
| extern void power_supply_changed(struct power_supply *psy); | extern void power_supply_changed(struct power_supply *psy); | ||||||
| extern int power_supply_am_i_supplied(struct power_supply *psy); | extern int power_supply_am_i_supplied(struct power_supply *psy); | ||||||
| extern int power_supply_set_battery_charged(struct power_supply *psy); | extern int power_supply_set_battery_charged(struct power_supply *psy); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds