Hi,
this is a possible redisign. Now I will move the hdq to the timer 2
instead of 3
Michael
GTA02-vibrator rewrite. Maybe GTA01 use a pin instead of TOUT3, I will check
Not-yet-signed-off: Michael Trimarchi <[email protected]>
diff --git a/drivers/leds/leds-gta02-vibrator.c b/drivers/leds/leds-gta02-vibrator.c
index 138af6d..e99f4eb 100644
--- a/drivers/leds/leds-gta02-vibrator.c
+++ b/drivers/leds/leds-gta02-vibrator.c
@@ -2,6 +2,7 @@
* LED driver for the vibrator of the Openmoko GTA01/GTA02 GSM Phones
*
* (C) 2006-2008 by Openmoko, Inc.
+ * (C) 2009 Michael Trimarchi <[email protected]>
* Author: Harald Welte <[email protected]>
* All rights reserved.
*
@@ -19,107 +20,88 @@
#include <linux/leds.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <plat/pwm.h>
+#include <linux/pwm.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-fns.h>
#include <plat/regs-timer.h>
#include <linux/gta02-vibrator.h>
-#define COUNTER 64
-
-static struct gta02_vib_priv {
+static struct gta02_vibrator_priv {
struct led_classdev cdev;
- unsigned int gpio;
- spinlock_t lock;
- unsigned int has_pwm;
- struct s3c2410_pwm pwm;
-
- unsigned long vib_gpio_pin; /* which pin to meddle with */
- uint8_t vib_pwm; /* 0 = OFF -- will ensure GPIO deasserted and stop FIQ */
- uint8_t vib_pwm_latched;
- uint8_t fiq_count;
-
- struct gta02_vib_platform_data *pdata;
-} gta02_vib_priv;
+ struct pwm_device *pwm;
+ int period_ns;
+ enum led_brightness value;
+} gta02_vibrator_priv;
-int gta02_vibrator_fiq_handler(void)
+static void gta02_vibrator_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- gta02_vib_priv.fiq_count++;
-
- if (!gta02_vib_priv.vib_pwm_latched && !gta02_vib_priv.vib_pwm)
- /* idle */
- return 0;
-
- if (gta02_vib_priv.fiq_count == gta02_vib_priv.vib_pwm_latched)
- s3c2410_gpio_setpin(gta02_vib_priv.vib_gpio_pin, 0);
-
- if (gta02_vib_priv.fiq_count)
- return 1;
-
- gta02_vib_priv.vib_pwm_latched = gta02_vib_priv.vib_pwm;
- if (gta02_vib_priv.vib_pwm_latched)
- s3c2410_gpio_setpin(gta02_vib_priv.vib_gpio_pin, 1);
-
- return 1;
+ struct gta02_vibrator_priv *gta02_vib;
+ int duty_ns;
+
+ /* update the duty cycle for the *next* period */
+ gta02_vib = container_of(led_cdev, struct gta02_vibrator_priv, cdev);
+
+ /*
+ * value == 255 -> 99% duty cycle (full power)
+ * value == 128 -> 50% duty cycle (medium power)
+ * value == 0 -> 0% duty cycle (zero power)
+ */
+ duty_ns = gta02_vib->period_ns * 255 / value;
+ if (value) {
+ pwm_config(gta02_vib->pwm, duty_ns, gta02_vib->period_ns);
+ pwm_enable(gta02_vib->pwm);
+ } else
+ pwm_disable(gta02_vib->pwm);
+
+ gta02_vib->value = value;
}
-static void gta02_vib_vib_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static int gta02_vibrator_init_hw(struct gta02_vibrator_priv *gta02_vib)
{
- gta02_vib_priv.vib_pwm = value; /* set it for FIQ */
- gta02_vib_priv.pdata->kick_fiq(); /* start up FIQs if not already going */
-}
+ int ret = 0;
-static struct gta02_vib_priv gta02_vib_led = {
- .cdev = {
- .name = "gta02:vibrator",
- .brightness_set = gta02_vib_vib_set,
- },
-};
-
-static int gta02_vib_init_hw(struct gta02_vib_priv *vp)
-{
- int rc;
-
- rc = s3c2410_pwm_init(&vp->pwm);
- if (rc)
- return rc;
-
- vp->pwm.timerid = PWM3;
- /* use same prescaler as arch/arm/plat-s3c24xx/time.c */
- vp->pwm.prescaler = (6 - 1) / 2;
- vp->pwm.divider = S3C2410_TCFG1_MUX3_DIV2;
- vp->pwm.counter = COUNTER;
- vp->pwm.comparer = COUNTER;
+ gta02_vib->pwm = pwm_request(3, "vibrator-gta02");
+ if (!gta02_vib->pwm) {
+ ret = -EINVAL;
+ goto bail;
+ }
- rc = s3c2410_pwm_enable(&vp->pwm);
- if (rc)
- return rc;
+ ret = pwm_config(gta02_vib->pwm, 0, gta02_vib->period_ns);
+ if (ret)
+ goto bail;
- s3c2410_pwm_start(&vp->pwm);
+ gta02_vib->value = 0;
return 0;
+bail:
+ return ret;
}
#ifdef CONFIG_PM
-static int gta02_vib_suspend(struct platform_device *dev, pm_message_t state)
+static int gta02_vibrator_suspend(struct platform_device *dev,
+ pm_message_t state)
{
- led_classdev_suspend(>a02_vib_led.cdev);
- if (gta02_vib_priv.pdata)
- gta02_vib_priv.pdata->disable_fiq();
+ struct gta02_vibrator_priv *gta02_vib = platform_get_drvdata(dev);
+
+ if (!gta02_vib->pwm)
+ pwm_free(gta02_vib->pwm);
+
+ gta02_vib->pwm = NULL;
+
+ led_classdev_suspend(>a02_vib->cdev);
+
return 0;
}
-static int gta02_vib_resume(struct platform_device *dev)
+static int gta02_vibrator_resume(struct platform_device *dev)
{
- struct gta02_vib_priv *vp = platform_get_drvdata(dev);
+ struct gta02_vibrator_priv *gta02_vib = platform_get_drvdata(dev);
- if (vp->has_pwm)
- gta02_vib_init_hw(vp);
+ if (!gta02_vib->pwm)
+ gta02_vibrator_init_hw(gta02_vib);
- led_classdev_resume(>a02_vib_led.cdev);
- if (gta02_vib_priv.pdata)
- gta02_vib_priv.pdata->enable_fiq();
+ led_classdev_resume(>a02_vib->cdev);
return 0;
}
@@ -128,64 +110,63 @@ static int gta02_vib_resume(struct platform_device *dev)
#define gta02_vib_resume NULL
#endif /* CONFIG_PM */
-static int __init gta02_vib_probe(struct platform_device *pdev)
+static int __init gta02_vibrator_probe(struct platform_device *pdev)
{
- struct resource *r;
+ struct gta02_vibrator_priv *gta02_vib;
+ struct gta02_vibrator_platform_data *pdata = platform_get_drvdata(pdev);
- r = platform_get_resource(pdev, 0, 0);
- if (!r || !r->start)
- return -EIO;
+ if (!pdata)
+ return -ENODEV;
- gta02_vib_led.gpio = r->start;
+ gta02_vib = kmalloc(sizeof(gta02_vibrator_priv), GFP_KERNEL);
+ if (!gta02_vib)
+ return -ENOMEM;
- gta02_vib_priv.pdata = pdev->dev.platform_data;
- platform_set_drvdata(pdev, >a02_vib_led);
+ gta02_vib->period_ns = pdata->period_ns;
+ gta02_vib->cdev.name = "gta02:vibrator";
+ gta02_vib->cdev.brightness_set = gta02_vibrator_set;
- s3c2410_gpio_setpin(gta02_vib_led.gpio, 0); /* off */
- s3c2410_gpio_cfgpin(gta02_vib_led.gpio, S3C2410_GPIO_OUTPUT);
- /* safe, kmalloc'd copy needed for FIQ ISR */
- gta02_vib_priv.vib_gpio_pin = gta02_vib_led.gpio;
- gta02_vib_priv.vib_pwm = 0; /* off */
- spin_lock_init(>a02_vib_led.lock);
+ platform_set_drvdata(pdev, >a02_vib);
- return led_classdev_register(&pdev->dev, >a02_vib_led.cdev);
+ return led_classdev_register(&pdev->dev, >a02_vib->cdev);
}
-static int gta02_vib_remove(struct platform_device *pdev)
+static int gta02_vibrator_remove(struct platform_device *pdev)
{
- gta02_vib_priv.vib_pwm = 0; /* off */
- /* would only need kick if already off so no kick needed */
+ struct gta02_vibrator_priv *gta02_vib = platform_get_drvdata(pdev);
- if (gta02_vib_led.has_pwm)
- s3c2410_pwm_disable(>a02_vib_led.pwm);
+ if (!gta02_vib->pwm)
+ pwm_free(gta02_vib->pwm);
- led_classdev_unregister(>a02_vib_led.cdev);
+ led_classdev_unregister(>a02_vib->cdev);
+ kfree(gta02_vib);
return 0;
}
-static struct platform_driver gta02_vib_driver = {
- .probe = gta02_vib_probe,
- .remove = gta02_vib_remove,
- .suspend = gta02_vib_suspend,
- .resume = gta02_vib_resume,
+static struct platform_driver gta02_vibrator_driver = {
+ .probe = gta02_vibrator_probe,
+ .remove = gta02_vibrator_remove,
+ .suspend = gta02_vibrator_suspend,
+ .resume = gta02_vibrator_resume,
.driver = {
.name = "gta02-vibrator",
},
};
-static int __init gta02_vib_init(void)
+static int __init gta02_vibrator_init(void)
{
- return platform_driver_register(>a02_vib_driver);
+ return platform_driver_register(>a02_vibrator_driver);
}
-module_init(gta02_vib_init);
+module_init(gta02_vibrator_init);
-static void __exit gta02_vib_exit(void)
+static void __exit gta02_vibrator_exit(void)
{
- platform_driver_unregister(>a02_vib_driver);
+ platform_driver_unregister(>a02_vibrator_driver);
}
-module_exit(gta02_vib_exit);
+module_exit(gta02_vibrator_exit);
-MODULE_AUTHOR("Harald Welte <[email protected]>");
+MODULE_AUTHOR("Harald Welte <[email protected]>"
+ "Michael Trimarchi <[email protected]>");
MODULE_DESCRIPTION("Openmoko Freerunner vibrator driver");
MODULE_LICENSE("GPL");