OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [power/] [pda_power.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Common power driver for PDAs and phones with one or two external
3
 * power supplies (AC/USB) connected to main and backup batteries,
4
 * and optional builtin charger.
5
 *
6
 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License version 2 as
10
 * published by the Free Software Foundation.
11
 */
12
 
13
#include <linux/module.h>
14
#include <linux/platform_device.h>
15
#include <linux/interrupt.h>
16
#include <linux/power_supply.h>
17
#include <linux/pda_power.h>
18
#include <linux/timer.h>
19
#include <linux/jiffies.h>
20
 
21
static inline unsigned int get_irq_flags(struct resource *res)
22
{
23
        unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
24
 
25
        flags |= res->flags & IRQF_TRIGGER_MASK;
26
 
27
        return flags;
28
}
29
 
30
static struct device *dev;
31
static struct pda_power_pdata *pdata;
32
static struct resource *ac_irq, *usb_irq;
33
static struct timer_list charger_timer;
34
static struct timer_list supply_timer;
35
 
36
static int pda_power_get_property(struct power_supply *psy,
37
                                  enum power_supply_property psp,
38
                                  union power_supply_propval *val)
39
{
40
        switch (psp) {
41
        case POWER_SUPPLY_PROP_ONLINE:
42
                if (psy->type == POWER_SUPPLY_TYPE_MAINS)
43
                        val->intval = pdata->is_ac_online ?
44
                                      pdata->is_ac_online() : 0;
45
                else
46
                        val->intval = pdata->is_usb_online ?
47
                                      pdata->is_usb_online() : 0;
48
                break;
49
        default:
50
                return -EINVAL;
51
        }
52
        return 0;
53
}
54
 
55
static enum power_supply_property pda_power_props[] = {
56
        POWER_SUPPLY_PROP_ONLINE,
57
};
58
 
59
static char *pda_power_supplied_to[] = {
60
        "main-battery",
61
        "backup-battery",
62
};
63
 
64
static struct power_supply pda_power_supplies[] = {
65
        {
66
                .name = "ac",
67
                .type = POWER_SUPPLY_TYPE_MAINS,
68
                .supplied_to = pda_power_supplied_to,
69
                .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
70
                .properties = pda_power_props,
71
                .num_properties = ARRAY_SIZE(pda_power_props),
72
                .get_property = pda_power_get_property,
73
        },
74
        {
75
                .name = "usb",
76
                .type = POWER_SUPPLY_TYPE_USB,
77
                .supplied_to = pda_power_supplied_to,
78
                .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
79
                .properties = pda_power_props,
80
                .num_properties = ARRAY_SIZE(pda_power_props),
81
                .get_property = pda_power_get_property,
82
        },
83
};
84
 
85
static void update_charger(void)
86
{
87
        if (!pdata->set_charge)
88
                return;
89
 
90
        if (pdata->is_ac_online && pdata->is_ac_online()) {
91
                dev_dbg(dev, "charger on (AC)\n");
92
                pdata->set_charge(PDA_POWER_CHARGE_AC);
93
        } else if (pdata->is_usb_online && pdata->is_usb_online()) {
94
                dev_dbg(dev, "charger on (USB)\n");
95
                pdata->set_charge(PDA_POWER_CHARGE_USB);
96
        } else {
97
                dev_dbg(dev, "charger off\n");
98
                pdata->set_charge(0);
99
        }
100
}
101
 
102
static void supply_timer_func(unsigned long power_supply_ptr)
103
{
104
        void *power_supply = (void *)power_supply_ptr;
105
 
106
        power_supply_changed(power_supply);
107
}
108
 
109
static void charger_timer_func(unsigned long power_supply_ptr)
110
{
111
        update_charger();
112
 
113
        /* Okay, charger set. Now wait a bit before notifying supplicants,
114
         * charge power should stabilize. */
115
        supply_timer.data = power_supply_ptr;
116
        mod_timer(&supply_timer,
117
                  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
118
}
119
 
120
static irqreturn_t power_changed_isr(int irq, void *power_supply)
121
{
122
        /* Wait a bit before reading ac/usb line status and setting charger,
123
         * because ac/usb status readings may lag from irq. */
124
        charger_timer.data = (unsigned long)power_supply;
125
        mod_timer(&charger_timer,
126
                  jiffies + msecs_to_jiffies(pdata->wait_for_status));
127
        return IRQ_HANDLED;
128
}
129
 
130
static int pda_power_probe(struct platform_device *pdev)
131
{
132
        int ret = 0;
133
 
134
        dev = &pdev->dev;
135
 
136
        if (pdev->id != -1) {
137
                dev_err(dev, "it's meaningless to register several "
138
                        "pda_powers; use id = -1\n");
139
                ret = -EINVAL;
140
                goto wrongid;
141
        }
142
 
143
        pdata = pdev->dev.platform_data;
144
 
145
        update_charger();
146
 
147
        if (!pdata->wait_for_status)
148
                pdata->wait_for_status = 500;
149
 
150
        if (!pdata->wait_for_charger)
151
                pdata->wait_for_charger = 500;
152
 
153
        setup_timer(&charger_timer, charger_timer_func, 0);
154
        setup_timer(&supply_timer, supply_timer_func, 0);
155
 
156
        ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
157
        usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
158
        if (!ac_irq && !usb_irq) {
159
                dev_err(dev, "no ac/usb irq specified\n");
160
                ret = -ENODEV;
161
                goto noirqs;
162
        }
163
 
164
        if (pdata->supplied_to) {
165
                pda_power_supplies[0].supplied_to = pdata->supplied_to;
166
                pda_power_supplies[1].supplied_to = pdata->supplied_to;
167
                pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
168
                pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
169
        }
170
 
171
        ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
172
        if (ret) {
173
                dev_err(dev, "failed to register %s power supply\n",
174
                        pda_power_supplies[0].name);
175
                goto supply0_failed;
176
        }
177
 
178
        ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
179
        if (ret) {
180
                dev_err(dev, "failed to register %s power supply\n",
181
                        pda_power_supplies[1].name);
182
                goto supply1_failed;
183
        }
184
 
185
        if (ac_irq) {
186
                ret = request_irq(ac_irq->start, power_changed_isr,
187
                                  get_irq_flags(ac_irq), ac_irq->name,
188
                                  &pda_power_supplies[0]);
189
                if (ret) {
190
                        dev_err(dev, "request ac irq failed\n");
191
                        goto ac_irq_failed;
192
                }
193
        }
194
 
195
        if (usb_irq) {
196
                ret = request_irq(usb_irq->start, power_changed_isr,
197
                                  get_irq_flags(usb_irq), usb_irq->name,
198
                                  &pda_power_supplies[1]);
199
                if (ret) {
200
                        dev_err(dev, "request usb irq failed\n");
201
                        goto usb_irq_failed;
202
                }
203
        }
204
 
205
        goto success;
206
 
207
usb_irq_failed:
208
        if (ac_irq)
209
                free_irq(ac_irq->start, &pda_power_supplies[0]);
210
ac_irq_failed:
211
        power_supply_unregister(&pda_power_supplies[1]);
212
supply1_failed:
213
        power_supply_unregister(&pda_power_supplies[0]);
214
supply0_failed:
215
noirqs:
216
wrongid:
217
success:
218
        return ret;
219
}
220
 
221
static int pda_power_remove(struct platform_device *pdev)
222
{
223
        if (usb_irq)
224
                free_irq(usb_irq->start, &pda_power_supplies[1]);
225
        if (ac_irq)
226
                free_irq(ac_irq->start, &pda_power_supplies[0]);
227
        del_timer_sync(&charger_timer);
228
        del_timer_sync(&supply_timer);
229
        power_supply_unregister(&pda_power_supplies[1]);
230
        power_supply_unregister(&pda_power_supplies[0]);
231
        return 0;
232
}
233
 
234
static struct platform_driver pda_power_pdrv = {
235
        .driver = {
236
                .name = "pda-power",
237
        },
238
        .probe = pda_power_probe,
239
        .remove = pda_power_remove,
240
};
241
 
242
static int __init pda_power_init(void)
243
{
244
        return platform_driver_register(&pda_power_pdrv);
245
}
246
 
247
static void __exit pda_power_exit(void)
248
{
249
        platform_driver_unregister(&pda_power_pdrv);
250
}
251
 
252
module_init(pda_power_init);
253
module_exit(pda_power_exit);
254
MODULE_LICENSE("GPL");
255
MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.