mtk平台闪光灯流程分析

驱动模块加载和卸载

module_init(flashlight_init);
module_exit(flashlight_exit);

static int __init flashlight_init(void)
{
    int ret = 0;
    logI("[flashlight_probe] start ~");
	ret = platform_device_register (&flashlight_platform_device);   // 注册设备
	if (ret) {
        logE("[flashlight_probe] platform_device_register fail ~");
        return ret;
	}
    ret = platform_driver_register(&flashlight_platform_driver);   // 注册驱动
	if(ret){
		logE("[flashlight_probe] platform_driver_register fail ~");
		return ret;
	}
	register_low_battery_notify(&Lbat_protection_powerlimit_flash, LOW_BATTERY_PRIO_FLASHLIGHT);
	register_battery_percent_notify(&bat_per_protection_powerlimit_flashlight, BATTERY_PERCENT_PRIO_FLASHLIGHT);
//  register_battery_oc_notify(&bat_oc_protection_powerlimit, BATTERY_OC_PRIO_FLASHLIGHT);
	logI("[flashlight_probe] done! ~");
    return ret;
}

设备注册
static struct platform_device flashlight_platform_device = {
    .name = FLASHLIGHT_DEVNAME,  // 设备名必须与驱动名匹配
    .id = 0,  
    .dev = {
    }
};

驱动注册
static struct platform_driver flashlight_platform_driver =
{
    .probe      = flashlight_probe,  // 探测函数
    .remove     = flashlight_remove,
    .shutdown   = flashlight_shutdown,
    .driver     = {
        .name = FLASHLIGHT_DEVNAME,
	.owner	= THIS_MODULE,
    },
};

#define ALLOC_DEVNO
static int flashlight_probe(struct platform_device *dev)
{
    int ret = 0, err = 0;
	logI("[flashlight_probe] start ~");
#ifdef ALLOC_DEVNO
    ret = alloc_chrdev_region(&flashlight_devno, 0, 1, FLASHLIGHT_DEVNAME);  // 动态申请字符设备
    if (ret) {
        logE("[flashlight_probe] alloc_chrdev_region fail: %d ~", ret);
        goto flashlight_probe_error;
    } else {
        logI("[flashlight_probe] major: %d, minor: %d ~", MAJOR(flashlight_devno), MINOR(flashlight_devno));
    }
    cdev_init(&flashlight_cdev, &flashlight_fops);  // 初始化设备操作集
    flashlight_cdev.owner = THIS_MODULE;
    err = cdev_add(&flashlight_cdev, flashlight_devno, 1);  // 设备操作集链接到系统中
    if (err) {
        logE("[flashlight_probe] cdev_add fail: %d ~", err);
        goto flashlight_probe_error;
    }
#else
    #define FLASHLIGHT_MAJOR 242
    ret = register_chrdev(FLASHLIGHT_MAJOR, FLASHLIGHT_DEVNAME, &flashlight_fops);   // 手动注册字符设备
    if (ret != 0) {
        logE("[flashlight_probe] Unable to register chardev on major=%d (%d) ~", FLASHLIGHT_MAJOR, ret);
        return ret;
    }
    flashlight_devno = MKDEV(FLASHLIGHT_MAJOR, 0);
#endif
    flashlight_class = class_create(THIS_MODULE, "flashlightdrv");  // 创建类节点   /sys/class/flashlightdrv 
    if (IS_ERR(flashlight_class)) {
        logE("[flashlight_probe] Unable to create class, err = %d ~", (int)PTR_ERR(flashlight_class));
        goto flashlight_probe_error;
    }
    flashlight_device = device_create(flashlight_class, NULL, flashlight_devno, NULL, FLASHLIGHT_DEVNAME);  注册设备节点 /dev/kd_camera_flashlight  
    if(NULL == flashlight_device){
        logE("[flashlight_probe] device_create fail ~");
        goto flashlight_probe_error;
    }
    //initialize members
    spin_lock_init(&flashlight_private.lock);  // 初始化自旋锁
    init_waitqueue_head(&flashlight_private.read_wait);  // 初始化等待队列
    //init_MUTEX(&flashlight_private.sem);
    sema_init(&flashlight_private.sem, 1);  // 初始化信号量
    logI("[flashlight_probe] Done ~");
    return 0;

flashlight_probe_error:
#ifdef ALLOC_DEVNO
    if (err == 0)
        cdev_del(&flashlight_cdev);
    if (ret == 0)
        unregister_chrdev_region(flashlight_devno, 1);
#else
    if (ret == 0)
        unregister_chrdev(MAJOR(flashlight_devno), FLASHLIGHT_DEVNAME);
#endif
    return -1;
}


