Make vfio MSI interrupt be non-threaded.
[kvmfornfv.git] / kernel / 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");