aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/goldfish_battery.c
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2013-01-25 10:30:00 -0500
committerAnton Vorontsov <anton@enomsg.org>2013-02-02 22:06:34 -0500
commit84d7b768748943db2bb658b43931fdab04c224cc (patch)
tree8fc3e930ba86848187820d89157fa88ec80f946b /drivers/power/goldfish_battery.c
parent8fd526fd18233887ba652079a369f4eee0de9d9d (diff)
power: Add battery driver for goldfish emulator
Add the emulated power driver for the Goldfish platform. This folds together the code from the Google tree, Jun Nakajima's cleanups and x86 porting work, and then a tidy up to pass checkpatch. Signed-off-by: Mike A. Chan <mikechan@google.com> [cleanup and x86 support] Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com> Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com> Signed-off-by: Jun Nakajima <jun.nakajima@intel.com> Signed-off-by: Bruce Beare <bruce.j.beare@intel.com> [ported to 3.4] Signed-off-by: Tom Keel <thomas.keel@intel.com> [ported to 3.7 and final tidy] Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Anton Vorontsov <anton@enomsg.org>
Diffstat (limited to 'drivers/power/goldfish_battery.c')
-rw-r--r--drivers/power/goldfish_battery.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c
new file mode 100644
index 000000000000..c10f460f986f
--- /dev/null
+++ b/drivers/power/goldfish_battery.c
@@ -0,0 +1,236 @@
1/*
2 * Power supply driver for the goldfish emulator
3 *
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>
8 *
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.
12 *
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.
17 */
18
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>
26#include <linux/io.h>
27
28struct goldfish_battery_data {
29 void __iomem *reg_base;
30 int irq;
31 spinlock_t lock;
32
33 struct power_supply battery;
34 struct power_supply ac;
35};
36
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))
41
42/*
43 * Temporary variable used between goldfish_battery_probe() and
44 * goldfish_battery_open().
45 */
46static struct goldfish_battery_data *battery_data;
47
48enum {
49 /* status register */
50 BATTERY_INT_STATUS = 0x00,
51 /* set this to enable IRQ */
52 BATTERY_INT_ENABLE = 0x04,
53
54 BATTERY_AC_ONLINE = 0x08,
55 BATTERY_STATUS = 0x0C,
56 BATTERY_HEALTH = 0x10,
57 BATTERY_PRESENT = 0x14,
58 BATTERY_CAPACITY = 0x18,
59
60 BATTERY_STATUS_CHANGED = 1U << 0,
61 AC_STATUS_CHANGED = 1U << 1,
62 BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
63};
64
65
66static int goldfish_ac_get_property(struct power_supply *psy,
67 enum power_supply_property psp,
68 union power_supply_propval *val)
69{
70 struct goldfish_battery_data *data = container_of(psy,
71 struct goldfish_battery_data, ac);
72 int ret = 0;
73
74 switch (psp) {
75 case POWER_SUPPLY_PROP_ONLINE:
76 val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
77 break;
78 default:
79 ret = -EINVAL;
80 break;
81 }
82 return ret;
83}
84
85static int goldfish_battery_get_property(struct power_supply *psy,
86 enum power_supply_property psp,
87 union power_supply_propval *val)
88{
89 struct goldfish_battery_data *data = container_of(psy,
90 struct goldfish_battery_data, battery);
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 default:
110 ret = -EINVAL;
111 break;
112 }
113
114 return ret;
115}
116
117static 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,
123};
124
125static enum power_supply_property goldfish_ac_props[] = {
126 POWER_SUPPLY_PROP_ONLINE,
127};
128
129static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
130{
131 unsigned long irq_flags;
132 struct goldfish_battery_data *data = dev_id;
133 uint32_t status;
134
135 spin_lock_irqsave(&data->lock, irq_flags);
136
137 /* read status flags, which will clear the interrupt */
138 status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
139 status &= BATTERY_INT_MASK;
140
141 if (status & BATTERY_STATUS_CHANGED)
142 power_supply_changed(&data->battery);
143 if (status & AC_STATUS_CHANGED)
144 power_supply_changed(&data->ac);
145
146 spin_unlock_irqrestore(&data->lock, irq_flags);
147 return status ? IRQ_HANDLED : IRQ_NONE;
148}
149
150
151static int goldfish_battery_probe(struct platform_device *pdev)
152{
153 int ret;
154 struct resource *r;
155 struct goldfish_battery_data *data;
156
157 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
158 if (data == NULL)
159 return -ENOMEM;
160
161 spin_lock_init(&data->lock);
162
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;
168
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;
174
175 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
176 if (r == NULL) {
177 dev_err(&pdev->dev, "platform_get_resource failed\n");
178 return -ENODEV;
179 }
180
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");
184 return -ENOMEM;
185 }
186
187 data->irq = platform_get_irq(pdev, 0);
188 if (data->irq < 0) {
189 dev_err(&pdev->dev, "platform_get_irq failed\n");
190 return -ENODEV;
191 }
192
193 ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt,
194 IRQF_SHARED, pdev->name, data);
195 if (ret)
196 return ret;
197
198 ret = power_supply_register(&pdev->dev, &data->ac);
199 if (ret)
200 return ret;
201
202 ret = power_supply_register(&pdev->dev, &data->battery);
203 if (ret) {
204 power_supply_unregister(&data->ac);
205 return ret;
206 }
207
208 platform_set_drvdata(pdev, data);
209 battery_data = data;
210
211 GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
212 return 0;
213}
214
215static int goldfish_battery_remove(struct platform_device *pdev)
216{
217 struct goldfish_battery_data *data = platform_get_drvdata(pdev);
218
219 power_supply_unregister(&data->battery);
220 power_supply_unregister(&data->ac);
221 battery_data = NULL;
222 return 0;
223}
224
225static struct platform_driver goldfish_battery_device = {
226 .probe = goldfish_battery_probe,
227 .remove = goldfish_battery_remove,
228 .driver = {
229 .name = "goldfish-battery"
230 }
231};
232module_platform_driver(goldfish_battery_device);
233
234MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
235MODULE_LICENSE("GPL");
236MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");