diff options
Diffstat (limited to 'drivers/leds/rtfled.c')
| -rw-r--r-- | drivers/leds/rtfled.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/drivers/leds/rtfled.c b/drivers/leds/rtfled.c new file mode 100644 index 00000000..fa9802bb --- /dev/null +++ b/drivers/leds/rtfled.c @@ -0,0 +1,380 @@ +/* drivers/leds/rtfled.c + * Richtek Flash LED Universal Architecture + * + * Copyright (C) 2013 Richtek Technology Corp. + * Author: Patrick Chang <patrick_chang@richtek.com> + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/leds/rtfled.h> +#include <linux/init.h> +#include <linux/version.h> + +#define RTFLED_INFO(format, args...) \ + printk(KERN_INFO "%s:%s() line-%d: " format, \ + ALIAS_NAME, __FUNCTION__, __LINE__, ## args) +#define RTFLED_WARN(format, args...) \ + printk(KERN_WARNING "%s:%s() line-%d: " format, \ + ALIAS_NAME, __FUNCTION__, __LINE__, ## args) +#define RTFLED_ERR(format, args...) \ + printk(KERN_ERR "%s:%s() line-%d: " format, \ + ALIAS_NAME, __FUNCTION__, __LINE__, ## args) + +#define RT_FLED_DEVICE "rt-flash-led" +#define ALIAS_NAME RT_FLED_DEVICE + + + +rt_fled_info_t *rt_fled_get_info_by_name(char *name) +{ + struct flashlight_device *flashlight_dev; + flashlight_dev = find_flashlight_by_name(name ? name : RT_FLED_DEVICE); + if (flashlight_dev == NULL) + return (rt_fled_info_t *)NULL; + return flashlight_get_data(flashlight_dev); +} +EXPORT_SYMBOL(rt_fled_get_info_by_name); + + +static int rtfled_set_torch_brightness(struct flashlight_device *flashlight_dev, + int brightness_sel) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + return info->hal->fled_set_torch_current_sel(info, brightness_sel); +} + +static int rtfled_set_strobe_brightness(struct flashlight_device + *flashlight_dev, + int brightness_sel) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + return info->hal->fled_set_strobe_current_sel(info, brightness_sel); +} + +static int rtfled_set_strobe_timeout(struct flashlight_device *flashlight_dev, + int timeout) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + int sel; + + return info->hal->fled_set_strobe_timeout(info, timeout, + timeout, &sel); +} + +static int rtfled_list_strobe_timeout(struct flashlight_device *flashlight_dev, + int selector) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + return info->hal->fled_strobe_timeout_list(info, selector); +} + +static int rtfled_set_mode(struct flashlight_device *flashlight_dev, int mode) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + return info->hal->fled_set_mode(info, mode); +} + +static int rtfled_strobe(struct flashlight_device *flashlight_dev) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + return info->hal->fled_strobe(info); +} + +static int rtfled_set_color_temperature(struct flashlight_device + *flashlight_dev, + int color_temp) +{ + /* Doesn't support color temperature */ + return -EINVAL; +} + +static int rtfled_list_color_temperature(struct flashlight_device + *flashlight_dev, + int selector) +{ + /* Doesn't support color temperature */ + return -EINVAL; +} +static int rtfled_suspend(struct flashlight_device *flashlight_dev, + pm_message_t state) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + if (info->hal->fled_suspend) + return info->hal->fled_suspend(info, state); + return 0; +} +static int rtfled_resume(struct flashlight_device *flashlight_dev) +{ + rt_fled_info_t *info = flashlight_get_data(flashlight_dev); + if (info->hal->fled_resume) + return info->hal->fled_resume(info); + return 0; +} + +static struct flashlight_ops rtfled_impl_ops = { + .set_torch_brightness = rtfled_set_torch_brightness, + .set_strobe_brightness = rtfled_set_strobe_brightness, + .set_strobe_timeout = rtfled_set_strobe_timeout, + .list_strobe_timeout = rtfled_list_strobe_timeout, + .set_mode = rtfled_set_mode, + .strobe = rtfled_strobe, + .set_color_temperature = rtfled_set_color_temperature, + .list_color_temperature = rtfled_list_color_temperature, + .suspend = rtfled_suspend, + .resume = rtfled_resume, +}; + + +static void rfled_shutdown(struct platform_device *pdev) +{ + struct rt_fled_info *info = platform_get_drvdata(pdev); + if (info->hal->fled_shutdown) + info->hal->fled_shutdown(info); +} + +static int rtled_impl_set_torch_current(struct rt_fled_info *info, + int min_uA, int max_uA, int *selector) +{ + int sel = 0; + int rc; + for (sel = 0; ; sel++) { + rc = info->hal->fled_troch_current_list(info, sel); + if (rc < 0) + return rc; + if (rc >= min_uA && rc <= max_uA) { + *selector = sel; + return info->hal->fled_set_torch_current_sel(info, sel); + } + } + return -EINVAL; +} + +static int rtled_impl_set_strobe_current(struct rt_fled_info *info, + int min_uA, int max_uA, int *selector) +{ + int sel = 0; + int rc; + for (sel = 0; ; sel++) { + rc = info->hal->fled_strobe_current_list(info, sel); + if (rc < 0) + return rc; + if (rc >= min_uA && rc <= max_uA) { + *selector = sel; + return info->hal->fled_set_strobe_current_sel(info, sel); + } + } + return -EINVAL; +} + +static int rtled_impl_set_timeout_level(struct rt_fled_info *info, + int min_uA, int max_uA, int *selector) +{ + int sel = 0; + int rc; + for (sel = 0; ; sel++) { + rc = info->hal->fled_timeout_level_list(info, sel); + if (rc < 0) + return rc; + if (rc >= min_uA && rc <= max_uA) { + *selector = sel; + return info->hal->fled_set_timeout_level_sel(info, sel); + } + } + return -EINVAL; +} + +static int rtled_impl_set_lv_protection(struct rt_fled_info *info, + int min_mV, int max_mV, int *selector) +{ + int sel = 0; + int rc; + for (sel = 0; ; sel++) { + rc = info->hal->fled_lv_protection_list(info, sel); + if (rc < 0) + return rc; + if (rc >= min_mV && rc <= max_mV) { + *selector = sel; + return info->hal->fled_set_lv_protection_sel(info, sel); + } + } + return -EINVAL; +} + +static int rtled_impl_set_strobe_timeout(struct rt_fled_info *info, + int min_ms, int max_ms, int *selector) +{ + int sel = 0; + int rc; + for (sel = 0; ; sel++) { + rc = info->hal->fled_strobe_timeout_list(info, sel); + if (rc < 0) + return rc; + if (rc >= min_ms && rc <= max_ms) { + *selector = sel; + return info->hal->fled_set_strobe_timeout_sel(info, sel); + } + } + return -EINVAL; +} + +static int rtled_impl_get_torch_current(struct rt_fled_info *info) +{ + int sel = info->hal->fled_get_torch_current_sel(info); + if (sel < 0) + return sel; + return info->hal->fled_troch_current_list(info, sel); +} + +static int rtled_impl_get_strobe_current(struct rt_fled_info *info) +{ + int sel = info->hal->fled_get_strobe_current_sel(info); + if (sel < 0) + return sel; + return info->hal->fled_strobe_current_list(info, sel); +} + +static int rtled_impl_get_timeout_level(struct rt_fled_info *info) +{ + int sel = info->hal->fled_get_timeout_level_sel(info); + if (sel < 0) + return sel; + return info->hal->fled_timeout_level_list(info, sel); +} + +static int rtled_impl_get_lv_protection(struct rt_fled_info *info) +{ + int sel = info->hal->fled_get_lv_protection_sel(info); + if (sel < 0) + return sel; + return info->hal->fled_lv_protection_list(info, sel); +} + +static int rtled_impl_get_strobe_timeout(struct rt_fled_info *info) +{ + int sel = info->hal->fled_get_strobe_timeout_sel(info); + if (sel < 0) + return sel; + return info->hal->fled_strobe_timeout_list(info, sel); +} + +#define HAL_NOT_IMPLEMENTED(x) (hal->x == NULL) +#define CHECK_HAL_IMPLEMENTED(x) if (hal->x == NULL) return -EINVAL + +static int rtfled_check_hal_implement(struct rt_fled_hal *hal) +{ + if (HAL_NOT_IMPLEMENTED(fled_set_torch_current)) + hal->fled_set_torch_current = rtled_impl_set_torch_current; + if (HAL_NOT_IMPLEMENTED(fled_set_strobe_current)) + hal->fled_set_strobe_current = rtled_impl_set_strobe_current; + if (HAL_NOT_IMPLEMENTED(fled_set_timeout_level)) + hal->fled_set_timeout_level = rtled_impl_set_timeout_level; + if (HAL_NOT_IMPLEMENTED(fled_set_lv_protection)) + hal->fled_set_lv_protection = rtled_impl_set_lv_protection; + if (HAL_NOT_IMPLEMENTED(fled_set_strobe_timeout)) + hal->fled_set_strobe_timeout = rtled_impl_set_strobe_timeout; + if (HAL_NOT_IMPLEMENTED(fled_get_torch_current)) + hal->fled_get_torch_current = rtled_impl_get_torch_current; + if (HAL_NOT_IMPLEMENTED(fled_get_strobe_current)) + hal->fled_get_strobe_current = rtled_impl_get_strobe_current; + if (HAL_NOT_IMPLEMENTED(fled_get_timeout_level)) + hal->fled_get_timeout_level = rtled_impl_get_timeout_level; + if (HAL_NOT_IMPLEMENTED(fled_get_lv_protection)) + hal->fled_get_lv_protection = rtled_impl_get_lv_protection; + if (HAL_NOT_IMPLEMENTED(fled_get_strobe_timeout)) + hal->fled_get_strobe_timeout = rtled_impl_get_strobe_timeout; + CHECK_HAL_IMPLEMENTED(fled_set_mode); + CHECK_HAL_IMPLEMENTED(fled_get_mode); + CHECK_HAL_IMPLEMENTED(fled_strobe); + CHECK_HAL_IMPLEMENTED(fled_troch_current_list); + CHECK_HAL_IMPLEMENTED(fled_strobe_current_list); + CHECK_HAL_IMPLEMENTED(fled_timeout_level_list); + CHECK_HAL_IMPLEMENTED(fled_lv_protection_list); + CHECK_HAL_IMPLEMENTED(fled_strobe_timeout_list); + CHECK_HAL_IMPLEMENTED(fled_set_torch_current_sel); + CHECK_HAL_IMPLEMENTED(fled_set_strobe_current_sel); + CHECK_HAL_IMPLEMENTED(fled_set_timeout_level_sel); + CHECK_HAL_IMPLEMENTED(fled_set_lv_protection_sel); + CHECK_HAL_IMPLEMENTED(fled_set_strobe_timeout_sel); + CHECK_HAL_IMPLEMENTED(fled_get_torch_current_sel); + CHECK_HAL_IMPLEMENTED(fled_get_strobe_current_sel); + CHECK_HAL_IMPLEMENTED(fled_get_timeout_level_sel); + CHECK_HAL_IMPLEMENTED(fled_get_lv_protection_sel); + CHECK_HAL_IMPLEMENTED(fled_get_strobe_timeout_sel); + return 0; +} + + +static int rtfled_probe(struct platform_device *pdev) +{ + rt_fled_info_t *info = dev_get_drvdata(pdev->dev.parent); + int rc; + BUG_ON(info == NULL); + BUG_ON(info->hal == NULL); + + RTFLED_INFO("Richtek FlashLED Driver is probing\n"); + rc = rtfled_check_hal_implement(info->hal); + if (rc < 0) { + RTFLED_ERR("HAL implemented incompletely\n"); + goto err_check_hal; + } + platform_set_drvdata(pdev, info); + info->flashlight_dev = flashlight_device_register( + info->name ? info->name : RT_FLED_DEVICE, + &pdev->dev, info, &rtfled_impl_ops, + info->init_props); + if (info->hal->fled_init) { + rc = info->hal->fled_init(info); + if (rc < 0) { + RTFLED_ERR("Initialization failed\n"); + goto err_init; + } + } + RTFLED_INFO("Richtek FlashLED Driver initialized successfully\n"); + return 0; +err_init: + flashlight_device_unregister(info->flashlight_dev); +err_check_hal: + return rc; +} + +static int rtfled_remove(struct platform_device *pdev) +{ + rt_fled_info_t *info = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + flashlight_device_unregister(info->flashlight_dev); + return 0; +} + +static struct platform_driver rt_flash_led_driver = { + .driver = { + .name = RT_FLED_DEVICE, + .owner = THIS_MODULE, + }, + .shutdown = rfled_shutdown, + .probe = rtfled_probe, + .remove = rtfled_remove, +}; + +static int __init rtfled_init(void) +{ + return platform_driver_register(&rt_flash_led_driver); +} +subsys_initcall(rtfled_init); + +static void __exit rtfled_exit(void) +{ + platform_driver_unregister(&rt_flash_led_driver); +} +module_exit(rtfled_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Chang <patrick_chang@richtek.com"); +MODULE_VERSION("1.0.0_G"); +MODULE_DESCRIPTION("Richtek Flash LED Driver"); |
