提交 56a9ccb7 编写于 作者: L Linus Torvalds

Merge git://git.infradead.org/battery-2.6

* git://git.infradead.org/battery-2.6: (30 commits)
  bq20z75: Fix time and temp units
  bq20z75: Fix issues with present and suspend
  z2_battery: Fix count of properties
  s3c_adc_battery: Fix method names when PM not set
  z2_battery: Add MODULE_DEVICE_TABLE
  ds2782_battery: Add MODULE_DEVICE_TABLE
  bq20z75: Add MODULE_DEVICE_TABLE
  power_supply: Update power_supply_is_watt_property
  bq20z75: Add i2c retry mechanism
  bq20z75: Add optional battery detect gpio
  twl4030_charger: Make the driver atomic notifier safe
  bq27x00: Use single i2c_transfer call for property read
  bq27x00: Cleanup bq27x00_i2c_read
  bq27x00: Minor cleanups
  bq27x00: Give more specific reports on battery status
  bq27x00: Add MODULE_DEVICE_TABLE
  bq27x00: Add new properties
  bq27x00: Poll battery state
  bq27x00: Cache battery registers
  bq27x00: Add bq27000 support
  ...
......@@ -231,6 +231,26 @@ void led_trigger_event(struct led_trigger *trigger,
}
EXPORT_SYMBOL_GPL(led_trigger_event);
void led_trigger_blink(struct led_trigger *trigger,
unsigned long *delay_on,
unsigned long *delay_off)
{
struct list_head *entry;
if (!trigger)
return;
read_lock(&trigger->leddev_list_lock);
list_for_each(entry, &trigger->led_cdevs) {
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
led_blink_set(led_cdev, delay_on, delay_off);
}
read_unlock(&trigger->leddev_list_lock);
}
EXPORT_SYMBOL_GPL(led_trigger_blink);
void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
struct led_trigger *trigger;
......
......@@ -117,10 +117,24 @@ config BATTERY_BQ20Z75
config BATTERY_BQ27x00
tristate "BQ27x00 battery driver"
help
Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.
config BATTERY_BQ27X00_I2C
bool "BQ27200/BQ27500 support"
depends on BATTERY_BQ27x00
depends on I2C
default y
help
Say Y here to enable support for batteries with BQ27x00 (I2C) chips.
config BATTERY_BQ27X00_PLATFORM
bool "BQ27000 support"
depends on BATTERY_BQ27x00
default y
help
Say Y here to enable support for batteries with BQ27000 (HDQ) chips.
config BATTERY_DA9030
tristate "DA9030 battery driver"
depends on PMIC_DA903X
......
......@@ -25,6 +25,10 @@
#include <linux/power_supply.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/power/bq20z75.h>
enum {
REG_MANUFACTURER_DATA,
......@@ -38,11 +42,22 @@ enum {
REG_CYCLE_COUNT,
REG_SERIAL_NUMBER,
REG_REMAINING_CAPACITY,
REG_REMAINING_CAPACITY_CHARGE,
REG_FULL_CHARGE_CAPACITY,
REG_FULL_CHARGE_CAPACITY_CHARGE,
REG_DESIGN_CAPACITY,
REG_DESIGN_CAPACITY_CHARGE,
REG_DESIGN_VOLTAGE,
};
/* Battery Mode defines */
#define BATTERY_MODE_OFFSET 0x03
#define BATTERY_MODE_MASK 0x8000
enum bq20z75_battery_mode {
BATTERY_MODE_AMPS,
BATTERY_MODE_WATTS
};
/* manufacturer access defines */
#define MANUFACTURER_ACCESS_STATUS 0x0006
#define MANUFACTURER_ACCESS_SLEEP 0x0011
......@@ -78,8 +93,12 @@ static const struct bq20z75_device_data {
BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
[REG_REMAINING_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
[REG_REMAINING_CAPACITY_CHARGE] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
[REG_FULL_CHARGE_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
[REG_FULL_CHARGE_CAPACITY_CHARGE] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
[REG_TIME_TO_EMPTY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
65535),
......@@ -93,6 +112,9 @@ static const struct bq20z75_device_data {
[REG_DESIGN_CAPACITY] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
65535),
[REG_DESIGN_CAPACITY_CHARGE] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0,
65535),
[REG_DESIGN_VOLTAGE] =
BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
65535),
......@@ -117,39 +139,72 @@ static enum power_supply_property bq20z75_properties[] = {
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_ENERGY_FULL,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
struct bq20z75_info {
struct i2c_client *client;
struct power_supply power_supply;
struct i2c_client *client;
struct power_supply power_supply;
struct bq20z75_platform_data *pdata;
bool is_present;
bool gpio_detect;
bool enable_detection;
int irq;
};
static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
{
s32 ret;
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
s32 ret = 0;
int retries = 1;
if (bq20z75_device->pdata)
retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
while (retries > 0) {
ret = i2c_smbus_read_word_data(client, address);
if (ret >= 0)
break;
retries--;
}
ret = i2c_smbus_read_word_data(client, address);
if (ret < 0) {
dev_err(&client->dev,
dev_dbg(&client->dev,
"%s: i2c read at address 0x%x failed\n",
__func__, address);
return ret;
}
return le16_to_cpu(ret);
}
static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
u16 value)
{
s32 ret;
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
s32 ret = 0;
int retries = 1;
if (bq20z75_device->pdata)
retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
while (retries > 0) {
ret = i2c_smbus_write_word_data(client, address,
le16_to_cpu(value));
if (ret >= 0)
break;
retries--;
}
ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
if (ret < 0) {
dev_err(&client->dev,
dev_dbg(&client->dev,
"%s: i2c write to address 0x%x failed\n",
__func__, address);
return ret;
}
return 0;
}
......@@ -158,6 +213,19 @@ static int bq20z75_get_battery_presence_and_health(
union power_supply_propval *val)
{
s32 ret;
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
if (psp == POWER_SUPPLY_PROP_PRESENT &&
bq20z75_device->gpio_detect) {
ret = gpio_get_value(
bq20z75_device->pdata->battery_detect);
if (ret == bq20z75_device->pdata->battery_detect_present)
val->intval = 1;
else
val->intval = 0;
bq20z75_device->is_present = val->intval;
return ret;
}
/* Write to ManufacturerAccess with
* ManufacturerAccess command and then
......@@ -165,9 +233,11 @@ static int bq20z75_get_battery_presence_and_health(
ret = bq20z75_write_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr,
MANUFACTURER_ACCESS_STATUS);
if (ret < 0)
if (ret < 0) {
if (psp == POWER_SUPPLY_PROP_PRESENT)
val->intval = 0; /* battery removed */
return ret;
}
ret = bq20z75_read_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr);
......@@ -248,30 +318,39 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
{
#define BASE_UNIT_CONVERSION 1000
#define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION)
#define TIME_UNIT_CONVERSION 600
#define TEMP_KELVIN_TO_CELCIUS 2731
#define TIME_UNIT_CONVERSION 60
#define TEMP_KELVIN_TO_CELSIUS 2731
switch (psp) {
case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_ENERGY_FULL:
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
/* bq20z75 provides energy in units of 10mWh.
* Convert to µWh
*/
val->intval *= BATTERY_MODE_CAP_MULT_WATT;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_CHARGE_NOW:
case POWER_SUPPLY_PROP_CHARGE_FULL:
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval *= BASE_UNIT_CONVERSION;
break;
case POWER_SUPPLY_PROP_TEMP:
/* bq20z75 provides battery tempreture in 0.1°K
* so convert it to 0.1°C */
val->intval -= TEMP_KELVIN_TO_CELCIUS;
val->intval *= 10;
/* bq20z75 provides battery temperature in 0.1K
* so convert it to 0.1°C
*/
val->intval -= TEMP_KELVIN_TO_CELSIUS;
break;
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
/* bq20z75 provides time to empty and time to full in minutes.
* Convert to seconds
*/
val->intval *= TIME_UNIT_CONVERSION;
break;
......@@ -281,11 +360,44 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
}
}
static enum bq20z75_battery_mode
bq20z75_set_battery_mode(struct i2c_client *client,
enum bq20z75_battery_mode mode)
{
int ret, original_val;
original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET);
if (original_val < 0)
return original_val;
if ((original_val & BATTERY_MODE_MASK) == mode)
return mode;
if (mode == BATTERY_MODE_AMPS)
ret = original_val & ~BATTERY_MODE_MASK;
else
ret = original_val | BATTERY_MODE_MASK;
ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret);
if (ret < 0)
return ret;
return original_val & BATTERY_MODE_MASK;
}
static int bq20z75_get_battery_capacity(struct i2c_client *client,
int reg_offset, enum power_supply_property psp,
union power_supply_propval *val)
{
s32 ret;
enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS;
if (power_supply_is_amp_property(psp))
mode = BATTERY_MODE_AMPS;
mode = bq20z75_set_battery_mode(client, mode);
if (mode < 0)
return mode;
ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
if (ret < 0)
......@@ -298,6 +410,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client,
} else
val->intval = ret;
ret = bq20z75_set_battery_mode(client, mode);
if (ret < 0)
return ret;
return 0;
}
......@@ -318,12 +434,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client,
return 0;
}
static int bq20z75_get_property_index(struct i2c_client *client,
enum power_supply_property psp)
{
int count;
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++)
if (psp == bq20z75_data[count].psp)
return count;
dev_warn(&client->dev,
"%s: Invalid Property - %d\n", __func__, psp);
return -EINVAL;
}
static int bq20z75_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
int count;
int ret;
int ret = 0;
struct bq20z75_info *bq20z75_device = container_of(psy,
struct bq20z75_info, power_supply);
struct i2c_client *client = bq20z75_device->client;
......@@ -332,8 +461,8 @@ static int bq20z75_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_HEALTH:
ret = bq20z75_get_battery_presence_and_health(client, psp, val);
if (ret)
return ret;
if (psp == POWER_SUPPLY_PROP_PRESENT)
return 0;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
......@@ -343,22 +472,19 @@ static int bq20z75_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_ENERGY_FULL:
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
case POWER_SUPPLY_PROP_CHARGE_NOW:
case POWER_SUPPLY_PROP_CHARGE_FULL:
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_CAPACITY:
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
if (psp == bq20z75_data[count].psp)
break;
}
ret = bq20z75_get_battery_capacity(client, count, psp, val);
if (ret)
return ret;
ret = bq20z75_get_property_index(client, psp);
if (ret < 0)
break;
ret = bq20z75_get_battery_capacity(client, ret, psp, val);
break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = bq20z75_get_battery_serial_number(client, val);
if (ret)
return ret;
break;
case POWER_SUPPLY_PROP_STATUS:
......@@ -369,15 +495,11 @@ static int bq20z75_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
if (psp == bq20z75_data[count].psp)
break;
}
ret = bq20z75_get_battery_property(client, count, psp, val);
if (ret)
return ret;
ret = bq20z75_get_property_index(client, psp);
if (ret < 0)
break;
ret = bq20z75_get_battery_property(client, ret, psp, val);
break;
default:
......@@ -386,26 +508,58 @@ static int bq20z75_get_property(struct power_supply *psy,
return -EINVAL;
}
/* Convert units to match requirements for power supply class */
bq20z75_unit_adjustment(client, psp, val);
if (!bq20z75_device->enable_detection)
goto done;
if (!bq20z75_device->gpio_detect &&
bq20z75_device->is_present != (ret >= 0)) {
bq20z75_device->is_present = (ret >= 0);
power_supply_changed(&bq20z75_device->power_supply);
}
done:
if (!ret) {
/* Convert units to match requirements for power supply class */
bq20z75_unit_adjustment(client, psp, val);
}
dev_dbg(&client->dev,
"%s: property = %d, value = %d\n", __func__, psp, val->intval);
"%s: property = %d, value = %x\n", __func__, psp, val->intval);
if (ret && bq20z75_device->is_present)
return ret;
/* battery not present, so return NODATA for properties */
if (ret)
return -ENODATA;
return 0;
}
static int bq20z75_probe(struct i2c_client *client,
static irqreturn_t bq20z75_irq(int irq, void *devid)
{
struct power_supply *battery = devid;
power_supply_changed(battery);
return IRQ_HANDLED;
}
static int __devinit bq20z75_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct bq20z75_info *bq20z75_device;
struct bq20z75_platform_data *pdata = client->dev.platform_data;
int rc;
int irq;
bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
if (!bq20z75_device)
return -ENOMEM;
bq20z75_device->client = client;
bq20z75_device->enable_detection = false;
bq20z75_device->gpio_detect = false;
bq20z75_device->power_supply.name = "battery";
bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
bq20z75_device->power_supply.properties = bq20z75_properties;
......@@ -413,26 +567,86 @@ static int bq20z75_probe(struct i2c_client *client,
ARRAY_SIZE(bq20z75_properties);
bq20z75_device->power_supply.get_property = bq20z75_get_property;
if (pdata) {
bq20z75_device->gpio_detect =
gpio_is_valid(pdata->battery_detect);
bq20z75_device->pdata = pdata;
}
i2c_set_clientdata(client, bq20z75_device);
if (!bq20z75_device->gpio_detect)
goto skip_gpio;
rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
if (rc) {
dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
bq20z75_device->gpio_detect = false;
goto skip_gpio;
}
rc = gpio_direction_input(pdata->battery_detect);
if (rc) {
dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
gpio_free(pdata->battery_detect);
bq20z75_device->gpio_detect = false;
goto skip_gpio;
}
irq = gpio_to_irq(pdata->battery_detect);
if (irq <= 0) {
dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
gpio_free(pdata->battery_detect);
bq20z75_device->gpio_detect = false;
goto skip_gpio;
}
rc = request_irq(irq, bq20z75_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dev_name(&client->dev), &bq20z75_device->power_supply);
if (rc) {
dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
gpio_free(pdata->battery_detect);
bq20z75_device->gpio_detect = false;
goto skip_gpio;
}
bq20z75_device->irq = irq;
skip_gpio:
rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
if (rc) {
dev_err(&client->dev,
"%s: Failed to register power supply\n", __func__);
kfree(bq20z75_device);
return rc;
goto exit_psupply;
}
dev_info(&client->dev,
"%s: battery gas gauge device registered\n", client->name);
return 0;
exit_psupply:
if (bq20z75_device->irq)
free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
if (bq20z75_device->gpio_detect)
gpio_free(pdata->battery_detect);
kfree(bq20z75_device);
return rc;
}
static int bq20z75_remove(struct i2c_client *client)
static int __devexit bq20z75_remove(struct i2c_client *client)
{
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
if (bq20z75_device->irq)
free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
if (bq20z75_device->gpio_detect)
gpio_free(bq20z75_device->pdata->battery_detect);
power_supply_unregister(&bq20z75_device->power_supply);
kfree(bq20z75_device);
bq20z75_device = NULL;
......@@ -444,13 +658,14 @@ static int bq20z75_remove(struct i2c_client *client)
static int bq20z75_suspend(struct i2c_client *client,
pm_message_t state)
{
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
s32 ret;
/* write to manufacturer access with sleep command */
ret = bq20z75_write_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr,
MANUFACTURER_ACCESS_SLEEP);
if (ret < 0)
if (bq20z75_device->is_present && ret < 0)
return ret;
return 0;
......@@ -465,10 +680,11 @@ static const struct i2c_device_id bq20z75_id[] = {
{ "bq20z75", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, bq20z75_id);
static struct i2c_driver bq20z75_battery_driver = {
.probe = bq20z75_probe,
.remove = bq20z75_remove,
.remove = __devexit_p(bq20z75_remove),
.suspend = bq20z75_suspend,
.resume = bq20z75_resume,
.id_table = bq20z75_id,
......
此差异已折叠。
......@@ -393,6 +393,7 @@ static const struct i2c_device_id ds278x_id[] = {
{"ds2786", DS2786},
{},
};
MODULE_DEVICE_TABLE(i2c, ds278x_id);
static struct i2c_driver ds278x_battery_driver = {
.driver = {
......
......@@ -171,6 +171,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
dev_set_drvdata(dev, psy);
psy->dev = dev;
INIT_WORK(&psy->changed_work, power_supply_changed_work);
rc = kobject_set_name(&dev->kobj, "%s", psy->name);
if (rc)
goto kobject_set_name_failed;
......@@ -179,8 +181,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
if (rc)
goto device_add_failed;
INIT_WORK(&psy->changed_work, power_supply_changed_work);
rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed;
......
......@@ -21,6 +21,8 @@
static void power_supply_update_bat_leds(struct power_supply *psy)
{
union power_supply_propval status;
unsigned long delay_on = 0;
unsigned long delay_off = 0;
if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
return;
......@@ -32,16 +34,22 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
led_trigger_event(psy->charging_full_trig, LED_FULL);
led_trigger_event(psy->charging_trig, LED_OFF);
led_trigger_event(psy->full_trig, LED_FULL);
led_trigger_event(psy->charging_blink_full_solid_trig,
LED_FULL);
break;
case POWER_SUPPLY_STATUS_CHARGING:
led_trigger_event(psy->charging_full_trig, LED_FULL);
led_trigger_event(psy->charging_trig, LED_FULL);
led_trigger_event(psy->full_trig, LED_OFF);
led_trigger_blink(psy->charging_blink_full_solid_trig,
&delay_on, &delay_off);
break;
default:
led_trigger_event(psy->charging_full_trig, LED_OFF);
led_trigger_event(psy->charging_trig, LED_OFF);
led_trigger_event(psy->full_trig, LED_OFF);
led_trigger_event(psy->charging_blink_full_solid_trig,
LED_OFF);
break;
}
}
......@@ -64,15 +72,24 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
if (!psy->full_trig_name)
goto full_failed;
psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
"%s-charging-blink-full-solid", psy->name);
if (!psy->charging_blink_full_solid_trig_name)
goto charging_blink_full_solid_failed;
led_trigger_register_simple(psy->charging_full_trig_name,
&psy->charging_full_trig);
led_trigger_register_simple(psy->charging_trig_name,
&psy->charging_trig);
led_trigger_register_simple(psy->full_trig_name,
&psy->full_trig);
led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
&psy->charging_blink_full_solid_trig);
goto success;
charging_blink_full_solid_failed:
kfree(psy->full_trig_name);
full_failed:
kfree(psy->charging_trig_name);
charging_failed:
......@@ -88,6 +105,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
led_trigger_unregister_simple(psy->charging_full_trig);
led_trigger_unregister_simple(psy->charging_trig);
led_trigger_unregister_simple(psy->full_trig);
led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
kfree(psy->charging_blink_full_solid_trig_name);
kfree(psy->full_trig_name);
kfree(psy->charging_trig_name);
kfree(psy->charging_full_trig_name);
......
......@@ -270,7 +270,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
attr = &power_supply_attrs[psy->properties[j]];
ret = power_supply_show_property(dev, attr, prop_buf);
if (ret == -ENODEV) {
if (ret == -ENODEV || ret == -ENODATA) {
/* When a battery is absent, we expect -ENODEV. Don't abort;
send the uevent with at least the the PRESENT=0 property */
ret = 0;
......
......@@ -406,8 +406,8 @@ static int s3c_adc_bat_resume(struct platform_device *pdev)
return 0;
}
#else
#define s3c_adc_battery_suspend NULL
#define s3c_adc_battery_resume NULL
#define s3c_adc_bat_suspend NULL
#define s3c_adc_bat_resume NULL
#endif
static struct platform_driver s3c_adc_bat_driver = {
......
......@@ -71,8 +71,11 @@ struct twl4030_bci {
struct power_supply usb;
struct otg_transceiver *transceiver;
struct notifier_block otg_nb;
struct work_struct work;
int irq_chg;
int irq_bci;
unsigned long event;
};
/*
......@@ -258,14 +261,11 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
return IRQ_HANDLED;
}
static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
void *priv)
static void twl4030_bci_usb_work(struct work_struct *data)
{
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
dev_dbg(bci->dev, "OTG notify %lu\n", val);
switch (val) {
switch (bci->event) {
case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
twl4030_charger_enable_usb(bci, true);
......@@ -274,6 +274,17 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
twl4030_charger_enable_usb(bci, false);
break;
}
}
static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
void *priv)
{
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
dev_dbg(bci->dev, "OTG notify %lu\n", val);
bci->event = val;
schedule_work(&bci->work);
return NOTIFY_OK;
}
......@@ -466,6 +477,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
goto fail_bci_irq;
}
INIT_WORK(&bci->work, twl4030_bci_usb_work);
bci->transceiver = otg_get_transceiver();
if (bci->transceiver != NULL) {
bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
......
......@@ -134,6 +134,8 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props)
enum power_supply_property *prop;
struct z2_battery_info *info = charger->info;
if (info->charge_gpio >= 0)
props++; /* POWER_SUPPLY_PROP_STATUS */
if (info->batt_tech >= 0)
props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
if (info->batt_I2C_reg >= 0)
......@@ -293,6 +295,7 @@ static const struct i2c_device_id z2_batt_id[] = {
{ "aer915", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, z2_batt_id);
static struct i2c_driver z2_batt_driver = {
.driver = {
......
......@@ -145,6 +145,9 @@ extern void led_trigger_register_simple(const char *name,
extern void led_trigger_unregister_simple(struct led_trigger *trigger);
extern void led_trigger_event(struct led_trigger *trigger,
enum led_brightness event);
extern void led_trigger_blink(struct led_trigger *trigger,
unsigned long *delay_on,
unsigned long *delay_off);
#else
......
/*
* Gas Gauge driver for TI's BQ20Z75
*
* Copyright (c) 2010, NVIDIA 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; 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __LINUX_POWER_BQ20Z75_H_
#define __LINUX_POWER_BQ20Z75_H_
#include <linux/power_supply.h>
#include <linux/types.h>
/**
* struct bq20z75_platform_data - platform data for bq20z75 devices
* @battery_detect: GPIO which is used to detect battery presence
* @battery_detect_present: gpio state when battery is present (0 / 1)
* @i2c_retry_count: # of times to retry on i2c IO failure
*/
struct bq20z75_platform_data {
int battery_detect;
int battery_detect_present;
int i2c_retry_count;
};
#endif
#ifndef __LINUX_BQ27X00_BATTERY_H__
#define __LINUX_BQ27X00_BATTERY_H__
/**
* struct bq27000_plaform_data - Platform data for bq27000 devices
* @name: Name of the battery. If NULL the driver will fallback to "bq27000".
* @read: HDQ read callback.
* This function should provide access to the HDQ bus the battery is
* connected to.
* The first parameter is a pointer to the battery device, the second the
* register to be read. The return value should either be the content of
* the passed register or an error value.
*/
struct bq27000_platform_data {
const char *name;
int (*read)(struct device *dev, unsigned int);
};
#endif
......@@ -173,6 +173,8 @@ struct power_supply {
char *full_trig_name;
struct led_trigger *online_trig;
char *online_trig_name;
struct led_trigger *charging_blink_full_solid_trig;
char *charging_blink_full_solid_trig_name;
#endif
};
......@@ -213,4 +215,49 @@ extern void power_supply_unregister(struct power_supply *psy);
/* For APM emulation, think legacy userspace. */
extern struct class *power_supply_class;
static inline bool power_supply_is_amp_property(enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
case POWER_SUPPLY_PROP_CHARGE_FULL:
case POWER_SUPPLY_PROP_CHARGE_EMPTY:
case POWER_SUPPLY_PROP_CHARGE_NOW:
case POWER_SUPPLY_PROP_CHARGE_AVG:
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
case POWER_SUPPLY_PROP_CURRENT_MAX:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_CURRENT_AVG:
return 1;
default:
break;
}
return 0;
}
static inline bool power_supply_is_watt_property(enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN:
case POWER_SUPPLY_PROP_ENERGY_FULL:
case POWER_SUPPLY_PROP_ENERGY_EMPTY:
case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_ENERGY_AVG:
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
case POWER_SUPPLY_PROP_POWER_NOW:
return 1;
default:
break;
}
return 0;
}
#endif /* __LINUX_POWER_SUPPLY_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册