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:
Linus Torvalds 2014-01-21 11:36:20 -08:00
commit 03d11a0e45
20 changed files with 1043 additions and 132 deletions

View file

@ -112,6 +112,15 @@ Following are properties of regulator subnode.
ams,enable-tracking: Enable tracking with SD1, only supported
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:
--------
#include <dt-bindings/mfd/as3722.h>
@ -120,6 +129,8 @@ ams3722 {
compatible = "ams,as3722";
reg = <0x48>;
ams,system-power-controller;
interrupt-parent = <&intc>;
interrupt-controller;
#interrupt-cells = <2>;

View 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>;
};

View file

@ -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>;
};
};
};

View file

@ -6712,7 +6712,7 @@ F: include/linux/timer*
F: kernel/*timer*
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>
T: git git://git.infradead.org/battery-2.6.git
S: Maintained

View file

@ -317,6 +317,13 @@ config CHARGER_MANAGER
runtime and in suspend-to-RAM by waking up the system periodically
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
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
depends on MFD_MAX8997 && REGULATOR_MAX8997

View file

@ -48,6 +48,7 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.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_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o

View file

@ -1,7 +1,7 @@
/*
* 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
* 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 power_supply charger;
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 mode; /* current configured mode */
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 void bq2415x_hook_function(enum bq2415x_mode mode, void *data)
static int bq2415x_notifier_call(struct notifier_block *nb,
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)
return;
if (val != PSY_EVENT_PROP_CHANGED)
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;
/* if automode is not enabled do not tell about reported_mode */
if (bq->automode < 1)
return;
return NOTIFY_OK;
sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode");
bq2415x_set_mode(bq, bq->reported_mode);
return NOTIFY_OK;
}
/**** timer functions ****/
@ -1512,9 +1543,11 @@ static int bq2415x_probe(struct i2c_client *client,
int num;
char *name;
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) {
dev_err(&client->dev, "platform data not set\n");
if (!np && !pdata) {
dev_err(&client->dev, "platform data missing\n");
return -ENODEV;
}
@ -1539,6 +1572,17 @@ static int bq2415x_probe(struct i2c_client *client,
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);
bq->id = num;
@ -1550,8 +1594,34 @@ static int bq2415x_probe(struct i2c_client *client,
bq->autotimer = 0;
bq->automode = 0;
memcpy(&bq->init_data, client->dev.platform_data,
sizeof(bq->init_data));
if (np) {
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);
@ -1573,16 +1643,20 @@ static int bq2415x_probe(struct i2c_client *client,
goto error_4;
}
if (bq->init_data.set_mode_hook) {
if (bq->init_data.set_mode_hook(
bq2415x_hook_function, bq)) {
bq->automode = 1;
bq2415x_set_mode(bq, bq->reported_mode);
dev_info(bq->dev, "automode enabled\n");
} else {
bq->automode = -1;
dev_info(bq->dev, "automode failed\n");
if (bq->notify_psy) {
bq->nb.notifier_call = bq2415x_notifier_call;
ret = power_supply_reg_notifier(&bq->nb);
if (ret) {
dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
goto error_5;
}
/* 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 {
bq->automode = -1;
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");
return 0;
error_5:
error_4:
bq2415x_sysfs_exit(bq);
error_3:
@ -1614,8 +1689,8 @@ static int bq2415x_remove(struct i2c_client *client)
{
struct bq2415x_device *bq = i2c_get_clientdata(client);
if (bq->init_data.set_mode_hook)
bq->init_data.set_mode_hook(NULL, NULL);
if (bq->notify_psy)
power_supply_unreg_notifier(&bq->nb);
bq2415x_sysfs_exit(bq);
bq2415x_power_supply_exit(bq);

View file

@ -25,12 +25,23 @@
#include <linux/power/charger-manager.h>
#include <linux/regulator/consumer.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[] = {
[CM_EVENT_UNKNOWN] = "Unknown",
[CM_EVENT_BATT_FULL] = "Battery Full",
[CM_EVENT_BATT_IN] = "Battery Inserted",
[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_CHG_START_STOP] = "Charging Start/Stop",
[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;
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);
uevent_notify(cm, "Discharging");
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 &&
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);
uevent_notify(cm, "Recharging");
try_charger_enable(cm, true);
@ -540,6 +551,60 @@ static int check_charging_duration(struct charger_manager *cm)
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: 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)
{
struct charger_desc *desc = cm->desc;
int temp = desc->temperature_out_of_range(&cm->last_temp_mC);
int temp_alrt;
dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n",
cm->last_temp_mC / 1000, cm->last_temp_mC % 1000);
temp_alrt = cm_check_thermal_status(cm);
/* It has been stopped already */
if (temp && cm->emergency_stop)
if (temp_alrt && cm->emergency_stop)
return false;
/*
* Check temperature whether overheat or cold.
* If temperature is out of range normal state, stop charging.
*/
if (temp) {
cm->emergency_stop = temp;
if (!try_charger_enable(cm, false)) {
if (temp > 0)
uevent_notify(cm, "OVERHEAT");
else
uevent_notify(cm, "COLD");
}
if (temp_alrt) {
cm->emergency_stop = temp_alrt;
if (!try_charger_enable(cm, false))
uevent_notify(cm, default_event_names[temp_alrt]);
/*
* 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);
break;
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:
/* 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;
return cm_get_battery_temperature(cm, &val->intval);
case POWER_SUPPLY_PROP_CAPACITY:
if (!cm->fuel_gauge) {
ret = -ENODEV;
@ -1439,9 +1485,183 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
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)
{
struct charger_desc *desc = dev_get_platdata(&pdev->dev);
struct charger_desc *desc = cm_get_drv_data(pdev);
struct charger_manager *cm;
int ret = 0, i = 0;
int j = 0;
@ -1470,7 +1690,6 @@ static int charger_manager_probe(struct platform_device *pdev)
/* Basic Values. Unspecified are Null or 0 */
cm->dev = &pdev->dev;
cm->desc = desc;
cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */
/*
* The following two do not need to be errors.
@ -1533,11 +1752,6 @@ static int charger_manager_probe(struct platform_device *pdev)
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 ||
!desc->discharging_max_duration_ms) {
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++;
}
if (desc->measure_battery_temp) {
cm->charger_psy.properties[cm->charger_psy.num_properties] =
POWER_SUPPLY_PROP_TEMP;
cm->charger_psy.num_properties++;
} else {
cm->charger_psy.properties[cm->charger_psy.num_properties] =
POWER_SUPPLY_PROP_TEMP_AMBIENT;
cm->charger_psy.num_properties++;
ret = cm_init_thermal_data(cm);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize thermal data\n");
cm->desc->measure_battery_temp = false;
}
INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
@ -1808,6 +2018,7 @@ static struct platform_driver charger_manager_driver = {
.name = "charger-manager",
.owner = THIS_MODULE,
.pm = &charger_manager_pm,
.of_match_table = charger_manager_match,
},
.probe = charger_manager_probe,
.remove = charger_manager_remove,

View file

@ -28,6 +28,7 @@
struct gpio_charger {
const struct gpio_charger_platform_data *pdata;
unsigned int irq;
bool wakeup_enabled;
struct power_supply charger;
};
@ -136,6 +137,8 @@ static int gpio_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio_charger);
device_init_wakeup(&pdev->dev, 1);
return 0;
err_gpio_free:
@ -159,18 +162,32 @@ static int gpio_charger_remove(struct platform_device *pdev)
}
#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)
{
struct platform_device *pdev = to_platform_device(dev);
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);
return 0;
}
#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 = {
.probe = gpio_charger_probe,

View file

@ -29,6 +29,8 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/usb/otg.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)
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;
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);
if (!isp)
return -ENOMEM;
isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(isp->phy))
if (np)
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;
isp->dev = &pdev->dev;
@ -464,7 +503,6 @@ static int isp1704_charger_probe(struct platform_device *pdev)
power_supply_unregister(&isp->psy);
fail1:
isp1704_charger_set_power(isp, 0);
usb_put_phy(isp->phy);
fail0:
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);
power_supply_unregister(&isp->psy);
usb_put_phy(isp->phy);
isp1704_charger_set_power(isp, 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 = {
.driver = {
.name = "isp1704_charger",
.of_match_table = of_match_ptr(omap_isp1704_of_match),
},
.probe = isp1704_charger_probe,
.remove = isp1704_charger_remove,

View 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, &reg_data);
if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0)
goto state_set;
max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, &reg_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, &reg_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, &reg_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, &reg_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");

View file

@ -741,9 +741,9 @@ static int max17042_probe(struct i2c_client *client,
if (client->irq) {
ret = request_threaded_irq(client->irq, NULL,
max17042_thread_handler,
IRQF_TRIGGER_FALLING,
chip->battery.name, chip);
max17042_thread_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
chip->battery.name, chip);
if (!ret) {
regmap_read(chip->regmap, MAX17042_CONFIG, &val);
val |= CONFIG_ALRT_BIT_ENBL;

View file

@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/err.h>
#include <linux/power_supply.h>
#include <linux/thermal.h>
@ -24,6 +25,9 @@
struct class *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 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,
__power_supply_changed_work);
power_supply_update_leds(psy);
atomic_notifier_call_chain(&power_supply_notifier,
PSY_EVENT_PROP_CHANGED, psy);
kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
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);
#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)
{
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);
}
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
static int power_supply_read_temp(struct thermal_zone_device *tzd,
unsigned long *temp)

View file

@ -6,6 +6,12 @@ menuconfig POWER_RESET
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
bool "GPIO power-off driver"
depends on OF_GPIO && POWER_RESET

View file

@ -1,3 +1,4 @@
obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o

View 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");

View file

@ -1,7 +1,7 @@
/*
* 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
* 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
* and termination current will not be possible.
*
* Function set_mode_hook is needed for automode (setting correct current
* limit when charger is connected/disconnected or setting boost mode).
* When is NULL, automode function is disabled. When is not NULL, it must
* 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.
* For automode support is needed to provide name of power supply device
* in value notify_device. Device driver must immediately report property
* POWER_SUPPLY_PROP_CURRENT_MAX when current changed.
*/
/* Supported modes with maximal current limit */
@ -89,8 +52,7 @@ struct bq2415x_platform_data {
int charge_current; /* mA */
int termination_current; /* mA */
int resistor_sense; /* m ohm */
int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data),
void *data);
const char *notify_device; /* name */
};
#endif

View file

@ -37,6 +37,8 @@ enum cm_event_types {
CM_EVENT_BATT_FULL,
CM_EVENT_BATT_IN,
CM_EVENT_BATT_OUT,
CM_EVENT_BATT_OVERHEAT,
CM_EVENT_BATT_COLD,
CM_EVENT_EXT_PWR_IN_OUT,
CM_EVENT_CHG_START_STOP,
CM_EVENT_OTHERS,
@ -173,11 +175,10 @@ struct charger_regulator {
* @num_charger_regulator: the number of entries in charger_regulators
* @charger_regulators: array of charger regulators
* @psy_fuel_gauge: the name of power-supply for fuel gauge
* @temperature_out_of_range:
* Determine whether the status is overheat or cold or normal.
* return_value > 0: overheat
* return_value == 0: normal
* return_value < 0: cold
* @thermal_zone : the name of thermal zone for battery
* @temp_min : Minimum battery temperature for charging.
* @temp_max : Maximum battery temperature for charging.
* @temp_diff : Temperature diffential to restart charging.
* @measure_battery_temp:
* true: measure battery temperature
* false: measure ambient temperature
@ -190,7 +191,7 @@ struct charger_regulator {
* max_duration_ms', cm start charging.
*/
struct charger_desc {
char *psy_name;
const char *psy_name;
enum polling_modes polling_mode;
unsigned int polling_interval_ms;
@ -203,18 +204,23 @@ struct charger_desc {
enum data_source battery_present;
char **psy_charger_stat;
const char **psy_charger_stat;
int num_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;
u64 charging_max_duration_ms;
u64 discharging_max_duration_ms;
u32 charging_max_duration_ms;
u32 discharging_max_duration_ms;
};
#define PSY_NAME_MAX 30
@ -226,13 +232,13 @@ struct charger_desc {
* @desc: instance of charger_desc
* @fuel_gauge: power_supply for fuel gauge
* @charger_stat: array of power_supply for chargers
* @tzd_batt : thermal zone device for battery
* @charger_enabled: the state of charger
* @fullbatt_vchk_jiffies_at:
* jiffies at the time full battery check will occur.
* @fullbatt_vchk_work: work queue for full battery check
* @emergency_stop:
* 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
* @charger_psy: power_supply for charger manager
* @status_save_ext_pwr_inserted:
@ -250,13 +256,15 @@ struct charger_manager {
struct power_supply *fuel_gauge;
struct power_supply **charger_stat;
#ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd_batt;
#endif
bool charger_enabled;
unsigned long fullbatt_vchk_jiffies_at;
struct delayed_work fullbatt_vchk_work;
int emergency_stop;
int last_temp_mC;
char psy_name_buf[PSY_NAME_MAX + 1];
struct power_supply charger_psy;

View file

@ -24,6 +24,7 @@
struct isp1704_charger_data {
void (*set_power)(bool on);
int enable_gpio;
};
#endif

View file

@ -16,6 +16,7 @@
#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
struct device;
@ -158,6 +159,10 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
};
enum power_supply_notifier_events {
PSY_EVENT_PROP_CHANGED,
};
union power_supply_propval {
int intval;
const char *strval;
@ -235,7 +240,18 @@ struct power_supply_info {
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);
#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 int power_supply_am_i_supplied(struct power_supply *psy);
extern int power_supply_set_battery_charged(struct power_supply *psy);