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
= power_supply_get_drvdata(psy
);
74 case POWER_SUPPLY_PROP_ONLINE
:
75 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_AC_ONLINE
);
84 static int goldfish_battery_get_property(struct power_supply
*psy
,
85 enum power_supply_property psp
,
86 union power_supply_propval
*val
)
88 struct goldfish_battery_data
*data
= power_supply_get_drvdata(psy
);
92 case POWER_SUPPLY_PROP_STATUS
:
93 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_STATUS
);
95 case POWER_SUPPLY_PROP_HEALTH
:
96 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_HEALTH
);
98 case POWER_SUPPLY_PROP_PRESENT
:
99 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_PRESENT
);
101 case POWER_SUPPLY_PROP_TECHNOLOGY
:
102 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LION
;
104 case POWER_SUPPLY_PROP_CAPACITY
:
105 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CAPACITY
);
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
,
123 static enum power_supply_property goldfish_ac_props
[] = {
124 POWER_SUPPLY_PROP_ONLINE
,
127 static irqreturn_t
goldfish_battery_interrupt(int irq
, void *dev_id
)
129 unsigned long irq_flags
;
130 struct goldfish_battery_data
*data
= dev_id
;
133 spin_lock_irqsave(&data
->lock
, irq_flags
);
135 /* read status flags, which will clear the interrupt */
136 status
= GOLDFISH_BATTERY_READ(data
, BATTERY_INT_STATUS
);
137 status
&= BATTERY_INT_MASK
;
139 if (status
& BATTERY_STATUS_CHANGED
)
140 power_supply_changed(data
->battery
);
141 if (status
& AC_STATUS_CHANGED
)
142 power_supply_changed(data
->ac
);
144 spin_unlock_irqrestore(&data
->lock
, irq_flags
);
145 return status
? IRQ_HANDLED
: IRQ_NONE
;
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
,
153 .type
= POWER_SUPPLY_TYPE_BATTERY
,
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
,
161 .type
= POWER_SUPPLY_TYPE_MAINS
,
164 static int goldfish_battery_probe(struct platform_device
*pdev
)
168 struct goldfish_battery_data
*data
;
169 struct power_supply_config psy_cfg
= {};
171 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
175 spin_lock_init(&data
->lock
);
177 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
179 dev_err(&pdev
->dev
, "platform_get_resource failed\n");
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");
189 data
->irq
= platform_get_irq(pdev
, 0);
191 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
195 ret
= devm_request_irq(&pdev
->dev
, data
->irq
, goldfish_battery_interrupt
,
196 IRQF_SHARED
, pdev
->name
, data
);
200 psy_cfg
.drv_data
= data
;
202 data
->ac
= power_supply_register(&pdev
->dev
, &ac_desc
, &psy_cfg
);
203 if (IS_ERR(data
->ac
))
204 return PTR_ERR(data
->ac
);
206 data
->battery
= power_supply_register(&pdev
->dev
, &battery_desc
,
208 if (IS_ERR(data
->battery
)) {
209 power_supply_unregister(data
->ac
);
210 return PTR_ERR(data
->battery
);
213 platform_set_drvdata(pdev
, data
);
216 GOLDFISH_BATTERY_WRITE(data
, BATTERY_INT_ENABLE
, BATTERY_INT_MASK
);
220 static int goldfish_battery_remove(struct platform_device
*pdev
)
222 struct goldfish_battery_data
*data
= platform_get_drvdata(pdev
);
224 power_supply_unregister(data
->battery
);
225 power_supply_unregister(data
->ac
);
230 static struct platform_driver goldfish_battery_device
= {
231 .probe
= goldfish_battery_probe
,
232 .remove
= goldfish_battery_remove
,
234 .name
= "goldfish-battery"
237 module_platform_driver(goldfish_battery_device
);
239 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
240 MODULE_LICENSE("GPL");
241 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");