Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

Linux/drivers/power/goldfish_battery.c

  1 /*
  2  * Power supply driver for the goldfish emulator
  3  *
  4  * Copyright (C) 2008 Google, Inc.
  5  * Copyright (C) 2012 Intel, Inc.
  6  * Copyright (C) 2013 Intel, Inc.
  7  * Author: Mike Lockwood <lockwood@android.com>
  8  *
  9  * This software is licensed under the terms of the GNU General Public
 10  * License version 2, as published by the Free Software Foundation, and
 11  * may be copied, distributed, and modified under those terms.
 12  *
 13  * This program is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  * GNU General Public License for more details.
 17  */
 18 
 19 #include <linux/module.h>
 20 #include <linux/err.h>
 21 #include <linux/platform_device.h>
 22 #include <linux/power_supply.h>
 23 #include <linux/types.h>
 24 #include <linux/pci.h>
 25 #include <linux/interrupt.h>
 26 #include <linux/io.h>
 27 
 28 struct goldfish_battery_data {
 29         void __iomem *reg_base;
 30         int irq;
 31         spinlock_t lock;
 32 
 33         struct power_supply *battery;
 34         struct power_supply *ac;
 35 };
 36 
 37 #define GOLDFISH_BATTERY_READ(data, addr) \
 38         (readl(data->reg_base + addr))
 39 #define GOLDFISH_BATTERY_WRITE(data, addr, x) \
 40         (writel(x, data->reg_base + addr))
 41 
 42 /*
 43  * Temporary variable used between goldfish_battery_probe() and
 44  * goldfish_battery_open().
 45  */
 46 static struct goldfish_battery_data *battery_data;
 47 
 48 enum {
 49         /* status register */
 50         BATTERY_INT_STATUS          = 0x00,
 51         /* set this to enable IRQ */
 52         BATTERY_INT_ENABLE          = 0x04,
 53 
 54         BATTERY_AC_ONLINE       = 0x08,
 55         BATTERY_STATUS          = 0x0C,
 56         BATTERY_HEALTH          = 0x10,
 57         BATTERY_PRESENT         = 0x14,
 58         BATTERY_CAPACITY        = 0x18,
 59 
 60         BATTERY_STATUS_CHANGED  = 1U << 0,
 61         AC_STATUS_CHANGED       = 1U << 1,
 62         BATTERY_INT_MASK        = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
 63 };
 64 
 65 
 66 static int goldfish_ac_get_property(struct power_supply *psy,
 67                         enum power_supply_property psp,
 68                         union power_supply_propval *val)
 69 {
 70         struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
 71         int ret = 0;
 72 
 73         switch (psp) {
 74         case POWER_SUPPLY_PROP_ONLINE:
 75                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
 76                 break;
 77         default:
 78                 ret = -EINVAL;
 79                 break;
 80         }
 81         return ret;
 82 }
 83 
 84 static int goldfish_battery_get_property(struct power_supply *psy,
 85                                  enum power_supply_property psp,
 86                                  union power_supply_propval *val)
 87 {
 88         struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
 89         int ret = 0;
 90 
 91         switch (psp) {
 92         case POWER_SUPPLY_PROP_STATUS:
 93                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);
 94                 break;
 95         case POWER_SUPPLY_PROP_HEALTH:
 96                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);
 97                 break;
 98         case POWER_SUPPLY_PROP_PRESENT:
 99                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);
