Merge tag 'f2fs-for-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeu...
[linux-2.6-microblaze.git] / drivers / power / supply / goldfish_battery.c
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 #ifdef CONFIG_ACPI
270 static const struct acpi_device_id goldfish_battery_acpi_match[] = {
271         { "GFSH0001", 0 },
272         { },
273 };
274 MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
275 #endif
276
277 static struct platform_driver goldfish_battery_device = {
278         .probe          = goldfish_battery_probe,
279         .remove         = goldfish_battery_remove,
280         .driver = {
281                 .name = "goldfish-battery",
282                 .of_match_table = goldfish_battery_of_match,
283                 .acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),
284         }
285 };
286 module_platform_driver(goldfish_battery_device);
287
288 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
289 MODULE_LICENSE("GPL");
290 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");