root/drivers/power/supply/goldfish_battery.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. goldfish_ac_get_property
  2. goldfish_battery_get_property
  3. goldfish_battery_interrupt
  4. goldfish_battery_probe
  5. goldfish_battery_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Power supply driver for the goldfish emulator
   4  *
   5  * Copyright (C) 2008 Google, Inc.
   6  * Copyright (C) 2012 Intel, Inc.
   7  * Copyright (C) 2013 Intel, Inc.
   8  * Author: Mike Lockwood <lockwood@android.com>
   9  */
  10 
  11 #include <linux/module.h>
  12 #include <linux/err.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/power_supply.h>
  15 #include <linux/types.h>
  16 #include <linux/pci.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/io.h>
  19 #include <linux/acpi.h>
  20 
  21 struct goldfish_battery_data {
  22         void __iomem *reg_base;
  23         int irq;
  24         spinlock_t lock;
  25 
  26         struct power_supply *battery;
  27         struct power_supply *ac;
  28 };
  29 
  30 #define GOLDFISH_BATTERY_READ(data, addr) \
  31         (readl(data->reg_base + addr))
  32 #define GOLDFISH_BATTERY_WRITE(data, addr, x) \
  33         (writel(x, data->reg_base + addr))
  34 
  35 enum {
  36         /* status register */
  37         BATTERY_INT_STATUS      = 0x00,
  38         /* set this to enable IRQ */
  39         BATTERY_INT_ENABLE      = 0x04,
  40 
  41         BATTERY_AC_ONLINE       = 0x08,
  42         BATTERY_STATUS          = 0x0C,
  43         BATTERY_HEALTH          = 0x10,
  44         BATTERY_PRESENT         = 0x14,
  45         BATTERY_CAPACITY        = 0x18,
  46         BATTERY_VOLTAGE         = 0x1C,
  47         BATTERY_TEMP            = 0x20,
  48         BATTERY_CHARGE_COUNTER  = 0x24,
  49         BATTERY_VOLTAGE_MAX     = 0x28,
  50         BATTERY_CURRENT_MAX     = 0x2C,
  51         BATTERY_CURRENT_NOW     = 0x30,
  52         BATTERY_CURRENT_AVG     = 0x34,
  53         BATTERY_CHARGE_FULL_UAH = 0x38,
  54         BATTERY_CYCLE_COUNT     = 0x40,
  55 
  56         BATTERY_STATUS_CHANGED  = 1U << 0,
  57         AC_STATUS_CHANGED       = 1U << 1,
  58         BATTERY_INT_MASK        = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
  59 };
  60 
  61 
  62 static int goldfish_ac_get_property(struct power_supply *psy,
  63                         enum power_supply_property psp,
  64                         union power_supply_propval *val)
  65 {
  66         struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
  67         int ret = 0;
  68 
  69         switch (psp) {
  70         case POWER_SUPPLY_PROP_ONLINE:
  71                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
  72                 break;
  73         case POWER_SUPPLY_PROP_VOLTAGE_MAX:
  74                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE_MAX);
  75                 break;
  76         case POWER_SUPPLY_PROP_CURRENT_MAX:
  77                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_MAX);
  78                 break;
  79         default:
  80                 ret = -EINVAL;
  81                 break;
  82         }
  83         return ret;
  84 }
  85 
  86 static int goldfish_battery_get_property(struct power_supply *psy,
  87                                  enum power_supply_property psp,
  88                                  union power_supply_propval *val)
  89 {
  90         struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
  91         int ret = 0;
  92 
  93         switch (psp) {
  94         case POWER_SUPPLY_PROP_STATUS:
  95                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);
  96                 break;
  97         case POWER_SUPPLY_PROP_HEALTH:
  98                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);
  99                 break;
 100         case POWER_SUPPLY_PROP_PRESENT:
 101                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);
 102                 break;
 103         case POWER_SUPPLY_PROP_TECHNOLOGY:
 104                 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 105                 break;
 106         case POWER_SUPPLY_PROP_CAPACITY:
 107                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
 108                 break;
 109         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 110                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE);
 111                 break;
 112         case POWER_SUPPLY_PROP_TEMP:
 113                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_TEMP);
 114                 break;
 115         case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 116                 val->intval = GOLDFISH_BATTERY_READ(data,
 117                                                     BATTERY_CHARGE_COUNTER);
 118                 break;
 119         case POWER_SUPPLY_PROP_CURRENT_NOW:
 120                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_NOW);
 121                 break;
 122         case POWER_SUPPLY_PROP_CURRENT_AVG:
 123                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_AVG);
 124                 break;
 125         case POWER_SUPPLY_PROP_CHARGE_FULL:
 126                 val->intval = GOLDFISH_BATTERY_READ(data,
 127                                                     BATTERY_CHARGE_FULL_UAH);
 128                 break;
 129         case POWER_SUPPLY_PROP_CYCLE_COUNT:
 130                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CYCLE_COUNT);
 131                 break;
 132         default:
 133                 ret = -EINVAL;
 134                 break;
 135         }
 136 
 137         return ret;
 138 }
 139 
 140 static enum power_supply_property goldfish_battery_props[] = {
 141         POWER_SUPPLY_PROP_STATUS,
 142         POWER_SUPPLY_PROP_HEALTH,
 143         POWER_SUPPLY_PROP_PRESENT,
 144         POWER_SUPPLY_PROP_TECHNOLOGY,
 145         POWER_SUPPLY_PROP_CAPACITY,
 146         POWER_SUPPLY_PROP_VOLTAGE_NOW,
 147         POWER_SUPPLY_PROP_TEMP,
 148         POWER_SUPPLY_PROP_CHARGE_COUNTER,
 149         POWER_SUPPLY_PROP_CURRENT_NOW,
 150         POWER_SUPPLY_PROP_CURRENT_AVG,
 151         POWER_SUPPLY_PROP_CHARGE_FULL,
 152         POWER_SUPPLY_PROP_CYCLE_COUNT,
 153 };
 154 
 155 static enum power_supply_property goldfish_ac_props[] = {
 156         POWER_SUPPLY_PROP_ONLINE,
 157         POWER_SUPPLY_PROP_VOLTAGE_MAX,
 158         POWER_SUPPLY_PROP_CURRENT_MAX,
 159 };
 160 
 161 static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
 162 {
 163         unsigned long irq_flags;
 164         struct goldfish_battery_data *data = dev_id;
 165         uint32_t status;
 166 
 167         spin_lock_irqsave(&data->lock, irq_flags);
 168 
 169         /* read status flags, which will clear the interrupt */
 170         status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
 171         status &= BATTERY_INT_MASK;
 172 
 173         if (status & BATTERY_STATUS_CHANGED)
 174                 power_supply_changed(data->battery);
 175         if (status & AC_STATUS_CHANGED)
 176                 power_supply_changed(data->ac);
 177 
 178         spin_unlock_irqrestore(&data->lock, irq_flags);
 179         return status ? IRQ_HANDLED : IRQ_NONE;
 180 }
 181 
 182 static const struct power_supply_desc battery_desc = {
 183         .properties     = goldfish_battery_props,
 184         .num_properties = ARRAY_SIZE(goldfish_battery_props),
 185         .get_property   = goldfish_battery_get_property,
 186         .name           = "battery",
 187         .type           = POWER_SUPPLY_TYPE_BATTERY,
 188 };
 189 
 190 static const struct power_supply_desc ac_desc = {
 191         .properties     = goldfish_ac_props,
 192         .num_properties = ARRAY_SIZE(goldfish_ac_props),
 193         .get_property   = goldfish_ac_get_property,
 194         .name           = "ac",
 195         .type           = POWER_SUPPLY_TYPE_MAINS,
 196 };
 197 
 198 static int goldfish_battery_probe(struct platform_device *pdev)
 199 {
 200         int ret;
 201         struct resource *r;
 202         struct goldfish_battery_data *data;
 203         struct power_supply_config psy_cfg = {};
 204 
 205         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 206         if (data == NULL)
 207                 return -ENOMEM;
 208 
 209         spin_lock_init(&data->lock);
 210 
 211         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 212         if (r == NULL) {
 213                 dev_err(&pdev->dev, "platform_get_resource failed\n");
 214                 return -ENODEV;
 215         }
 216 
 217         data->reg_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
 218         if (data->reg_base == NULL) {
 219                 dev_err(&pdev->dev, "unable to remap MMIO\n");
 220                 return -ENOMEM;
 221         }
 222 
 223         data->irq = platform_get_irq(pdev, 0);
 224         if (data->irq < 0) {
 225                 dev_err(&pdev->dev, "platform_get_irq failed\n");
 226                 return -ENODEV;
 227         }
 228 
 229         ret = devm_request_irq(&pdev->dev, data->irq,
 230                                goldfish_battery_interrupt,
 231                                IRQF_SHARED, pdev->name, data);
 232         if (ret)
 233                 return ret;
 234 
 235         psy_cfg.drv_data = data;
 236 
 237         data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);
 238         if (IS_ERR(data->ac))
 239                 return PTR_ERR(data->ac);
 240 
 241         data->battery = power_supply_register(&pdev->dev, &battery_desc,
 242                                                 &psy_cfg);
 243         if (IS_ERR(data->battery)) {
 244                 power_supply_unregister(data->ac);
 245                 return PTR_ERR(data->battery);
 246         }
 247 
 248         platform_set_drvdata(pdev, data);
 249 
 250         GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
 251         return 0;
 252 }
 253 
 254 static int goldfish_battery_remove(struct platform_device *pdev)
 255 {
 256         struct goldfish_battery_data *data = platform_get_drvdata(pdev);
 257 
 258         power_supply_unregister(data->battery);
 259         power_supply_unregister(data->ac);
 260         return 0;
 261 }
 262 
 263 static const struct of_device_id goldfish_battery_of_match[] = {
 264         { .compatible = "google,goldfish-battery", },
 265         {},
 266 };
 267 MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);
 268 
 269 static const struct acpi_device_id goldfish_battery_acpi_match[] = {
 270         { "GFSH0001", 0 },
 271         { },
 272 };
 273 MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
 274 
 275 static struct platform_driver goldfish_battery_device = {
 276         .probe          = goldfish_battery_probe,
 277         .remove         = goldfish_battery_remove,
 278         .driver = {
 279                 .name = "goldfish-battery",
 280                 .of_match_table = goldfish_battery_of_match,
 281                 .acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),
 282         }
 283 };
 284 module_platform_driver(goldfish_battery_device);
 285 
 286 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
 287 MODULE_LICENSE("GPL");
 288 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");

/* [<][>][^][v][top][bottom][index][help] */