diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2009-10-04 13:18:19 +0200 |
---|---|---|
committer | Lars-Peter Clausen <lars@metafoo.de> | 2009-10-04 13:18:19 +0200 |
commit | 9cdce49cd28baeb9187a0ed8031839ad726312a9 (patch) | |
tree | fe87a9c0aa3a4cb90a58aff4bd6a3ec3ab7dd46c | |
parent | 74fca6a42863ffacaf7ba6f1936a9f228950f657 (diff) |
Add gta02-vibrator driver.
-rw-r--r-- | drivers/leds/Kconfig | 6 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-gta02-vibrator.c | 191 | ||||
-rw-r--r-- | include/linux/gta02-vibrator.h | 10 |
4 files changed, 208 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 7c8e7122aaa..4ec74ef5e0b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -229,6 +229,12 @@ config LEDS_BD2802 This option enables support for BD2802GU RGB LED driver chips accessed via the I2C bus. +config LEDS_GTA02_VIBRATOR + tristate "Vibrator Support for the Openmoko Freerunner GSM phone" + depends on LEDS_CLASS && MACH_NEO1973_GTA02 + help + This option enables support for the vibrator on the Openmoko Freerunner. + comment "LED Triggers" config LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e8cdcf77a4c..edc24c2bebe 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o +obj-$(CONFIG_LEDS_GTA02_VIBRATOR) += leds-gta02-vibrator.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o diff --git a/drivers/leds/leds-gta02-vibrator.c b/drivers/leds/leds-gta02-vibrator.c new file mode 100644 index 00000000000..138af6d1496 --- /dev/null +++ b/drivers/leds/leds-gta02-vibrator.c @@ -0,0 +1,191 @@ +/* + * LED driver for the vibrator of the Openmoko GTA01/GTA02 GSM Phones + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Javi Roman <javiroman@kernel-labs.org>: + * Implement PWM support for GTA01Bv4 and later + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <plat/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 { + 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; + +int gta02_vibrator_fiq_handler(void) +{ + 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; +} + +static void gta02_vib_vib_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + gta02_vib_priv.vib_pwm = value; /* set it for FIQ */ + gta02_vib_priv.pdata->kick_fiq(); /* start up FIQs if not already going */ +} + +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; + + rc = s3c2410_pwm_enable(&vp->pwm); + if (rc) + return rc; + + s3c2410_pwm_start(&vp->pwm); + + return 0; +} + +#ifdef CONFIG_PM +static int gta02_vib_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(); + return 0; +} + +static int gta02_vib_resume(struct platform_device *dev) +{ + struct gta02_vib_priv *vp = platform_get_drvdata(dev); + + if (vp->has_pwm) + gta02_vib_init_hw(vp); + + led_classdev_resume(>a02_vib_led.cdev); + if (gta02_vib_priv.pdata) + gta02_vib_priv.pdata->enable_fiq(); + + return 0; +} +#else +#define gta02_vib_suspend NULL +#define gta02_vib_resume NULL +#endif /* CONFIG_PM */ + +static int __init gta02_vib_probe(struct platform_device *pdev) +{ + struct resource *r; + + r = platform_get_resource(pdev, 0, 0); + if (!r || !r->start) + return -EIO; + + gta02_vib_led.gpio = r->start; + + gta02_vib_priv.pdata = pdev->dev.platform_data; + platform_set_drvdata(pdev, >a02_vib_led); + + 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); + + return led_classdev_register(&pdev->dev, >a02_vib_led.cdev); +} + +static int gta02_vib_remove(struct platform_device *pdev) +{ + gta02_vib_priv.vib_pwm = 0; /* off */ + /* would only need kick if already off so no kick needed */ + + if (gta02_vib_led.has_pwm) + s3c2410_pwm_disable(>a02_vib_led.pwm); + + led_classdev_unregister(>a02_vib_led.cdev); + + 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, + .driver = { + .name = "gta02-vibrator", + }, +}; + +static int __init gta02_vib_init(void) +{ + return platform_driver_register(>a02_vib_driver); +} +module_init(gta02_vib_init); + +static void __exit gta02_vib_exit(void) +{ + platform_driver_unregister(>a02_vib_driver); +} +module_exit(gta02_vib_exit); + +MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); +MODULE_DESCRIPTION("Openmoko Freerunner vibrator driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/gta02-vibrator.h b/include/linux/gta02-vibrator.h new file mode 100644 index 00000000000..be7300b3a39 --- /dev/null +++ b/include/linux/gta02-vibrator.h @@ -0,0 +1,10 @@ +#ifndef __LINUX_GTA02_VIBRATOR +#define __LINUX_GTA02_VIBRATOR + +struct gta02_vib_platform_data { + int (* enable_fiq)(void); + void (*disable_fiq)(void); + void (*kick_fiq)(void); +}; + +#endif |