From 5c2e792bff37c3e18bbef594b14408964ee721b4 Mon Sep 17 00:00:00 2001 From: zyc Date: Mon, 10 Nov 2014 11:45:56 +0800 Subject: [PATCH] camsys_drv: v0.0x18.0 camsys_head: v0.0xa.0 --- arch/arm/configs/rockchip_defconfig | 3 + drivers/media/video/rk_camsys/Kconfig | 3 + drivers/media/video/rk_camsys/Makefile | 1 + drivers/media/video/rk_camsys/camsys_drv.c | 28 +- drivers/media/video/rk_camsys/camsys_gpio.h | 6 +- .../media/video/rk_camsys/camsys_internal.h | 10 +- drivers/media/video/rk_camsys/camsys_marvin.c | 2 +- .../video/rk_camsys/ext_flashled_drv/Kconfig | 26 + .../video/rk_camsys/ext_flashled_drv/Makefile | 3 + .../rk_camsys/ext_flashled_drv/flashlight.c | 544 +++++++++++ .../rk_camsys/ext_flashled_drv/flashlight.h | 138 +++ .../rk_camsys/ext_flashled_drv/leds-rt8547.c | 881 ++++++++++++++++++ .../rk_camsys/ext_flashled_drv/leds-rt8547.h | 84 ++ .../ext_flashled_drv/rk_ext_fshled_ctl.c | 168 ++++ .../ext_flashled_drv/rk_ext_fshled_ctl.h | 10 + .../video/rk_camsys/ext_flashled_drv/rtfled.c | 401 ++++++++ .../video/rk_camsys/ext_flashled_drv/rtfled.h | 147 +++ include/media/camsys_head.h | 8 +- 18 files changed, 2455 insertions(+), 8 deletions(-) create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/Kconfig create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/Makefile create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.c create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.h create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.c create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.h create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.c create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.h create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/rtfled.c create mode 100755 drivers/media/video/rk_camsys/ext_flashled_drv/rtfled.h diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index 1a636b52c3ef..1591c45da8e1 100644 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -387,6 +387,9 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FLASHLIGHT=y +CONFIG_LEDS_RT8547=y +# CONFIG_RK30_CAMERA_ONEFRAME is not set CONFIG_MALI_MIDGARD=m CONFIG_MALI_MIDGARD_DVFS=y CONFIG_MALI_MIDGARD_RT_PM=y diff --git a/drivers/media/video/rk_camsys/Kconfig b/drivers/media/video/rk_camsys/Kconfig index 8d22522235c7..bd2b7e7bc970 100755 --- a/drivers/media/video/rk_camsys/Kconfig +++ b/drivers/media/video/rk_camsys/Kconfig @@ -5,6 +5,8 @@ config CAMSYS_DRV menu "RockChip camera system driver" depends on CAMSYS_DRV +source "drivers/media/video/rk_camsys/ext_flashled_drv/Kconfig" + config CAMSYS_MRV tristate "camsys driver for marvin isp " default y @@ -16,3 +18,4 @@ config CAMSYS_CIF ---help--- endmenu + diff --git a/drivers/media/video/rk_camsys/Makefile b/drivers/media/video/rk_camsys/Makefile index dfd880042164..5704148ecc43 100755 --- a/drivers/media/video/rk_camsys/Makefile +++ b/drivers/media/video/rk_camsys/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_CAMSYS_DRV) += camsys_drv.o obj-$(CONFIG_CAMSYS_MRV) += camsys_marvin.o camsys_mipicsi_phy.o camsys_soc_priv.o obj-$(CONFIG_CAMSYS_CIF) += camsys_cif.o +obj-y += ext_flashled_drv/ diff --git a/drivers/media/video/rk_camsys/camsys_drv.c b/drivers/media/video/rk_camsys/camsys_drv.c index f0a088a69e1f..93bbab53a200 100755 --- a/drivers/media/video/rk_camsys/camsys_drv.c +++ b/drivers/media/video/rk_camsys/camsys_drv.c @@ -5,6 +5,7 @@ #include "camsys_mipicsi_phy.h" #include "camsys_gpio.h" #include "camsys_soc_priv.h" +#include "ext_flashled_drv/rk_ext_fshled_ctl.h" unsigned int camsys_debug=1; module_param(camsys_debug, int, S_IRUGO|S_IWUSR); @@ -186,6 +187,18 @@ static int camsys_extdev_register(camsys_devio_name_t *devio, camsys_dev_t *cams extdev->dev_cfg = devio->dev_cfg; extdev->fl.fl.active = devio->fl.fl.active; + extdev->fl.ext_fsh_dev = NULL; + //should register external flash device ? + if(strlen(devio->fl.fl_drv_name) && (strcmp(devio->fl.fl_drv_name,"Internal") != 0) + && (strcmp(devio->fl.fl_drv_name,"NC") != 0)){ + //register flash device + extdev->fl.ext_fsh_dev = camsys_register_ext_fsh_dev(&devio->fl); + if(extdev->fl.ext_fsh_dev == NULL){ + camsys_err("register ext flash %s failed!",devio->fl.fl_drv_name); + err = -EINVAL; + goto fail; + } + } regulator_info = &devio->avdd; regulator = &extdev->avdd; for (i=(CamSys_Vdd_Start_Tag+1); ifl.ext_fsh_dev != NULL){ + camsys_deregister_ext_fsh_dev(extdev->fl.ext_fsh_dev); + } //spin_lock(&camsys_dev->lock); mutex_lock(&camsys_dev->extdevs.mut); list_del_init(&extdev->list); @@ -340,6 +356,10 @@ static int camsys_extdev_deregister(unsigned int dev_id, camsys_dev_t *camsys_de } gpio++; } + + if(extdev->fl.ext_fsh_dev != NULL){ + camsys_deregister_ext_fsh_dev(extdev->fl.ext_fsh_dev); + } camsys_trace(1,"Extdev(dev_id: 0x%x) is deregister success", extdev->dev_id); list_del_init(&extdev->list); list_del_init(&extdev->active); @@ -387,7 +407,7 @@ static int camsys_sysctl(camsys_sysctrl_t *devctl, camsys_dev_t *camsys_dev) } case CamSys_Flash_Trigger: { - camsys_dev->flash_trigger_cb(camsys_dev, devctl->on); + camsys_dev->flash_trigger_cb(camsys_dev,devctl->rev[0], devctl->on); break; } case CamSys_IOMMU: @@ -423,6 +443,8 @@ static int camsys_sysctl(camsys_sysctrl_t *devctl, camsys_dev_t *camsys_dev) } } } + }else if(devctl->ops == CamSys_Flash_Trigger){ + err = camsys_ext_fsh_ctrl(extdev->fl.ext_fsh_dev,devctl->rev[0],devctl->on); } } else { @@ -1184,7 +1206,7 @@ static int camsys_platform_probe(struct platform_device *pdev){ list_add_tail(&camsys_dev->list, &camsys_devs.devs); spin_unlock(&camsys_devs.lock); - + camsys_init_ext_fsh_module(); camsys_trace(1, "Probe %s device success ", dev_name(&pdev->dev)); return 0; request_mem_fail: @@ -1259,6 +1281,8 @@ static int camsys_platform_remove(struct platform_device *pdev) list_del_init(&camsys_dev->list); spin_unlock(&camsys_devs.lock); + camsys_deinit_ext_fsh_module(); + kfree(camsys_dev); camsys_dev=NULL; } else { diff --git a/drivers/media/video/rk_camsys/camsys_gpio.h b/drivers/media/video/rk_camsys/camsys_gpio.h index 6d6e81e1fe4e..e75fac61b526 100755 --- a/drivers/media/video/rk_camsys/camsys_gpio.h +++ b/drivers/media/video/rk_camsys/camsys_gpio.h @@ -56,7 +56,11 @@ static inline unsigned int camsys_gpio_group(unsigned char *io_name) group = 5; } else if (strstr(io_name,"PIN6")) { group = 6; - } + } else if (strstr(io_name,"PIN7")) { + group = 7; + } else if (strstr(io_name,"PIN8")) { + group = 8; + } return group; } diff --git a/drivers/media/video/rk_camsys/camsys_internal.h b/drivers/media/video/rk_camsys/camsys_internal.h index c0c413b80484..58b372dfb41b 100755 --- a/drivers/media/video/rk_camsys/camsys_internal.h +++ b/drivers/media/video/rk_camsys/camsys_internal.h @@ -103,8 +103,11 @@ 1) enable or disable IOMMU just depending on CONFIG_ROCKCHIP_IOMMU. *v0.0x17.0: 1) isp iommu status depend on vpu iommu status. +*v0.0x18.0: + 1) add flashlight RT8547 driver + 2) support torch mode */ -#define CAMSYS_DRIVER_VERSION KERNEL_VERSION(0,0x17,0) +#define CAMSYS_DRIVER_VERSION KERNEL_VERSION(0,0x18,0) #define CAMSYS_PLATFORM_DRV_NAME "RockChip-CamSys" @@ -197,6 +200,9 @@ typedef struct camsys_gpio_s { } camsys_gpio_t; typedef struct camsys_flash_s { camsys_gpio_t fl; + camsys_gpio_t fl_en; + void* ext_fsh_dev; + //flash call back } camsys_flash_t; typedef struct camsys_extdev_s { unsigned char dev_name[CAMSYS_NAME_LEN]; @@ -264,7 +270,7 @@ typedef struct camsys_dev_s { int (*phy_cb) (camsys_extdev_t *extdev, camsys_sysctrl_t *devctl, void* ptr); int (*iomux)(camsys_extdev_t *extdev,void *ptr); int (*platform_remove)(struct platform_device *pdev); - int (*flash_trigger_cb)(void *ptr, unsigned int on); + int (*flash_trigger_cb)(void *ptr,int mode , unsigned int on); int (*iommu_cb)(void *ptr,camsys_sysctrl_t *devctl); } camsys_dev_t; diff --git a/drivers/media/video/rk_camsys/camsys_marvin.c b/drivers/media/video/rk_camsys/camsys_marvin.c index c6a61d8b7317..a7544ca3080c 100755 --- a/drivers/media/video/rk_camsys/camsys_marvin.c +++ b/drivers/media/video/rk_camsys/camsys_marvin.c @@ -126,7 +126,7 @@ fail: return -1; } -static int camsys_mrv_flash_trigger_cb(void *ptr,unsigned int on) +static int camsys_mrv_flash_trigger_cb(void *ptr,int mode,unsigned int on) { camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr; struct device *dev = &(camsys_dev->pdev->dev); diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/Kconfig b/drivers/media/video/rk_camsys/ext_flashled_drv/Kconfig new file mode 100755 index 000000000000..370ee54b73e0 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/Kconfig @@ -0,0 +1,26 @@ +config FLASHLIGHT + bool "Flashlight Support" + default n + help + This option enables the led sysfs class in /sys/class/flashlight. + +config LEDS_RT8547 + bool "LED Support for RT8547" + select RT_FLASH_LED + default n + help + This option enabled support for RT8547 LED drivers + +config LEDS_RT8547_DBG + bool "LED RT8547 Debug Info" + depends on LEDS_RT8547 + default n + help + This option enabled RT8547 LED drivers debug option + +config RT_FLASH_LED + bool "Richtek flash LED driver support" + depends on FLASHLIGHT + default n + help + Say Y here to enable Richtek's flash LED driver HAL architecture diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/Makefile b/drivers/media/video/rk_camsys/ext_flashled_drv/Makefile new file mode 100755 index 000000000000..c96b20eb4769 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_FLASHLIGHT) += flashlight.o rk_ext_fshled_ctl.o +obj-$(CONFIG_RT_FLASH_LED) += rtfled.o +obj-$(CONFIG_LEDS_RT8547) += leds-rt8547.o diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.c b/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.c new file mode 100755 index 000000000000..f63a65f8d440 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.c @@ -0,0 +1,544 @@ +/* drivers/leds/flashlight.c + * Flashlight Class Device Driver + * + * Copyright (C) 2013 Richtek Technology Corp. + * Author: Patrick Chang + * + * 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 +#include +#include "flashlight.h" +#include +#include +#include + +static const char const *flashlight_type_string[] = { + [FLASHLIGHT_TYPE_XENON] = "Xenon", + [FLASHLIGHT_TYPE_LED] = "LED", + [FLASHLIFHT_TYPE_BULB] = "Bulb", +}; + +static const char const *flashlight_mode_string[] = { + [FLASHLIGHT_MODE_OFF] = "Off", + [FLASHLIGHT_MODE_TORCH] = "Torch", + [FLASHLIGHT_MODE_FLASH] = "Flash", + [FLASHLIGHT_MODE_MIXED] = "Mixed", +}; + +static ssize_t flashlight_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%s\n", + flashlight_dev->props.alias_name ? + flashlight_dev->props.alias_name : "anonymous"); +} + +static ssize_t flashlight_show_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%s\n", + flashlight_type_string[flashlight_dev->props.type]); +} + +static ssize_t flashlight_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%s\n", + flashlight_mode_string[flashlight_dev->props.mode]); +} + +static ssize_t flashlight_show_torch_max_brightness(struct device *dev, + struct device_attribute + *attr, char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.torch_max_brightness); +} + +static ssize_t flashlight_show_strobe_max_brightness(struct device *dev, + struct device_attribute + *attr, char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", + flashlight_dev->props.strobe_max_brightness); +} + +static ssize_t flashlight_show_color_temperature(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.color_temperature); +} + +static ssize_t flashlight_show_strobe_delay(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.strobe_delay); +} + +static ssize_t flashlight_store_strobe_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + long timeout; + + rc = kstrtol(buf, 0, &timeout); + if (rc) + return rc; + rc = flashlight_dev->ops->set_strobe_timeout(flashlight_dev, timeout); + if (rc == 0) + rc = count; + return rc; +} + +static ssize_t flashlight_show_strobe_timeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.strobe_timeout); +} + +static ssize_t flashlight_store_torch_brightness(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + long brightness; + + rc = kstrtol(buf, 0, &brightness); + if (rc) + return rc; + + rc = -ENXIO; + + mutex_lock(&flashlight_dev->ops_lock); + if (flashlight_dev->ops && flashlight_dev->ops->set_torch_brightness) { + if (brightness > flashlight_dev->props.torch_max_brightness) + rc = -EINVAL; + else { + pr_debug("flashlight: set torch brightness to %ld\n", + brightness); + flashlight_dev->props.torch_brightness = brightness; + flashlight_dev->ops-> + set_torch_brightness(flashlight_dev, brightness); + rc = count; + } + } + mutex_unlock(&flashlight_dev->ops_lock); + + return rc; +} + +static ssize_t flashlight_show_torch_brightness(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.torch_brightness); +} + +static ssize_t flashlight_store_strobe_brightness(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + long brightness; + + rc = kstrtol(buf, 0, &brightness); + if (rc) + return rc; + + rc = -ENXIO; + + mutex_lock(&flashlight_dev->ops_lock); + if (flashlight_dev->ops && flashlight_dev->ops->set_strobe_brightness) { + if (brightness > flashlight_dev->props.strobe_max_brightness) + rc = -EINVAL; + else { + pr_debug("flashlight: set strobe brightness to %ld\n", + brightness); + flashlight_dev->props.strobe_brightness = brightness; + flashlight_dev->ops-> + set_strobe_brightness(flashlight_dev, brightness); + rc = count; + } + } + mutex_unlock(&flashlight_dev->ops_lock); + return rc; +} + +static ssize_t flashlight_show_strobe_brightness(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + return sprintf(buf, "%d\n", flashlight_dev->props.strobe_brightness); +} + +static struct class *flashlight_class; + +static int flashlight_suspend(struct device *dev, pm_message_t state) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + if (flashlight_dev->ops) + flashlight_dev->ops->suspend(flashlight_dev, state); + return 0; +} + +static int flashlight_resume(struct device *dev) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + if (flashlight_dev->ops) + flashlight_dev->ops->resume(flashlight_dev); + return 0; +} + +static void flashlight_device_release(struct device *dev) +{ + struct flashlight_device *flashlight_dev = to_flashlight_device(dev); + + kfree(flashlight_dev); +} + +static struct device_attribute flashlight_device_attributes[] = { + __ATTR(name, 0444, flashlight_show_name, NULL), + __ATTR(type, 0444, flashlight_show_type, NULL), + __ATTR(mode, 0444, flashlight_show_mode, NULL), + __ATTR(torch_max_brightness, 0444, + flashlight_show_torch_max_brightness, NULL), + __ATTR(strobe_max_brightness, 0444, + flashlight_show_strobe_max_brightness, NULL), + __ATTR(color_temperature, 0444, + flashlight_show_color_temperature, NULL), + __ATTR(strobe_delay, 0444, + flashlight_show_strobe_delay, NULL), + __ATTR(strobe_timeout, 0644, + flashlight_show_strobe_timeout, + flashlight_store_strobe_timeout), + __ATTR(torch_brightness, 0644, + flashlight_show_torch_brightness, + flashlight_store_torch_brightness), + __ATTR(strobe_brightness, 0644, + flashlight_show_strobe_brightness, + flashlight_store_strobe_brightness), + __ATTR_NULL, +}; + +/** + * flashlight_device_register - create and register a new object of + * flashlight_device class. + * @name: the name of the new object(must be the same as the name of the + * respective framebuffer device). + * @parent: a pointer to the parent device + * @devdata: an optional pointer to be stored for private driver use. The + * methods may retrieve it by using bl_get_data(flashlight_dev). + * @ops: the flashlight operations structure. + * + * Creates and registers new flashlight device. Returns either an + * ERR_PTR() or a pointer to the newly allocated device. + */ +struct flashlight_device *flashlight_device_register(const char *name, + struct device *parent, + void *devdata, + const struct flashlight_ops + *ops, + const struct + flashlight_properties + *props) +{ + struct flashlight_device *flashlight_dev; + int rc; + + pr_debug("flashlight_device_register: name=%s\n", name); + flashlight_dev = kzalloc(sizeof(*flashlight_dev), GFP_KERNEL); + if (!flashlight_dev) + return ERR_PTR(-ENOMEM); + + mutex_init(&flashlight_dev->ops_lock); + flashlight_dev->dev.class = flashlight_class; + flashlight_dev->dev.parent = parent; + flashlight_dev->dev.release = flashlight_device_release; + dev_set_name(&flashlight_dev->dev, name); + dev_set_drvdata(&flashlight_dev->dev, devdata); + /* Copy properties */ + if (props) { + memcpy(&flashlight_dev->props, props, + sizeof(struct flashlight_properties)); + } + rc = device_register(&flashlight_dev->dev); + if (rc) { + kfree(flashlight_dev); + return ERR_PTR(rc); + } + flashlight_dev->ops = ops; + return flashlight_dev; +} +EXPORT_SYMBOL(flashlight_device_register); + +/** + * flashlight_device_unregister - unregisters a flashlight device object. + * @flashlight_dev: the flashlight device object to be unregistered and freed. + * + * Unregisters a previously registered via flashlight_device_register object. + */ +void flashlight_device_unregister(struct flashlight_device *flashlight_dev) +{ + if (!flashlight_dev) + return; + + mutex_lock(&flashlight_dev->ops_lock); + flashlight_dev->ops = NULL; + mutex_unlock(&flashlight_dev->ops_lock); + device_unregister(&flashlight_dev->dev); +} +EXPORT_SYMBOL(flashlight_device_unregister); + +int flashlight_list_color_temperature(struct flashlight_device *flashlight_dev, + int selector) +{ + if (flashlight_dev->ops && flashlight_dev->ops->list_color_temperature) + return flashlight_dev->ops-> + list_color_temperature(flashlight_dev, selector); + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_list_color_temperature); + +int flashlight_set_color_temperature(struct flashlight_device *flashlight_dev, + int minK, int maxK) +{ + int selector = 0; + int rc; + + if ((flashlight_dev->ops == NULL) || + (flashlight_dev->ops->set_color_temperature == NULL)) + return -EINVAL; + for (selector = 0;; selector++) { + rc = flashlight_list_color_temperature(flashlight_dev, + selector); + if (rc < 0) + return rc; + if (rc >= minK && rc <= maxK) { + mutex_lock(&flashlight_dev->ops_lock); + rc = flashlight_dev->ops-> + set_color_temperature(flashlight_dev, rc); + mutex_unlock(&flashlight_dev->ops_lock); + if (rc == 0) + flashlight_dev->props.color_temperature = rc; + return rc; + } + + } + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_set_color_temperature); + +int flashlight_set_torch_brightness(struct flashlight_device *flashlight_dev, + int brightness_level) +{ + int rc; + + if ((flashlight_dev->ops == NULL) || + (flashlight_dev->ops->set_torch_brightness == NULL)) + return -EINVAL; + if (brightness_level > flashlight_dev->props.torch_max_brightness) + return -EINVAL; + mutex_lock(&flashlight_dev->ops_lock); + rc = flashlight_dev->ops->set_torch_brightness(flashlight_dev, + brightness_level); + mutex_unlock(&flashlight_dev->ops_lock); + if (rc < 0) + return rc; + flashlight_dev->props.torch_brightness = brightness_level; + return rc; + +} +EXPORT_SYMBOL(flashlight_set_torch_brightness); + +int flashlight_set_strobe_brightness(struct flashlight_device *flashlight_dev, + int brightness_level) +{ + int rc; + + if ((flashlight_dev->ops == NULL) || + (flashlight_dev->ops->set_strobe_brightness == NULL)) + return -EINVAL; + if (brightness_level > flashlight_dev->props.strobe_max_brightness) + return -EINVAL; + mutex_lock(&flashlight_dev->ops_lock); + rc = flashlight_dev->ops->set_strobe_brightness(flashlight_dev, + brightness_level); + mutex_unlock(&flashlight_dev->ops_lock); + if (rc < 0) + return rc; + flashlight_dev->props.strobe_brightness = brightness_level; + return rc; +} +EXPORT_SYMBOL(flashlight_set_strobe_brightness); + +int flashlight_list_strobe_timeout(struct flashlight_device *flashlight_dev, + int selector) +{ + if (flashlight_dev->ops && flashlight_dev->ops->list_strobe_timeout) { + return flashlight_dev->ops->list_strobe_timeout(flashlight_dev, + selector); + } + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_list_strobe_timeout); + +int flashlight_set_strobe_timeout(struct flashlight_device *flashlight_dev, + int min_ms, int max_ms) +{ + int selector = 0; + int rc = -EINVAL; + int timeout; + + if ((flashlight_dev->ops == NULL) || + (flashlight_dev->ops->set_strobe_timeout == NULL)) + return -EINVAL; + for (selector = 0;; selector++) { + timeout = + flashlight_list_strobe_timeout(flashlight_dev, selector); + if (timeout < 0) + return timeout; + if (timeout >= min_ms && timeout <= max_ms) { + mutex_lock(&flashlight_dev->ops_lock); + rc = flashlight_dev->ops-> + set_strobe_timeout(flashlight_dev, timeout); + mutex_unlock(&flashlight_dev->ops_lock); + if (rc == 0) + flashlight_dev->props.strobe_timeout = timeout; + return rc; + } + } + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_set_strobe_timeout); + +int flashlight_set_mode(struct flashlight_device *flashlight_dev, int mode) +{ + int rc; + + if (mode >= FLASHLIGHT_MODE_MAX || mode < 0) + return -EINVAL; + if ((flashlight_dev->ops == NULL) || + (flashlight_dev->ops->set_mode == NULL)) { + flashlight_dev->props.mode = mode; + return 0; + } + mutex_lock(&flashlight_dev->ops_lock); + rc = flashlight_dev->ops->set_mode(flashlight_dev, mode); + mutex_unlock(&flashlight_dev->ops_lock); + if (rc < 0) + return rc; + flashlight_dev->props.mode = mode; + return rc; +} +EXPORT_SYMBOL(flashlight_set_mode); + +int flashlight_strobe(struct flashlight_device *flashlight_dev) +{ + if (flashlight_dev->props.mode == FLASHLIGHT_MODE_FLASH + || flashlight_dev->props.mode == FLASHLIGHT_MODE_MIXED) { + if (flashlight_dev->ops == NULL || + flashlight_dev->ops->strobe == NULL) + return -EINVAL; + return flashlight_dev->ops->strobe(flashlight_dev); + } + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_strobe); + +static int flashlight_match_device_by_name(struct device *dev, const void *data) +{ + const char *name = data; + + return strcmp(dev_name(dev), name) == 0; +} + +struct flashlight_device *find_flashlight_by_name(char *name) +{ + struct device *dev; + + if (!name) + return (struct flashlight_device *)NULL; + dev = class_find_device(flashlight_class, NULL, (void*)name, + flashlight_match_device_by_name); + + return dev ? to_flashlight_device(dev) : NULL; + +} +EXPORT_SYMBOL(find_flashlight_by_name); + +int flashlight_strobe_charge(struct flashlight_device *flashlight_dev, + flashlight_charge_event_cb cb, void *data, + int start) +{ + + if (flashlight_dev->ops->strobe_charge) + return flashlight_dev->ops->strobe_charge(flashlight_dev, + cb, data, start); + if (flashlight_dev->props.type == FLASHLIGHT_TYPE_LED) { + if (cb) + cb(data, 0); + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(flashlight_strobe_charge); + +static void __exit flashlight_class_exit(void) +{ + class_destroy(flashlight_class); +} + +static int __init flashlight_class_init(void) +{ + flashlight_class = class_create(THIS_MODULE, "flashlight"); + if (IS_ERR(flashlight_class)) { + pr_err( + "Unable to create flashlight class; errno = %ld\n", + PTR_ERR(flashlight_class)); + return PTR_ERR(flashlight_class); + } + flashlight_class->dev_attrs = flashlight_device_attributes; + flashlight_class->suspend = flashlight_suspend; + flashlight_class->resume = flashlight_resume; + return 0; +} +subsys_initcall(flashlight_class_init); +module_exit(flashlight_class_exit); + +MODULE_DESCRIPTION("Flashlight Class Device"); +MODULE_AUTHOR("Patrick Chang "); +MODULE_VERSION("1.0.0_G"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.h b/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.h new file mode 100755 index 000000000000..48b1ea22db81 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/flashlight.h @@ -0,0 +1,138 @@ +/* include/linux/leds/flashlight.h + * Header of Flashlight Class Device Driver + * + * Copyright (C) 2013 Richtek Technology Corp. + * Patrick Chang + * + * 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. + */ + +#ifndef LINUX_LEDS_FLASHLIGHT_H +#define LINUX_LEDS_FLASHLIGHT_H + +#include +#include + +typedef enum flashlight_type { + FLASHLIGHT_TYPE_XENON = 0, + FLASHLIGHT_TYPE_LED, + FLASHLIFHT_TYPE_BULB, + FLASHLIGHT_TYPE_MAX, +} flashlight_type_t; +typedef enum flashlight_mode { + FLASHLIGHT_MODE_OFF = 0, + FLASHLIGHT_MODE_TORCH, + FLASHLIGHT_MODE_FLASH, + /* MIXED mode means TORCH + FLASH */ + FLASHLIGHT_MODE_MIXED, + FLASHLIGHT_MODE_MAX, +} flashlight_mode_t; + +struct flashlight_device; + +typedef int (*flashlight_charge_event_cb) (void *data, int remains); + +struct flashlight_ops { + int (*set_torch_brightness)(struct flashlight_device *, int); + int (*set_strobe_brightness)(struct flashlight_device *, int); + int (*set_strobe_timeout)(struct flashlight_device *, int); + int (*list_strobe_timeout)(struct flashlight_device *, int); + int (*set_mode)(struct flashlight_device *, int); + int (*set_color_temperature)(struct flashlight_device *, int); + int (*list_color_temperature)(struct flashlight_device *, int); + int (*strobe_charge)(struct flashlight_device *, + flashlight_charge_event_cb, void *, int); + int (*strobe)(struct flashlight_device *); + int (*suspend)(struct flashlight_device *, pm_message_t); + int (*resume)(struct flashlight_device *); +}; + +struct flashlight_properties { + /* Flashlight type */ + enum flashlight_type type; + /* Xenon type flashlight doesn't support torch mode */ + enum flashlight_mode mode; + /* Color temperature, unit: K, 0 means unknown */ + int color_temperature; + int torch_brightness; + int torch_max_brightness; + int strobe_brightness; + int strobe_max_brightness; + int strobe_delay; + int strobe_timeout; + const char *alias_name; +}; + +struct flashlight_device { + /* Flashlight properties */ + struct flashlight_properties props; + const struct flashlight_ops *ops; + struct mutex ops_lock; + struct device dev; +}; + +extern struct flashlight_device *flashlight_device_register(const char *name, + struct device *parent, + void *devdata, + const struct + flashlight_ops * ops, + const struct + flashlight_properties + *props); +extern void flashlight_device_unregister(struct flashlight_device + *flashlight_dev); +extern struct flashlight_device *find_flashlight_by_name(char *name); +extern int flashlight_list_color_temperature(struct flashlight_device + *flashlight_dev, int selector); +extern int flashlight_set_color_temperature(struct flashlight_device + *flashlight_dev, int minK, + int maxK); +extern int flashlight_set_torch_brightness(struct flashlight_device + *flashlight_dev, + int brightness_level); +extern int flashlight_set_strobe_brightness(struct flashlight_device + *flashlight_dev, + int brightness_level); +extern int flashlight_list_strobe_timeout(struct flashlight_device + *flashlight_dev, int selector); +extern int flashlight_set_strobe_timeout(struct flashlight_device + *flashlight_dev, int min_ms, + int max_ms); +extern int flashlight_set_mode(struct flashlight_device *flashlight_dev, + int mode); + +extern int flashlight_strobe(struct flashlight_device *flashlight_dev); + +/* flashlight_charge_event_cb(void *data, int remains) + * description : + * callback function of flashlight charging progress + * arguments : + * @data : data pass by flashlight_strobe_charge() + * @remains : remained time to full chargerd, unit : ms ; 0 means ready + * return : 0 means succeess, otherwise see definitions in errno.h + */ + +/* flashlight_strobe_chargestruct flashlight_device *flashlight_dev, + * flashlight_charge_event_cb cb, void *data, int start) + * description : + * flashlight start / stop charging + * @flashlight_dev : flashlight devices + * @flashlight_charge_event_cb : callback function to report progress + * @data : bypass to callback function + * @start : 1 means start; 0 means stop + */ +extern int flashlight_strobe_charge(struct flashlight_device *flashlight_dev, + flashlight_charge_event_cb cb, void *data, + int start); + +#define to_flashlight_device(obj) \ + container_of(obj, struct flashlight_device, dev) + +static inline void *flashlight_get_data(struct flashlight_device + *flashlight_dev) +{ + return dev_get_drvdata(&flashlight_dev->dev); +} +#endif /*LINUX_LEDS_FLASHLIGHT_H */ diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.c b/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.c new file mode 100755 index 000000000000..f4cdc7e87023 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.c @@ -0,0 +1,881 @@ +/* + * drivers/leds/leds-rt8547.c + * Driver for Richtek RT8547 LED Flash IC + * + * Copyright (C) 2014 Richtek Technology Corp. + * cy_huang + * + * 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 +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif /* #ifdef CONFIG_OF */ +#ifdef CONFIG_DEBUG_FS +#include +#include +#endif /* #ifdef CONFIG_DEBUG_FS */ + +#include "rtfled.h" +#include "leds-rt8547.h" + +struct rt8547_chip { + rt_fled_info_t base; + struct device *dev; + struct rt8547_platform_data *pdata; + spinlock_t io_lock; + unsigned char suspend:1; + int in_use_mode; +#ifdef CONFIG_DEBUG_FS + struct flashlight_device *fled_dev; + unsigned char reg_addr; + unsigned char reg_data; +#endif /* #ifdef CONFIG_DEBUG_FS */ +}; + +#ifdef CONFIG_DEBUG_FS +struct rt_debug_st { + void *info; + int id; +}; + +enum { + RT8547_DBG_REG, + RT8547_DBG_DATA, + RT8547_DBG_REGS, + RT8547_DBG_FLED, + RT8547_DBG_MAX +}; + +static struct dentry *debugfs_rt_dent; +static struct dentry *debugfs_file[RT8547_DBG_MAX]; +static struct rt_debug_st rtdbg_data[RT8547_DBG_MAX]; +#endif /* #ifdef CONFIG_DEBUG_FS */ + +static unsigned char rt8547_reg_initval[] = { + 0x06, /* REG 0x01 */ + 0x12, /* REG 0x02 */ + 0x02, /* REG 0x03 */ + 0x0F, /* REG 0x04 */ +}; + +static inline int rt8547_send_bit(struct rt8547_platform_data *pdata, + unsigned char bit) +{ + if (bit) { + gpio_set_value(pdata->flset_gpio, (~(pdata->flset_active) & 0x1)); + udelay(RT8547_SHORT_DELAY); + gpio_set_value(pdata->flset_gpio, ((pdata->flset_active) & 0x1)); + udelay(RT8547_LONG_DELAY); + } else { + gpio_set_value(pdata->flset_gpio, (~(pdata->flset_active) & 0x1)); + udelay(RT8547_LONG_DELAY); + gpio_set_value(pdata->flset_gpio, ((pdata->flset_active) & 0x1)); + udelay(RT8547_SHORT_DELAY); + } + return 0; +} + +static inline int rt8547_send_byte(struct rt8547_platform_data *pdata, + unsigned char byte) +{ + int i; + + /*Send order is high bit to low bit */ + for (i = 7; i >= 0; i--) + rt8547_send_bit(pdata, byte & (0x1 << i)); + return 0; +} + +static inline int rt8547_send_special_byte(struct rt8547_platform_data *pdata, + unsigned char byte) +{ + int i; + + /*Only send three bit for register address */ + for (i = 2; i >= 0; i--) + rt8547_send_bit(pdata, byte & (0x1 << i)); + return 0; +} + +static inline int rt8547_start_xfer(struct rt8547_platform_data *pdata) +{ + gpio_set_value(pdata->flset_gpio, ((pdata->flset_active) & 0x1)); + udelay(RT8547_START_DELAY); + return 0; +} + +static inline int rt8547_stop_xfer(struct rt8547_platform_data *pdata) +{ + /*Redundant one bit as the stop condition */ + rt8547_send_bit(pdata, 1); + return 0; +} + +static int rt8547_send_data(struct rt8547_chip *chip, unsigned char reg, + unsigned char data) +{ + struct rt8547_platform_data *pdata = chip->pdata; + unsigned long flags; + unsigned char xfer_data[3]; /*0: adddr, 1: reg, 2: reg data*/ + + xfer_data[0] = RT8547_ONEWIRE_ADDR; + xfer_data[1] = reg; + xfer_data[2] = data; + RT_DBG("rt8547-> 0: 0x%02x, 1: 0x%02x, 2: 0x%02x\n", xfer_data[0], + xfer_data[1], xfer_data[2]); + spin_lock_irqsave(&chip->io_lock, flags); + rt8547_start_xfer(pdata); + rt8547_send_byte(pdata, xfer_data[0]); + rt8547_send_special_byte(pdata, xfer_data[1]); + rt8547_send_byte(pdata, xfer_data[2]); + rt8547_stop_xfer(pdata); + spin_unlock_irqrestore(&chip->io_lock, flags); + /*write back to reg array*/ + rt8547_reg_initval[reg - 1] = data; + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int reg_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, long int *param1, int num_of_par) +{ + char *token; + int base, cnt; + + token = strsep(&buf, " "); + + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token != NULL) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtoul(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else + return -EINVAL; + } + return 0; +} + +static ssize_t reg_debug_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct rt_debug_st *st = filp->private_data; + struct rt8547_chip *di = st->info; + char lbuf[1000]; + int i = 0, j = 0; + + lbuf[0] = '\0'; + switch (st->id) { + case RT8547_DBG_REG: + snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_addr); + break; + case RT8547_DBG_DATA: + di->reg_data = rt8547_reg_initval[di->reg_addr - 1]; + snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_data); + break; + case RT8547_DBG_REGS: + for (i = RT8547_FLED_REG0; i < RT8547_FLED_REGMAX; i++) + j += snprintf(lbuf + j, 20, "0x%02x:%02x\n", i, + rt8547_reg_initval[i - 1]); + break; + case RT8547_DBG_FLED: + snprintf(lbuf, sizeof(lbuf), "%d\n", di->in_use_mode); + break; + default: + return -EINVAL; + + } + return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf)); +} + +static ssize_t reg_debug_write(struct file *filp, + const char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + struct rt_debug_st *st = filp->private_data; + struct rt8547_chip *di = st->info; + char lbuf[32]; + int rc; + long int param[5]; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + + switch (st->id) { + case RT8547_DBG_REG: + rc = get_parameters(lbuf, param, 1); + if ((param[0] < RT8547_FLED_REGMAX) && (rc == 0)) { + if ((param[0] >= RT8547_FLED_REG0 + && param[0] <= RT8547_FLED_REG3)) + di->reg_addr = (unsigned char)param[0]; + else + rc = -EINVAL; + } else + rc = -EINVAL; + break; + case RT8547_DBG_DATA: + rc = get_parameters(lbuf, param, 1); + if ((param[0] <= 0xff) && (rc == 0)) { + rt8547_send_data(di, di->reg_addr, + (unsigned char)param[0]); + } else + rc = -EINVAL; + break; + case RT8547_DBG_FLED: + if (!di->fled_dev) + di->fled_dev = find_flashlight_by_name("rt-flash-led"); + rc = get_parameters(lbuf, param, 1); + if ((param[0] <= FLASHLIGHT_MODE_FLASH) && (rc == 0) + && di->fled_dev) { + switch (param[0]) { + case FLASHLIGHT_MODE_TORCH: + flashlight_set_torch_brightness(di->fled_dev, + 2); + flashlight_set_mode(di->fled_dev, + FLASHLIGHT_MODE_TORCH); + break; + case FLASHLIGHT_MODE_FLASH: + flashlight_set_strobe_timeout(di->fled_dev, + 256, 256); + flashlight_set_strobe_brightness(di->fled_dev, + 18); + flashlight_set_mode(di->fled_dev, + FLASHLIGHT_MODE_FLASH); + flashlight_strobe(di->fled_dev); + break; + case FLASHLIGHT_MODE_OFF: + flashlight_set_mode(di->fled_dev, + FLASHLIGHT_MODE_OFF); + break; + } + } else + rc = -EINVAL; + break; + default: + return -EINVAL; + } + if (rc == 0) + rc = cnt; + return rc; +} + +static const struct file_operations reg_debug_ops = { + .open = reg_debug_open, + .write = reg_debug_write, + .read = reg_debug_read +}; + +static void rt8547_create_debugfs(struct rt8547_chip *chip) +{ + RT_DBG("add debugfs for RT8547\n"); + debugfs_rt_dent = debugfs_create_dir("rt8547_dbg", 0); + if (!IS_ERR(debugfs_rt_dent)) { + rtdbg_data[0].info = chip; + rtdbg_data[0].id = RT8547_DBG_REG; + debugfs_file[0] = debugfs_create_file("reg", + S_IFREG | S_IRUGO, + debugfs_rt_dent, + (void *)&rtdbg_data[0], + ®_debug_ops); + + rtdbg_data[1].info = chip; + rtdbg_data[1].id = RT8547_DBG_DATA; + debugfs_file[1] = debugfs_create_file("data", + S_IFREG | S_IRUGO, + debugfs_rt_dent, + (void *)&rtdbg_data[1], + ®_debug_ops); + + rtdbg_data[2].info = chip; + rtdbg_data[2].id = RT8547_DBG_REGS; + debugfs_file[2] = debugfs_create_file("regs", + S_IFREG | S_IRUGO, + debugfs_rt_dent, + (void *)&rtdbg_data[2], + ®_debug_ops); + + rtdbg_data[3].info = chip; + rtdbg_data[3].id = RT8547_DBG_FLED; + debugfs_file[3] = debugfs_create_file("fled", + S_IFREG | S_IRUGO, + debugfs_rt_dent, + (void *)&rtdbg_data[3], + ®_debug_ops); + } else { + dev_err(chip->dev, "create debugfs failed\n"); + } +} + +static void rt8547_remove_debugfs(void) +{ + if (!IS_ERR(debugfs_rt_dent)) + debugfs_remove_recursive(debugfs_rt_dent); +} +#endif /* #ifdef CONFIG_DEBUG_FS */ + +static inline void rt8547_fled_power_on(struct rt8547_platform_data *pdata) +{ + if (gpio_is_valid(pdata->flset_gpio)) + gpio_set_value(pdata->flset_gpio, ((pdata->flset_active) & 0x1)); +} + +static inline void rt8547_fled_power_off(struct rt8547_platform_data *pdata) +{ + if (gpio_is_valid(pdata->flset_gpio)) + gpio_set_value(pdata->flset_gpio, (~(pdata->flset_active) & 0x1)); + udelay(RT8547_STOP_DELAY); +} + +static inline void rt8547_fled_ctrl_en(struct rt8547_platform_data *pdata, + int en) +{ + if (gpio_is_valid(pdata->ctl_gpio)){ + if (en) + gpio_set_value(pdata->ctl_gpio, ((pdata->ctl_active) & 0x1)); + else + gpio_set_value(pdata->ctl_gpio, (~(pdata->ctl_active) & 0x1)); + } + RT_DBG("en %d\n", en); +} + +static inline void rt8547_fled_flash_en(struct rt8547_platform_data *pdata, + int en) +{ + if (gpio_is_valid(pdata->flen_gpio)){ + if (en) + gpio_set_value(pdata->flen_gpio, ((pdata->flen_active) & 0x1)); + else + gpio_set_value(pdata->flen_gpio, (~(pdata->flen_active) & 0x1)); + } + RT_DBG("en %d\n", en); +} + +static int rt8547_fled_init(struct rt_fled_info *info) +{ + RT_DBG("\n"); + return 0; +} + +static int rt8547_fled_resume(struct rt_fled_info *info) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + + RT_DBG("\n"); + fi->suspend = 0; + return 0; +} + +static int rt8547_fled_suspend(struct rt_fled_info *info, pm_message_t state) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + + RT_DBG("\n"); + fi->suspend = 1; + return 0; +} + +static int rt8547_fled_set_mode(struct rt_fled_info *info, + flashlight_mode_t mode) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + int ret = 0; + + RT_DBG("mode=%d\n", mode); + switch (mode) { + case FLASHLIGHT_MODE_TORCH: + if (fi->in_use_mode == FLASHLIGHT_MODE_OFF) + rt8547_fled_power_on(fi->pdata); + tmp = rt8547_reg_initval[RT8547_FLED_REG2 - 1]; + tmp |= RT8547_MODESEL_MASK; + rt8547_send_data(fi, RT8547_FLED_REG2, tmp); + rt8547_fled_ctrl_en(fi->pdata, 1); + rt8547_fled_flash_en(fi->pdata, 1); + fi->in_use_mode = mode; + break; + case FLASHLIGHT_MODE_FLASH: + if (fi->in_use_mode == FLASHLIGHT_MODE_OFF) + rt8547_fled_power_on(fi->pdata); + tmp = rt8547_reg_initval[RT8547_FLED_REG2 - 1]; + tmp &= ~RT8547_MODESEL_MASK; + rt8547_send_data(fi, RT8547_FLED_REG2, tmp); + fi->in_use_mode = mode; + break; + case FLASHLIGHT_MODE_OFF: + rt8547_fled_flash_en(fi->pdata, 0); + rt8547_fled_ctrl_en(fi->pdata, 0); + if (fi->in_use_mode != FLASHLIGHT_MODE_OFF) + rt8547_fled_power_off(fi->pdata); + fi->in_use_mode = mode; + break; + case FLASHLIGHT_MODE_MIXED: + default: + ret = -EINVAL; + } + return 0; +} + +static int rt8547_fled_get_mode(struct rt_fled_info *info) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + + RT_DBG("\n"); + return fi->in_use_mode; +} + +static int rt8547_fled_strobe(struct rt_fled_info *info) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + + RT_DBG("\n"); + rt8547_fled_flash_en(fi->pdata, 0); + rt8547_fled_ctrl_en(fi->pdata, 0); + rt8547_fled_ctrl_en(fi->pdata, 1); + rt8547_fled_flash_en(fi->pdata, 1); + return 0; +} + +static int rt8547_fled_torch_current_list(struct rt_fled_info *info, + int selector) +{ + RT_DBG("selector=%d\n", selector); + return 25000 + selector * 25000; /* unit: uA */ +} + +static int rt8547_fled_strobe_current_list(struct rt_fled_info *info, + int selector) +{ + RT_DBG("selector=%d\n", selector); + return 100000 + selector * 50000; /* unit: uA */ +} + +static int rt8547_fled_timeout_level_list(struct rt_fled_info *info, + int selector) +{ + RT_DBG("selector=%d\n", selector); + return 100000 + selector * 50000; /* unit: uA */ +} + +static int rt8547_fled_lv_protection_list(struct rt_fled_info *info, + int selector) +{ + RT_DBG("selector=%d\n", selector); + return 3000 + selector * 100; /* unit: mV */ +} + +static int rt8547_fled_strobe_timeout_list(struct rt_fled_info *info, + int selector) +{ + RT_DBG("selector=%d\n", selector); + return 64 + selector * 32; /* unit: mS */ +} + +static int rt8547_fled_set_torch_current_sel(struct rt_fled_info *info, + int selector) +{ + + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + + RT_DBG("selector=%d\n", selector); + tmp = rt8547_reg_initval[RT8547_FLED_REG2 - 1]; + tmp &= ~RT8547_TCLEVEL_MASK; + tmp |= selector; + rt8547_send_data(fi, RT8547_FLED_REG2, tmp); + return 0; +} + +static int rt8547_fled_set_strobe_current_sel(struct rt_fled_info *info, + int selector) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + + RT_DBG("selector=%d\n", selector); + tmp = rt8547_reg_initval[RT8547_FLED_REG1 - 1]; + tmp &= ~RT8547_SCLEVEL_MASK; + tmp |= selector; + rt8547_send_data(fi, RT8547_FLED_REG1, tmp); + return 0; +} + +static int rt8547_fled_set_timeout_level_sel(struct rt_fled_info *info, + int selector) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + + RT_DBG("selector=%d\n", selector); + if (selector > RT8547_TOL_MAX) + return -EINVAL; + tmp = rt8547_reg_initval[RT8547_FLED_REG1 - 1]; + tmp &= ~RT8547_TOCLEVEL_MASK; + tmp |= (selector << RT8547_TOCLEVEL_SHFT); + rt8547_send_data(fi, RT8547_FLED_REG1, tmp); + return 0; +} + +static int rt8547_fled_set_lv_protection_sel(struct rt_fled_info *info, + int selector) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + + RT_DBG("selector=%d\n", selector); + if (selector > RT8547_LVP_MAX) + return -EINVAL; + tmp = rt8547_reg_initval[RT8547_FLED_REG0 - 1]; + tmp &= ~RT8547_LVP_MASK; + tmp |= selector; + rt8547_send_data(fi, RT8547_FLED_REG0, tmp); + return 0; +} + +static int rt8547_fled_set_strobe_timeout_sel(struct rt_fled_info *info, + int selector) +{ + struct rt8547_chip *fi = (struct rt8547_chip *)info; + unsigned char tmp = 0; + + RT_DBG("selector=%d\n", selector); + if (selector > RT8547_STO_MAX) + return -EINVAL; + tmp = rt8547_reg_initval[RT8547_FLED_REG3 - 1]; + tmp &= ~RT8547_STO_MASK; + tmp |= selector; + rt8547_send_data(fi, RT8547_FLED_REG3, tmp); + return 0; +} + +static int rt8547_fled_get_torch_current_sel(struct rt_fled_info *info) +{ + int selector = + rt8547_reg_initval[RT8547_FLED_REG2 - 1] & RT8547_TCLEVEL_MASK; + + return selector; +} + +static int rt8547_fled_get_strobe_current_sel(struct rt_fled_info *info) +{ + int selector = + rt8547_reg_initval[RT8547_FLED_REG1 - 1] & RT8547_SCLEVEL_MASK; + + return selector; +} + +static int rt8547_fled_get_timeout_level_sel(struct rt_fled_info *info) +{ + int selector = + rt8547_reg_initval[RT8547_FLED_REG1 - 1] & RT8547_TOCLEVEL_MASK; + + selector >>= RT8547_TOCLEVEL_SHFT; + return selector; +} + +static int rt8547_fled_get_lv_protection_sel(struct rt_fled_info *info) +{ + int selector = + rt8547_reg_initval[RT8547_FLED_REG0 - 1] & RT8547_LVP_MASK; + + return selector; +} + +static int rt8547_fled_get_strobe_timeout_sel(struct rt_fled_info *info) +{ + int selector = + rt8547_reg_initval[RT8547_FLED_REG3 - 1] & RT8547_STO_MASK; + + return selector; +} + +static struct rt_fled_hal rt8547_fled_hal = { + .fled_init = rt8547_fled_init, + .fled_suspend = rt8547_fled_suspend, + .fled_resume = rt8547_fled_resume, + .fled_set_mode = rt8547_fled_set_mode, + .fled_get_mode = rt8547_fled_get_mode, + .fled_strobe = rt8547_fled_strobe, + .fled_torch_current_list = rt8547_fled_torch_current_list, + .fled_strobe_current_list = rt8547_fled_strobe_current_list, + .fled_timeout_level_list = rt8547_fled_timeout_level_list, + .fled_lv_protection_list = rt8547_fled_lv_protection_list, + .fled_strobe_timeout_list = rt8547_fled_strobe_timeout_list, + /* method to set */ + .fled_set_torch_current_sel = rt8547_fled_set_torch_current_sel, + .fled_set_strobe_current_sel = rt8547_fled_set_strobe_current_sel, + .fled_set_timeout_level_sel = rt8547_fled_set_timeout_level_sel, + .fled_set_lv_protection_sel = rt8547_fled_set_lv_protection_sel, + .fled_set_strobe_timeout_sel = rt8547_fled_set_strobe_timeout_sel, + /* method to get */ + .fled_get_torch_current_sel = rt8547_fled_get_torch_current_sel, + .fled_get_strobe_current_sel = rt8547_fled_get_strobe_current_sel, + .fled_get_timeout_level_sel = rt8547_fled_get_timeout_level_sel, + .fled_get_lv_protection_sel = rt8547_fled_get_lv_protection_sel, + .fled_get_strobe_timeout_sel = rt8547_fled_get_strobe_timeout_sel, +}; + +static struct flashlight_properties rt8547_fled_props = { + .type = FLASHLIGHT_TYPE_LED, + .torch_brightness = 2, + .torch_max_brightness = 15, + .strobe_brightness = 18, + .strobe_max_brightness = 30, + .strobe_delay = 2, + .strobe_timeout = 544, + .alias_name = "rt8547-fled", +}; + +static void rt8547_parse_dt(struct rt8547_platform_data *pdata, + struct device *dev) +{ +#ifdef CONFIG_OF + struct device_node *np = dev->of_node; + u32 tmp; + + if (of_property_read_u32(np, "rt,def_lvp", &tmp) < 0) { + dev_warn(dev, "use 3V as the default lvp\n"); + } else { + if (tmp > RT8547_LVP_MAX) + tmp = RT8547_LVP_MAX; + rt8547_reg_initval[RT8547_FLED_REG0 - 1] &= ~RT8547_LVP_MASK; + rt8547_reg_initval[RT8547_FLED_REG0 - 1] |= tmp; + } + + if (of_property_read_u32(np, "rt,def_tol", &tmp) < 0) { + dev_warn(dev, "use 100mA as the default timeout level\n"); + } else { + if (tmp > RT8547_TOL_MAX) + tmp = RT8547_TOL_MAX; + tmp <<= RT8547_TOCLEVEL_SHFT; + rt8547_reg_initval[RT8547_FLED_REG1 - 1] &= + ~RT8547_TOCLEVEL_MASK; + rt8547_reg_initval[RT8547_FLED_REG1 - 1] |= tmp; + } + pdata->flen_gpio = of_get_named_gpio(np, "rt,flen_gpio", 0); + pdata->ctl_gpio = of_get_named_gpio(np, "rt,ctl_gpio", 0); + pdata->flset_gpio = of_get_named_gpio(np, "rt,flset_gpio", 0); +#endif /* #ifdef CONFIG_OF */ +} + +static void rt8547_parse_pdata(struct rt8547_platform_data *pdata, + struct device *dev) +{ + u32 tmp; + + tmp = pdata->def_lvp; + rt8547_reg_initval[RT8547_FLED_REG0 - 1] &= ~RT8547_LVP_MASK; + rt8547_reg_initval[RT8547_FLED_REG0 - 1] |= tmp; + + tmp = pdata->def_tol; + tmp <<= RT8547_TOCLEVEL_SHFT; + rt8547_reg_initval[RT8547_FLED_REG1 - 1] &= ~RT8547_TOCLEVEL_MASK; + rt8547_reg_initval[RT8547_FLED_REG1 - 1] |= tmp; +} + +static int rt8547_io_init(struct rt8547_platform_data *pdata, + struct device *dev) +{ + int rc = 0; + + if (gpio_is_valid(pdata->flen_gpio)) { + rc = gpio_request_one(pdata->flen_gpio, ((~(pdata->flen_active) & 0x1) ? GPIOF_OUT_INIT_HIGH:GPIOF_OUT_INIT_LOW), + "rt8547_flen"); + if (rc < 0) { + dev_err(dev, "request rt8547 flash en pin fail\n"); + goto gpio_request1; + } + + } + + if(gpio_is_valid(pdata->ctl_gpio)){ + rc = gpio_request_one(pdata->ctl_gpio, ((~(pdata->ctl_active) & 0x1) ? GPIOF_OUT_INIT_HIGH:GPIOF_OUT_INIT_LOW), + "rt8547_ctl"); + if (rc < 0) { + dev_err(dev, "request rt8547 ctl pin fail\n"); + goto gpio_request2; + } + } + + if(gpio_is_valid(pdata->flset_gpio)){ + rc = gpio_request_one(pdata->flset_gpio, ((~(pdata->flset_active) & 0x1) ? GPIOF_OUT_INIT_HIGH:GPIOF_OUT_INIT_LOW), + "rt8547_flset"); + if (rc < 0) { + dev_err(dev, "request rt8547 flash set pin fail\n"); + goto gpio_request3; + } + } + return 0; +gpio_request3: + if(gpio_is_valid(pdata->ctl_gpio)) + gpio_free(pdata->ctl_gpio); +gpio_request2: + if (gpio_is_valid(pdata->flen_gpio)) + gpio_free(pdata->flen_gpio); +gpio_request1: + return rc; + +} + +static int rt8547_io_deinit(struct rt8547_platform_data *pdata) +{ + if (gpio_is_valid(pdata->flen_gpio)){ + gpio_direction_input(pdata->flen_gpio); + gpio_free(pdata->flen_gpio); + } + if(gpio_is_valid(pdata->ctl_gpio)){ + gpio_direction_input(pdata->ctl_gpio); + gpio_free(pdata->ctl_gpio); + } + if(gpio_is_valid(pdata->flset_gpio)){ + gpio_direction_input(pdata->flset_gpio); + gpio_free(pdata->flset_gpio); + } + return 0; +} + +static void rt8547_reg_init(struct rt8547_chip *chip) +{ + RT_DBG("\n"); + rt8547_send_data(chip, RT8547_FLED_REG0, + rt8547_reg_initval[RT8547_FLED_REG0 - 1]); + rt8547_send_data(chip, RT8547_FLED_REG1, + rt8547_reg_initval[RT8547_FLED_REG1 - 1]); + rt8547_send_data(chip, RT8547_FLED_REG2, + rt8547_reg_initval[RT8547_FLED_REG2 - 1]); + rt8547_send_data(chip, RT8547_FLED_REG3, + rt8547_reg_initval[RT8547_FLED_REG3 - 1]); +} + +static struct platform_device rt_fled_pdev = { + .name = "rt-flash-led", + .id = -1, +}; + +static int rt8547_led_probe(struct platform_device *pdev) +{ + struct rt8547_platform_data *pdata = pdev->dev.platform_data; + struct rt8547_chip *chip; + bool use_dt = pdev->dev.of_node; + int ret = 0; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + if (use_dt) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto err_probe; + rt8547_parse_dt(pdata, &pdev->dev); + } else { + if (!pdata) + goto err_probe; + rt8547_parse_pdata(pdata, &pdev->dev); + } + + ret = rt8547_io_init(pdata, &pdev->dev); + if (ret < 0) + goto err_io; + + chip->dev = &pdev->dev; + chip->pdata = pdata; + spin_lock_init(&chip->io_lock); + chip->in_use_mode = FLASHLIGHT_MODE_OFF; + platform_set_drvdata(pdev, chip); + + rt8547_fled_power_on(pdata); + rt8547_reg_init(chip); + rt8547_fled_power_off(pdata); + + chip->base.hal = &rt8547_fled_hal; + chip->base.init_props = &rt8547_fled_props; + rt_fled_pdev.dev.parent = &pdev->dev; + ret = platform_device_register(&rt_fled_pdev); + if (ret < 0) { + dev_err(&pdev->dev, "register rtfled fail\n"); + goto err_io; + } +#ifdef CONFIG_DEBUG_FS + rt8547_create_debugfs(chip); +#endif /* #ifdef CONFIG_DEBUG_FS */ + dev_info(&pdev->dev, "driver successfully registered\n"); + return 0; +err_io: + if (use_dt) + devm_kfree(&pdev->dev, pdata); +err_probe: + devm_kfree(&pdev->dev, chip); + return ret; +} + +static int rt8547_led_remove(struct platform_device *pdev) +{ + struct rt8547_chip *chip = platform_get_drvdata(pdev); + +#ifdef CONFIG_DEBUG_FS + rt8547_remove_debugfs(); +#endif /* #ifdef CONFIG_DEBUG_FS */ + platform_device_unregister(&rt_fled_pdev); + rt8547_io_deinit(chip->pdata); + return 0; +} + +static const struct of_device_id rt_match_table[] = { + {.compatible = "rt,rt8547",}, + {}, +}; + +static struct platform_driver rt8547_led_driver = { + .driver = { + .name = "rt8547", + .owner = THIS_MODULE, + .of_match_table = rt_match_table, + }, + .probe = rt8547_led_probe, + .remove = rt8547_led_remove, +}; + +static int rt8547_led_init(void) +{ + return platform_driver_register(&rt8547_led_driver); +} + +module_init(rt8547_led_init); + +static void rt8547_led_exit(void) +{ + platform_driver_unregister(&rt8547_led_driver); +} + +module_exit(rt8547_led_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CY Huang "); +MODULE_DESCRIPTION("LED Flash Driver for RT8547"); +MODULE_VERSION(RT8547_DRV_VER); diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.h b/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.h new file mode 100755 index 000000000000..a1a7a8e75498 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/leds-rt8547.h @@ -0,0 +1,84 @@ +/* include/linux/leds-rt8547.h + * Include file of driver to Richtek RT8547 LED Flash IC + * + * Copyright (C) 2014 Richtek Technology Corporation + * Author: CY_Huang + * + * 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. + */ + +#ifndef __LINUX_LEDS_RT8547_H +#define __LINUX_LEDS_RT8547_H + +#define RT8547_DRV_VER "1.0.2_G" + +enum { + RT8547_FLED_REG0 = 0x01, + RT8547_FLED_REG1, + RT8547_FLED_REG2, + RT8547_FLED_REG3, + RT8547_FLED_REGMAX, +}; + +enum { + RT8547_LVP_3V, + RT8547_LVP_3P1V, + RT8547_LVP_3P2V, + RT8547_LVP_3P3V, + RT8547_LVP_3P4V, + RT8547_LVP_3P5V, + RT8547_LVP_3P6V, + RT8547_LVP_3P7V, + RT8547_LVP_3P8V, + RT8547_LVP_MAX = RT8547_LVP_3P8V, +}; + +enum { + RT8547_TOL_100mA, + RT8547_TOL_150mA, + RT8547_TOL_200mA, + RT8547_TOL_250mA, + RT8547_TOL_300mA, + RT8547_TOL_350mA, + RT8547_TOL_400mA, + RT8547_TOL_MAX = RT8547_TOL_400mA, +}; + +#define RT8547_STO_MAX 36 + +#define RT8547_LVP_MASK 0x0F +#define RT8547_TOCLEVEL_MASK 0xE0 +#define RT8547_TOCLEVEL_SHFT 5 +#define RT8547_SCLEVEL_MASK 0x1F +#define RT8547_SWRST_MASK 0x20 +#define RT8547_MODESEL_MASK 0x10 +#define RT8547_TCLEVEL_MASK 0x0F +#define RT8547_STO_MASK 0x3F + +struct rt8547_platform_data { + int flen_gpio; + int flen_active; + int ctl_gpio; + int ctl_active; + int flset_gpio; + int flset_active; + unsigned char def_lvp:4; + unsigned char def_tol:3; +}; + +/* one wire protocol parameter */ +#define RT8547_ONEWIRE_ADDR 0x99 +#define RT8547_LONG_DELAY 9 +#define RT8547_SHORT_DELAY 4 +#define RT8547_START_DELAY 10 +#define RT8547_STOP_DELAY 1500 + +#ifdef CONFIG_LEDS_RT8547_DBG +#define RT_DBG(fmt, args...) pr_info("%s: " fmt, __func__, ##args) +#else +#define RT_DBG(fmt, args...) +#endif /* #ifdef CONFIG_LEDS_RT8547_DBG */ + +#endif /* #ifndef __LINUX_LEDS_RT8547_H */ diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.c b/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.c new file mode 100755 index 000000000000..8d1101930b6e --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.c @@ -0,0 +1,168 @@ +#include "rk_ext_fshled_ctl.h" +#include "../camsys_gpio.h" +#include "flashlight.h" +#include "leds-rt8547.h" + +typedef struct ext_fsh_info_s{ + struct platform_device pdev; + char* dev_model; + struct list_head list; +}ext_fsh_info_t; + +struct ext_fsh_dev_list_s{ + struct list_head dev_list; +}; + +static struct ext_fsh_dev_list_s g_ext_fsh_devs; + +int camsys_init_ext_fsh_module() +{ + camsys_trace(1,"init external flash module"); + INIT_LIST_HEAD(&g_ext_fsh_devs.dev_list); + return 0; +} + +int camsys_deinit_ext_fsh_module() +{ + ext_fsh_info_t* cur_fsh_info = NULL; + camsys_trace(1,"deinit external flash module"); + if (!list_empty(&g_ext_fsh_devs.dev_list)) { + list_for_each_entry(cur_fsh_info, &g_ext_fsh_devs.dev_list, list) { + if (cur_fsh_info) { + platform_device_unregister(&cur_fsh_info->pdev); + list_del_init(&cur_fsh_info->list); + /* free after unregister device ?*/ + kfree(cur_fsh_info->pdev.dev.platform_data); + kfree(cur_fsh_info); + cur_fsh_info = NULL; + } + } + } + + INIT_LIST_HEAD(&g_ext_fsh_devs.dev_list); + return 0; +} +void* camsys_register_ext_fsh_dev(camsys_flash_info_t *fsh_info) +{ + ext_fsh_info_t* new_dev = NULL; + if(strcmp(fsh_info->fl_drv_name,"rt8547") == 0){ + struct rt8547_platform_data* new_rt_dev = NULL; + new_dev = kzalloc(sizeof(ext_fsh_info_t),GFP_KERNEL); + if(!new_dev){ + camsys_err("register new ext flash dev erro !"); + goto fail0; + } + + new_rt_dev = kzalloc(sizeof(ext_fsh_info_t),GFP_KERNEL); + if(!new_rt_dev){ + camsys_err("register new ext flash dev erro !"); + goto fail1; + } + + new_dev->pdev.id = -1; + new_dev->pdev.name = fsh_info->fl_drv_name; + new_dev->pdev.dev.platform_data = (void*)new_rt_dev; + new_dev->dev_model = "rt-flash-led"; + + new_rt_dev->flen_gpio = camsys_gpio_get(fsh_info->fl_en.name); + new_rt_dev->flen_active = fsh_info->fl_en.active; + camsys_trace(1,"flen name :%s,gpio %d,active %d \n",fsh_info->fl_en.name,new_rt_dev->flen_gpio,new_rt_dev->flen_active); + new_rt_dev->flset_gpio = camsys_gpio_get(fsh_info->fl.name ); + new_rt_dev->flset_active = fsh_info->fl.active; + camsys_trace(1,"flset name :%s, gpio %d, active %d \n",fsh_info->fl.name,new_rt_dev->flset_gpio,new_rt_dev->flset_active); + new_rt_dev->ctl_gpio = -1; + new_rt_dev->def_lvp = RT8547_LVP_3V; + new_rt_dev->def_tol = RT8547_TOL_100mA; + + // new_rt_dev->def_lvp = RT8547_LVP_MAX; + // new_rt_dev->def_tol = RT8547_TOL_MAX; + + if(platform_device_register(&new_dev->pdev) < 0){ + camsys_err("register rtfled fail\n"); + kfree(new_rt_dev); + goto fail1; + } + + list_add_tail(&new_dev->list, &g_ext_fsh_devs.dev_list); + camsys_trace(1,"register new rt led dev success !"); + } + + return (void*)new_dev; +fail1: + if(new_dev) + kfree(new_dev); +fail0: + return NULL; +} + +int camsys_deregister_ext_fsh_dev(void* dev) +{ + ext_fsh_info_t* cur_fsh_info = NULL; + if (!list_empty(&g_ext_fsh_devs.dev_list)) { + list_for_each_entry(cur_fsh_info, &g_ext_fsh_devs.dev_list, list) { + if (dev == cur_fsh_info) { + camsys_trace(1,"unregister ext flsh dev !"); + platform_device_unregister(&cur_fsh_info->pdev); + list_del_init(&cur_fsh_info->list); + /* free after unregister device ?*/ + kfree(cur_fsh_info->pdev.dev.platform_data); + kfree(cur_fsh_info); + } + } + } + return 0; +} + +/******************************* +mode: + 0: CAM_ENGINE_FLASH_OFF = 0x00, + 1: CAM_ENGINE_FLASH_AUTO = 0x01, + 2: CAM_ENGINE_FLASH_ON = 0x02, + 3: CAM_ENGINE_FLASH_RED_EYE = 0x03, + 5: CAM_ENGINE_FLASH_TORCH = 0x05 +********************************/ +int camsys_ext_fsh_ctrl(void* dev,int mode,unsigned int on) +{ + ext_fsh_info_t* cur_fsh_info = NULL; + struct flashlight_device *fled_dev = NULL; + if (!list_empty(&g_ext_fsh_devs.dev_list)) { + list_for_each_entry(cur_fsh_info, &g_ext_fsh_devs.dev_list, list) { + if (dev == cur_fsh_info) { + break; + } + } + } + if(cur_fsh_info == NULL){ + camsys_err("this flash dev have not been registered !"); + return -1; + } + + fled_dev = find_flashlight_by_name(cur_fsh_info->dev_model); + switch(mode){ + case 0: /* off */ + /* set flashlight mode to Off */ + flashlight_set_mode(fled_dev, FLASHLIGHT_MODE_OFF); + break; + case 2: /* flash on */ + /* set strobe timeout to 256ms */ + //flashlight_set_strobe_timeout(fled_dev, 256, 256); + flashlight_set_strobe_timeout(fled_dev, 512, 512); + /* set strobe brightness to to index 18 (1A), refer to the datasheet for the others */ + flashlight_set_strobe_brightness(fled_dev, 18); + /* set flashlight mode to Strobe */ + flashlight_set_mode(fled_dev, FLASHLIGHT_MODE_FLASH); + flashlight_strobe(fled_dev); + break; + case 5: /* torch */ + /* set the torch brightness index 2 (75mA), refer to the datasheet for index current value. */ + flashlight_set_torch_brightness(fled_dev, 2); + /* set flashlight mode to Torch */ + flashlight_set_mode(fled_dev, FLASHLIGHT_MODE_TORCH); + break; + default: + camsys_err("not support this mode %d !",mode); + } + + return 0; +} + diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.h b/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.h new file mode 100755 index 000000000000..d66af0ddd9c3 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/rk_ext_fshled_ctl.h @@ -0,0 +1,10 @@ +#ifndef __RK_EXT_FSHLED_H__ +#define __RK_EXT_FSHLED_H__ +#include "../camsys_internal.h" +//register flash dev +extern int camsys_init_ext_fsh_module(void); +extern int camsys_deinit_ext_fsh_module(void); +extern void* camsys_register_ext_fsh_dev(camsys_flash_info_t *fsh_info); +extern int camsys_deregister_ext_fsh_dev(void* dev); +extern int camsys_ext_fsh_ctrl(void* dev,int mode,unsigned int on); +#endif diff --git a/drivers/media/video/rk_camsys/ext_flashled_drv/rtfled.c b/drivers/media/video/rk_camsys/ext_flashled_drv/rtfled.c new file mode 100755 index 000000000000..841743148595 --- /dev/null +++ b/drivers/media/video/rk_camsys/ext_flashled_drv/rtfled.c @@ -0,0 +1,401 @@ +/* drivers/leds/rtfled.c + * Richtek Flash LED Universal Architecture + * + * Copyright (C) 2013 Richtek Technology Corp. + * Author: Patrick Chang + * + * 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 +#include +#include +#include "rtfled.h" +#include +#include + +#define RTFLED_INFO(format, args...) \ + pr_info("%s:%s() line-%d: " format, \ + ALIAS_NAME, __func__, __LINE__, ## args) +#define RTFLED_WARN(format, args...) \ + pr_warn("%s:%s() line-%d: " format, \ + ALIAS_NAME, __func__, __LINE__, ## args) +#define RTFLED_ERR(format, args...) \ + pr_err("%s:%s() line-%d: " format, \ + ALIAS_NAME, __func__, __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_torch_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_torch_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) \ + do { \ + if (hal->x == NULL) \ + return -EINVAL; \ + } while (0) + +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_torch_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 uncompletedly\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 rtfled_init(void) +{ + return platform_driver_register(&rt_flash_led_driver); +} +subsys_initcall(rtfled_init); + +static void rtfled_exit(void) +{ + platform_driver_unregister(&rt_flash_led_driver); +} +module_exit(rtfled_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Chang + * + *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. + */ + +#ifndef LINUX_LEDS_RTFLED_H +#define LINUX_LEDS_RTFLED_H +#include "flashlight.h" + +struct rt_fled_info; +typedef int (*rt_hal_fled_init) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_suspend) (struct rt_fled_info *info, + pm_message_t state); +typedef int (*rt_hal_fled_resume) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_set_mode) (struct rt_fled_info *info, + flashlight_mode_t mode); +typedef int (*rt_hal_fled_get_mode) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_strobe) (struct rt_fled_info *info); + +/* + *Return value : -EINVAL => selector parameter is out of range, + *otherwise current in uA + */ +typedef int (*rt_hal_fled_torch_current_list) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_strobe_current_list) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_timeout_level_list) (struct rt_fled_info *info, + int selector); +/* + *Return value : -EINVAL => selector parameter is out of range, + *otherwise voltage in mV + */ +typedef int (*rt_hal_fled_lv_protection_list) (struct rt_fled_info *info, + int selector); +/* + *Return value : -EINVAL => selector parameter is out of range, + *otherwise time in ms + */ +typedef int (*rt_hal_fled_strobe_timeout_list) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_set_torch_current) (struct rt_fled_info *info, + int min_uA, int max_uA, + int *selector); +typedef int (*rt_hal_fled_set_strobe_current) (struct rt_fled_info *info, + int min_uA, int max_uA, + int *selector); +typedef int (*rt_hal_fled_set_timeout_level) (struct rt_fled_info *info, + int min_uA, int max_uA, + int *selector); +typedef int (*rt_hal_fled_set_lv_protection) (struct rt_fled_info *info, + int min_mV, int max_mV, + int *selector); +typedef int (*rt_hal_fled_set_strobe_timeout) (struct rt_fled_info *info, + int min_ms, int max_ms, + int *selector); +typedef int (*rt_hal_fled_set_torch_current_sel) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_set_strobe_current_sel) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_set_timeout_level_sel) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_set_lv_protection_sel) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_set_strobe_timeout_sel) (struct rt_fled_info *info, + int selector); +typedef int (*rt_hal_fled_get_torch_current_sel) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_strobe_current_sel) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_timeout_level_sel) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_lv_protection_sel) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_strobe_timeout_sel) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_torch_current) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_strobe_current) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_timeout_level) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_lv_protection) (struct rt_fled_info *info); +typedef int (*rt_hal_fled_get_strobe_timeout) (struct rt_fled_info *info); +typedef void (*rt_hal_fled_shutdown) (struct rt_fled_info *info); + +struct rt_fled_hal { + rt_hal_fled_init fled_init; + rt_hal_fled_suspend fled_suspend; + rt_hal_fled_resume fled_resume; + rt_hal_fled_set_mode fled_set_mode; + rt_hal_fled_get_mode fled_get_mode; + rt_hal_fled_strobe fled_strobe; + rt_hal_fled_torch_current_list fled_torch_current_list; + rt_hal_fled_strobe_current_list fled_strobe_current_list; + rt_hal_fled_timeout_level_list fled_timeout_level_list; + rt_hal_fled_lv_protection_list fled_lv_protection_list; + rt_hal_fled_strobe_timeout_list fled_strobe_timeout_list; + /*method to set */ + rt_hal_fled_set_torch_current_sel fled_set_torch_current_sel; + rt_hal_fled_set_strobe_current_sel fled_set_strobe_current_sel; + rt_hal_fled_set_timeout_level_sel fled_set_timeout_level_sel; + rt_hal_fled_set_lv_protection_sel fled_set_lv_protection_sel; + rt_hal_fled_set_strobe_timeout_sel fled_set_strobe_timeout_sel; + /*method to set, optional */ + rt_hal_fled_set_torch_current fled_set_torch_current; + rt_hal_fled_set_strobe_current fled_set_strobe_current; + rt_hal_fled_set_timeout_level fled_set_timeout_level; + rt_hal_fled_set_lv_protection fled_set_lv_protection; + rt_hal_fled_set_strobe_timeout fled_set_strobe_timeout; + /*method to get */ + rt_hal_fled_get_torch_current_sel fled_get_torch_current_sel; + rt_hal_fled_get_strobe_current_sel fled_get_strobe_current_sel; + rt_hal_fled_get_timeout_level_sel fled_get_timeout_level_sel; + rt_hal_fled_get_lv_protection_sel fled_get_lv_protection_sel; + rt_hal_fled_get_strobe_timeout_sel fled_get_strobe_timeout_sel; + /*method to get, optional */ + rt_hal_fled_get_torch_current fled_get_torch_current; + rt_hal_fled_get_strobe_current fled_get_strobe_current; + rt_hal_fled_get_timeout_level fled_get_timeout_level; + rt_hal_fled_get_lv_protection fled_get_lv_protection; + rt_hal_fled_get_strobe_timeout fled_get_strobe_timeout; + /*PM shutdown, optional */ + rt_hal_fled_shutdown fled_shutdown; +}; + +typedef struct rt_fled_info { + struct rt_fled_hal *hal; + struct flashlight_device *flashlight_dev; + const struct flashlight_properties *init_props; + char *name; + char *chip_name; +} rt_fled_info_t; + +/*Public funtions + *argument + * @name : Flash LED's name;pass NULL menas "rt-flash-led" + */ + +rt_fled_info_t *rt_fled_get_info_by_name(char *name); + +/*Usage : + *fled_info = rt_fled_get_info_by_name("FlashLED1"); + *fled_info->hal->fled_set_strobe_current(fled_info, + * 150, 200); + */ + +#endif /*LINUX_LEDS_RTFLED_H */ diff --git a/include/media/camsys_head.h b/include/media/camsys_head.h index 28dcc5b01a13..31a828f7bebf 100755 --- a/include/media/camsys_head.h +++ b/include/media/camsys_head.h @@ -25,8 +25,10 @@ 1) support isp iommu *v0.9.0: 1) add dev_name in struct camsys_devio_name_s; +*v0.a.0: + 1) support external flash IC */ -#define CAMSYS_HEAD_VERSION KERNEL_VERSION(0,9,0) +#define CAMSYS_HEAD_VERSION KERNEL_VERSION(0,0xa,0) #define CAMSYS_MARVIN_DEVNAME "camsys_marvin" #define CAMSYS_CIF0_DEVNAME "camsys_cif0" @@ -152,7 +154,9 @@ typedef struct camsys_sysctrl_s { } camsys_sysctrl_t; typedef struct camsys_flash_info_s { - camsys_gpio_info_t fl; + unsigned char fl_drv_name[CAMSYS_NAME_LEN]; + camsys_gpio_info_t fl; //fl_trig + camsys_gpio_info_t fl_en; } camsys_flash_info_t; typedef struct camsys_mipiphy_s { -- 2.34.1