static struct file_operations flashlight_fops = {
    .owner      = THIS_MODULE,
    .unlocked_ioctl      = flashlight_ioctl,
    .open       = flashlight_open,
    .release    = flashlight_release,
#ifdef CONFIG_COMPAT
    .compat_ioctl = my_ioctl_compat,
#endif
};


static int flashlight_open(struct inode *inode, struct file *file)
{
	int i4RetValue = 0;
	static int bInited=0;  
	if(bInited==0)  // 该动作执行一次
	{
		globalInit();
		bInited=1;
	}
    logI("[flashlight_open] E ~");
    return i4RetValue;
}


static FLASHLIGHT_FUNCTION_STRUCT *g_pFlashInitFunc[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev][e_Max_Part_Num_Per_Dev];
static int gLowBatDuty[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev];
static int g_strobePartId[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev];
int globalInit(void)    // 初始化参数
{
	int i;
	int j;
	int k;
	logI("globalInit");
	for(i=0;i<e_Max_Sensor_Dev_Num;i++)
	for(j=0;j<e_Max_Strobe_Num_Per_Dev;j++)
	{
	    gLowBatDuty[i][j]=-1;
		g_strobePartId[i][j]=1;
		for(k=0;k<e_Max_Part_Num_Per_Dev;k++)
		{
			g_pFlashInitFunc[i][j][k]=0;
		}

	}
	return 0;
}

//上层调用底层的IOCTL接口函数操作
static long flashlight_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int err;
//    int dir;
    err = flashlight_ioctl_core(file, cmd, arg);  // 调用核心接口
    //dir  = _IOC_DIR(cmd);
    //if(dir &_IOC_READ)
    {
      //  copy_to_user
    }
    return err;
}

typedef struct
{
    int sensorDev;
	int strobeId;
    int arg;

}kdStrobeDrvArg;