100                 break;
101         case POWER_SUPPLY_PROP_TECHNOLOGY:
102                 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
103                 break;
104         case POWER_SUPPLY_PROP_CAPACITY:
105                 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
106                 break;
107         default:
108                 ret = -EINVAL;
109                 break;
110         }
111 
112         return ret;
113 }
114 
115 static enum power_supply_property goldfish_battery_props[] = {
116         POWER_SUPPLY_PROP_STATUS,
117         POWER_SUPPLY_PROP_HEALTH,
118         POWER_SUPPLY_PROP_PRESENT,
119         POWER_SUPPLY_PROP_TECHNOLOGY,
120         POWER_SUPPLY_PROP_CAPACITY,
121 };
122 
123 static enum power_supply_property goldfish_ac_props[] = {
124         POWER_SUPPLY_PROP_ONLINE,
125 };
126 
127 static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
128 {
129         unsigned long irq_flags;
130         struct goldfish_battery_data *data = dev_id;
131         uint32_t status;
132 
133         spin_lock_irqsave(&data->lock, irq_flags);
134 
135         /* read status flags, which will clear the interrupt */
136         status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
137         status &= BATTERY_INT_MASK;
138 
139         if (status & BATTERY_STATUS_CHANGED)
140                 power_supply_changed(data->battery);
141         if (status & AC_STATUS_CHANGED)
142                 power_supply_changed(data->ac);
143 
144         spin_unlock_irqrestore(&data->lock, irq_flags);
145         return status ? IRQ_HANDLED : IRQ_NONE;
146 }
147 
148 static const struct power_supply_desc battery_desc = {
149         .properties     = goldfish_battery_props,
150         .num_properties = ARRAY_SIZE(goldfish_battery_props),
151         .get_property   = goldfish_battery_get_property,
152         .name           = "battery",
153         .type           = POWER_SUPPLY_TYPE_BATTERY,
154 };
155 
156 static const struct power_supply_desc ac_desc = {
157         .properties     = goldfish_ac_props,
158         .num_properties = ARRAY_SIZE(goldfish_ac_props),
159         .get_property   = goldfish_ac_get_property,
160         .name           = "ac",
161         .type           = POWER_SUPPLY_TYPE_MAINS,
162 };
163 
164 static int goldfish_battery_probe(struct platform_device *pdev)
165 {
166         int ret;
167         struct resource *r;
168         struct goldfish_battery_data *data;
169         struct power_supply_config psy_cfg = {};
170 
171         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
172         if (data == NULL)
173                 return -ENOMEM;
174 
175         spin_lock_init(&data->lock);
176 
177         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
178         if (r == NULL) {
179                 dev_err(&pdev->dev, "platform_get_resource failed\n");
180                 return -ENODEV;
181         }
182 
183         data->reg_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
184         if (data->reg_base == NULL) {
185                 dev_err(&pdev->dev, "unable to remap MMIO\n");
186                 return -ENOMEM;
187         }
188 
189         data->irq = platform_get_irq(pdev, 0);
190         if (data->irq < 0) {
191                 dev_err(&pdev->dev, "platform_get_irq failed\n");
192                 return -ENODEV;
193         }
194 
195         ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt,
196                                                 IRQF_SHARED, pdev->name, data);
197         if (ret)
198                 return ret;
199 
200         psy_cfg.drv_data = data;
201 
202         data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);
203         if (IS_ERR(data->ac))
204                 return PTR_ERR(data->ac);
205 
206         data->battery = power_supply_register(&pdev->dev, &battery_desc,
207                                                 &psy_cfg);
208         if (IS_ERR(data->battery)) {
209                 power_supply_unregister(data->ac);
210                 return PTR_ERR(data->battery);
211         }
212 
213         platform_set_drvdata(pdev, data);
214         battery_data = data;
215 
216         GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
217         return 0;
218 }
219 
220 static int goldfish_battery_remove(struct platform_device *pdev)
221 {
222         struct goldfish_battery_data *data = platform_get_drvdata(pdev);
223 
224         power_supply_unregister(data->battery);
225         power_supply_unregister(data->ac);
226         battery_data = NULL;
227         return 0;
228 }
229 
230 static struct platform_driver goldfish_battery_device = {
231         .probe          = goldfish_battery_probe,
232         .remove         = goldfish_battery_remove,
233         .driver = {
234                 .name = "goldfish-battery"
235         }
236 };
237 module_platform_driver(goldfish_battery_device);
238 
239 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
240 MODULE_LICENSE("GPL");
241 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");
242 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us