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(&gta02_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(&gta02_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(&gta02_vib_led.cdev);
-	if (gta02_vib_priv.pdata)
-		gta02_vib_priv.pdata->enable_fiq();
+	led_classdev_resume(&gta02_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, &gta02_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(&gta02_vib_led.lock);
+	platform_set_drvdata(pdev, &gta02_vib);
 
-	return led_classdev_register(&pdev->dev, &gta02_vib_led.cdev);
+	return led_classdev_register(&pdev->dev, &gta02_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(&gta02_vib_led.pwm);
+	if (!gta02_vib->pwm)
+		pwm_free(gta02_vib->pwm);
 
-	led_classdev_unregister(&gta02_vib_led.cdev);
+	led_classdev_unregister(&gta02_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(&gta02_vib_driver);
+	return platform_driver_register(&gta02_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(&gta02_vib_driver);
+	platform_driver_unregister(&gta02_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");

Reply via email to