零、閃光燈配置步驟(以真閃IC:DIO5151爲例):
1. 查看硬件原理圖,得知閃關燈IC接在cpu的哪兩個GPIO上:
main_flashlight:(後閃)
enable : GPIO43
mode : GPIO80(H-flashlight模式 L-torch手電筒模式)
sub_flashlight:(前攝)
enable : GPIO42
2. dws配置pin腳:
EintMode|Def.Mode M0|M1|M2|M3|M4|M5|M6|M7|InPull En|InPull SelHigh|Def.Dir|In|Out|OutHigh|VarName1
GPIO42 NC // 有點奇怪NC也能控制?
GPIO43 0:GPIO43 1 0 0 1 1 0 1 0 1 0 OUT 0 1 0 GPIO_CAMERA_FLASH_EN_PIN
GPIO80 0:GPIO80 1 0 0 0 0 0 0 0 1 0 OUT 0 1 0 GPIO_CAMERA_FLASH_MOOD_PIN
3. dts配置gpio控制接口:
3.1 mt6580.dtsi:
+ strobe: strobe {
+ compatible = "mediatek,mt6580-strobe";
+ };
3.2 k80hd_bsp_fwv_512m.dts
+ /* STROBE GPIO standardization */
+ &pio {
+ strobe_intpin_default: strobedefaultcfg {
+ };
+ main_strobe_oh: mainstrobe@1 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO43__FUNC_GPIO43>;
+ slew-rate = <1>;
+ output-high;
+ };
+ };
+
+ main_strobe_ol: mainstrobe@2 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO43__FUNC_GPIO43>;
+ slew-rate = <1>;
+ output-low;
+ };
+ };
+ main_strobe_mode_oh: mainstrobemode@1 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO80__FUNC_GPIO80>;
+ slew-rate = <1>;
+ output-high;
+ };
+ };
+ main_strobe_mode_ol: mainstrobemode@2 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO80__FUNC_GPIO80>;
+ slew-rate = <1>;
+ output-low;
+ };
+ };
+ sub_strobe_oh: substrobe@1 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO42__FUNC_GPIO42>;
+ slew-rate = <1>;
+ output-high;
+ };
+ };
+ sub_strobe_ol: substrobe@2 {
+ pins_cmd_dat {
+ pins = <PINMUX_GPIO42__FUNC_GPIO42>;
+ slew-rate = <1>;
+ output-low;
+ };
+ };
+ };
+
+ &strobe {
+ pinctrl-names = "default", "main_strobe_oh", "main_strobe_ol", "main_strobe_mode_oh", "main_strobe_mode_ol", "sub_strobe_oh", "sub_strobe_ol";
+ pinctrl-0 = <&strobe_intpin_default>;
+ pinctrl-1 = <&main_strobe_oh>;
+ pinctrl-2 = <&main_strobe_ol>;
+ pinctrl-4 = <&main_strobe_mode_ol>;
+ pinctrl-5 = <&sub_strobe_oh>;
+ pinctrl-6 = <&sub_strobe_ol>;
+ status = "okay";
+ };
+ /* STROBE GPIO end */
3.3 alps/kernel-3.18/drivers/misc/mediatek/flashlight/inc/kd_flashlight.h
+ int strobe_gpio_init(struct platform_device *pdev);
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ int sub_strobe_gpio_init(struct platform_device *pdev);
+ #endif
3.4 alps/kernel-3.18/drivers/misc/mediatek/flashlight/src/mt6580/kd_flashlightlist.c
+ #ifdef CONFIG_OF
+ #include <linux/of.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #endif
+ #ifdef CONFIG_OF
+ static const struct of_device_id strobe_of_ids[] = {
+ {.compatible = "mediatek,mt6580-strobe",},
+ {}
+ };
+ #endif
static struct platform_driver flashlight_platform_driver = {
.probe = flashlight_probe,
.remove = flashlight_remove,
.shutdown = flashlight_shutdown,
.driver = {
.name = FLASHLIGHT_DEVNAME,
.owner = THIS_MODULE,
+ #ifdef CONFIG_OF
+ .of_match_table = strobe_of_ids,
+ #endif
},
};
+ #ifndef CONFIG_OF
static struct platform_device flashlight_platform_device = {
.name = FLASHLIGHT_DEVNAME,
.id = 0,
.dev = {
}
};
+ #endif
static int __init flashlight_init(void)
{
int ret = 0;
logI("[flashlight_probe] start ~");
+ #ifndef CONFIG_OF
ret = platform_device_register(&flashlight_platform_device);
if (ret) {
logI("[flashlight_probe] platform_device_register fail ~");
return ret;
}
+ #endif
static int flashlight_probe(struct platform_device *dev)
{
int ret = 0, err = 0;
logI("[flashlight_probe] start ~");
+ #ifdef CONFIG_OF
+ strobe_gpio_init(dev);
+ #endif
- #ifdef WIN32
+ #if 0 //#ifdef WIN32
3.5 alps/kernel-3.18/drivers/misc/mediatek/flashlight/src/mt6580/constant_flashlight/leds_strobe.c
+ struct pinctrl *strobectrl = NULL;
+ struct pinctrl_state *main_strobe_oh = NULL;
+ struct pinctrl_state *main_strobe_ol = NULL;
+ #ifdef CONFIG_KST_REAL_FLASH_MODE
+ struct pinctrl_state *main_strobe_mode_oh = NULL;
+ struct pinctrl_state *main_strobe_mode_ol = NULL;
+ #endif
+ static DEFINE_MUTEX(main_strobe_gpio_mutex);
+ int strobe_gpio_init(struct platform_device *pdev)
+ {
+ int ret = 0;
+
+ strobectrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(strobectrl)) {
+ dev_err(&pdev->dev, "Cannot find strobe pinctrl!");
+ ret = PTR_ERR(strobectrl);
+ }
+
+ main_strobe_oh = pinctrl_lookup_state(strobectrl, "main_strobe_oh");
+ if (IS_ERR(main_strobe_oh)) {
+ ret = PTR_ERR(main_strobe_oh);
+ pr_debug("%s : pinctrl err, main_strobe_oh\n", __func__);
+ }
+
+ main_strobe_ol = pinctrl_lookup_state(strobectrl, "main_strobe_ol");
+ if (IS_ERR(main_strobe_ol)) {
+ ret = PTR_ERR(main_strobe_ol);
+ pr_debug("%s : pinctrl err, main_strobe_ol\n", __func__);
+ }
+ #ifdef CONFIG_KST_REAL_FLASH_MODE
+ main_strobe_mode_oh = pinctrl_lookup_state(strobectrl, "main_strobe_mode_oh");
+ if (IS_ERR(main_strobe_mode_oh)) {
+ ret = PTR_ERR(main_strobe_mode_oh);
+ pr_debug("%s : pinctrl err, main_strobe_mode_oh\n", __func__);
+ }
+ main_strobe_mode_ol = pinctrl_lookup_state(strobectrl, "main_strobe_mode_ol");
+ if (IS_ERR(main_strobe_mode_ol)) {
+ ret = PTR_ERR(main_strobe_mode_ol);
+ pr_debug("%s : pinctrl err, main_strobe_mode_ol\n", __func__);
+ }
+ #endif
+
+ return ret;
+ }
+
+ void strobe_gpio_set(int level)
+ {
+ mutex_lock(&main_strobe_gpio_mutex);
+ if (level == 0)
+ pinctrl_select_state(strobectrl, main_strobe_ol);
+ else
+ pinctrl_select_state(strobectrl, main_strobe_oh);
+ mutex_unlock(&main_strobe_gpio_mutex);
+ }
+
+ #ifdef CONFIG_KST_REAL_FLASH_MODE
+ void strobe_mode_gpio_set(int level)
+ {
+ mutex_lock(&main_strobe_gpio_mutex);
+ if (level == 0)
+ pinctrl_select_state(strobectrl, main_strobe_mode_ol);
+ else
+ pinctrl_select_state(strobectrl, main_strobe_mode_oh);
+ mutex_unlock(&main_strobe_gpio_mutex);
+ }
+ #endif
+ #ifdef CONFIG_KST_REAL_FLASH_MODE
+ #define LEDS_TORCH_MODE 0
+ #define LEDS_FLASH_MODE 1
+ #define LEDS_CUSTOM_MODE_THRES 0
+ static int flash_mode_pin = 0;
+ #ifdef EN_PWM_CTRL
+ static int g_timePWMOutTimeMs=0;
+ static struct hrtimer g_timePWMOutTimer;
+ void timerPWMInit(void);
+ static bool g_enble_led=false;
+ ktime_t ktime;
+ enum hrtimer_restart ledPWMTimeOutCallback(struct hrtimer *timer)
+ {
+ if(g_enble_led == true) {
+ strobe_gpio_set(0);
+ #ifdef CONFIG_KST_FLASHLIGHT_CURRENT_DOWN
+ g_timePWMOutTimeMs=9;
+ #else
+ g_timePWMOutTimeMs=2;
+ #endif
+ ktime = ktime_set( 0, g_timePWMOutTimeMs*1000000 ); //1s
+ g_enble_led = false;
+ }
+ else if(g_enble_led == false) {
+ strobe_gpio_set(1);
+ #ifdef CONFIG_KST_FLASHLIGHT_CURRENT_DOWN
+ g_timePWMOutTimeMs=1;
+ #else
+ g_timePWMOutTimeMs=8;
+ #endif
+ ktime = ktime_set( 0, g_timePWMOutTimeMs*1000000 ); //1s
+ g_enble_led = true;
+ }
+ hrtimer_forward(&g_timePWMOutTimer, g_timePWMOutTimer.base->get_time(), ktime);
+ return HRTIMER_RESTART;
+ }
+ void timerPWMInit(void)
+ {
+ g_timePWMOutTimeMs=5;
+ hrtimer_init( &g_timePWMOutTimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+ g_timePWMOutTimer.function=ledPWMTimeOutCallback;
+ }
+ #endif
+ #endif
int FL_Enable(void)
{
+ #if 0
...
+ #else
+ strobe_gpio_set(1);
+
+ #ifdef EN_PWM_CTRL
+ ktime = ktime_set( 0, g_timePWMOutTimeMs*1000000 ); //1s
+ hrtimer_start( &g_timePWMOutTimer, ktime, HRTIMER_MODE_REL );
+ g_enble_led=true;
+ #endif
+
+ #endif
return 0;
}
int FL_Disable(void)
{
+ #if 0
...
+ #else
+ #ifdef EN_PWM_CTRL
+ hrtimer_cancel( &g_timePWMOutTimer );
+ g_enble_led=false;
+ #endif
+ strobe_gpio_set(0);
+ #endif
return 0;
}
int FL_dim_duty(kal_uint32 duty)
{
PK_DBG(" FL_dim_duty line=%d\n", __LINE__);
g_duty = duty;
+ #ifdef CONFIG_KST_REAL_FLASH_MODE
+ PK_DBG("FL_dim_duty %d, thres %d", duty, LEDS_CUSTOM_MODE_THRES);
+
+ flash_mode_pin = 0;
+ if(duty < LEDS_CUSTOM_MODE_THRES)
+ strobe_mode_gpio_set(LEDS_TORCH_MODE);
+ else {
+ flash_mode_pin = 1;
+ strobe_mode_gpio_set(LEDS_FLASH_MODE);
+ }
+
+ if((g_timeOutTimeMs == 0) && (duty > LEDS_CUSTOM_MODE_THRES))
+ {
+ PK_DBG("FL_dim_duty %d > thres %d, FLASH mode but timeout %d", duty, LEDS_CUSTOM_MODE_THRES, g_timeOutTimeMs);
+ strobe_mode_gpio_set(LEDS_TORCH_MODE);
+ flash_mode_pin = 0;
+ }
+ #endif
return 0;
}
int FL_Init(void)
{
...
+ #ifdef EN_PWM_CTRL
+ timerPWMInit();
+ #endif
3.6 alps/kernel-3.18/drivers/misc/mediatek/flashlight/src/mt6580/sub_strobe.c
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT // 此宏包括全部爲新加
+ static DEFINE_SPINLOCK(g_strobeSMPLock);
static DEFINE_MUTEX(sub_strobe_gpio_mutex);
struct pinctrl *substrobectrl = NULL;
struct pinctrl_state *sub_strobe_oh = NULL;
struct pinctrl_state *sub_strobe_ol = NULL;
static u32 strobe_Res = 0;
static u32 strobe_Timeus = 0;
static int g_duty=-1;
static int g_timeOutTimeMs=0;
static DEFINE_MUTEX(g_strobeSem);
static struct work_struct workTimeOut;
int sub_strobe_gpio_init(struct platform_device *pdev)
{
int ret = 0;
substrobectrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(substrobectrl)) {
dev_err(&pdev->dev, "Cannot find sub strobe pinctrl!");
ret = PTR_ERR(substrobectrl);
}
sub_strobe_oh = pinctrl_lookup_state(substrobectrl, "sub_strobe_oh");
if (IS_ERR(sub_strobe_oh)) {
ret = PTR_ERR(sub_strobe_oh);
pr_debug("%s : pinctrl err, sub_strobe_oh\n", __func__);
}
sub_strobe_ol = pinctrl_lookup_state(substrobectrl, "sub_strobe_ol");
if (IS_ERR(sub_strobe_ol)) {
ret = PTR_ERR(sub_strobe_ol);
pr_debug("%s : pinctrl err, sub_strobe_ol\n", __func__);
}
return ret;
}
void sub_strobe_gpio_set(int level)
{
mutex_lock(&sub_strobe_gpio_mutex);
if (level == 0)
pinctrl_select_state(substrobectrl, sub_strobe_ol);
else
pinctrl_select_state(substrobectrl, sub_strobe_oh);
mutex_unlock(&sub_strobe_gpio_mutex);
}
int SUB_FL_Enable(void)
{
sub_strobe_gpio_set(1);
PK_DBG(" SUB_FL_Enable line=%d\n",__LINE__);
return 0;
}
int SUB_FL_Disable(void)
{
sub_strobe_gpio_set(0);
PK_DBG(" SUB_FL_Disable line=%d\n",__LINE__);
return 0;
}
int SUB_FL_dim_duty(kal_uint32 duty)
{
PK_DBG(" SUB_FL_dim_duty line=%d\n",__LINE__);
g_duty = duty;
return 0;
}
int SUB_FL_Init(void)
{
PK_DBG(" SUB_FL_Init line=%d\n",__LINE__);
return 0;
}
int SUB_FL_Uninit(void)
{
SUB_FL_Disable();
return 0;
}
static void Sub_work_timeOutFunc(struct work_struct *data)
{
SUB_FL_Disable();
PK_DBG("ledTimeOut_callback\n");
}
enum hrtimer_restart Sub_ledTimeOutCallback(struct hrtimer *timer)
{
schedule_work(&workTimeOut);
return HRTIMER_NORESTART;
}
static struct hrtimer g_timeOutTimer;
void Sub_timerInit(void)
{
INIT_WORK(&workTimeOut, Sub_work_timeOutFunc);
g_timeOutTimeMs=1000; //1s
hrtimer_init( &g_timeOutTimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
g_timeOutTimer.function=Sub_ledTimeOutCallback;
}
static int Sub_constant_flashlight_flashlight_ioctl(unsigned int cmd, unsigned long arg)
{
int i4RetValue = 0;
int ior_shift;
int iow_shift;
int iowr_shift;
ior_shift = cmd - (_IOR(FLASHLIGHT_MAGIC,0, int));
iow_shift = cmd - (_IOW(FLASHLIGHT_MAGIC,0, int));
iowr_shift = cmd - (_IOWR(FLASHLIGHT_MAGIC,0, int));
PK_DBG("LM3642 Sub_constant_flashlight_flashlight_ioctl() line=%d ior_shift=%d, iow_shift=%d iowr_shift=%d arg=%d\n",__LINE__, ior_shift, iow_shift, iowr_shift,(int)arg);
switch(cmd)
{
case FLASH_IOC_SET_TIME_OUT_TIME_MS:
PK_DBG("FLASH_IOC_SET_TIME_OUT_TIME_MS: %d\n",(int)arg);
g_timeOutTimeMs=arg;
break;
case FLASH_IOC_SET_DUTY :
PK_DBG("FLASHLIGHT_DUTY: %d\n",(int)arg);
SUB_FL_dim_duty(arg);
break;
case FLASH_IOC_SET_STEP:
PK_DBG("FLASH_IOC_SET_STEP: %d\n",(int)arg);
break;
case FLASH_IOC_SET_ONOFF :
PK_DBG("FLASHLIGHT_ONOFF: %d\n",(int)arg);
if(arg==1)
{
int s;
int ms;
if(g_timeOutTimeMs>1000)
{
s = g_timeOutTimeMs/1000;
ms = g_timeOutTimeMs - s*1000;
}
else
{
s = 0;
ms = g_timeOutTimeMs;
}
if(g_timeOutTimeMs!=0)
{
ktime_t ktime;
ktime = ktime_set( s, ms*1000000 );
hrtimer_start( &g_timeOutTimer, ktime, HRTIMER_MODE_REL );
}
SUB_FL_Enable();
}
else
{
SUB_FL_Disable();
hrtimer_cancel( &g_timeOutTimer );
}
break;
default :
PK_DBG(" No such command \n");
i4RetValue = -EPERM;
break;
}
return i4RetValue;
}
static int Sub_constant_flashlight_open(void *pArg)
{
int i4RetValue = 0;
PK_DBG("Sub_constant_flashlight_open line=%d\n", __LINE__);
if (0 == strobe_Res)
{
SUB_FL_Init();
Sub_timerInit();
}
PK_DBG("Sub_constant_flashlight_open line=%d\n", __LINE__);
spin_lock_irq(&g_strobeSMPLock);
if(strobe_Res)
{
PK_ERR(" busy!\n");
i4RetValue = -EBUSY;
}
else
{
strobe_Res += 1;
}
spin_unlock_irq(&g_strobeSMPLock);
PK_DBG("Sub_constant_flashlight_open line=%d\n", __LINE__);
return i4RetValue;
}
static int Sub_constant_flashlight_release(void *pArg)
{
PK_DBG(" Sub_constant_flashlight_release\n");
if (strobe_Res)
{
spin_lock_irq(&g_strobeSMPLock);
strobe_Res = 0;
strobe_Timeus = 0;
spin_unlock_irq(&g_strobeSMPLock);
SUB_FL_Uninit();
}
PK_DBG(" Done\n");
return 0;
}
FLASHLIGHT_FUNCTION_STRUCT Sub_constantFlashlightFunc=
{
Sub_constant_flashlight_open,
Sub_constant_flashlight_release,
Sub_constant_flashlight_flashlight_ioctl
};
MUINT32 subStrobeInit(PFLASHLIGHT_FUNCTION_STRUCT *pfFunc)
{
if (pfFunc != NULL)
{
*pfFunc = &Sub_constantFlashlightFunc;
}
return 0;
}
+ // 以上全部爲新加
+ #else
...
MUINT32 subStrobeInit(PFLASHLIGHT_FUNCTION_STRUCT *pfFunc)
{
if (pfFunc != NULL)
*pfFunc = &subStrobeFunc;
return 0;
}
+ #endif
============sub strobe需要配置修改hal層,以下爲hal層=======================
3.7 alps/vendor/mediatek/proprietary/custom/mt6580/hal/flashlight/flash_tuning_custom2.h
+ #ifdef KST_SUB_FLASH_SUPPORT
+ #define SUB_FLASH_SUPPORT 1
+ #else
#define SUB_FLASH_SUPPORT 0
+ #endif
3.8 alps/vendor/mediatek/proprietary/custom/mt6580/hal/imgsensor_metadata/common/config_static_metadata_common.h
STATIC_METADATA_BEGIN(DEVICE, CAMERA, COMMON)
switch (rInfo.getDeviceId()){
case 0:
case 1:
+ #if defined(KST_SUB_FLASH_SUPPORT)
+ CONFIG_ENTRY_VALUE(MTK_FLASH_INFO_AVAILABLE_TRUE, MUINT8)
+ #else
CONFIG_ENTRY_VALUE(MTK_FLASH_INFO_AVAILABLE_FALSE, MUINT8)
+ #endif
CONFIG_METADATA_END()
break;
default:
3.9 配置: alps\kernel-3.18\arch\arm64\configs\xxx_debug_defconfig
CONFIG_MTK_FLASHLIGHT=y
CONFIG_KST_SUB_STROBE_SUPPORT=y // 前閃配置
CONFIG_KST_REAL_FLASH_MODE=y // 後真閃配置 - 有一個模式引腳
CONFIG_CUSTOM_KERNEL_FLASHLIGHT="constant_flashlight"
3.10 配置: alps\device\xxx\xxx\ProjectConfig.mk
+ AUTO_ADD_GLOBAL_DEFINE_BY_VALUE = KST_MISC_CUSTOM // 添加:KST_MISC_CUSTOM
+ KST_MISC_CUSTOM = KST_SUB_FLASH_SUPPORT // 前閃配置
CUSTOM_KERNEL_FLASHLIGHT=constant_flashlight
CUSTOM_HAL_FLASHLIGHT=constant_flashlight
零一、mt6739平臺(kernel-4.4 ):
1. dws配置pin腳:
EintMode|Def.Mode M0|M1|M2|M3|M4|M5|M6|M7|InPull En|InPull SelHigh|Def.Dir|In|Out|OutHigh|VarName1
GPIO42 NC // 有點奇怪NC也能控制?
GPIO10 0:GPIO10 1 0 0 1 1 0 1 0 1 0 OUT 0 1 0 GPIO_FLASH_LED_EN
GPIO13 NC // 有點奇怪NC也能控制?
2. dts配置gpio控制接口:
2.1 mt6580.dtsi:
- flashlights_rt4505: flashlights_rt4505 {
- compatible = "mediatek,flashlights_rt4505";
- };
+ strobe: strobe {
+ compatible = "mediatek,flashlights_dummy_gpio";
decouple = <0>;
channel@1 {
type = <0>;
ct = <0>;
part = <0>;
};
channel@2 {
type = <1>;
ct = <0>;
part = <0>;
+ };
+ };
2.2 k39tv1_bsp_1g.dts
+ /* FLASHLIGHT GPIO standardization */
+ &strobe {
pinctrl-names = "xxx_high", "xxx_low", "sub_xxx_high", "sub_xxx_low";
pinctrl-0 = <&xxx_high>;
pinctrl-1 = <&xxx_low>;
pinctrl-2 = <&sub_xxx_high>;
pinctrl-3 = <&sub_xxx_low>;
status = "okay";
};
&pio {
xxx_high: xxx_high {
pins_cmd_dat {
pins = <PINMUX_GPIO10__FUNC_GPIO10>;
slew-rate = <1>;
output-high;
};
};
xxx_low: xxx_low {
pins_cmd_dat {
pins = <PINMUX_GPIO10__FUNC_GPIO10>;
slew-rate = <1>;
output-low;
};
};
sub_xxx_high: sub_xxx_high {
pins_cmd_dat {
pins = <PINMUX_GPIO13__FUNC_GPIO13>;
slew-rate = <1>;
output-high;
};
};
sub_xxx_low: sub_xxx_low {
pins_cmd_dat {
pins = <PINMUX_GPIO13__FUNC_GPIO13>;
slew-rate = <1>;
output-low;
};
};
+ };
+ /* FLASHLIGHT end */
3. kernel-4.4/drivers/misc/mediatek/flashlight/flashlights-dummy-gpio.c
#define DUMMY_PINCTRL_PIN_XXX 0
#define DUMMY_PINCTRL_PINSTATE_LOW 0
#define DUMMY_PINCTRL_PINSTATE_HIGH 1
#define DUMMY_PINCTRL_STATE_XXX_HIGH "xxx_high"
#define DUMMY_PINCTRL_STATE_XXX_LOW "xxx_low"
static struct pinctrl *dummy_pinctrl;
static struct pinctrl_state *dummy_xxx_high;
static struct pinctrl_state *dummy_xxx_low;
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ #define SUB_DUMMY_PINCTRL_PIN_XXX 1
+ #define SUB_DUMMY_PINCTRL_PINSTATE_LOW 0
+ #define SUB_DUMMY_PINCTRL_PINSTATE_HIGH 1
+ #define SUB_DUMMY_PINCTRL_STATE_XXX_HIGH "sub_xxx_high"
+ #define SUB_DUMMY_PINCTRL_STATE_XXX_LOW "sub_xxx_low"
+ static struct pinctrl_state *sub_dummy_xxx_high;
+ static struct pinctrl_state *sub_dummy_xxx_low;
+ #endif
static int dummy_pinctrl_init(struct platform_device *pdev)
{
int ret = 0;
/* get pinctrl */
dummy_pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(dummy_pinctrl)) {
pr_err("Failed to get flashlight pinctrl.\n");
ret = PTR_ERR(dummy_pinctrl);
}
/* TODO: Flashlight XXX pin initialization */
dummy_xxx_high = pinctrl_lookup_state(dummy_pinctrl, DUMMY_PINCTRL_STATE_XXX_HIGH);
if (IS_ERR(dummy_xxx_high)) {
pr_err("Failed to init (%s)\n", DUMMY_PINCTRL_STATE_XXX_HIGH);
ret = PTR_ERR(dummy_xxx_high);
}
dummy_xxx_low = pinctrl_lookup_state(dummy_pinctrl, DUMMY_PINCTRL_STATE_XXX_LOW);
if (IS_ERR(dummy_xxx_low)) {
pr_err("Failed to init (%s)\n", DUMMY_PINCTRL_STATE_XXX_LOW);
ret = PTR_ERR(dummy_xxx_low);
}
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ /* TODO: sub Flashlight XXX pin initialization */
+ sub_dummy_xxx_high = pinctrl_lookup_state(dummy_pinctrl, SUB_DUMMY_PINCTRL_STATE_XXX_HIGH);
+ if (IS_ERR(sub_dummy_xxx_high)) {
+ pr_err("Failed to init (%s)\n", SUB_DUMMY_PINCTRL_STATE_XXX_HIGH);
+ ret = PTR_ERR(sub_dummy_xxx_high);
+ }
+ sub_dummy_xxx_low = pinctrl_lookup_state(dummy_pinctrl, SUB_DUMMY_PINCTRL_STATE_XXX_LOW);
+ if (IS_ERR(sub_dummy_xxx_low)) {
+ pr_err("Failed to init (%s)\n", SUB_DUMMY_PINCTRL_STATE_XXX_LOW);
+ ret = PTR_ERR(sub_dummy_xxx_low);
+ }
+ #endif
return ret;
}
static int dummy_pinctrl_set(int pin, int state)
{
...
switch (pin) {
case DUMMY_PINCTRL_PIN_XXX:
if (state == DUMMY_PINCTRL_PINSTATE_LOW && !IS_ERR(dummy_xxx_low))
pinctrl_select_state(dummy_pinctrl, dummy_xxx_low);
else if (state == DUMMY_PINCTRL_PINSTATE_HIGH && !IS_ERR(dummy_xxx_high))
pinctrl_select_state(dummy_pinctrl, dummy_xxx_high);
else
pr_err("set err, pin(%d) state(%d)\n", pin, state);
break;
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ case SUB_DUMMY_PINCTRL_PIN_XXX:
+ if (state == SUB_DUMMY_PINCTRL_PINSTATE_LOW && !IS_ERR(sub_dummy_xxx_low))
+ pinctrl_select_state(dummy_pinctrl, sub_dummy_xxx_low);
+ else if (state == SUB_DUMMY_PINCTRL_PINSTATE_HIGH && !IS_ERR(sub_dummy_xxx_high))
+ pinctrl_select_state(dummy_pinctrl, sub_dummy_xxx_high);
+ else
+ pr_err("set err, pin(%d) state(%d)\n", pin, state);
+ break;
+ #endif
...
}
static int dummy_enable(void)
{
int pin = 0, state = 1; //0;
return dummy_pinctrl_set(pin, state);
}
/* flashlight disable function */
static int dummy_disable(void)
{
int pin = 0, state = 0;
return dummy_pinctrl_set(pin, state);
}
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ static int sub_dummy_enable(void)
+ {
+ int pin = 1, state = 1;
+ return dummy_pinctrl_set(pin, state);
+ }
+ static int sub_dummy_disable(void)
+ {
+ int pin = 1, state = 0;
+ return dummy_pinctrl_set(pin, state);
+ }
+ #endif
static int dummy_ioctl(unsigned int cmd, unsigned long arg)
{
struct flashlight_dev_arg *fl_arg;
int channel;
ktime_t ktime;
fl_arg = (struct flashlight_dev_arg *)arg;
channel = fl_arg->channel;
switch (cmd) {
...
case FLASH_IOC_SET_ONOFF:
pr_debug("FLASH_IOC_SET_ONOFF(%d): %d\n",
channel, (int)fl_arg->arg);
if (fl_arg->arg == 1) {
if (dummy_timeout_ms) {
ktime = ktime_set(dummy_timeout_ms / 1000,
(dummy_timeout_ms % 1000) * 1000000);
hrtimer_start(&dummy_timer, ktime, HRTIMER_MODE_REL);
}
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ if(channel == 0)
+ dummy_enable();
+ else if(channel == 1)
+ sub_dummy_enable();
+ #else
dummy_enable();
+ #endif
} else {
+ #ifdef CONFIG_KST_SUB_STROBE_SUPPORT
+ if(channel == 0)
+ dummy_disable();
+ else if(channel == 1)
+ sub_dummy_disable();
+ #else
dummy_disable();
+ #endif
hrtimer_cancel(&dummy_timer);
}
break;
...
}
4.vendor/mediatek/proprietary/custom/mt6739/hal/flashlight/flash_tuning_custom2.h
- #if MTKCAM_SUB_FLASHLIGHT_SUPPORT
+ #ifdef KST_SUB_FLASH_SUPPORT // 改成用我們的宏控制,這個宏配置在ProjectConfig.mk
#define SUB_FLASH_SUPPORT 1
#else
#define SUB_FLASH_SUPPORT 0
#endif
5. vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/core/featureio/drv/strobe/flashlight_drv.cpp
int FlashlightDrv::setOnOff(int a_isOn)
{
...
if(m_duty > mOnDuty)
mOnDuty = m_duty;
int minPreOnTime;
- err = getPreOnTimeMsDuty(m_duty, &minPreOnTime);
+ getPreOnTimeMsDuty(m_duty, &minPreOnTime);
如若閃光燈還是無功能: 檢查驅動代碼,最好是先找一個ok的工程,從那邊移植過來
一、FlashLight(strobe)概要
1.FlashLiht分爲真閃和假閃,
真閃: 需要一個IC - 查bom可知v618上貼的是DIO5151(10pin)
假閃: 由一個三極管實現電流放大
兼容: 通常硬件上對真閃假閃做了兼容,即真假閃的電路都實現,二者使能腳爲同一引腳,
貼ic爲真閃,不貼即爲假閃(軟件不需要作區分)
2.真閃可以選擇模式(閃光燈/手電筒),通過對ic的GPIO_FLASH_STROBE引腳操作(HIGH - 閃光燈 LOW - 手電筒)
閃關燈: 電流可爲500mA
手電筒: 電流應該限制爲100mA
怎切換: HIGH - 閃光燈 LOW - 手電筒
3.驅動中實現了一個定時器來控制閃光燈的時長,閃光燈亮20s就自動滅,
實測: camera拍照閃光燈的關閉由上層ioctl關閉(log顯示)
實測: 手電筒不會20s自動滅 - ???
二、調試
1.真假閃均可以通過PWM的佔空比控制閃光的亮度 - 已驗證ok
alps\kernel-3.18\drivers\misc\mediatek\flashlight\src\mt6735\constant_flashlight\leds_strobe.c
enum hrtimer_restart ledPWMTimeOutCallback(struct hrtimer *timer)
{
if(g_enble_led == true) {
strobe_gpio_set(0);
g_timePWMOutTimeMs=2; // 低電平(滅燈)佔空比2/10
ktime = ktime_set( 0, g_timePWMOutTimeMs*800000 ); //1s
g_enble_led = false;
}
else if(g_enble_led == false) {
strobe_gpio_set(1);
g_timePWMOutTimeMs=8; // 高電平(亮燈)佔空比8/10
ktime = ktime_set( 0, g_timePWMOutTimeMs*800000 ); //1s
g_enble_led = true;
}
hrtimer_forward(&g_timePWMOutTimer, g_timePWMOutTimer.base->get_time(), ktime);
return HRTIMER_RESTART;
}
2. 方便測量電流 - 控制循環閃爍
alps\kernel-3.18\drivers\misc\mediatek\flashlight\src\mt6735\constant_flashlight\leds_strobe.c
case FLASH_IOC_SET_ONOFF:
PK_DBG("FLASHLIGHT_ONOFF: %d\n", (int)arg);
printk("201707 [%s] [%d] FLASH_IOC_SET_ONOFF: %d \n", __func__, __LINE__, (int)arg);
if (arg == 1) {
int s;
int ms;
/*
//==============================
int i = 0;
for(i = 0 ; i < 3; i++){
printk("201707 [%s] [%d] set(LEDS_TORCH_MODE) \n", __func__, __LINE__);
strobe_mode_gpio_set(LEDS_TORCH_MODE); // 手電筒模式
mdelay(5);
strobe_gpio_set(1); // 輸出1 - 亮
mdelay(10000);
strobe_gpio_set(0); // 輸出0 - 滅
mdelay(1000);
printk("201707 [%s] [%d] set(LEDS_FLASH_MODE) \n", __func__, __LINE__);
strobe_mode_gpio_set(LEDS_FLASH_MODE); // 閃光燈模式
mdelay(5);
strobe_gpio_set(1); // 輸出1 - 亮
mdelay(4000);
strobe_gpio_set(0); // 輸出0 - 滅
mdelay(1000);
}
//==============================
*/
案例一: 真閃IC:DIO5151(10pin) - 400ma的閃光燈電流只持續400ms,過後自動變小
更換pin對pin的另一個閃光燈IC(SGM3141B), 電流正常
案例二: 39平臺實現前後閃光燈
1. mt6739上mtk默認的閃光燈是使用rt4505這個ic來控制的,而當前我們的硬件電路的前後閃光燈的是假閃
修改k39tv1_bsp_1g_defconfig
- #CONFIG_MTK_FLASHLIGHT_RT4505=y
+ CONFIG_MTK_FLASHLIGHT_DUMMY_GPIO=y
2. 在mt6739.dts中這樣添加閃光燈的配置
+ strobe: strobe {
+ compatible = "mediatek,flashlights_dummy_gpio";
+ };
使之和flashlights-dummy-gpio.c相匹配
#define DUMMY_DTNAME "mediatek,flashlights_dummy_gpio"
static const struct of_device_id dummy_gpio_of_match[] = {
{.compatible = DUMMY_DTNAME},
{},
};
3. flashlights-dummy-gpio.c雖然加載起來了,但在攝像頭界面打開閃光燈,或者點擊手電筒圖標時,
並不會執行FLASH_IOC_SET_ONOFF這個case來操作GPIO控制語句
static int dummy_ioctl(unsigned int cmd, unsigned long arg)
{
……
case FLASH_IOC_SET_ONOFF:
pr_debug("FLASH_IOC_SET_ONOFF(%d): %d\n", // log未打印
……
}
4. 查看閃光燈從hal層往kernel端的調用流程
使用git grep -n "FLASH_IOC_SET_ONOFF" alps/vendor/mediatek/proprietary/命令,查找FLASH_IOC_SET_ONOFF是從哪個hal的cpp代碼下發到驅動的,發現在如下代碼內有調用
alps/vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/core/featureio/drv/strobe/flashlight_drv.cpp
int FlashlightDrv::setOnOff(int a_isOn)
{
int hasHw;
hasHw = hasFlashHw();
if(hasHw != 1)
return 0;
logI("setOnOff() isOn = %d\n",a_isOn);
if(checkValid()!=0)
return StrobeDrv::STROBE_UNKNOWN_ERROR;
int err = 0;
StrobeGlobalDriver* pKDrv;
pKDrv = StrobeGlobalDriver::getInstance();
if (a_isOn == 1) {
if(m_isOn == 0) {
mTurnOnTime = getMs();
mOnDuty = m_duty;
}
if(m_duty > mOnDuty)
mOnDuty = m_duty;
int minPreOnTime;
err = getPreOnTimeMsDuty(m_duty, &minPreOnTime);
//在此處添加調試信息,發現err是小於0的,追蹤getPreOnTimeMsDuty的函數定義。
if (minPreOnTime > 100)
minPreOnTime = 100;
else if (minPreOnTime < 0)
minPreOnTime = -1;
if (err < 0) {
logI("no preon");
} else {
if(minPreOnTime == -1) {
logI("no preon(preontime=-1)");
} else {
logI("preon support %d",m_preOnTime);
if (m_preOnTime == -1) {
setPreOn();
sleepMs(minPreOnTime);
} else {
int curTime;
int sleepTimeMs;
curTime = getMs();
sleepTimeMs = (minPreOnTime-(curTime-m_preOnTime));
logI("preon sleep %d ms", sleepTimeMs);
if(sleepTimeMs > minPreOnTime)
sleepTimeMs = minPreOnTime;
if(sleepTimeMs > 0) {
sleepMs( sleepTimeMs);
}
}
}
}
err = pKDrv->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 1);
//在此處添加調試信息,發現並未打印信息出來,在前面的語句添加調試信息。
} else if(a_isOn == 0) {
if (m_isOn == 1) {
mTurnOffTime= getMs();
if((mTurnOffTime-mTurnOnTime > mTimeOutTime) && (mTimeOutTime != 0))
logE("TimeOut");
}
m_preOnTime=-1;
err = pKDrv->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 0);
//在此處添加調試信息,發現並未打印信息出來,在前面的語句添加調試信息。
} else {
err = STROBE_ERR_PARA_INVALID;
}
if (err < 0) {
logE("setOnOff() err=%d\n", err);
}
if(!err)
m_isOn = a_isOn;
return err;
}
5. FLASH_IOC_GET_PRE_ON_TIME_MS_DUTY 和 FLASH_IOC_GET_PRE_ON_TIME_MS 未在flashlights-dummy-gpio.c定義,
hal層通過ioctl未獲取到返回值,導致flashlight_drv.cpp
未執行到
err = pKDrv->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 1);
err = pKDrv->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 0);
alps/vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/core/featureio/drv/strobe/flashlight_drv.cpp
int FlashlightDrv::getPreOnTimeMsDuty(int duty, int* ms)
{
logI("getPreOnTimeMsDuty()");
StrobeGlobalDriver* pKDrv;
pKDrv = StrobeGlobalDriver::getInstance();
int err;
err = pKDrv->sendCommand(FLASH_IOC_GET_PRE_ON_TIME_MS_DUTY, mTypeId, mCtId, (long)duty);
err = pKDrv->sendCommandRet(FLASH_IOC_GET_PRE_ON_TIME_MS, mTypeId, mCtId, ms);
logI("getPreOnTimeMs=%d err=%d", *ms, err);
return err;
}
git grep -n "sendCommand" alps/vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/
alps/vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/core/featureio/drv/strobe/strobe_global_driver.cpp
int StrobeGlobalDriver::sendCommandRet(int cmd, int typeId, int ctId, int *arg)
{
Mutex::Autolock lock(mLock);
return sendCommandRet_nolock(cmd, typeId, ctId, arg);
}
int StrobeGlobalDriver::sendCommandRet_nolock(int cmd, int typeId, int ctId, int *arg)
{
if (mStrobeHandle < 0) {
logE("sendCommand() mStrobeHandle <= 0 ~");
return StrobeDrv::STROBE_UNKNOWN_ERROR;
}
/* setup arguments */
/* TODO: redefine ioctl argument */
struct flashlight_user_arg stbArg;
stbArg.type_id = typeId;
stbArg.ct_id = ctId;
stbArg.arg = 0;
/* send ioctl */
int ret;
ret = ioctl(mStrobeHandle, cmd, &stbArg);
*arg = stbArg.arg;
return ret;
}
int StrobeGlobalDriver::sendCommand(int cmd, int typeId, int ctId, int arg)
{
Mutex::Autolock lock(mLock);
return sendCommand_nolock(cmd, typeId, ctId, arg);
}
int StrobeGlobalDriver::sendCommand_nolock(int cmd, int typeId, int ctId, int arg)
{
if (mStrobeHandle < 0) {
logE("sendCommand() mStrobeHandle <= 0 ~");
return StrobeDrv::STROBE_UNKNOWN_ERROR;
}
/* setup arguments */
struct flashlight_user_arg stbArg;
stbArg.type_id = typeId;
stbArg.ct_id = ctId;
stbArg.arg = arg;
/* send ioctl */
return ioctl(mStrobeHandle, cmd, &stbArg);
}
6. 不做getPreOnTimeMsDuty返回值的判斷就能進行對FLASH_IOC_SET_ONOFF的ioctl調用
alps/vendor/mediatek/proprietary/hardware/mtkcam/legacy/platform/mt6739/core/featureio/drv/strobe/flashlight_drv.cpp
int FlashlightDrv::setOnOff(int a_isOn)
{
……
int err = 0;
StrobeGlobalDriver* pKDrv;
pKDrv = StrobeGlobalDriver::getInstance();
if (a_isOn == 1) {
if(m_isOn == 0) {
mTurnOnTime = getMs();
mOnDuty = m_duty;
}
if(m_duty > mOnDuty)
mOnDuty = m_duty;
int minPreOnTime;
/*err = */getPreOnTimeMsDuty(m_duty, &minPreOnTime);
//在此處不把getPreOnTimeMsDuty的返回值賦給err即可。
if (minPreOnTime > 100)
minPreOnTime = 100;
else if (minPreOnTime < 0)
minPreOnTime = -1;
if (err < 0) {
logI("no preon");
} else {
……
}
7. 代碼修改
7.1 mt6739.dts
strobe: strobe {
compatible = "mediatek,flashlights_dummy_gpio";
decouple = <0>;
channel@1 {
type = <0>;
ct = <0>;
part = <0>;
};
channel@2 {
type = <1>;
ct = <0>;
part = <0>;
};
};
7.2 k39tv1_bsp_1g.dts
&strobe {
pinctrl-names = "xxx_high", "xxx_low", "sub_xxx_high", "sub_xxx_low";
pinctrl-0 = <&xxx_high>;
pinctrl-1 = <&xxx_low>;
pinctrl-2 = <&sub_xxx_high>;
pinctrl-3 = <&sub_xxx_low>;
status = "okay";
};
&pio {
xxx_high: xxx_high {
pins_cmd_dat {
pins = <PINMUX_GPIO10__FUNC_GPIO10>;
slew-rate = <1>;
output-high;
};
};
xxx_low: xxx_low {
pins_cmd_dat {
pins = <PINMUX_GPIO10__FUNC_GPIO10>;
slew-rate = <1>;
output-low;
};
};
sub_xxx_high: sub_xxx_high {
pins_cmd_dat {
pins = <PINMUX_GPIO13__FUNC_GPIO13>;
slew-rate = <1>;
output-high;
};
};
sub_xxx_low: sub_xxx_low {
pins_cmd_dat {
pins = <PINMUX_GPIO13__FUNC_GPIO13>;
slew-rate = <1>;
output-low;
};
};
};
7.3 flashlights-dummy-gpio.c
static int dummy_ioctl(unsigned int cmd, unsigned long arg)
{
……
case FLASH_IOC_SET_ONOFF:
pr_debug("FLASH_IOC_SET_ONOFF(%d): %d\n",
channel, (int)fl_arg->arg);
if (fl_arg->arg == 1) {
if (dummy_timeout_ms) {
ktime = ktime_set(dummy_timeout_ms / 1000,
(dummy_timeout_ms % 1000) * 1000000);
hrtimer_start(&dummy_timer, ktime, HRTIMER_MODE_REL);
}
#ifdef CONFIG_KST_SUB_STROBE_SUPPORT
if(channel == 0)
dummy_enable(); //支持前後假閃的後閃使用pinctrl的方式使能對應GPIO
else if(channel == 1)
sub_dummy_enable(); //支持前後假閃的後閃使用pinctrl的方式使能對應GPIO
#else
dummy_enable(); //只支持後假閃的後閃使用pinctrl的方式使能對應GPIO
#endif
} else {
#ifdef CONFIG_KST_SUB_STROBE_SUPPORT
if(channel == 0)
dummy_disable(); //支持前後假閃的後閃使用pinctrl的方式關閉對應GPIO
else if(channel == 1)
sub_dummy_disable(); //支持前後假閃的後閃使用pinctrl的方式關閉對應GPIO
#else
dummy_disable(); //只支持後假閃的後閃使用pinctrl的方式關閉對應GPIO
#endif
hrtimer_cancel(&dummy_timer);
}
break;
……
}
xxx.mk中配置是否支持前假閃的宏
#主板型號及內核宏定義配置
KST_KERNEL_BOARD_CUSTOM00 = KST_BOARD_V630K
KST_KERNEL_BOARD_CUSTOM01 = KST_SUB_STROBE_SUPPORT // 作用在kernel config
KST_KERNEL_BOARD_CUSTOM02 =
KST_KERNEL_BOARD_CUSTOM03 =
KST_KERNEL_BOARD_CUSTOM04 =
KST_KERNEL_BOARD_CUSTOM05 =
KST_KERNEL_BOARD_CUSTOM06 =
KST_KERNEL_BOARD_CUSTOM07 =
KST_KERNEL_BOARD_CUSTOM08 =
KST_KERNEL_BOARD_CUSTOM09 =
#Misc 配置
KST_MISC_CUSTOM= KST_SUB_FLASH_SUPPORT // 作用在ProjectConfig.mk
20. FlashLight調試日誌
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.