[s3c24xx] bump to 2.6.30-rc6
[openwrt.git] / target / linux / s3c24xx / files-2.6.30 / drivers / leds / leds-gta02.c
1 /*
2  * LED driver for the Openmoko GTA02 GSM phone
3  *
4  * (C) 2006-2008 by Openmoko, Inc.
5  * Author: Harald Welte <laforge@openmoko.org>
6  * All rights reserved.
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
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/leds.h>
18 #include <mach/hardware.h>
19 #include <asm/mach-types.h>
20 #include <mach/gta02.h>
21 #include <plat/regs-timer.h>
22 #include <linux/gta02-shadow.h>
23
24 #define MAX_LEDS 3
25 #define COUNTER 256
26
27 struct gta02_led_priv
28 {
29         spinlock_t lock;
30         struct led_classdev cdev;
31         unsigned int gpio;
32 };
33
34 struct gta02_led_bundle
35 {
36         int num_leds;
37         struct gta02_led_priv led[MAX_LEDS];
38 };
39
40 static inline struct gta02_led_priv *to_priv(struct led_classdev *led_cdev)
41 {
42         return container_of(led_cdev, struct gta02_led_priv, cdev);
43 }
44
45 static inline struct gta02_led_bundle *to_bundle(struct led_classdev *led_cdev)
46 {
47         return dev_get_drvdata(led_cdev->dev->parent);
48 }
49
50 static void gta02led_set(struct led_classdev *led_cdev,
51                          enum led_brightness value)
52 {
53         unsigned long flags;
54         struct gta02_led_priv *lp = to_priv(led_cdev);
55
56         spin_lock_irqsave(&lp->lock, flags);
57         gta02_gpb_setpin(lp->gpio, value ? 1 : 0);
58         spin_unlock_irqrestore(&lp->lock, flags);
59 }
60
61 #ifdef CONFIG_PM
62 static int gta02led_suspend(struct platform_device *pdev, pm_message_t state)
63 {
64         struct gta02_led_bundle *bundle = platform_get_drvdata(pdev);
65         int i;
66
67         for (i = 0; i < bundle->num_leds; i++)
68                 led_classdev_suspend(&bundle->led[i].cdev);
69
70         return 0;
71 }
72
73 static int gta02led_resume(struct platform_device *pdev)
74 {
75         struct gta02_led_bundle *bundle = platform_get_drvdata(pdev);
76         int i;
77
78         for (i = 0; i < bundle->num_leds; i++)
79                 led_classdev_resume(&bundle->led[i].cdev);
80
81         return 0;
82 }
83 #endif
84
85 static int __init gta02led_probe(struct platform_device *pdev)
86 {
87         int i, rc;
88         struct gta02_led_bundle *bundle;
89
90         if (!machine_is_neo1973_gta02())
91                 return -EIO;
92
93         bundle = kzalloc(sizeof(struct gta02_led_bundle), GFP_KERNEL);
94         if (!bundle)
95                 return -ENOMEM;
96         platform_set_drvdata(pdev, bundle);
97
98         for (i = 0; i < pdev->num_resources; i++) {
99                 struct gta02_led_priv *lp;
100                 struct resource *r;
101
102                 if (i >= MAX_LEDS)
103                         break;
104
105                 r = platform_get_resource(pdev, 0, i);
106                 if (!r || !r->start || !r->name)
107                         continue;
108
109                 lp = &bundle->led[i];
110
111                 lp->gpio = r->start;
112                 lp->cdev.name = r->name;
113                 lp->cdev.brightness_set = gta02led_set;
114
115                 switch (lp->gpio) {
116                 case S3C2410_GPB0:
117                 case S3C2410_GPB1:
118                 case S3C2410_GPB2:
119                         s3c2410_gpio_cfgpin(lp->gpio, S3C2410_GPIO_OUTPUT);
120                         gta02_gpb_add_shadow_gpio(lp->gpio);
121                         break;
122                 default:
123                         break;
124                 }
125
126                 spin_lock_init(&lp->lock);
127                 rc = led_classdev_register(&pdev->dev, &lp->cdev);
128         }
129
130         bundle->num_leds = i;
131
132         return 0;
133 }
134
135 static int gta02led_remove(struct platform_device *pdev)
136 {
137         struct gta02_led_bundle *bundle = platform_get_drvdata(pdev);
138         int i;
139
140         for (i = 0; i < bundle->num_leds; i++) {
141                 struct gta02_led_priv *lp = &bundle->led[i];
142                 gta02led_set(&lp->cdev, 0);
143                 led_classdev_unregister(&lp->cdev);
144         }
145
146         platform_set_drvdata(pdev, NULL);
147         kfree(bundle);
148
149         return 0;
150 }
151
152 static struct platform_driver gta02led_driver = {
153         .probe          = gta02led_probe,
154         .remove         = gta02led_remove,
155 #ifdef CONFIG_PM
156         .suspend        = gta02led_suspend,
157         .resume         = gta02led_resume,
158 #endif
159         .driver         = {
160                 .name           = "gta02-led",
161         },
162 };
163
164 static int __init gta02led_init(void)
165 {
166         return platform_driver_register(&gta02led_driver);
167 }
168
169 static void __exit gta02led_exit(void)
170 {
171         platform_driver_unregister(&gta02led_driver);
172 }
173
174 module_init(gta02led_init);
175 module_exit(gta02led_exit);
176
177 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
178 MODULE_DESCRIPTION("Openmoko GTA02 LED driver");
179 MODULE_LICENSE("GPL");