2 * Power supply driver for the goldfish emulator
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>
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.
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.
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>
28 struct goldfish_battery_data
{
29 void __iomem
*reg_base
;
33 struct power_supply battery
;
34 struct power_supply ac
;
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))
43 * Temporary variable used between goldfish_battery_probe() and
44 * goldfish_battery_open().
46 static struct goldfish_battery_data
*battery_data
;
50 BATTERY_INT_STATUS
= 0x00,
51 /* set this to enable IRQ */
52 BATTERY_INT_ENABLE
= 0x04,
54 BATTERY_AC_ONLINE
= 0x08,
55 BATTERY_STATUS
= 0x0C,
56 BATTERY_HEALTH
= 0x10,
57 BATTERY_PRESENT
= 0x14,
58 BATTERY_CAPACITY
= 0x18,
60 BATTERY_STATUS_CHANGED
= 1U << 0,
61 AC_STATUS_CHANGED
= 1U << 1,
62 BATTERY_INT_MASK
= BATTERY_STATUS_CHANGED
| AC_STATUS_CHANGED
,
66 static int goldfish_ac_get_property(struct power_supply
*psy
,
67 enum power_supply_property psp
,
68 union power_supply_propval
*val
)
70 struct goldfish_battery_data
*data
= container_of(psy
,
71 struct goldfish_battery_data
, ac
);
75 case POWER_SUPPLY_PROP_ONLINE
:
76 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_AC_ONLINE
);
85 static int goldfish_battery_get_property(struct power_supply
*psy
,
86 enum power_supply_property psp
,
87 union power_supply_propval
*val
)
89 struct goldfish_battery_data
*data
= container_of(psy
,
90 struct goldfish_battery_data
, battery
);
94 case POWER_SUPPLY_PROP_STATUS
:
95 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_STATUS
);
97 case POWER_SUPPLY_PROP_HEALTH
:
98 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_HEALTH
);
100 case POWER_SUPPLY_PROP_PRESENT
:
101 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_PRESENT
);
103 case POWER_SUPPLY_PROP_TECHNOLOGY
:
104 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LION
;
106 case POWER_SUPPLY_PROP_CAPACITY
:
107 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CAPACITY
);
117 static enum power_supply_property goldfish_battery_props
[] = {
118 POWER_SUPPLY_PROP_STATUS
,
119 POWER_SUPPLY_PROP_HEALTH
,
120 POWER_SUPPLY_PROP_PRESENT
,
121 POWER_SUPPLY_PROP_TECHNOLOGY
,
122 POWER_SUPPLY_PROP_CAPACITY
,
125 static enum power_supply_property goldfish_ac_props
[] = {
126 POWER_SUPPLY_PROP_ONLINE
,
129 static irqreturn_t
goldfish_battery_interrupt(int irq
, void *dev_id
)
131 unsigned long irq_flags
;
132 struct goldfish_battery_data
*data
= dev_id
;
135 spin_lock_irqsave(&data
->lock
, irq_flags
);
137 /* read status flags, which will clear the interrupt */
138 status
= GOLDFISH_BATTERY_READ(data
, BATTERY_INT_STATUS
);
139 status
&= BATTERY_INT_MASK
;
141 if (status
& BATTERY_STATUS_CHANGED
)
142 power_supply_changed(&data
->battery
);
143 if (status
& AC_STATUS_CHANGED
)
144 power_supply_changed(&data
->ac
);
146 spin_unlock_irqrestore(&data
->lock
, irq_flags
);
147 return status
? IRQ_HANDLED
: IRQ_NONE
;
151 static int goldfish_battery_probe(struct platform_device
*pdev
)
155 struct goldfish_battery_data
*data
;
157 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
161 spin_lock_init(&data
->lock
);
163 data
->battery
.properties
= goldfish_battery_props
;
164 data
->battery
.num_properties
= ARRAY_SIZE(goldfish_battery_props
);
165 data
->battery
.get_property
= goldfish_battery_get_property
;
166 data
->battery
.name
= "battery";
167 data
->battery
.type
= POWER_SUPPLY_TYPE_BATTERY
;
169 data
->ac
.properties
= goldfish_ac_props
;
170 data
->ac
.num_properties
= ARRAY_SIZE(goldfish_ac_props
);
171 data
->ac
.get_property
= goldfish_ac_get_property
;
172 data
->ac
.name
= "ac";
173 data
->ac
.type
= POWER_SUPPLY_TYPE_MAINS
;
175 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
177 dev_err(&pdev
->dev
, "platform_get_resource failed\n");
181 data
->reg_base
= devm_ioremap(&pdev
->dev
, r
->start
, r
->end
- r
->start
+ 1);
182 if (data
->reg_base
== NULL
) {
183 dev_err(&pdev
->dev
, "unable to remap MMIO\n");
187 data
->irq
= platform_get_irq(pdev
, 0);
189 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
193 ret
= devm_request_irq(&pdev
->dev
, data
->irq
, goldfish_battery_interrupt
,
194 IRQF_SHARED
, pdev
->name
, data
);
198 ret
= power_supply_register(&pdev
->dev
, &data
->ac
);
202 ret
= power_supply_register(&pdev
->dev
, &data
->battery
);
204 power_supply_unregister(&data
->ac
);
208 platform_set_drvdata(pdev
, data
);
211 GOLDFISH_BATTERY_WRITE(data
, BATTERY_INT_ENABLE
, BATTERY_INT_MASK
);
215 static int goldfish_battery_remove(struct platform_device
*pdev
)
217 struct goldfish_battery_data
*data
= platform_get_drvdata(pdev
);
219 power_supply_unregister(&data
->battery
);
220 power_supply_unregister(&data
->ac
);
225 static struct platform_driver goldfish_battery_device
= {
226 .probe
= goldfish_battery_probe
,
227 .remove
= goldfish_battery_remove
,
229 .name
= "goldfish-battery"
232 module_platform_driver(goldfish_battery_device
);
234 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
235 MODULE_LICENSE("GPL");
236 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");