linux/drivers/power/power_supply_core.c
<<
>>
Prefs
   1/*
   2 *  Universal power supply monitor class
   3 *
   4 *  Copyright \xC2\xA9 2007  Anton Vorontsov <cbou@mail.ru>
   5 *  Copyright \xC2\xA9 2004  Szabolcs Gyurko
   6 *  Copyright \xC2\xA9 2003  Ian Molton <spyro@f2s.com>
   7 *
   8 *  Modified: 2004, Oct     Szabolcs Gyurko
   9 *
  10 *  You may use this code as per GPL version 2
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/types.h>
  15#include <linux/init.h>
  16#include <linux/device.h>
  17#include <linux/err.h>
  18#include <linux/power_supply.h>
  19#include "power_supply.h"
  20
  21struct class *power_supply_class;
  22
  23static int __power_supply_changed_work(struct device *dev, void *data)
  24{
  25        struct power_supply *psy = (struct power_supply *)data;
  26        struct power_supply *pst = dev_get_drvdata(dev);
  27        int i;
  28
  29        for (i = 0; i < psy->num_supplicants; i++)
  30                if (!strcmp(psy->supplied_to[i], pst->name)) {
  31                        if (pst->external_power_changed)
  32                                pst->external_power_changed(pst);
  33                }
  34        return 0;
  35}
  36
  37static void power_supply_changed_work(struct work_struct *work)
  38{
  39        struct power_supply *psy = container_of(work, struct power_supply,
  40                                                changed_work);
  41
  42        dev_dbg(psy->dev, "%s\n", __func__);
  43
  44        class_for_each_device(power_supply_class, NULL, psy,
  45                              __power_supply_changed_work);
  46
  47        power_supply_update_leds(psy);
  48
  49        kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
  50}
  51
  52void power_supply_changed(struct power_supply *psy)
  53{
  54        dev_dbg(psy->dev, "%s\n", __func__);
  55
  56        schedule_work(&psy->changed_work);
  57}
  58
  59static int __power_supply_am_i_supplied(struct device *dev, void *data)
  60{
  61        union power_supply_propval ret = {0,};
  62        struct power_supply *psy = (struct power_supply *)data;
  63        struct power_supply *epsy = dev_get_drvdata(dev);
  64        int i;
  65
  66        for (i = 0; i < epsy->num_supplicants; i++) {
  67                if (!strcmp(epsy->supplied_to[i], psy->name)) {
  68                        if (epsy->get_property(epsy,
  69                                  POWER_SUPPLY_PROP_ONLINE, &ret))
  70                                continue;
  71                        if (ret.intval)
  72                                return ret.intval;
  73                }
  74        }
  75        return 0;
  76}
  77
  78int power_supply_am_i_supplied(struct power_supply *psy)
  79{
  80        int error;
  81
  82        error = class_for_each_device(power_supply_class, NULL, psy,
  83                                      __power_supply_am_i_supplied);
  84
  85        dev_dbg(psy->dev, "%s %d\n", __func__, error);
  86
  87        return error;
  88}
  89
  90static int __power_supply_is_system_supplied(struct device *dev, void *data)
  91{
  92        union power_supply_propval ret = {0,};
  93        struct power_supply *psy = dev_get_drvdata(dev);
  94
  95        if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
  96                if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
  97                        return 0;
  98                if (ret.intval)
  99                        return ret.intval;
 100        }
 101        return 0;
 102}
 103
 104int power_supply_is_system_supplied(void)
 105{
 106        int error;
 107
 108        error = class_for_each_device(power_supply_class, NULL, NULL,
 109                                      __power_supply_is_system_supplied);
 110
 111        return error;
 112}
 113
 114int power_supply_register(struct device *parent, struct power_supply *psy)
 115{
 116        int rc = 0;
 117
 118        psy->dev = device_create(power_supply_class, parent, 0, psy,
 119                                 "%s", psy->name);
 120        if (IS_ERR(psy->dev)) {
 121                rc = PTR_ERR(psy->dev);
 122                goto dev_create_failed;
 123        }
 124
 125        INIT_WORK(&psy->changed_work, power_supply_changed_work);
 126
 127        rc = power_supply_create_attrs(psy);
 128        if (rc)
 129                goto create_attrs_failed;
 130
 131        rc = power_supply_create_triggers(psy);
 132        if (rc)
 133                goto create_triggers_failed;
 134
 135        power_supply_changed(psy);
 136
 137        goto success;
 138
 139create_triggers_failed:
 140        power_supply_remove_attrs(psy);
 141create_attrs_failed:
 142        device_unregister(psy->dev);
 143dev_create_failed:
 144success:
 145        return rc;
 146}
 147
 148void power_supply_unregister(struct power_supply *psy)
 149{
 150        flush_scheduled_work();
 151        power_supply_remove_triggers(psy);
 152        power_supply_remove_attrs(psy);
 153        device_unregister(psy->dev);
 154}
 155
 156static int __init power_supply_class_init(void)
 157{
 158        power_supply_class = class_create(THIS_MODULE, "power_supply");
 159
 160        if (IS_ERR(power_supply_class))
 161                return PTR_ERR(power_supply_class);
 162
 163        power_supply_class->dev_uevent = power_supply_uevent;
 164
 165        return 0;
 166}
 167
 168static void __exit power_supply_class_exit(void)
 169{
 170        class_destroy(power_supply_class);
 171}
 172
 173EXPORT_SYMBOL_GPL(power_supply_changed);
 174EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
 175EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
 176EXPORT_SYMBOL_GPL(power_supply_register);
 177EXPORT_SYMBOL_GPL(power_supply_unregister);
 178
 179/* exported for the APM Power driver, APM emulation */
 180EXPORT_SYMBOL_GPL(power_supply_class);
 181
 182subsys_initcall(power_supply_class_init);
 183module_exit(power_supply_class_exit);
 184
 185MODULE_DESCRIPTION("Universal power supply monitor class");
 186MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
 187              "Szabolcs Gyurko, "
 188              "Anton Vorontsov <cbou@mail.ru>");
 189MODULE_LICENSE("GPL");
 190