1 // SPDX-License-Identifier: GPL-2.0
3 * Power supply driver for the goldfish emulator
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>
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>
19 #include <linux/acpi.h>
21 struct goldfish_battery_data
{
22 void __iomem
*reg_base
;
26 struct power_supply
*battery
;
27 struct power_supply
*ac
;
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))
37 BATTERY_INT_STATUS
= 0x00,
38 /* set this to enable IRQ */
39 BATTERY_INT_ENABLE
= 0x04,
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,
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,
56 BATTERY_STATUS_CHANGED
= 1U << 0,
57 AC_STATUS_CHANGED
= 1U << 1,
58 BATTERY_INT_MASK
= BATTERY_STATUS_CHANGED
| AC_STATUS_CHANGED
,
62 static int goldfish_ac_get_property(struct power_supply
*psy
,
63 enum power_supply_property psp
,
64 union power_supply_propval
*val
)
66 struct goldfish_battery_data
*data
= power_supply_get_drvdata(psy
);
70 case POWER_SUPPLY_PROP_ONLINE
:
71 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_AC_ONLINE
);
73 case POWER_SUPPLY_PROP_VOLTAGE_MAX
:
74 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_VOLTAGE_MAX
);
76 case POWER_SUPPLY_PROP_CURRENT_MAX
:
77 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CURRENT_MAX
);
86 static int goldfish_battery_get_property(struct power_supply
*psy
,
87 enum power_supply_property psp
,
88 union power_supply_propval
*val
)
90 struct goldfish_battery_data
*data
= power_supply_get_drvdata(psy
);
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
);
109 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
110 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_VOLTAGE
);
112 case POWER_SUPPLY_PROP_TEMP
:
113 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_TEMP
);
115 case POWER_SUPPLY_PROP_CHARGE_COUNTER
:
116 val
->intval
= GOLDFISH_BATTERY_READ(data
,
117 BATTERY_CHARGE_COUNTER
);
119 case POWER_SUPPLY_PROP_CURRENT_NOW
:
120 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CURRENT_NOW
);
122 case POWER_SUPPLY_PROP_CURRENT_AVG
:
123 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CURRENT_AVG
);
125 case POWER_SUPPLY_PROP_CHARGE_FULL
:
126 val
->intval
= GOLDFISH_BATTERY_READ(data
,
127 BATTERY_CHARGE_FULL_UAH
);
129 case POWER_SUPPLY_PROP_CYCLE_COUNT
:
130 val
->intval
= GOLDFISH_BATTERY_READ(data
, BATTERY_CYCLE_COUNT
);
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
,
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
,
161 static irqreturn_t
goldfish_battery_interrupt(int irq
, void *dev_id
)
163 unsigned long irq_flags
;
164 struct goldfish_battery_data
*data
= dev_id
;
167 spin_lock_irqsave(&data
->lock
, irq_flags
);
169 /* read status flags, which will clear the interrupt */
170 status
= GOLDFISH_BATTERY_READ(data
, BATTERY_INT_STATUS
);
171 status
&= BATTERY_INT_MASK
;
173 if (status
& BATTERY_STATUS_CHANGED
)
174 power_supply_changed(data
->battery
);
175 if (status
& AC_STATUS_CHANGED
)
176 power_supply_changed(data
->ac
);
178 spin_unlock_irqrestore(&data
->lock
, irq_flags
);
179 return status
? IRQ_HANDLED
: IRQ_NONE
;
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
,
187 .type
= POWER_SUPPLY_TYPE_BATTERY
,
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
,
195 .type
= POWER_SUPPLY_TYPE_MAINS
,
198 static int goldfish_battery_probe(struct platform_device
*pdev
)
202 struct goldfish_battery_data
*data
;
203 struct power_supply_config psy_cfg
= {};
205 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
209 spin_lock_init(&data
->lock
);
211 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
213 dev_err(&pdev
->dev
, "platform_get_resource failed\n");
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");
223 data
->irq
= platform_get_irq(pdev
, 0);
225 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
229 ret
= devm_request_irq(&pdev
->dev
, data
->irq
,
230 goldfish_battery_interrupt
,
231 IRQF_SHARED
, pdev
->name
, data
);
235 psy_cfg
.drv_data
= data
;
237 data
->ac
= power_supply_register(&pdev
->dev
, &ac_desc
, &psy_cfg
);
238 if (IS_ERR(data
->ac
))
239 return PTR_ERR(data
->ac
);
241 data
->battery
= power_supply_register(&pdev
->dev
, &battery_desc
,
243 if (IS_ERR(data
->battery
)) {
244 power_supply_unregister(data
->ac
);
245 return PTR_ERR(data
->battery
);
248 platform_set_drvdata(pdev
, data
);
250 GOLDFISH_BATTERY_WRITE(data
, BATTERY_INT_ENABLE
, BATTERY_INT_MASK
);
254 static int goldfish_battery_remove(struct platform_device
*pdev
)
256 struct goldfish_battery_data
*data
= platform_get_drvdata(pdev
);
258 power_supply_unregister(data
->battery
);
259 power_supply_unregister(data
->ac
);
263 static const struct of_device_id goldfish_battery_of_match
[] = {
264 { .compatible
= "google,goldfish-battery", },
267 MODULE_DEVICE_TABLE(of
, goldfish_battery_of_match
);
270 static const struct acpi_device_id goldfish_battery_acpi_match
[] = {
274 MODULE_DEVICE_TABLE(acpi
, goldfish_battery_acpi_match
);
277 static struct platform_driver goldfish_battery_device
= {
278 .probe
= goldfish_battery_probe
,
279 .remove
= goldfish_battery_remove
,
281 .name
= "goldfish-battery",
282 .of_match_table
= goldfish_battery_of_match
,
283 .acpi_match_table
= ACPI_PTR(goldfish_battery_acpi_match
),
286 module_platform_driver(goldfish_battery_device
);
288 MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
289 MODULE_LICENSE("GPL");
290 MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");