power supply changes for the v3.17 series
- Added iPaq h3xxx battery driver - Added Broadcom STB reset driver - DT support for rx51-battery - misc. fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJT4WyFAAoJENju1/PIO/qaYvwP/0EcchAHFS6mCyYAs8/h9JPC HMwlGh899FlFtu1Ggr5VIZnWKOdKKmOTcg0HFS63KjFGglyCzrRysXU2oa62LMla d6n7sGzlFFC+OE5neBFs44ieg5iFcff++Vw2Xij804SZDNMTaMzpNASh4jmjmxD3 DHxVLYLQd1Xx30kB/KyXhi+UIMvZDKF2F06CmViNg8eQiq59FTsjYeIJAxFJrfyN C95a3BEnzDuK8w9ylj0pN25bWpScI7B+AaC/bFz9qBRDqeKTQkj1D0t6ZLr7pJnN a2lf+w3px6RBaK+O2fez9z8Drpi35BuaJ4x4f0ieWvlONanvRc6kyLwzggs40X2U BQbgSj88Chk3S6rfdGDYxw8qxcgtrkG1jeazsusdQxRik1vLnjWIw26yYB2Qs5mg zz38h21Ur3l72GTUuTYU+gvX7fHZe81asZaQvb9j/SgYu5NSX2xrVmwYB4z6V0Uj SK5Chp45X7xonRQO9jqnFIN2ADF49cOjPflBHBr7bU4lMFciG2DEN10W9YeVMLDG iYvjNWaztzuxIVEXIwiVAJluVp/379TLZ47/dmdMt4zUBqccAFn0ZiyZFScOku2F gxHzQhFPZueOfo3Mv65SP8RXEVn4ZaLAK+vk/u//orXHf5KGmNf8hLg+40aZT/bw FL2MkAtOgwKtuz70ddya =6Y4V -----END PGP SIGNATURE----- Merge tag 'for-v3.17' of git://git.infradead.org/battery-2.6 Pull power supply changes from Sebastian Reichel: - Added iPaq h3xxx battery driver - Added Broadcom STB reset driver - DT support for rx51-battery - misc. fixes * tag 'for-v3.17' of git://git.infradead.org/battery-2.6: ipaq_micro_battery: fix sparse non static symbol warning power: add driver for battery reading on iPaq h3xxx power: twl4030_charger: detect battery presence prior to enabling charger power: reset: Add reboot driver for brcmstb power_supply: Fix sparse non static symbol warning power_supply: Add inlmt,iterm, min/max temp props charger: tps65090: Allow charger module to be used when no irq power/reset: Fix GPL v2 license string typo power: poweroff: gpio: convert to use descriptors bq27000: report missing device better. bq27x00_battery: Introduce the use of the managed version of kzalloc Documentation: DT: Document rx51-battery binding rx51_battery: convert to iio consumer bq2415x_charger: Fix Atomic Sleep Bug
This commit is contained in:
Коммит
0498cf8429
|
@ -0,0 +1,25 @@
|
|||
Binding for Nokia N900 battery
|
||||
|
||||
The Nokia N900 battery status can be read via the TWL4030's A/D converter.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
* "nokia,n900-battery"
|
||||
- io-channels: Should contain IIO channel specifiers
|
||||
for each element in io-channel-names.
|
||||
- io-channel-names: Should contain the following values:
|
||||
* "temp" - The ADC channel for temperature reading
|
||||
* "bsi" - The ADC channel for battery size identification
|
||||
* "vbat" - The ADC channel to measure the battery voltage
|
||||
|
||||
Example from Nokia N900:
|
||||
|
||||
battery: n900-battery {
|
||||
compatible = "nokia,n900-battery";
|
||||
io-channels = <&twl4030_madc 0>,
|
||||
<&twl4030_madc 4>,
|
||||
<&twl4030_madc 12>;
|
||||
io-channel-names = "temp",
|
||||
"bsi",
|
||||
"vbat";
|
||||
};
|
|
@ -118,6 +118,10 @@ relative, time-based measurements.
|
|||
CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
|
||||
CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the
|
||||
power supply object.
|
||||
INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates
|
||||
the current drawn from a charging source.
|
||||
CHARGE_TERM_CURRENT - Charge termination current used to detect the end of charge
|
||||
condition.
|
||||
|
||||
CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
|
||||
CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the
|
||||
|
@ -140,6 +144,8 @@ TEMP_ALERT_MAX - maximum battery temperature alert.
|
|||
TEMP_AMBIENT - ambient temperature.
|
||||
TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert.
|
||||
TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert.
|
||||
TEMP_MIN - minimum operatable temperature
|
||||
TEMP_MAX - maximum operatable temperature
|
||||
|
||||
TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e.
|
||||
while battery powers a load)
|
||||
|
|
|
@ -137,6 +137,13 @@ config BATTERY_COLLIE
|
|||
Say Y to enable support for the battery on the Sharp Zaurus
|
||||
SL-5500 (collie) models.
|
||||
|
||||
config BATTERY_IPAQ_MICRO
|
||||
tristate "iPAQ Atmel Micro ASIC battery driver"
|
||||
depends on MFD_IPAQ_MICRO
|
||||
help
|
||||
Choose this option if you want to monitor battery status on
|
||||
Compaq/HP iPAQ h3100 and h3600.
|
||||
|
||||
config BATTERY_WM97XX
|
||||
bool "WM97xx generic battery driver"
|
||||
depends on TOUCHSCREEN_WM97XX=y
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
|
|||
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
|
||||
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
|
||||
obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
|
||||
obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
|
||||
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
|
||||
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
|
||||
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
|
||||
|
|
|
@ -840,8 +840,7 @@ static int bq2415x_notifier_call(struct notifier_block *nb,
|
|||
if (bq->automode < 1)
|
||||
return NOTIFY_OK;
|
||||
|
||||
sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode");
|
||||
bq2415x_set_mode(bq, bq->reported_mode);
|
||||
schedule_delayed_work(&bq->work, 0);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
@ -892,6 +891,11 @@ static void bq2415x_timer_work(struct work_struct *work)
|
|||
int error;
|
||||
int boost;
|
||||
|
||||
if (bq->automode > 0 && (bq->reported_mode != bq->mode)) {
|
||||
sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode");
|
||||
bq2415x_set_mode(bq, bq->reported_mode);
|
||||
}
|
||||
|
||||
if (!bq->autotimer)
|
||||
return;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* http://www.ti.com/product/bq27425-g1
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -415,6 +416,9 @@ static void bq27x00_update(struct bq27x00_device_info *di)
|
|||
bool is_bq27425 = di->chip == BQ27425;
|
||||
|
||||
cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500);
|
||||
if ((cache.flags & 0xff) == 0xff)
|
||||
/* read error */
|
||||
cache.flags = -1;
|
||||
if (cache.flags >= 0) {
|
||||
if (!is_bq27500 && !is_bq27425
|
||||
&& (cache.flags & BQ27000_FLAG_CI)) {
|
||||
|
@ -804,7 +808,7 @@ static int bq27x00_battery_probe(struct i2c_client *client,
|
|||
goto batt_failed_1;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&client->dev, "failed to allocate device info data\n");
|
||||
retval = -ENOMEM;
|
||||
|
@ -819,14 +823,12 @@ static int bq27x00_battery_probe(struct i2c_client *client,
|
|||
|
||||
retval = bq27x00_powersupply_init(di);
|
||||
if (retval)
|
||||
goto batt_failed_3;
|
||||
goto batt_failed_2;
|
||||
|
||||
i2c_set_clientdata(client, di);
|
||||
|
||||
return 0;
|
||||
|
||||
batt_failed_3:
|
||||
kfree(di);
|
||||
batt_failed_2:
|
||||
kfree(name);
|
||||
batt_failed_1:
|
||||
|
@ -849,8 +851,6 @@ static int bq27x00_battery_remove(struct i2c_client *client)
|
|||
idr_remove(&battery_id, di->id);
|
||||
mutex_unlock(&battery_mutex);
|
||||
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -933,7 +933,6 @@ static int bq27000_battery_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct bq27x00_device_info *di;
|
||||
struct bq27000_platform_data *pdata = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform_data supplied\n");
|
||||
|
@ -945,7 +944,7 @@ static int bq27000_battery_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "failed to allocate device info data\n");
|
||||
return -ENOMEM;
|
||||
|
@ -959,16 +958,7 @@ static int bq27000_battery_probe(struct platform_device *pdev)
|
|||
di->bat.name = pdata->name ?: dev_name(&pdev->dev);
|
||||
di->bus.read = &bq27000_read_platform;
|
||||
|
||||
ret = bq27x00_powersupply_init(di);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(di);
|
||||
|
||||
return ret;
|
||||
return bq27x00_powersupply_init(di);
|
||||
}
|
||||
|
||||
static int bq27000_battery_remove(struct platform_device *pdev)
|
||||
|
@ -977,8 +967,6 @@ static int bq27000_battery_remove(struct platform_device *pdev)
|
|||
|
||||
bq27x00_powersupply_unregister(di);
|
||||
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* h3xxx atmel micro companion support, battery subdevice
|
||||
* based on previous kernel 2.4 version
|
||||
* Author : Alessandro Gardich <gremlin@gremlin.it>
|
||||
* Author : Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/ipaq-micro.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define BATT_PERIOD 100000 /* 100 seconds in milliseconds */
|
||||
|
||||
#define MICRO_BATT_CHEM_ALKALINE 0x01
|
||||
#define MICRO_BATT_CHEM_NICD 0x02
|
||||
#define MICRO_BATT_CHEM_NIMH 0x03
|
||||
#define MICRO_BATT_CHEM_LION 0x04
|
||||
#define MICRO_BATT_CHEM_LIPOLY 0x05
|
||||
#define MICRO_BATT_CHEM_NOT_INSTALLED 0x06
|
||||
#define MICRO_BATT_CHEM_UNKNOWN 0xff
|
||||
|
||||
#define MICRO_BATT_STATUS_HIGH 0x01
|
||||
#define MICRO_BATT_STATUS_LOW 0x02
|
||||
#define MICRO_BATT_STATUS_CRITICAL 0x04
|
||||
#define MICRO_BATT_STATUS_CHARGING 0x08
|
||||
#define MICRO_BATT_STATUS_CHARGEMAIN 0x10
|
||||
#define MICRO_BATT_STATUS_DEAD 0x20 /* Battery will not charge */
|
||||
#define MICRO_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */
|
||||
#define MICRO_BATT_STATUS_FULL 0x40 /* Battery fully charged */
|
||||
#define MICRO_BATT_STATUS_NOBATTERY 0x80
|
||||
#define MICRO_BATT_STATUS_UNKNOWN 0xff
|
||||
|
||||
struct micro_battery {
|
||||
struct ipaq_micro *micro;
|
||||
struct workqueue_struct *wq;
|
||||
struct delayed_work update;
|
||||
u8 ac;
|
||||
u8 chemistry;
|
||||
unsigned int voltage;
|
||||
u16 temperature;
|
||||
u8 flag;
|
||||
};
|
||||
|
||||
static void micro_battery_work(struct work_struct *work)
|
||||
{
|
||||
struct micro_battery *mb = container_of(work,
|
||||
struct micro_battery, update.work);
|
||||
struct ipaq_micro_msg msg_battery = {
|
||||
.id = MSG_BATTERY,
|
||||
};
|
||||
struct ipaq_micro_msg msg_sensor = {
|
||||
.id = MSG_THERMAL_SENSOR,
|
||||
};
|
||||
|
||||
/* First send battery message */
|
||||
ipaq_micro_tx_msg_sync(mb->micro, &msg_battery);
|
||||
if (msg_battery.rx_len < 4)
|
||||
pr_info("ERROR");
|
||||
|
||||
/*
|
||||
* Returned message format:
|
||||
* byte 0: 0x00 = Not plugged in
|
||||
* 0x01 = AC adapter plugged in
|
||||
* byte 1: chemistry
|
||||
* byte 2: voltage LSB
|
||||
* byte 3: voltage MSB
|
||||
* byte 4: flags
|
||||
* byte 5-9: same for battery 2
|
||||
*/
|
||||
mb->ac = msg_battery.rx_data[0];
|
||||
mb->chemistry = msg_battery.rx_data[1];
|
||||
mb->voltage = ((((unsigned short)msg_battery.rx_data[3] << 8) +
|
||||
msg_battery.rx_data[2]) * 5000L) * 1000 / 1024;
|
||||
mb->flag = msg_battery.rx_data[4];
|
||||
|
||||
if (msg_battery.rx_len == 9)
|
||||
pr_debug("second battery ignored\n");
|
||||
|
||||
/* Then read the sensor */
|
||||
ipaq_micro_tx_msg_sync(mb->micro, &msg_sensor);
|
||||
mb->temperature = msg_sensor.rx_data[1] << 8 | msg_sensor.rx_data[0];
|
||||
|
||||
queue_delayed_work(mb->wq, &mb->update, msecs_to_jiffies(BATT_PERIOD));
|
||||
}
|
||||
|
||||
static int get_capacity(struct power_supply *b)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(b->dev->parent);
|
||||
|
||||
switch (mb->flag & 0x07) {
|
||||
case MICRO_BATT_STATUS_HIGH:
|
||||
return 100;
|
||||
break;
|
||||
case MICRO_BATT_STATUS_LOW:
|
||||
return 50;
|
||||
break;
|
||||
case MICRO_BATT_STATUS_CRITICAL:
|
||||
return 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_status(struct power_supply *b)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(b->dev->parent);
|
||||
|
||||
if (mb->flag == MICRO_BATT_STATUS_UNKNOWN)
|
||||
return POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
||||
if (mb->flag & MICRO_BATT_STATUS_FULL)
|
||||
return POWER_SUPPLY_STATUS_FULL;
|
||||
|
||||
if ((mb->flag & MICRO_BATT_STATUS_CHARGING) ||
|
||||
(mb->flag & MICRO_BATT_STATUS_CHARGEMAIN))
|
||||
return POWER_SUPPLY_STATUS_CHARGING;
|
||||
|
||||
return POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
static int micro_batt_get_property(struct power_supply *b,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(b->dev->parent);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
switch (mb->chemistry) {
|
||||
case MICRO_BATT_CHEM_NICD:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd;
|
||||
break;
|
||||
case MICRO_BATT_CHEM_NIMH:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
|
||||
break;
|
||||
case MICRO_BATT_CHEM_LION:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case MICRO_BATT_CHEM_LIPOLY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
|
||||
break;
|
||||
default:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
|
||||
break;
|
||||
};
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = get_status(b);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
|
||||
val->intval = 4700000;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = get_capacity(b);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = mb->temperature;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = mb->voltage;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_ac_get_property(struct power_supply *b,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(b->dev->parent);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = mb->ac;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property micro_batt_power_props[] = {
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
};
|
||||
|
||||
static struct power_supply micro_batt_power = {
|
||||
.name = "main-battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = micro_batt_power_props,
|
||||
.num_properties = ARRAY_SIZE(micro_batt_power_props),
|
||||
.get_property = micro_batt_get_property,
|
||||
.use_for_apm = 1,
|
||||
};
|
||||
|
||||
static enum power_supply_property micro_ac_power_props[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static struct power_supply micro_ac_power = {
|
||||
.name = "ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = micro_ac_power_props,
|
||||
.num_properties = ARRAY_SIZE(micro_ac_power_props),
|
||||
.get_property = micro_ac_get_property,
|
||||
};
|
||||
|
||||
static int micro_batt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct micro_battery *mb;
|
||||
|
||||
mb = devm_kzalloc(&pdev->dev, sizeof(*mb), GFP_KERNEL);
|
||||
if (!mb)
|
||||
return -ENOMEM;
|
||||
|
||||
mb->micro = dev_get_drvdata(pdev->dev.parent);
|
||||
mb->wq = create_singlethread_workqueue("ipaq-battery-wq");
|
||||
INIT_DELAYED_WORK(&mb->update, micro_battery_work);
|
||||
platform_set_drvdata(pdev, mb);
|
||||
queue_delayed_work(mb->wq, &mb->update, 1);
|
||||
power_supply_register(&pdev->dev, µ_batt_power);
|
||||
power_supply_register(&pdev->dev, µ_ac_power);
|
||||
|
||||
dev_info(&pdev->dev, "iPAQ micro battery driver\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_batt_remove(struct platform_device *pdev)
|
||||
|
||||
{
|
||||
struct micro_battery *mb = platform_get_drvdata(pdev);
|
||||
|
||||
power_supply_unregister(µ_ac_power);
|
||||
power_supply_unregister(µ_batt_power);
|
||||
cancel_delayed_work_sync(&mb->update);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_batt_suspend(struct device *dev)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&mb->update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_batt_resume(struct device *dev)
|
||||
{
|
||||
struct micro_battery *mb = dev_get_drvdata(dev);
|
||||
|
||||
queue_delayed_work(mb->wq, &mb->update, msecs_to_jiffies(BATT_PERIOD));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops micro_batt_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(micro_batt_suspend, micro_batt_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver micro_batt_device_driver = {
|
||||
.driver = {
|
||||
.name = "ipaq-micro-battery",
|
||||
.pm = µ_batt_dev_pm_ops,
|
||||
},
|
||||
.probe = micro_batt_probe,
|
||||
.remove = micro_batt_remove,
|
||||
};
|
||||
module_platform_driver(micro_batt_device_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery");
|
||||
MODULE_ALIAS("platform:battery-ipaq-micro");
|
|
@ -537,7 +537,8 @@ static void psy_unregister_cooler(struct power_supply *psy)
|
|||
}
|
||||
#endif
|
||||
|
||||
int __power_supply_register(struct device *parent, struct power_supply *psy, bool ws)
|
||||
static int __power_supply_register(struct device *parent,
|
||||
struct power_supply *psy, bool ws)
|
||||
{
|
||||
struct device *dev;
|
||||
int rc;
|
||||
|
|
|
@ -167,6 +167,7 @@ static struct device_attribute power_supply_attrs[] = {
|
|||
POWER_SUPPLY_ATTR(constant_charge_voltage_max),
|
||||
POWER_SUPPLY_ATTR(charge_control_limit),
|
||||
POWER_SUPPLY_ATTR(charge_control_limit_max),
|
||||
POWER_SUPPLY_ATTR(input_current_limit),
|
||||
POWER_SUPPLY_ATTR(energy_full_design),
|
||||
POWER_SUPPLY_ATTR(energy_empty_design),
|
||||
POWER_SUPPLY_ATTR(energy_full),
|
||||
|
@ -178,6 +179,8 @@ static struct device_attribute power_supply_attrs[] = {
|
|||
POWER_SUPPLY_ATTR(capacity_alert_max),
|
||||
POWER_SUPPLY_ATTR(capacity_level),
|
||||
POWER_SUPPLY_ATTR(temp),
|
||||
POWER_SUPPLY_ATTR(temp_max),
|
||||
POWER_SUPPLY_ATTR(temp_min),
|
||||
POWER_SUPPLY_ATTR(temp_alert_min),
|
||||
POWER_SUPPLY_ATTR(temp_alert_max),
|
||||
POWER_SUPPLY_ATTR(temp_ambient),
|
||||
|
@ -189,6 +192,7 @@ static struct device_attribute power_supply_attrs[] = {
|
|||
POWER_SUPPLY_ATTR(time_to_full_avg),
|
||||
POWER_SUPPLY_ATTR(type),
|
||||
POWER_SUPPLY_ATTR(scope),
|
||||
POWER_SUPPLY_ATTR(charge_term_current),
|
||||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_ATTR(model_name),
|
||||
POWER_SUPPLY_ATTR(manufacturer),
|
||||
|
|
|
@ -20,6 +20,17 @@ config POWER_RESET_AXXIA
|
|||
|
||||
Say Y if you have an Axxia family SoC.
|
||||
|
||||
config POWER_RESET_BRCMSTB
|
||||
bool "Broadcom STB reset driver" if COMPILE_TEST
|
||||
depends on POWER_RESET && ARM
|
||||
default ARCH_BRCMSTB
|
||||
help
|
||||
This driver provides restart support for ARM-based Broadcom STB
|
||||
boards.
|
||||
|
||||
Say Y here if you have an ARM-based Broadcom STB board and you wish
|
||||
to have restart support.
|
||||
|
||||
config POWER_RESET_GPIO
|
||||
bool "GPIO power-off driver"
|
||||
depends on OF_GPIO && POWER_RESET
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
|
||||
obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.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
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
#include <asm/system_misc.h>
|
||||
|
||||
#define RESET_SOURCE_ENABLE_REG 1
|
||||
#define SW_MASTER_RESET_REG 2
|
||||
|
||||
static struct regmap *regmap;
|
||||
static u32 rst_src_en;
|
||||
static u32 sw_mstr_rst;
|
||||
|
||||
static void brcmstb_reboot(enum reboot_mode mode, const char *cmd)
|
||||
{
|
||||
int rc;
|
||||
u32 tmp;
|
||||
|
||||
rc = regmap_write(regmap, rst_src_en, 1);
|
||||
if (rc) {
|
||||
pr_err("failed to write rst_src_en (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = regmap_read(regmap, rst_src_en, &tmp);
|
||||
if (rc) {
|
||||
pr_err("failed to read rst_src_en (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = regmap_write(regmap, sw_mstr_rst, 1);
|
||||
if (rc) {
|
||||
pr_err("failed to write sw_mstr_rst (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = regmap_read(regmap, sw_mstr_rst, &tmp);
|
||||
if (rc) {
|
||||
pr_err("failed to read sw_mstr_rst (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
static int brcmstb_reboot_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("failed to get syscon phandle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_index(np, "syscon", RESET_SOURCE_ENABLE_REG,
|
||||
&rst_src_en);
|
||||
if (rc) {
|
||||
pr_err("can't get rst_src_en offset (%d)\n", rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_index(np, "syscon", SW_MASTER_RESET_REG,
|
||||
&sw_mstr_rst);
|
||||
if (rc) {
|
||||
pr_err("can't get sw_mstr_rst offset (%d)\n", rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arm_pm_restart = brcmstb_reboot;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_match[] = {
|
||||
{ .compatible = "brcm,brcmstb-reboot", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver brcmstb_reboot_driver = {
|
||||
.probe = brcmstb_reboot_probe,
|
||||
.driver = {
|
||||
.name = "brcmstb-reboot",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init brcmstb_reboot_init(void)
|
||||
{
|
||||
return platform_driver_probe(&brcmstb_reboot_driver,
|
||||
brcmstb_reboot_probe);
|
||||
}
|
||||
subsys_initcall(brcmstb_reboot_init);
|
|
@ -15,31 +15,29 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Hold configuration here, cannot be more than one instance of the driver
|
||||
* since pm_power_off itself is global.
|
||||
*/
|
||||
static int gpio_num = -1;
|
||||
static int gpio_active_low;
|
||||
static struct gpio_desc *reset_gpio;
|
||||
|
||||
static void gpio_poweroff_do_poweroff(void)
|
||||
{
|
||||
BUG_ON(!gpio_is_valid(gpio_num));
|
||||
BUG_ON(!reset_gpio);
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
gpio_direction_output(gpio_num, !gpio_active_low);
|
||||
gpiod_direction_output(reset_gpio, 1);
|
||||
mdelay(100);
|
||||
/* drive inactive, also active->inactive edge */
|
||||
gpio_set_value(gpio_num, gpio_active_low);
|
||||
gpiod_set_value(reset_gpio, 0);
|
||||
mdelay(100);
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
gpio_set_value(gpio_num, !gpio_active_low);
|
||||
gpiod_set_value(reset_gpio, 1);
|
||||
|
||||
/* give it some time */
|
||||
mdelay(3000);
|
||||
|
@ -49,54 +47,42 @@ static void gpio_poweroff_do_poweroff(void)
|
|||
|
||||
static int gpio_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
enum of_gpio_flags flags;
|
||||
bool input = false;
|
||||
int ret;
|
||||
|
||||
/* If a pm_power_off function has already been added, leave it alone */
|
||||
if (pm_power_off != NULL) {
|
||||
pr_err("%s: pm_power_off function already registered",
|
||||
dev_err(&pdev->dev,
|
||||
"%s: pm_power_off function already registered",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpio_num = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
|
||||
if (!gpio_is_valid(gpio_num))
|
||||
return gpio_num;
|
||||
|
||||
gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
reset_gpio = devm_gpiod_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(reset_gpio))
|
||||
return PTR_ERR(reset_gpio);
|
||||
|
||||
input = of_property_read_bool(pdev->dev.of_node, "input");
|
||||
|
||||
ret = gpio_request(gpio_num, "poweroff-gpio");
|
||||
if (ret) {
|
||||
pr_err("%s: Could not get GPIO %d", __func__, gpio_num);
|
||||
return ret;
|
||||
}
|
||||
if (input) {
|
||||
if (gpio_direction_input(gpio_num)) {
|
||||
pr_err("Could not set direction of GPIO %d to input",
|
||||
gpio_num);
|
||||
goto err;
|
||||
if (gpiod_direction_input(reset_gpio)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not set direction of reset GPIO to input\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
if (gpio_direction_output(gpio_num, gpio_active_low)) {
|
||||
pr_err("Could not set direction of GPIO %d", gpio_num);
|
||||
goto err;
|
||||
if (gpiod_direction_output(reset_gpio, 0)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not set direction of reset GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
pm_power_off = &gpio_poweroff_do_poweroff;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
gpio_free(gpio_num);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int gpio_poweroff_remove(struct platform_device *pdev)
|
||||
{
|
||||
gpio_free(gpio_num);
|
||||
if (pm_power_off == &gpio_poweroff_do_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
|
|
|
@ -62,5 +62,5 @@ module_platform_driver(restart_poweroff_driver);
|
|||
|
||||
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch");
|
||||
MODULE_DESCRIPTION("restart poweroff driver");
|
||||
MODULE_LICENSE("GPLv2");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:poweroff-restart");
|
||||
|
|
|
@ -24,34 +24,27 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c/twl4030-madc.h>
|
||||
|
||||
/* RX51 specific channels */
|
||||
#define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
|
||||
#define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
|
||||
#include <linux/iio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct rx51_device_info {
|
||||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
struct iio_channel *channel_temp;
|
||||
struct iio_channel *channel_bsi;
|
||||
struct iio_channel *channel_vbat;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read ADCIN channel value, code copied from maemo kernel
|
||||
*/
|
||||
static int rx51_battery_read_adc(int channel)
|
||||
static int rx51_battery_read_adc(struct iio_channel *channel)
|
||||
{
|
||||
struct twl4030_madc_request req;
|
||||
|
||||
req.channels = channel;
|
||||
req.do_avg = 1;
|
||||
req.method = TWL4030_MADC_SW1;
|
||||
req.func_cb = NULL;
|
||||
req.type = TWL4030_MADC_WAIT;
|
||||
req.raw = true;
|
||||
|
||||
if (twl4030_madc_conversion(&req) <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
return req.rbuf[ffs(channel) - 1];
|
||||
int val, err;
|
||||
err = iio_read_channel_average_raw(channel, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -60,10 +53,12 @@ static int rx51_battery_read_adc(int channel)
|
|||
*/
|
||||
static int rx51_battery_read_voltage(struct rx51_device_info *di)
|
||||
{
|
||||
int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
|
||||
int voltage = rx51_battery_read_adc(di->channel_vbat);
|
||||
|
||||
if (voltage < 0)
|
||||
if (voltage < 0) {
|
||||
dev_err(di->dev, "Could not read ADC: %d\n", voltage);
|
||||
return voltage;
|
||||
}
|
||||
|
||||
return 1000 * (10000 * voltage / 1705);
|
||||
}
|
||||
|
@ -112,7 +107,10 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
|
|||
{
|
||||
int min = 0;
|
||||
int max = ARRAY_SIZE(rx51_temp_table2) - 1;
|
||||
int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
|
||||
int raw = rx51_battery_read_adc(di->channel_temp);
|
||||
|
||||
if (raw < 0)
|
||||
dev_err(di->dev, "Could not read ADC: %d\n", raw);
|
||||
|
||||
/* Zero and negative values are undefined */
|
||||
if (raw <= 0)
|
||||
|
@ -146,10 +144,12 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
|
|||
*/
|
||||
static int rx51_battery_read_capacity(struct rx51_device_info *di)
|
||||
{
|
||||
int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
|
||||
int capacity = rx51_battery_read_adc(di->channel_bsi);
|
||||
|
||||
if (capacity < 0)
|
||||
if (capacity < 0) {
|
||||
dev_err(di->dev, "Could not read ADC: %d\n", capacity);
|
||||
return capacity;
|
||||
}
|
||||
|
||||
return 1280 * (1200 * capacity)/(1024 - capacity);
|
||||
}
|
||||
|
@ -213,17 +213,46 @@ static int rx51_battery_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, di);
|
||||
|
||||
di->dev = &pdev->dev;
|
||||
di->bat.name = dev_name(&pdev->dev);
|
||||
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
di->bat.properties = rx51_battery_props;
|
||||
di->bat.num_properties = ARRAY_SIZE(rx51_battery_props);
|
||||
di->bat.get_property = rx51_battery_get_property;
|
||||
|
||||
di->channel_temp = iio_channel_get(di->dev, "temp");
|
||||
if (IS_ERR(di->channel_temp)) {
|
||||
ret = PTR_ERR(di->channel_temp);
|
||||
goto error;
|
||||
}
|
||||
|
||||
di->channel_bsi = iio_channel_get(di->dev, "bsi");
|
||||
if (IS_ERR(di->channel_bsi)) {
|
||||
ret = PTR_ERR(di->channel_bsi);
|
||||
goto error_channel_temp;
|
||||
}
|
||||
|
||||
di->channel_vbat = iio_channel_get(di->dev, "vbat");
|
||||
if (IS_ERR(di->channel_vbat)) {
|
||||
ret = PTR_ERR(di->channel_vbat);
|
||||
goto error_channel_bsi;
|
||||
}
|
||||
|
||||
ret = power_supply_register(di->dev, &di->bat);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto error_channel_vbat;
|
||||
|
||||
return 0;
|
||||
|
||||
error_channel_vbat:
|
||||
iio_channel_release(di->channel_vbat);
|
||||
error_channel_bsi:
|
||||
iio_channel_release(di->channel_bsi);
|
||||
error_channel_temp:
|
||||
iio_channel_release(di->channel_temp);
|
||||
error:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rx51_battery_remove(struct platform_device *pdev)
|
||||
|
@ -232,15 +261,28 @@ static int rx51_battery_remove(struct platform_device *pdev)
|
|||
|
||||
power_supply_unregister(&di->bat);
|
||||
|
||||
iio_channel_release(di->channel_vbat);
|
||||
iio_channel_release(di->channel_bsi);
|
||||
iio_channel_release(di->channel_temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id n900_battery_of_match[] = {
|
||||
{.compatible = "nokia,n900-battery", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, n900_battery_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver rx51_battery_driver = {
|
||||
.probe = rx51_battery_probe,
|
||||
.remove = rx51_battery_remove,
|
||||
.driver = {
|
||||
.name = "rx51-battery",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(n900_battery_of_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(rx51_battery_driver);
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -32,11 +34,15 @@
|
|||
#define TPS65090_VACG BIT(1)
|
||||
#define TPS65090_NOITERM BIT(5)
|
||||
|
||||
#define POLL_INTERVAL (HZ * 2) /* Used when no irq */
|
||||
|
||||
struct tps65090_charger {
|
||||
struct device *dev;
|
||||
int ac_online;
|
||||
int prev_ac_online;
|
||||
int irq;
|
||||
struct task_struct *poll_task;
|
||||
bool passive_mode;
|
||||
struct power_supply ac;
|
||||
struct tps65090_platform_data *pdata;
|
||||
};
|
||||
|
@ -49,6 +55,9 @@ static int tps65090_low_chrg_current(struct tps65090_charger *charger)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (charger->passive_mode)
|
||||
return 0;
|
||||
|
||||
ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5,
|
||||
TPS65090_NOITERM);
|
||||
if (ret < 0) {
|
||||
|
@ -64,6 +73,9 @@ static int tps65090_enable_charging(struct tps65090_charger *charger)
|
|||
int ret;
|
||||
uint8_t ctrl0 = 0;
|
||||
|
||||
if (charger->passive_mode)
|
||||
return 0;
|
||||
|
||||
ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0,
|
||||
&ctrl0);
|
||||
if (ret < 0) {
|
||||
|
@ -87,6 +99,9 @@ static int tps65090_config_charger(struct tps65090_charger *charger)
|
|||
uint8_t intrmask = 0;
|
||||
int ret;
|
||||
|
||||
if (charger->passive_mode)
|
||||
return 0;
|
||||
|
||||
if (charger->pdata->enable_low_current_chrg) {
|
||||
ret = tps65090_low_chrg_current(charger);
|
||||
if (ret < 0) {
|
||||
|
@ -164,10 +179,14 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* Clear interrupts. */
|
||||
ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_STS, 0x00);
|
||||
if (ret < 0) {
|
||||
dev_err(charger->dev, "%s(): Error in writing reg 0x%x\n",
|
||||
if (!charger->passive_mode) {
|
||||
ret = tps65090_write(charger->dev->parent,
|
||||
TPS65090_REG_INTR_STS, 0x00);
|
||||
if (ret < 0) {
|
||||
dev_err(charger->dev,
|
||||
"%s(): Error in writing reg 0x%x\n",
|
||||
__func__, TPS65090_REG_INTR_STS);
|
||||
}
|
||||
}
|
||||
|
||||
if (charger->prev_ac_online != charger->ac_online)
|
||||
|
@ -198,6 +217,18 @@ static struct tps65090_platform_data *
|
|||
|
||||
}
|
||||
|
||||
static int tps65090_charger_poll_task(void *data)
|
||||
{
|
||||
set_freezable();
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
schedule_timeout_interruptible(POLL_INTERVAL);
|
||||
try_to_freeze();
|
||||
tps65090_charger_isr(-1, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65090_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65090_charger *cdata;
|
||||
|
@ -244,22 +275,10 @@ static int tps65090_charger_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_warn(&pdev->dev, "Unable to get charger irq = %d\n", irq);
|
||||
ret = irq;
|
||||
goto fail_unregister_supply;
|
||||
}
|
||||
|
||||
if (irq < 0)
|
||||
irq = -ENXIO;
|
||||
cdata->irq = irq;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
tps65090_charger_isr, 0, "tps65090-charger", cdata);
|
||||
if (ret) {
|
||||
dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq,
|
||||
ret);
|
||||
goto fail_unregister_supply;
|
||||
}
|
||||
|
||||
ret = tps65090_config_charger(cdata);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
|
||||
|
@ -285,6 +304,27 @@ static int tps65090_charger_probe(struct platform_device *pdev)
|
|||
power_supply_changed(&cdata->ac);
|
||||
}
|
||||
|
||||
if (irq != -ENXIO) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
tps65090_charger_isr, 0, "tps65090-charger", cdata);
|
||||
if (ret) {
|
||||
dev_err(cdata->dev,
|
||||
"Unable to register irq %d err %d\n", irq,
|
||||
ret);
|
||||
goto fail_unregister_supply;
|
||||
}
|
||||
} else {
|
||||
cdata->poll_task = kthread_run(tps65090_charger_poll_task,
|
||||
cdata, "ktps65090charger");
|
||||
cdata->passive_mode = true;
|
||||
if (IS_ERR(cdata->poll_task)) {
|
||||
ret = PTR_ERR(cdata->poll_task);
|
||||
dev_err(cdata->dev,
|
||||
"Unable to run kthread err %d\n", ret);
|
||||
goto fail_unregister_supply;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_unregister_supply:
|
||||
|
@ -297,6 +337,8 @@ static int tps65090_charger_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct tps65090_charger *cdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (cdata->irq == -ENXIO)
|
||||
kthread_stop(cdata->poll_task);
|
||||
power_supply_unregister(&cdata->ac);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -28,10 +28,13 @@
|
|||
#define TWL4030_BCIICHG 0x08
|
||||
#define TWL4030_BCIVAC 0x0a
|
||||
#define TWL4030_BCIVBUS 0x0c
|
||||
#define TWL4030_BCIMFSTS3 0x0F
|
||||
#define TWL4030_BCIMFSTS4 0x10
|
||||
#define TWL4030_BCICTL1 0x23
|
||||
#define TWL4030_BB_CFG 0x12
|
||||
|
||||
#define TWL4030_BCIMFSTS1 0x01
|
||||
|
||||
#define TWL4030_BCIAUTOWEN BIT(5)
|
||||
#define TWL4030_CONFIG_DONE BIT(4)
|
||||
#define TWL4030_BCIAUTOUSB BIT(1)
|
||||
|
@ -52,6 +55,9 @@
|
|||
#define TWL4030_BBISEL_500uA 0x02
|
||||
#define TWL4030_BBISEL_1000uA 0x03
|
||||
|
||||
#define TWL4030_BATSTSPCHG BIT(2)
|
||||
#define TWL4030_BATSTSMCHG BIT(6)
|
||||
|
||||
/* BCI interrupts */
|
||||
#define TWL4030_WOVF BIT(0) /* Watchdog overflow */
|
||||
#define TWL4030_TMOVF BIT(1) /* Timer overflow */
|
||||
|
@ -144,6 +150,35 @@ static int twl4030bci_read_adc_val(u8 reg)
|
|||
return temp | val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if Battery Pack was present
|
||||
*/
|
||||
static int twl4030_is_battery_present(struct twl4030_bci *bci)
|
||||
{
|
||||
int ret;
|
||||
u8 val = 0;
|
||||
|
||||
/* Battery presence in Main charge? */
|
||||
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val & TWL4030_BATSTSMCHG)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* OK, It could be that bootloader did not enable main charger,
|
||||
* pre-charge is h/w auto. So, Battery presence in Pre-charge?
|
||||
*/
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
|
||||
TWL4030_BCIMFSTS1);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val & TWL4030_BATSTSPCHG)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if VBUS power is present
|
||||
*/
|
||||
|
@ -541,8 +576,14 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
|
|||
bci->irq_chg = platform_get_irq(pdev, 0);
|
||||
bci->irq_bci = platform_get_irq(pdev, 1);
|
||||
|
||||
platform_set_drvdata(pdev, bci);
|
||||
/* Only proceed further *IF* battery is physically present */
|
||||
ret = twl4030_is_battery_present(bci);
|
||||
if (ret) {
|
||||
dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
|
||||
goto fail_no_battery;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, bci);
|
||||
bci->ac.name = "twl4030_ac";
|
||||
bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
|
||||
bci->ac.properties = twl4030_charger_props;
|
||||
|
@ -633,6 +674,7 @@ fail_chg_irq:
|
|||
fail_register_usb:
|
||||
power_supply_unregister(&bci->ac);
|
||||
fail_register_ac:
|
||||
fail_no_battery:
|
||||
kfree(bci);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -120,6 +120,7 @@ enum power_supply_property {
|
|||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL,
|
||||
|
@ -131,6 +132,8 @@ enum power_supply_property {
|
|||
POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TEMP_MAX,
|
||||
POWER_SUPPLY_PROP_TEMP_MIN,
|
||||
POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
|
||||
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
|
||||
POWER_SUPPLY_PROP_TEMP_AMBIENT,
|
||||
|
@ -142,6 +145,7 @@ enum power_supply_property {
|
|||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
|
||||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
|
|
Загрузка…
Ссылка в новой задаче