static long flashlight_ioctl_core(struct file *file, unsigned int cmd, unsigned long arg)
{
	int partId;
	int sensorDevIndex;
	int strobeIndex;
	int partIndex;
   	 int i4RetValue = 0;
	kdStrobeDrvArg kdArg;
	unsigned long copyRet;
        copyRet = copy_from_user(&kdArg , (void *)arg , sizeof(kdStrobeDrvArg));  // 获取上次要操作的flashlight 设备信息
        logI("flashlight_ioctl cmd=0x%x(nr=%d), senorDev=0x%x ledId=0x%x arg=0x%lx",cmd, _IOC_NR(cmd), kdArg.sensorDev, kdArg.strobeId ,(unsigned long)kdArg.arg);
	sensorDevIndex = getSensorDevIndex(kdArg.sensorDev);  // 获得主 副摄像头
	strobeIndex = getStrobeIndex(kdArg.strobeId);  // 判断取值范围是否是1~2
	if(sensorDevIndex<0 || strobeIndex<0 )
		return -1;
	partId = g_strobePartId[sensorDevIndex][strobeIndex];  // flashlight_open初始化默认是1 
	partIndex = getPartIndex(partId); // 取值范围是否符合1~2  
	if(partIndex<0) 
		return -1;
    switch(cmd)
    {
        case FLASH_IOC_GET_PROTOCOL_VERSION:  
            i4RetValue=1; 
            break;
        case FLASH_IOC_IS_LOW_POWER:  // 上报低电量值1给上层
            logI("FLASH_IOC_IS_LOW_POWER");
            {
                int isLow=0;
                if(gLowPowerPer!=BATTERY_PERCENT_LEVEL_0 || gLowPowerVbat!=LOW_BATTERY_LEVEL_0 )
                    isLow=1;
                logI("FLASH_IOC_IS_LOW_POWER %d %d %d",gLowPowerPer,gLowPowerVbat,isLow);
                kdArg.arg = isLow;
                if(copy_to_user((void __user *) arg , (void*)&kdArg , sizeof(kdStrobeDrvArg)))
    			{
    				logE("[FLASH_IOC_IS_LOW_POWER] ioctl copy to user failed ~");
    				return -EFAULT;
    			}
		    }
			break;

        case FLASH_IOC_LOW_POWER_DETECT_START:  // 开始检测低电量
	    logI("FLASH_IOC_LOW_POWER_DETECT_START");
            gLowBatDuty[sensorDevIndex][strobeIndex]=kdArg.arg;
            break;

        case FLASH_IOC_LOW_POWER_DETECT_END:  // 设置当前低电量检测结束标志
   	    logI("FLASH_IOC_LOW_POWER_DETECT_END");
   	    gLowBatDuty[sensorDevIndex][strobeIndex]=-1;
            break;
        case FLASHLIGHTIOC_X_SET_DRIVER:  // 根据上层传下来的设备信息,执行flashlight的open函数,并且获得对应闪光灯的操作函数集地址
            i4RetValue = setFlashDrv(kdArg.sensorDev,  kdArg.strobeId);
            break;
	case FLASH_IOC_GET_PART_ID:
       	case FLASH_IOC_GET_MAIN_PART_ID:
	case FLASH_IOC_GET_SUB_PART_ID:
	case FLASH_IOC_GET_MAIN2_PART_ID:
		{
				int partId;
				partId = strobe_getPartId(kdArg.sensorDev, kdArg.strobeId);
				g_strobePartId[sensorDevIndex][strobeIndex]=partId;  // 判断是不是前后摄像头,若是的话返回1,否则返回100;
				kdArg.arg = partId;
				if(copy_to_user((void __user *) arg , (void*)&kdArg , sizeof(kdStrobeDrvArg)))
    			{
    				logE("[FLASH_IOC_GET_PART_ID] ioctl copy to user failed ~");
    				return -EFAULT;
    			}
				logI("FLASH_IOC_GET_PART_ID line=%d partId=%d",__LINE__,partId);
		}
          	break;
         case FLASH_IOC_SET_ONOFF:
            {
				FLASHLIGHT_FUNCTION_STRUCT *pF;
				pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
				if(pF!=0)
				{
					kicker_pbm_by_flash(kdArg.arg);
					i4RetValue = pF->flashlight_ioctl(cmd,kdArg.arg);  //设置闪光的constant_flashlight_ioctl函数
				}
				else
				{
					logE("[FLASH_IOC_SET_ONOFF] function pointer is wrong -");
				}
			}
            break;
	case FLASH_IOC_UNINIT: 
		{
				FLASHLIGHT_FUNCTION_STRUCT *pF;
				pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
				if(pF!=0)
				{
					i4RetValue = pF->flashlight_release((void*)0);  //调用对应的constant_flashlight_release函数
					pF=0;
				}
				else
				{
					logE("[FLASH_IOC_UNINIT] function pointer is wrong ~");
				}
		}
            break;
    	default :  
			{
				FLASHLIGHT_FUNCTION_STRUCT *pF;
				pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
				if(pF!=0)
				{
					i4RetValue = pF->flashlight_ioctl(cmd,kdArg.arg);  //设置闪光的constant_flashlight_ioctl函数
				}
				else
				{
					logE("[default] function pointer is wrong ~");
				}
			}
    		break;
    }
    return i4RetValue;
}

