diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 22:19:07 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 22:19:07 +0400 |
commit | 5a1203914a637b642442a861cf462d16401548e1 (patch) | |
tree | 894ea523ad45686b9103410f7daeb3a8e670553a /drivers/power/goldfish_battery.c | |
parent | c560dc8793ecf4c3bb4ba6e7b8cae8a64486d96b (diff) | |
parent | ac6324e7021dfa917ce4f9a836318c3e46fbb84e (diff) | |
download | linux-5a1203914a637b642442a861cf462d16401548e1.tar.xz |
Merge tag 'for-v3.9' of git://git.infradead.org/battery-2.6
Pull battery updates from Anton Vorontsov:
"Four new drivers:
- goldfish_battery:
This is Android Emulator battery driver. Originally from Google,
but Intel folks reshaped it for mainline
- pm2301_charger:
A new driver for ST-Ericsson 2301 Power Management chip, uses
AB8500 battery management core
- qnap-poweroff:
The driver adds poweroff functionality for QNAP NAS boxes
- restart-poweroff:
A generic driver that implements 'power off by restarting'. The
actual poweroff functionality is implemented through a bootloader,
so Linux' task is just to restart the box. The driver is useful on
Buffalo Linkstation LS-XHL and LS-CHLv2 boards. Andrew Lunn worked
on submitting the driver (as well as qnap-poweroff above).
Additionally:
- A lot of fixes for ab8500 drivers. This is a part of efforts of
syncing internal ST-Ericsson development tree with the mainline.
Lee Jones @ Linaro worked on compilation and reshaping these
series.
- New health properties for the power supplies: "Watchdog timer
expire" and "Safety timer expire"
- As usual, a bunch of fixes/cleanups here and there"
* tag 'for-v3.9' of git://git.infradead.org/battery-2.6: (81 commits)
bq2415x_charger: Add support for offline and 100mA mode
generic-adc-battery: Fix forever loop in gab_remove()
goldfish_battery: Add missing GENERIC_HARDIRQS dependency
da9030_battery: Include notifier.h
bq27x00_battery: Fix reporting battery temperature
power/reset: Remove newly introduced __dev* annotations
lp8727_charger: Small cleanup in naming
ab8500_btemp: Demote initcall sequence
ds2782_battery: Add power_supply_changed() calls for proper uevent support
power: Add battery driver for goldfish emulator
u8500-charger: Delay for USB enumeration
ab8500-bm: Remove individual [charger|btemp|fg|chargalg] pdata structures
ab8500-charger: Do not touch VBUSOVV bits
ab8500-fg: Use correct battery charge full design
pm2301: LPN mode control support
pm2301: Enable vbat low monitoring
ab8500-bm: Flush all work queues before suspending
ab8500-fg: Go to INIT_RECOVERY when charger removed
ab8500-charger: Add support for autopower on AB8505 and AB9540
abx500-chargalg: Add new sysfs interface to get current charge status
...
Fix up fairly straightforward conflicts in the ab8500 driver. But since
it seems to be ARM-specific, I can't even compile-test the result..
Diffstat (limited to 'drivers/power/goldfish_battery.c')
-rw-r--r-- | drivers/power/goldfish_battery.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c new file mode 100644 index 000000000000..c10f460f986f --- /dev/null +++ b/drivers/power/goldfish_battery.c @@ -0,0 +1,236 @@ +/* + * Power supply driver for the goldfish emulator + * + * Copyright (C) 2008 Google, Inc. + * Copyright (C) 2012 Intel, Inc. + * Copyright (C) 2013 Intel, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/err.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +struct goldfish_battery_data { + void __iomem *reg_base; + int irq; + spinlock_t lock; + + struct power_supply battery; + struct power_supply ac; +}; + +#define GOLDFISH_BATTERY_READ(data, addr) \ + (readl(data->reg_base + addr)) +#define GOLDFISH_BATTERY_WRITE(data, addr, x) \ + (writel(x, data->reg_base + addr)) + +/* + * Temporary variable used between goldfish_battery_probe() and + * goldfish_battery_open(). + */ +static struct goldfish_battery_data *battery_data; + +enum { + /* status register */ + BATTERY_INT_STATUS = 0x00, + /* set this to enable IRQ */ + BATTERY_INT_ENABLE = 0x04, + + BATTERY_AC_ONLINE = 0x08, + BATTERY_STATUS = 0x0C, + BATTERY_HEALTH = 0x10, + BATTERY_PRESENT = 0x14, + BATTERY_CAPACITY = 0x18, + + BATTERY_STATUS_CHANGED = 1U << 0, + AC_STATUS_CHANGED = 1U << 1, + BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, +}; + + +static int goldfish_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct goldfish_battery_data *data = container_of(psy, + struct goldfish_battery_data, ac); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int goldfish_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct goldfish_battery_data *data = container_of(psy, + struct goldfish_battery_data, battery); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum power_supply_property goldfish_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static enum power_supply_property goldfish_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id) +{ + unsigned long irq_flags; + struct goldfish_battery_data *data = dev_id; + uint32_t status; + + spin_lock_irqsave(&data->lock, irq_flags); + + /* read status flags, which will clear the interrupt */ + status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS); + status &= BATTERY_INT_MASK; + + if (status & BATTERY_STATUS_CHANGED) + power_supply_changed(&data->battery); + if (status & AC_STATUS_CHANGED) + power_supply_changed(&data->ac); + + spin_unlock_irqrestore(&data->lock, irq_flags); + return status ? IRQ_HANDLED : IRQ_NONE; +} + + +static int goldfish_battery_probe(struct platform_device *pdev) +{ + int ret; + struct resource *r; + struct goldfish_battery_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + spin_lock_init(&data->lock); + + data->battery.properties = goldfish_battery_props; + data->battery.num_properties = ARRAY_SIZE(goldfish_battery_props); + data->battery.get_property = goldfish_battery_get_property; + data->battery.name = "battery"; + data->battery.type = POWER_SUPPLY_TYPE_BATTERY; + + data->ac.properties = goldfish_ac_props; + data->ac.num_properties = ARRAY_SIZE(goldfish_ac_props); + data->ac.get_property = goldfish_ac_get_property; + data->ac.name = "ac"; + data->ac.type = POWER_SUPPLY_TYPE_MAINS; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + dev_err(&pdev->dev, "platform_get_resource failed\n"); + return -ENODEV; + } + + data->reg_base = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1); + if (data->reg_base == NULL) { + dev_err(&pdev->dev, "unable to remap MMIO\n"); + return -ENOMEM; + } + + data->irq = platform_get_irq(pdev, 0); + if (data->irq < 0) { + dev_err(&pdev->dev, "platform_get_irq failed\n"); + return -ENODEV; + } + + ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt, + IRQF_SHARED, pdev->name, data); + if (ret) + return ret; + + ret = power_supply_register(&pdev->dev, &data->ac); + if (ret) + return ret; + + ret = power_supply_register(&pdev->dev, &data->battery); + if (ret) { + power_supply_unregister(&data->ac); + return ret; + } + + platform_set_drvdata(pdev, data); + battery_data = data; + + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + return 0; +} + +static int goldfish_battery_remove(struct platform_device *pdev) +{ + struct goldfish_battery_data *data = platform_get_drvdata(pdev); + + power_supply_unregister(&data->battery); + power_supply_unregister(&data->ac); + battery_data = NULL; + return 0; +} + +static struct platform_driver goldfish_battery_device = { + .probe = goldfish_battery_probe, + .remove = goldfish_battery_remove, + .driver = { + .name = "goldfish-battery" + } +}; +module_platform_driver(goldfish_battery_device); + +MODULE_AUTHOR("Mike Lockwood lockwood@android.com"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Battery driver for the Goldfish emulator"); |