647e860343013cc237a8135fd14da1439905e3a1
[kernel.git] / drivers / leds / leds-neo1973-vibrator.c
1 /*
2  * LED driver for the vibrator of the FIC Neo1973 GSM Phone
3  *
4  * (C) 2006-2007 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  * Javi Roman <javiroman@kernel-labs.org>:
13  *      Implement PWM support for GTA01Bv4 and later
14  */
15
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/leds.h>
20 #include <asm/hardware.h>
21 #include <asm/mach-types.h>
22 #include <asm/arch/pwm.h>
23 #include <asm/arch/gta01.h>
24 #include <asm/plat-s3c/regs-timer.h>
25
26 #include <asm/arch-s3c2410/fiq_ipc_gta02.h>
27 #include <asm/plat-s3c24xx/neo1973.h>
28
29 #define COUNTER 64
30
31 struct neo1973_vib_priv {
32         struct led_classdev cdev;
33         unsigned int gpio;
34         struct mutex mutex;
35         unsigned int has_pwm;
36         struct s3c2410_pwm pwm;
37 };
38
39 static void neo1973_vib_vib_set(struct led_classdev *led_cdev,
40                 enum led_brightness value)
41 {
42         struct neo1973_vib_priv *vp =
43                 container_of(led_cdev, struct neo1973_vib_priv, cdev);
44
45         if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
46                 fiq_ipc.vib_pwm = value; /* set it for FIQ */
47                 fiq_kick(); /* start up FIQs if not already going */
48                 return;
49         }
50         /*
51          * value == 255 -> 99% duty cycle (full power)
52          * value == 128 -> 50% duty cycle (medium power)
53          * value == 0 -> 0% duty cycle (zero power)
54          */
55         mutex_lock(&vp->mutex);
56         if (vp->has_pwm)
57                 s3c2410_pwm_duty_cycle(value / 4, &vp->pwm);
58         else {
59                 if (value)
60                         neo1973_gpb_setpin(vp->gpio, 1);
61                 else
62                         neo1973_gpb_setpin(vp->gpio, 0);
63         }
64
65         mutex_unlock(&vp->mutex);
66 }
67
68 static struct neo1973_vib_priv neo1973_vib_led = {
69         .cdev = {
70                 .name = "neo1973:vibrator",
71                 .brightness_set = neo1973_vib_vib_set,
72         },
73 };
74
75 static int neo1973_vib_init_hw(struct neo1973_vib_priv *vp)
76 {
77         int rc;
78
79         rc = s3c2410_pwm_init(&vp->pwm);
80         if (rc)
81                 return rc;
82
83         vp->pwm.timerid = PWM3;
84         /* use same prescaler as arch/arm/plat-s3c24xx/time.c */
85         vp->pwm.prescaler = (6 - 1) / 2;
86         vp->pwm.divider = S3C2410_TCFG1_MUX3_DIV2;
87         vp->pwm.counter = COUNTER;
88         vp->pwm.comparer = COUNTER;
89
90         rc = s3c2410_pwm_enable(&vp->pwm);
91         if (rc)
92                 return rc;
93
94         s3c2410_pwm_start(&vp->pwm);
95
96         return 0;
97 }
98
99 #ifdef CONFIG_PM
100 static int neo1973_vib_suspend(struct platform_device *dev, pm_message_t state)
101 {
102         led_classdev_suspend(&neo1973_vib_led.cdev);
103         return 0;
104 }
105
106 static int neo1973_vib_resume(struct platform_device *dev)
107 {
108         struct neo1973_vib_priv *vp = platform_get_drvdata(dev);
109
110         if (vp->has_pwm)
111                 neo1973_vib_init_hw(vp);
112
113         led_classdev_resume(&neo1973_vib_led.cdev);
114
115         return 0;
116 }
117 #endif /* CONFIG_PM */
118
119 static int __init neo1973_vib_probe(struct platform_device *pdev)
120 {
121         struct resource *r;
122         int rc;
123
124         if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02())
125                 return -EIO;
126
127         r = platform_get_resource(pdev, 0, 0);
128         if (!r || !r->start)
129                 return -EIO;
130
131         neo1973_vib_led.gpio = r->start;
132         platform_set_drvdata(pdev, &neo1973_vib_led);
133
134         if (machine_is_neo1973_gta02()) { /* use FIQ to control GPIO */
135                 neo1973_gpb_setpin(neo1973_vib_led.gpio, 0); /* off */
136                 s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPIO_OUTPUT);
137                 /* safe, kmalloc'd copy needed for FIQ ISR */
138                 fiq_ipc.vib_gpio_pin = neo1973_vib_led.gpio;
139                 fiq_ipc.vib_pwm = 0; /* off */
140                 goto configured;
141         }
142
143         /* TOUT3 */
144         if (neo1973_vib_led.gpio == S3C2410_GPB3) {
145                 rc = neo1973_vib_init_hw(&neo1973_vib_led);
146                 if (rc)
147                         return rc;
148
149                 s3c2410_pwm_duty_cycle(0, &neo1973_vib_led.pwm);
150                 s3c2410_gpio_cfgpin(neo1973_vib_led.gpio, S3C2410_GPB3_TOUT3);
151                 neo1973_vib_led.has_pwm = 1;
152         }
153 configured:
154         mutex_init(&neo1973_vib_led.mutex);
155
156         return led_classdev_register(&pdev->dev, &neo1973_vib_led.cdev);
157 }
158
159 static int neo1973_vib_remove(struct platform_device *pdev)
160 {
161         if (machine_is_neo1973_gta02()) /* use FIQ to control GPIO */
162                 fiq_ipc.vib_pwm = 0; /* off */
163         /* would only need kick if already off so no kick needed */
164
165         if (neo1973_vib_led.has_pwm)
166                 s3c2410_pwm_disable(&neo1973_vib_led.pwm);
167
168         led_classdev_unregister(&neo1973_vib_led.cdev);
169
170         mutex_destroy(&neo1973_vib_led.mutex);
171
172         return 0;
173 }
174
175 static struct platform_driver neo1973_vib_driver = {
176         .probe          = neo1973_vib_probe,
177         .remove         = neo1973_vib_remove,
178 #ifdef CONFIG_PM
179         .suspend        = neo1973_vib_suspend,
180         .resume         = neo1973_vib_resume,
181 #endif
182         .driver         = {
183                 .name           = "neo1973-vibrator",
184         },
185 };
186
187 static int __init neo1973_vib_init(void)
188 {
189         return platform_driver_register(&neo1973_vib_driver);
190 }
191
192 static void __exit neo1973_vib_exit(void)
193 {
194         platform_driver_unregister(&neo1973_vib_driver);
195 }
196
197 module_init(neo1973_vib_init);
198 module_exit(neo1973_vib_exit);
199
200 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
201 MODULE_DESCRIPTION("FIC Neo1973 vibrator driver");
202 MODULE_LICENSE("GPL");