// 执行对应闪光灯芯片驱动的open 函数接口
static int setFlashDrv(int sensorDev, int strobeId)
{
	int partId;
	int sensorDevIndex;
    int strobeIndex;
	int partIndex;
	FLASHLIGHT_FUNCTION_STRUCT** ppF=0;
	sensorDevIndex = getSensorDevIndex(sensorDev);
	strobeIndex = getStrobeIndex(strobeId);
	if(sensorDevIndex<0 || strobeIndex<0 )
		return -1;
	partId = g_strobePartId[sensorDevIndex][strobeIndex];
	partIndex = getPartIndex(partId);
	if(partIndex<0)
		return -1;
	logI("setFlashDrv sensorDev=%d, strobeId=%d, partId=%d ~",sensorDev, strobeId, partId);
	ppF = &g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];  // 函数集地址
	if(sensorDev==e_CAMERA_MAIN_SENSOR)  // 根据主副摄像头获得前闪光灯与后闪光灯的操作函数地址
	{
    	#if defined(DUMMY_FLASHLIGHT)
    	    strobeInit_dummy(ppF);
    	#else
        	if(strobeId==1)
        	{
                if(partId==1)
        			constantFlashlightInit(ppF);  // 获取函数地址
        		else if(partId==2)
        			strobeInit_main_sid1_part2(ppF);
        	}
        	else if(strobeId==2)
        	{
        		if(partId==1)
        			strobeInit_main_sid2_part1(ppF);

        		else if(partId==2)
        			strobeInit_main_sid2_part2(ppF);
        	}
        #endif
	}
	else if(sensorDev==e_CAMERA_SUB_SENSOR)
	{
	    if(strobeId==1)
    	{
            if(partId==1)
    			subStrobeInit(ppF);
    		else if(partId==2)
    			strobeInit_sub_sid1_part2(ppF);
    	}
    	else if(strobeId==2)
    	{
    		if(partId==1)
    			strobeInit_sub_sid2_part1(ppF);
    		else if(partId==2)
    			strobeInit_sub_sid2_part2(ppF);
    	}
	}


	if((*ppF)!=0)
	{
		(*ppF)->flashlight_open(0);  // 执行对应函数 constant_flashlight_open
		logI("setFlashDrv ok %d",__LINE__);
	}
	else
	{
		logE("set function pointer not found!!");
		return -1;
	}
	return 0;
}


下面我们来看看IOCTL中调用的几个接口函数。
FLASHLIGHT_FUNCTION_STRUCT	constantFlashlightFunc=
{
	constant_flashlight_open,
	constant_flashlight_release,
	constant_flashlight_ioctl
};


MUINT32 constantFlashlightInit(PFLASHLIGHT_FUNCTION_STRUCT *pfFunc)
{
    if (pfFunc != NULL)
    {
        *pfFunc = &constantFlashlightFunc;
    }
    return 0;
}


static int constant_flashlight_open(void *pArg)
{
    int i4RetValue = 0;
    PK_DBG("constant_flashlight_open line=%d\n", __LINE__);
	if (0 == strobe_Res)  //全局静态变量, strobe_Res=0
	{
	    FL_Init();  // 初始化闪光灯对应的IC寄存器
		timerInit();  // 初始化工作队列,定时1s钟关闭闪光灯
	}
	PK_DBG("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("constant_flashlight_open line=%d\n", __LINE__);
    return i4RetValue;

}


static int constant_flashlight_release(void *pArg)
{
    PK_DBG(" constant_flashlight_release\n");
    if (strobe_Res)  // 若闪光灯已经打开,就关闭闪光灯
    {
        spin_lock_irq(&g_strobeSMPLock);

        strobe_Res = 0;  // 复位打开闪光灯标志位
        spin_unlock_irq(&g_strobeSMPLock);
    	FL_Uninit();  // 关闭闪光灯  -->FL_Disable 设置闪光灯IC寄存器关闭灯
    }
    PK_DBG(" Done\n");
    return 0;
}



static int constant_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 constant_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);
    		FL_dim_duty(arg);  // 设置duty值
    		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)  // 根据设置的超时时间启动定时器,如超过超时时间关闭闪光灯
	            {  //控制闪关灯打开时间小于1s
	            	ktime_t ktime;
			ktime = ktime_set( s, ms*1000000 );
			hrtimer_start( &g_timeOutTimer, ktime, HRTIMER_MODE_REL );
	            }
    		FL_Enable();  // 打开是闪光灯  根据duty值使能不同模式的闪光灯
    		}
    		else
    		{
    			FL_Disable(); // 关闭是闪光灯
			hrtimer_cancel( &g_timeOutTimer );  // 关闭定时器
    		}
    		break;
		default :
    		PK_DBG(" No such command \n");
    		i4RetValue = -EPERM;
    		break;
    }
    return i4RetValue;
}

