123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /*
- * arch/arm/mach-msm/flashlight.c - flashlight driver
- *
- * Copyright (C) 2009 zion huang <zion_huang@htc.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- */
- #define DEBUG
- #include <linux/delay.h>
- #include <linux/earlysuspend.h>
- #include <linux/platform_device.h>
- #include <linux/leds.h>
- #include <linux/wakelock.h>
- #include <linux/hrtimer.h>
- #include <mach/msm_iomap.h>
- #include <asm/gpio.h>
- #include <asm/io.h>
- #include "board-mahimahi-flashlight.h"
- struct flashlight_struct {
- struct led_classdev fl_lcdev;
- struct early_suspend early_suspend_flashlight;
- spinlock_t spin_lock;
- struct hrtimer timer;
- int brightness;
- int gpio_torch;
- int gpio_flash;
- int flash_duration_ms;
- };
- static struct flashlight_struct the_fl;
- static inline void toggle(void)
- {
- gpio_direction_output(the_fl.gpio_torch, 0);
- udelay(2);
- gpio_direction_output(the_fl.gpio_torch, 1);
- udelay(2);
- }
- static void flashlight_hw_command(uint8_t addr, uint8_t data)
- {
- int i;
- for (i = 0; i < addr + 17; i++)
- toggle();
- udelay(500);
- for (i = 0; i < data; i++)
- toggle();
- udelay(500);
- }
- static enum hrtimer_restart flashlight_timeout(struct hrtimer *timer)
- {
- unsigned long flags;
- pr_debug("%s\n", __func__);
- spin_lock_irqsave(&the_fl.spin_lock, flags);
- gpio_direction_output(the_fl.gpio_flash, 0);
- the_fl.brightness = LED_OFF;
- spin_unlock_irqrestore(&the_fl.spin_lock, flags);
- return HRTIMER_NORESTART;
- }
- int flashlight_control(int mode)
- {
- int ret = 0;
- unsigned long flags;
- pr_debug("%s: mode %d -> %d\n", __func__,
- the_fl.brightness, mode);
- spin_lock_irqsave(&the_fl.spin_lock, flags);
- the_fl.brightness = mode;
- switch (mode) {
- case FLASHLIGHT_TORCH:
- pr_info("%s: half\n", __func__);
- /* If we are transitioning from flash to torch, make sure to
- * cancel the flash timeout timer, otherwise when it expires,
- * the torch will go off as well.
- */
- hrtimer_cancel(&the_fl.timer);
- flashlight_hw_command(2, 4);
- break;
- case FLASHLIGHT_FLASH:
- pr_info("%s: full\n", __func__);
- hrtimer_cancel(&the_fl.timer);
- gpio_direction_output(the_fl.gpio_flash, 0);
- udelay(40);
- gpio_direction_output(the_fl.gpio_flash, 1);
- hrtimer_start(&the_fl.timer,
- ktime_set(the_fl.flash_duration_ms / 1000,
- (the_fl.flash_duration_ms % 1000) *
- NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
- /* Flash overrides torch mode, and after the flash period, the
- * flash LED will turn off.
- */
- mode = LED_OFF;
- break;
- case FLASHLIGHT_OFF:
- pr_info("%s: off\n", __func__);
- gpio_direction_output(the_fl.gpio_flash, 0);
- gpio_direction_output(the_fl.gpio_torch, 0);
- break;
- default:
- pr_err("%s: unknown flash_light flags: %d\n", __func__, mode);
- ret = -EINVAL;
- goto done;
- }
- done:
- spin_unlock_irqrestore(&the_fl.spin_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(flashlight_control);
- static void fl_lcdev_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
- {
- int level;
- switch (brightness) {
- case LED_HALF:
- level = FLASHLIGHT_TORCH;
- break;
- case LED_FULL:
- level = FLASHLIGHT_FLASH;
- break;
- case LED_OFF:
- default:
- level = FLASHLIGHT_OFF;
- };
- flashlight_control(level);
- }
- static void flashlight_early_suspend(struct early_suspend *handler)
- {
- flashlight_control(FLASHLIGHT_OFF);
- }
- static int flashlight_setup_gpio(struct flashlight_platform_data *fl_pdata)
- {
- int ret;
- pr_debug("%s\n", __func__);
- if (fl_pdata->gpio_init) {
- ret = fl_pdata->gpio_init();
- if (ret < 0) {
- pr_err("%s: gpio init failed: %d\n", __func__,
- ret);
- return ret;
- }
- }
- if (fl_pdata->torch) {
- ret = gpio_request(fl_pdata->torch, "flashlight_torch");
- if (ret < 0) {
- pr_err("%s: gpio_request failed\n", __func__);
- return ret;
- }
- }
- if (fl_pdata->flash) {
- ret = gpio_request(fl_pdata->flash, "flashlight_flash");
- if (ret < 0) {
- pr_err("%s: gpio_request failed\n", __func__);
- gpio_free(fl_pdata->torch);
- return ret;
- }
- }
- the_fl.gpio_torch = fl_pdata->torch;
- the_fl.gpio_flash = fl_pdata->flash;
- the_fl.flash_duration_ms = fl_pdata->flash_duration_ms;
- return 0;
- }
- static int flashlight_probe(struct platform_device *pdev)
- {
- struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
- int err = 0;
- pr_debug("%s\n", __func__);
- err = flashlight_setup_gpio(fl_pdata);
- if (err < 0) {
- pr_err("%s: setup GPIO failed\n", __func__);
- goto fail_free_mem;
- }
- spin_lock_init(&the_fl.spin_lock);
- the_fl.fl_lcdev.name = pdev->name;
- the_fl.fl_lcdev.brightness_set = fl_lcdev_brightness_set;
- the_fl.fl_lcdev.brightness = LED_OFF;
- err = led_classdev_register(&pdev->dev, &the_fl.fl_lcdev);
- if (err < 0) {
- pr_err("failed on led_classdev_register\n");
- goto fail_free_gpio;
- }
- hrtimer_init(&the_fl.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- the_fl.timer.function = flashlight_timeout;
- #ifdef CONFIG_HAS_EARLYSUSPEND
- the_fl.early_suspend_flashlight.suspend = flashlight_early_suspend;
- the_fl.early_suspend_flashlight.resume = NULL;
- register_early_suspend(&the_fl.early_suspend_flashlight);
- #endif
- return 0;
- fail_free_gpio:
- if (fl_pdata->torch)
- gpio_free(fl_pdata->torch);
- if (fl_pdata->flash)
- gpio_free(fl_pdata->flash);
- fail_free_mem:
- return err;
- }
- static int flashlight_remove(struct platform_device *pdev)
- {
- struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
- pr_debug("%s\n", __func__);
- hrtimer_cancel(&the_fl.timer);
- unregister_early_suspend(&the_fl.early_suspend_flashlight);
- flashlight_control(FLASHLIGHT_OFF);
- led_classdev_unregister(&the_fl.fl_lcdev);
- if (fl_pdata->torch)
- gpio_free(fl_pdata->torch);
- if (fl_pdata->flash)
- gpio_free(fl_pdata->flash);
- return 0;
- }
- static struct platform_driver flashlight_driver = {
- .probe = flashlight_probe,
- .remove = flashlight_remove,
- .driver = {
- .name = FLASHLIGHT_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __init flashlight_init(void)
- {
- pr_debug("%s\n", __func__);
- return platform_driver_register(&flashlight_driver);
- }
- static void __exit flashlight_exit(void)
- {
- pr_debug("%s\n", __func__);
- platform_driver_unregister(&flashlight_driver);
- }
- module_init(flashlight_init);
- module_exit(flashlight_exit);
- MODULE_AUTHOR("Zion Huang <zion_huang@htc.com>");
- MODULE_DESCRIPTION("flash light driver");
- MODULE_LICENSE("GPL");
|