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>
27 #include <linux/acpi.h>
29 struct goldfish_battery_data
{
30 void __iomem
*reg_base
;
34 struct power_supply
*battery
;
35 struct power_supply
*ac
;
38 #define GOLDFISH_BATTERY_READ(data, addr) \
39 (readl(data->reg_base + addr))
40 #define GOLDFISH_BATTERY_WRITE(data, addr, x) \
41 (writel(x, data->reg_base + addr))
44 * Temporary variable used between goldfish_battery_probe() and
45 * goldfish_battery_open().
47 static struct goldfish_battery_data
*battery_data
;
51 BATTERY_INT_STATUS
= 0x00,
52 /* set this to enable IRQ */
53 BATTERY_INT_ENABLE
= 0x04,
55 BATTERY_AC_ONLINE
= 0x08,
56 BATTERY_STATUS
= 0x0C,
57 BATTERY_HEALTH
= 0x10,
58 BATTERY_PRESENT
= 0x14,
59 BATTERY_CAPACITY
= 0x18,
61 BATTERY_STATUS_CHANGED
= 1U << 0,
62 AC_STATUS_CHANGED
= 1U << 1,
63 BATTERY_INT_MASK
= BATTERY_STATUS_CHANGED
| AC_STATUS_CHANGED
,
67 static int goldfish_ac_get_property(struct power_supply
*psy
,
68 enum power_supply_property psp
,
69 union power_supply_propval
*val
)
71 struct goldfish_battery_data
*data
= power_supply_get_drvdata(psy
);
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
= power_supply_get_drvdata(psy
);
93 case POWER_SUPPLY_PROP_STATUS
:
94 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_STATUS
);
96 case POWER_SUPPLY_PROP_HEALTH
:
97 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_HEALTH
);
99 case POWER_SUPPLY_PROP_PRESENT
:
100 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_PRESENT
);
102 case POWER_SUPPLY_PROP_TECHNOLOGY
:
103 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LION
;
105 case POWER_SUPPLY_PROP_CAPACITY
:
106 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CAPACITY
);
116 static enum power_supply_property goldfish_battery_props
[] = {
117 POWER_SUPPLY_PROP_STATUS
,
118 POWER_SUPPLY_PROP_HEALTH
,
119 POWER_SUPPLY_PROP_PRESENT
,
120 POWER_SUPPLY_PROP_TECHNOLOGY
,
121 POWER_SUPPLY_PROP_CAPACITY
,
124 static enum power_supply_property goldfish_ac_props
[] = {
125 POWER_SUPPLY_PROP_ONLINE
,
128 static irqreturn_t
goldfish_battery_interrupt(int irq
, void *dev_id
)
130 unsigned long irq_flags
;
131 struct goldfish_battery_data
*data
= dev_id
;
134 spin_lock_irqsave(&data
->lock
, irq_flags
);
136 /* read status flags, which will clear the interrupt */
137 status
= GOLDFISH_BATTERY_READ(data
, BATTERY_INT_STATUS
);
138 status
&= BATTERY_INT_MASK
;
140 if (status
& BATTERY_STATUS_CHANGED
)
141 power_supply_changed(data
->battery
);
142 if (status
& AC_STATUS_CHANGED
)
143 power_supply_changed(data
->ac
);
145 spin_unlock_irqrestore(&data
->lock
, irq_flags
);
146 return status
? IRQ_HANDLED
: IRQ_NONE
;
149 static const struct power_supply_desc battery_desc
= {
150 .properties
= goldfish_battery_props
,
151 .num_properties
= ARRAY_SIZE(goldfish_battery_props
),
152 .get_property
= goldfish_battery_get_property
,
154 .type
= POWER_SUPPLY_TYPE_BATTERY
,
157 static const struct power_supply_desc ac_desc
= {
158 .properties
= goldfish_ac_props
,
159 .num_properties
= ARRAY_SIZE(goldfish_ac_props
),
160 .get_property
= goldfish_ac_get_property
,
162 .type
= POWER_SUPPLY_TYPE_MAINS
,
165 static int goldfish_battery_probe(struct platform_device
*pdev
)
169 struct goldfish_battery_data
*data
;
170 struct power_supply_config psy_cfg
= {};
172 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
176 spin_lock_init(&data
->lock
);
178 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
180 dev_err(&pdev
->dev
, "platform_get_resource failed\n");
184 data
->reg_base
= devm_ioremap(&pdev
->dev
, r
->start
, resource_size(r
));
185 if (data
->reg_base
== NULL
) {
186 dev_err(&pdev
->dev
, "unable to remap MMIO\n");
190 data
->irq
= platform_get_irq(pdev
, 0);
192 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
196 ret
= devm_request_irq(&pdev
->dev
, data
->irq
, goldfish_battery_interrupt
,
197 IRQF_SHARED
, pdev
->name
, data
);
201 psy_cfg
.drv_data
= data
;
203 data
->ac
= power_supply_register(&pdev
->dev
, &ac_desc
, &psy_cfg
);
204 if (IS_ERR(data
->ac
))
205 return PTR_ERR(data
->ac
);
207 data
->battery
= power_supply_register(&pdev
->dev
, &battery_desc
,
209 if (IS_ERR(data
->battery
)) {
210 power_supply_unregister(data
->ac
);
211 return PTR_ERR(data
->battery
);
214 platform_set_drvdata(pdev
, data
);
217 GOLDFISH_BATTERY_WRITE(data
, BATTERY_INT_ENABLE
, BATTERY_INT_MASK
);
221 static int goldfish_battery_remove(struct platform_device
*pdev
)
223 struct goldfish_battery_data
*data
= platform_get_drvdata(pdev
);
225 power_supply_unregister(data
->battery
);
226 power_supply_unregister(data
->ac
);
231 static const struct of_device_id goldfish_battery_of_match
[] = {
232 { .compatible
= "google,goldfish-battery", },
235 MODULE_DEVICE_TABLE(of
, goldfish_battery_of_match
);
237 static const struct acpi_device_id goldfish_battery_acpi_match
[] = {
241 MODULE_DEVICE_TABLE(acpi
, goldfish_battery_acpi_match
);
243 static struct platform_driver goldfish_battery_device
= {
244 .probe
= goldfish_battery_probe
,
245 .remove
= goldfish_battery_remove
,
247 .name
= "goldfish-battery",
248 .of_match_table
= goldfish_battery_of_match
,
249 .acpi_match_table
= ACPI_PTR(goldfish_battery_acpi_match
),
252 module_platform_driver(goldfish_battery_device
);
254 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
255 MODULE_LICENSE("GPL");
256 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");