由于平台使用的flashlight为LM3642,因此针对这个芯片我们来看看它的打开与关闭闪光灯以及控制不同模式的闪光灯。比如,预闪 手电筒 主闪等模式。
int FL_Enable(void)
{
	char buf[2];
//	char bufR[2];
    if(g_duty<0)  // 设置duty值范围
        g_duty=0;
    else if(g_duty>16)
        g_duty=16;
  if(g_duty<=2)  // 根据duty值设置不同闪关灯效果
  {
        int val;
        if(g_bLtVersion==1)
        {
            if(g_duty==0)
                val=3;
            else if(g_duty==1)
                val=5;
            else //if(g_duty==2)
                val=7;
        }
        else
        {
            if(g_duty==0)
                val=1;
            else if(g_duty==1)
                val=2;
            else //if(g_duty==2)
                val=3;
        }
        buf[0]=9;
        buf[1]=val<<4;
        //iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
        LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
    buf[0]=10;
        buf[1]=0x02;
        //iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
        LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
  }
    else
  {
    int val;
    val = (g_duty-1);
    buf[0]=9;
	  buf[1]=val;
	  //iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	  LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);

	  buf[0]=10;
	  buf[1]=0x03;
	  //iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	  LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
  }
    PK_DBG(" FL_Enable line=%d\n",__LINE__);
    readReg(0);
	readReg(1);
	readReg(6);
	readReg(8);
	readReg(9);
	readReg(0xa);
	readReg(0xb);

    return 0;
}

// 关闭闪光灯
int FL_Disable(void)
{
char buf[2];
      buf[0]=10;
	buf[1]=0x00;
	//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
	PK_DBG(" FL_Disable line=%d\n",__LINE__);
    return 0;
}

// 设置不同的duty值
int FL_dim_duty(kal_uint32 duty)
{
    PK_DBG(" FL_dim_duty line=%d\n",__LINE__);
	g_duty = duty;
    return 0;
}

// 初始化LM3642寄存器
int FL_Init(void)
{
   int regVal0;
  char buf[2];
 	 buf[0]=0xa;
	buf[1]=0x0;
	//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);

	buf[0]=0x8;
	buf[1]=0x47;
	//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);

	buf[0]=9;
	buf[1]=0x35;
	//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
	LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
	//static int LM3642_read_reg(struct i2c_client *client, u8 reg)
	//regVal0 = readReg(0);
	regVal0 = LM3642_read_reg(LM3642_i2c_client, 0);

	if(regVal0==1)
	    g_bLtVersion=1;
	else
	    g_bLtVersion=0;
    PK_DBG(" FL_Init regVal0=%d isLtVer=%d\n",regVal0, g_bLtVersion);
/*
   if(mt_set_gpio_mode(FLASH_GPIO_ENT,GPIO_MODE_00)){PK_DBG("[constant_flashlight] set gpio mode failed!! \n");}
    if(mt_set_gpio_dir(FLASH_GPIO_ENT,GPIO_DIR_OUT)){PK_DBG("[constant_flashlight] set gpio dir failed!! \n");}
    if(mt_set_gpio_out(FLASH_GPIO_ENT,GPIO_OUT_ZERO)){PK_DBG("[constant_flashlight] set gpio failed!! \n");}

    if(mt_set_gpio_mode(FLASH_GPIO_ENF,GPIO_MODE_00)){PK_DBG("[constant_flashlight] set gpio mode failed!! \n");}
    if(mt_set_gpio_dir(FLASH_GPIO_ENF,GPIO_DIR_OUT)){PK_DBG("[constant_flashlight] set gpio dir failed!! \n");}
    if(mt_set_gpio_out(FLASH_GPIO_ENF,GPIO_OUT_ZERO)){PK_DBG("[constant_flashlight] set gpio failed!! \n");}
    */
    PK_DBG(" FL_Init line=%d\n",__LINE__);
    return 0;
}

// 取消闪光灯
int FL_Uninit(void)
{
    FL_Disable();
    return 0;
}
``
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值