static int aps_12d_probe(
	
	struct i2c_client *client, const struct i2c_device_id *id)
{	
	/* define and initialization the value */
	int value_lsb = 0;
	int value_msb = 0;   
	int ret;
	struct aps_data *aps;
	/*the aps_12d sensors ispower on*/
	int i;
#ifdef CONFIG_ARCH_MSM7X30
	struct vreg *vreg_gp4=NULL;
	int rc;
	/*delete this line,27A don't have to match the power supply*/
	
    vreg_gp4 = vreg_get(NULL, VREG_GP4_NAME);
    if (IS_ERR(vreg_gp4)) 
    {
	    pr_err("%s:gp4 power init get failed\n", __func__);
    }

    /* set gp4 voltage as 2700mV for all */
    rc = vreg_set_level(vreg_gp4,VREG_GP4_VOLTAGE_VALUE_2700);
    
    if (rc) {
        pr_err("%s: vreg_gp4 vreg_set_level failed (%d)\n", __func__, rc);
        return rc;
    }
    rc = vreg_enable(vreg_gp4);
    if (rc) {
        pr_err("%s: vreg_gp4 vreg_enable failed (%d)\n", __func__, rc);
        return rc;
    }
#endif
    mdelay(5);
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        printk(KERN_ERR "aps_12d_probe: need I2C_FUNC_I2C\n");
        ret = -ENODEV;
        goto err_check_functionality_failed;
    }

	/* if querry the board is T1 or T2 turn off the proximity */
    /* This modification for version A&B of U8800,only */
	if((machine_is_msm7x30_u8800())&&((get_hw_sub_board_id() == HW_VER_SUB_VA) || ((get_hw_sub_board_id() == HW_VER_SUB_VB))))
	{
		printk(KERN_ERR "aps_12d_probe: aps is not supported in U8800 and U8800 T1 board!\n");
		ret = -ENODEV;
		goto err_check_functionality_failed; 
	}    

	aps = kzalloc(sizeof(*aps), GFP_KERNEL);
	if (aps == NULL) {
		ret = -ENOMEM;
		goto err_alloc_data_failed;
	}

	mutex_init(&aps->mlock);
	
	INIT_WORK(&aps->work, aps_12d_work_func);
	aps->client = client;
	i2c_set_clientdata(client, aps);

	PROXIMITY_DEBUG(KERN_INFO "ghj aps_12d_probe send command 2\n ");
	
	/* Command 2 register: 25mA,DC,12bit,Range1 */
	/*power_down to avoid the iic read error */
	aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_POWER_DOWN);
	
	/*init the flag,because everlight's 0x06,0x07's register's value low 4 bit is 0*/
	value_lsb = aps_i2c_reg_read(aps, APS_INT_HT_LSB);
	value_msb = aps_i2c_reg_read(aps, APS_INT_HT_MSB);
	old_lsb = value_lsb;
	old_msb = value_msb;
	
	/* debug--- stare at the value of lsb & msb */
	APS_DBG("value_lsb=%d,value_msb=%d\n",value_lsb,value_msb);
	/* judge the device type */
	/* when 06 07 registers don't equal 0x00, we think it's a intersil hardware */
	if((0x00 == value_lsb) && (0x00 == value_msb))
	{
		intersil_flag = EVERLIGHT;
	}
	else
	{
		intersil_flag = INTERSIL;
	}
	
	/* write reg value for the two device */
	if(EVERLIGHT == intersil_flag)
	{
		ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
							(uint8_t)(APS_12D_IRDR_SEL_50MA << 6 | \
										APS_12D_FREQ_SEL_DC << 4 | \
										APS_12D_RES_SEL_12 << 2 | \
										APS_12D_RANGE_SEL_ALS_1000));
	}
	else 
	{
		/*because Power-up and Power Supply Considerations is not good enough for intersil's datasheet,so avoid it via software*/
		ret = aps_i2c_reg_write(aps, APS_TEST, APS_12D_POWER_DOWN);
		if (ret < 0) 
		{
			PROXIMITY_DEBUG("APS_TEST error!\n");
		}
		msleep(10);
		ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_POWER_DOWN);
		if (ret < 0) 
		{
			PROXIMITY_DEBUG("APS_12D_POWER_DOWN error!\n");
		}
		msleep(10);
		ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
								(uint8_t)(APS_12D_IRDR_SEL_INTERSIL_50MA << 4 | \
										APS_FREQ_INTERSIL_DC << 6 | \
										APS_ADC_12 << 2 | \
										APS_INTERSIL_SCHEME_OFF| \
										APS_12D_RANGE_SEL_ALS_1000));
	}
	err_threshold_value[1] = 50;
	if (ret < 0) {
		goto err_detect_failed;
	}
	range_index = 0;
    #ifdef CONFIG_HUAWEI_HW_DEV_DCT
    /* detect current device successful, set the flag as present */
    set_hw_dev_flag(DEV_I2C_APS);
    #endif

	for(i = 0; i < TOTAL_RANGE_NUM; i++)
	{
		/* NOTE: do NOT use the last one */
		/* get the down_range_value */
		if(EVERLIGHT == intersil_flag)
		{
			up_range_value[i] = MAX_ADC_OUTPUT - high_threshold_value_U8661[i] - RANGE_FIX + 500; 
		}
		else
		{
			up_range_value[i] = MAX_ADC_OUTPUT - high_threshold_value_U8661_I[i] - RANGE_FIX + 500; 
		}
	}

	down_range_value[0] = 0;
	for(i = 1; i < TOTAL_RANGE_NUM; i++)
	{
		/* NOTE: do not use the first one */
		/* get the down_range_value */
		if(EVERLIGHT == intersil_flag)
		{
			down_range_value[i] = (MAX_ADC_OUTPUT - high_threshold_value_U8661[i-1] - (MAX_ADC_OUTPUT / ADJUST_GATE)) / 4 - 650;
		}
		else
		{
			down_range_value[i] = (MAX_ADC_OUTPUT - high_threshold_value_U8661_I[i-1] - (MAX_ADC_OUTPUT / ADJUST_GATE)) / 4 - 650;
		}
	}
	
	/*we don't use the input device sensors again */
	aps->input_dev = input_allocate_device();
	if (aps->input_dev == NULL) {
		ret = -ENOMEM;
		PROXIMITY_DEBUG(KERN_ERR "aps_12d_probe: Failed to allocate input device\n");
		goto err_input_dev_alloc_failed;
	}
	aps->input_dev->name = "sensors_aps";
	
	aps->input_dev->id.bustype = BUS_I2C;
	
	input_set_drvdata(aps->input_dev, aps);
	
	ret = input_register_device(aps->input_dev);
	if (ret) {
		printk(KERN_ERR "aps_probe: Unable to register %s input device\n", aps->input_dev->name);
		goto err_input_register_device_failed;
	}
	
	set_bit(EV_ABS, aps->input_dev->evbit);
	input_set_abs_params(aps->input_dev, ABS_LIGHT, 0, 10240, 0, 0);
	input_set_abs_params(aps->input_dev, ABS_DISTANCE, 0, 1, 0, 0);

	ret = misc_register(&light_device);
	if (ret) {
		printk(KERN_ERR "aps_12d_probe: light_device register failed\n");
		goto err_light_misc_device_register_failed;
	}

	ret = misc_register(&proximity_device);
	if (ret) {
		printk(KERN_ERR "aps_12d_probe: proximity_device register failed\n");
		goto err_proximity_misc_device_register_failed;
	}


	if( light_device.minor != MISC_DYNAMIC_MINOR ){
		light_device_minor = light_device.minor;
	}

	

	if( proximity_device.minor != MISC_DYNAMIC_MINOR ){
		proximity_device_minor = proximity_device.minor ;
	}

	wake_lock_init(&proximity_wake_lock, WAKE_LOCK_SUSPEND, "proximity");


	hrtimer_init(&aps->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	aps->timer.function = aps_timer_func;
	
	aps_wq = create_singlethread_workqueue("aps_wq");

	if (!aps_wq) 
	{
		ret = -ENOMEM;
		goto err_create_workqueue_failed;
	}
	
	this_aps_data =aps;
	ret = set_sensor_input(PS, aps->input_dev->dev.kobj.name);
	if (ret) {
		dev_err(&client->dev, "%s set_sensor_input failed\n", __func__);
		goto err_create_workqueue_failed;
	}
	ret = set_sensor_input(ALS, aps->input_dev->dev.kobj.name);
	if (ret) {
		dev_err(&client->dev, "%s set_sensor_input failed\n", __func__);
		goto err_create_workqueue_failed;
	}
	/* delete the redundant code */

	printk(KERN_INFO "aps_12d_probe: Start Proximity Sensor APS-12D\n");

	set_sensors_list(L_SENSOR + P_SENSOR);
	return 0;
	
err_create_workqueue_failed:
	misc_deregister(&proximity_device);
err_proximity_misc_device_register_failed:
	misc_deregister(&light_device);
err_light_misc_device_register_failed:
err_input_register_device_failed:
	input_free_device(aps->input_dev);
err_input_dev_alloc_failed:
err_detect_failed:
	kfree(aps);
err_alloc_data_failed:
err_check_functionality_failed:
#ifdef CONFIG_ARCH_MSM7X30
	if(NULL != vreg_gp4)
	{
        /* can't use the flag ret here, it will change the return value of probe function */
        vreg_disable(vreg_gp4);
        /* delete a line */
	}
#endif
	return ret;
  
}
static void aps_12d_work_func(struct work_struct *work)
{
	int flag = -1;
	// delete flag_old
	int ret;
	int reg_val_lsb;
	int reg_val_msb;
	int	sesc = aps_12d_delay/1000;
	int nsesc = (aps_12d_delay%1000)*1000000;
	uint16_t high_threshold = 0;
    uint16_t low_threshold = 0;
	int ir_count = 0;
	int ps_count = 0;
	uint16_t als_count = 0;
	uint8_t als_level = 0;
	/* del als_level_old */
	uint8_t i;
	struct aps_data *aps = container_of(work, struct aps_data, work);
	/* add printf infomation at the key point */
	if(INTERSIL == intersil_flag)
	{
		APS_DBG("intersil!\n");
	}
	else
	{
		APS_DBG("everlight!\n");
	}
	if (atomic_read(&p_flag)) {
		/* Command 1 register: IR once */
		adjust_time = 0;
	re_adjust:
		/* init the range to the num last time we set */
		if(( range_index >=0 ) && ( range_index < TOTAL_RANGE_NUM ))
		{
			/* deal with intersil and everlight with diferent valure */
			if(EVERLIGHT == intersil_flag)
			{
				aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
				(uint8_t)(APS_12D_IRDR_SEL_50MA << 6 | \
						APS_12D_FREQ_SEL_DC << 4 | \
						APS_12D_RES_SEL_12 << 2 | \
						range_reg_value[range_index]));
				high_threshold = high_threshold_value_U8661[range_index];
				low_threshold = low_threshold_value_U8661[range_index];
			}
			else 
			{
				aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
						(uint8_t)(APS_12D_IRDR_SEL_INTERSIL_50MA << 4 | \
									APS_FREQ_INTERSIL_DC << 6 | \
									APS_ADC_12 << 2 | \
									APS_INTERSIL_SCHEME_OFF| \
									range_reg_value[range_index]));
				high_threshold = high_threshold_value_U8661_I[range_index];
				low_threshold = low_threshold_value_U8661_I[range_index];	
			}
		}
		else
		{
			PROXIMITY_DEBUG("BUG: range_index error!!!!\n");
			range_index = 0;
		}
	er_adjust:
		/* deal with intersil and everlight with diferent mode */
		if(EVERLIGHT == intersil_flag)
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_IR_ONCE);
		}
		else
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_IR_CONTINUOUS);
		}
	    msleep(45);
	    reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
	    reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
	    ir_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
		
	    PROXIMITY_DEBUG("IR once lsb=%d; msb=%d; ir_count=%d \n", reg_val_lsb, reg_val_msb, ir_count);
	    if (ir_count > 0xFFF){
		    PROXIMITY_DEBUG("get wrong ir value, ir_count=%d \n", ir_count);
		    ir_count = 0xFFF;
	    }
	    if (ir_count < 0){
		    PROXIMITY_DEBUG("get wrong ir value, ir_count=%d \n", ir_count);
		    ir_count = 0;
	    }
		/*
		 * auto adjust the range
		 * stratety:
		 * if current adc value >= up_range_value[i]
		 *     switch to upper range
		 * if current adc value < down_range_value[i]
		 *     switch to lower range
		 */
		if(ir_count > up_range_value[range_index])
		{
			if(adjust_time < TOTAL_RANGE_NUM-1)
			{
				if(range_index < TOTAL_RANGE_NUM-1)
				{
					range_index++;
					adjust_time++;
					goto re_adjust;
				}
				else
				{
					PROXIMITY_DEBUG("infrared ray TOO HIGH?\n");
				}
			}
			else
			{
				PROXIMITY_DEBUG("proximity readjust exceed max retry times.\n");
			}
		}
		else if((ir_count < down_range_value[range_index]))
		{
			if(adjust_time < TOTAL_RANGE_NUM-1)
			{
				if(range_index >= TOTAL_RANGE_NUM-1)
				{
					range_index--;
					adjust_time++;
					goto re_adjust;
				}
				else
				{
					PROXIMITY_DEBUG("BUG: no exist lux value!!\n");
				}
			}
			else
			{
				PROXIMITY_DEBUG("proximity readjust exceed max retry times.\n");
			}
		}
		/*all of the intersil's ONCE module has a big risk */
		if(EVERLIGHT == intersil_flag)
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_PROXIMITY_ONCE);
		}
		else
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_PROXIMITY_CONTINUOUS);
		}
	    msleep(45);
	    reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
	    reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
	    ps_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
	    PROXIMITY_DEBUG("PS once lsb=%d; msb=%d; ps_count=%d \n", reg_val_lsb, reg_val_msb, ps_count);
	    if (ps_count > 0xFFF){
		    PROXIMITY_DEBUG("get wrong ps value, ps_count=%d \n", ps_count);
		    ps_count = 0xFFF;
	    }
	    if (ps_count < 0){
		    PROXIMITY_DEBUG("get wrong ps value, ps_count=%d \n", ps_count);
		    ps_count = 0;
	    }
		/*get value of proximity and light*/
	     proximity_data_value = ps_count;
		if (range_index == 1){     
		     light_data_value = ir_count*RANG_VALUE;
		}		     
		else {		     
		     light_data_value = ir_count;
		}		     
		/* delete this if, because we don't want filtrate the negative value 
		* when the value is negative , we set the status to away 
		*/
		if( (ps_count - ir_count) < low_threshold )
			flag = 1;
		else if ( (ps_count - ir_count) > err_threshold_value[range_index] )
			flag = -1;
		else if( (ps_count - ir_count) > high_threshold )
			flag = 0;
		else{
			PROXIMITY_DEBUG("the value is in the threshold, do not report. \n");
		}
		APS_DBG("the ps -ir is %d,the ps is %d,the ir is %d,the range_index is %d!\n",ps_count - ir_count,ps_count,ir_count,range_index);
		/* add printf infomation at the key point */
		APS_DBG("approch flag is %d ,0 is close,1 is far\n",flag);
		APS_DBG("lsb = 0x%x,msb = 0x%x\n",old_lsb,old_msb);
		/* skip invalid event */
		if(-1 != flag)
		{
			if(1 == flag)
			{
				/* report far event immediately */
				/* 0 is close, 1 is far */
				input_report_abs(aps->input_dev, ABS_DISTANCE, flag);
				input_sync(aps->input_dev);
			}
			else if(last_event != flag)
			{
				PROXIMITY_DEBUG("NOTE: skip unstable data: %s !!!\n", flag ? "far" : "close");
				last_event = flag;
				goto er_adjust;
			}
			else
			{
				PROXIMITY_DEBUG("report distance flag=%d \n", flag);
				/* 0 is close, 1 is far */
				input_report_abs(aps->input_dev, ABS_DISTANCE, flag);
				input_sync(aps->input_dev);
			}
		}
		/* save the last event */
		last_event = flag;

		/*
		 * reset the sensor range to 1000.
		 */
		if(0 != range_index)
		{
			/*all of the intersil's ONCE module has a big risk */
			if(EVERLIGHT == intersil_flag)
			{
				aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
						(uint8_t)(APS_12D_IRDR_SEL_50MA << 6 | \
							APS_12D_FREQ_SEL_DC << 4 | \
							APS_12D_RES_SEL_12 << 2 | \
							APS_12D_RANGE_SEL_ALS_1000));
			}
			else 
			{
				aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
						(uint8_t)(APS_12D_IRDR_SEL_INTERSIL_50MA << 4 | \
						APS_FREQ_INTERSIL_DC << 6 | \
						APS_ADC_12 << 2 | \
						APS_INTERSIL_SCHEME_OFF | \
						APS_12D_RANGE_SEL_ALS_1000));
			}
		}
	}

	if (atomic_read(&l_flag)) 
		{
		/* deal with intersil and everlight with diferent mode */
		if(EVERLIGHT == intersil_flag)
		{
		    ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_ALS_ONCE);
		}
		else
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_ALS_CONTINUOUS);
		}
		msleep(45);
		reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
		reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
		als_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
		/* add printf infomation at the key point */
		APS_DBG("ALS once lsb=%d; msb=%d; als_count=%d \n", reg_val_lsb, reg_val_msb, als_count);
		if (als_count > 0xFFF){
			PROXIMITY_DEBUG("get wrong als value, als_count=%d \n", als_count);
			als_count = 0xFFF;
		}

		als_level = LSENSOR_MAX_LEVEL - 1;
		/* deal with intersil and everlight lsensor */
		for (i = 0; i < ARRAY_SIZE(lsensor_adc_U8661_table); i++)
		{
			if(EVERLIGHT == intersil_flag)
			{
				if (als_count <= lsensor_adc_U8661_table[i])
				{
					als_level = i;
					break;
				}
			}
			else
			{
				if (als_count <= lsensor_adc_U8661_Inter_table[i])
				{
					als_level = i;
					break;
				}
			}
		}
		/* if it's intersil,it shoule be a power_down,because Power-up and Power Supply Considerations is not correct */
		APS_DBG("report adc level=%d \n", als_level);
		if(INTERSIL == intersil_flag)
		{
			ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_POWER_DOWN);
			msleep(10);				
		}
		if(aps_first_read)
		{
			/* report a invalid key first */
			aps_first_read = 0;
			/*changge the report event as -1 so the app will not changge anything*/
			input_report_abs(aps->input_dev, ABS_LIGHT, -1);
			input_sync(aps->input_dev);
		}
		else
		{
			APS_DBG("report lux value=%d \n", lsensor_adc_table[als_level]);
			input_report_abs(aps->input_dev, ABS_LIGHT, als_level);
			input_sync(aps->input_dev);
		}
	}
     if (atomic_read(&p_flag) || atomic_read(&l_flag))
		hrtimer_start(&aps->timer, ktime_set(sesc, nsesc), HRTIMER_MODE_REL);
	
}
Пример #3
0
static int rpr400_enable_als(struct i2c_client *client, int enable)
{
	struct PS_ALS_DATA *obj = i2c_get_clientdata(client);
	u8 databuf[2];	 
	int res = 0;
	u8 buffer[1];
	u8 reg_value[1];	
	u8 power_state, power_set;
	PWR_ST  pwr_st;
	
	if(client == NULL)
	{
		APS_DBG("CLIENT CANN'T EQUL NULL\n");
		return -1;
	}
	
	buffer[0]= REG_MODECONTROL;
	res = i2c_master_send(client, buffer, 0x1);
	if(res <= 0){
		goto EXIT_ERR;
	}
	res = i2c_master_recv(client, reg_value, 0x1);
	if(res <= 0){
		goto EXIT_ERR;
	}

	power_state = reg_value[0] & 0xF;
    if (MCTL_TABLE[power_state].PS == 0){
       	pwr_st.ps_state = CTL_STANDBY;
    }else{
        pwr_st.ps_state = CTL_STANDALONE;
    }
		
	if(enable){
		if (pwr_st.ps_state == CTL_STANDALONE){
			power_set = PWRON_PS_ALS;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}	
		}else if (pwr_st.ps_state == CTL_STANDBY){
			power_set = PWRON_ONLY_ALS;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
		}
		/*modify ps to ALS below two lines */
		atomic_set(&obj->als_deb_on, 1);
		atomic_set(&obj->als_deb_end, jiffies+atomic_read(&obj->als_debounce)/(1000/HZ));				
	}else{
		if (pwr_st.ps_state == CTL_STANDALONE){
			power_set = PWRON_ONLY_PS;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
		}else if (pwr_st.ps_state == CTL_STANDBY){
			power_set = PWRON_STANDBY;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}			
		}		
		atomic_set(&obj->als_deb_on, 0);
	}
	return 0;
		
	EXIT_ERR:
		APS_ERR("rpr400_enable_als fail\n");
		return res;
}
Пример #4
0
static int rpr400_enable_ps(struct i2c_client *client, int enable)
{
	struct PS_ALS_DATA *obj = i2c_get_clientdata(client);
	u8 databuf[2];   
	int res = 0;
	u8 buffer[1];
	u8 reg_value[1];
	u8 power_state, power_set;
	PWR_ST  pwr_st;	

	if(client == NULL)
	{
		APS_DBG("CLIENT CANN'T EQUL NULL\n");
		return -1;
	}

	buffer[0]= REG_MODECONTROL;
	res = i2c_master_send(client, buffer, 0x1);
	if(res <= 0){
		goto EXIT_ERR;
	}
	res = i2c_master_recv(client, reg_value, 0x1);
	if(res <= 0){
		goto EXIT_ERR;
	}

	power_state = reg_value[0] & 0xF;
    if(MCTL_TABLE[power_state].ALS == 0){
       	pwr_st.als_state = CTL_STANDBY;
    }else{
      	pwr_st.als_state = CTL_STANDALONE;
    }
		
	if(enable){
		if (pwr_st.als_state == CTL_STANDALONE){
			power_set = PWRON_PS_ALS;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
		}else if(pwr_st.als_state == CTL_STANDBY){
			power_set = PWRON_ONLY_PS;
			databuf[0] = REG_MODECONTROL;	
			databuf[1] = power_set | (reg_value[0] & CLR_LOW4BIT);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
		}
		
		atomic_set(&obj->ps_deb_on, 1);
		atomic_set(&obj->ps_deb_end, jiffies+atomic_read(&obj->ps_debounce)/(1000/HZ));
		
		if(0 == obj->polling_mode_ps)				
		{			
			databuf[0] = REG_PSTL_LSB;	
			databuf[1] = (u8)(PS_ALS_SET_PS_TL & 0x00FF);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
			databuf[0] = REG_PSTL_MBS;	
			databuf[1] = (u8)((PS_ALS_SET_PS_TL & 0xFF00) >> 8);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
			databuf[0] = REG_PSTH_LSB;	
			databuf[1] = (u8)(PS_ALS_SET_ALS_TH & 0x00FF);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
			databuf[0] = REG_PSTH_MBS;
			databuf[1] = (u8)((PS_ALS_SET_ALS_TH & 0xFF00) >> 8);
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}

			buffer[0]= REG_INTERRUPT;
			res = i2c_master_send(client, buffer, 0x1);
			if(res <= 0){
				goto EXIT_ERR;
			}
			res = i2c_master_recv(client, reg_value, 0x1);
			if(res <= 0){
				goto EXIT_ERR;
			}

			databuf[0] = REG_INTERRUPT;
			databuf[1] = reg_value[0]|MODE_PROXIMITY;
			res = i2c_master_send(client, databuf, 0x2);
			if(res <= 0){
				goto EXIT_ERR;
			}
			APS_LOG("rpr400_enable_ps: ps enabled.");
		}
			
	}else{
Пример #5
0
static void aps_12d_work_func(struct work_struct *work)
{
/* < DTS2010072801000 zhangtao 20100728 begin */
	/* < DTS2010090300997 zhangtao 20100903 begin */
	int flag = -1;
	/* DTS2010090300997 zhangtao 20100903 end > */
	// delete flag_old
	int ret;
	int reg_val_lsb;
	int reg_val_msb;
	int	sesc = aps_12d_delay/1000;
	int nsesc = (aps_12d_delay%1000)*1000000;
	/* <DTS2010060100640 zhangtao 20100601 begin*/
	/* < DTS2010073101147 zhangtao 20100731 begin */
	/* < DTS2010081803338 zhangtao 20100818 begin */
/* < DTS2010102103994 zhangtao 20101112 begin */
	uint16_t high_threshold = 0;
    uint16_t low_threshold = 0;
/* DTS2010102103994 zhangtao 20101112 end > */
	/* DTS2010081803338 zhangtao 20100818 end > */
	/* DTS2010073101147 zhangtao 20100731 end > */
	/* DTS2010060100640 zhangtao 20100601 end>*/
	int ir_count = 0;
	int ps_count = 0;
	uint16_t als_count = 0;
	uint8_t als_level = 0;
	/* del als_level_old */
	uint8_t i;
/* DTS2010072801000 zhangtao 20100728 end > */
	struct aps_data *aps = container_of(work, struct aps_data, work);
	PROXIMITY_DEBUG("ghj aps_12d_work_func enter\n ");

	if (atomic_read(&p_flag))
	{
		/* Command 1 register: IR once */
/* <DTS2010100800714 liugaofei 20101008 begin */
		adjust_time = 0;
	re_adjust:
		/* init the range to the num last time we set */
		if(( range_index >=0 ) && ( range_index < TOTAL_RANGE_NUM ))
		{
			aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
/* < DTS2010102103994 zhangtao 20101112 begin */
					(uint8_t)(APS_12D_IRDR_SEL_50MA << 6 | \
						APS_12D_FREQ_SEL_DC << 4 | \
						APS_12D_RES_SEL_12 << 2 | \
						range_reg_value[range_index]));
			high_threshold = high_threshold_value[range_index];
			low_threshold = low_threshold_value[range_index];
/* DTS2010102103994 zhangtao 20101112 end > */
		}
		else
		{
			PROXIMITY_DEBUG("BUG: range_index error!!!!\n");
			range_index = 0;
		}
	er_adjust:
/* DTS2010100800714 liugaofei 20101008 end */
	    ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_IR_ONCE);
/* < DTS2010102103994 zhangtao 20101112 begin */
	    msleep(45);
/* DTS2010102103994 zhangtao 20101112 end > */
	    reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
	    reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
	    ir_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
		
	    PROXIMITY_DEBUG("IR once lsb=%d; msb=%d; ir_count=%d \n", reg_val_lsb, reg_val_msb, ir_count);
/* < DTS2010072801000 zhangtao 20100728 begin */
	    if (ir_count > 0xFFF){
		    PROXIMITY_DEBUG("get wrong ir value, ir_count=%d \n", ir_count);
		    ir_count = 0xFFF;
	    }
	    if (ir_count < 0){
		    PROXIMITY_DEBUG("get wrong ir value, ir_count=%d \n", ir_count);
		    ir_count = 0;
	    }
/* <DTS2010100800714 liugaofei 20101008 begin */
		/*
		 * auto adjust the range
		 * stratety:
		 * if current adc value >= up_range_value[i]
		 *     switch to upper range
		 * if current adc value < down_range_value[i]
		 *     switch to lower range
		 */
		if(ir_count > up_range_value[range_index])
		{
			if(adjust_time < TOTAL_RANGE_NUM-1)
			{
				if(range_index < TOTAL_RANGE_NUM-1)
				{
					range_index++;
					adjust_time++;
					goto re_adjust;
				}
				else
				{
					PROXIMITY_DEBUG("infrared ray TOO HIGH?\n");
				}
			}
			else
			{
				PROXIMITY_DEBUG("proximity readjust exceed max retry times.\n");
			}
		}
		else if((ir_count < down_range_value[range_index]))
		{
			if(adjust_time < TOTAL_RANGE_NUM-1)
			{
				if(range_index >= TOTAL_RANGE_NUM-1)
				{
					range_index--;
					adjust_time++;
					goto re_adjust;
				}
				else
				{
					PROXIMITY_DEBUG("BUG: no exist lux value!!\n");
				}
			}
			else
			{
				PROXIMITY_DEBUG("proximity readjust exceed max retry times.\n");
			}
		}
/* DTS2010100800714 liugaofei 20101008 end */	
/* DTS2010072801000 zhangtao 20100728 end > */

	    ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_PROXIMITY_ONCE);
/* < DTS2010102103994 zhangtao 20101112 begin */
	    msleep(45);
/* DTS2010102103994 zhangtao 20101112 end > */
	    reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
	    reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
	    ps_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
	    PROXIMITY_DEBUG("PS once lsb=%d; msb=%d; ps_count=%d \n", reg_val_lsb, reg_val_msb, ps_count);
/* < DTS2010072801000 zhangtao 20100728 begin */
	    if (ps_count > 0xFFF){
		    PROXIMITY_DEBUG("get wrong ps value, ps_count=%d \n", ps_count);
		    ps_count = 0xFFF;
	    }
	    if (ps_count < 0){
		    PROXIMITY_DEBUG("get wrong ps value, ps_count=%d \n", ps_count);
		    ps_count = 0;
	    }
/* <DTS2010100800714 liugaofei 20101008 begin */		
		/* < DTS2011071500961  liujinggang 20110715 begin */
		/*get value of proximity and light*/
	     proximity_data_value = ps_count;
		if (range_index == 1){     
		     light_data_value = ir_count*RANG_VALUE;
		}		     
		else {		     
		     light_data_value = ir_count;
		}		     
		/* DTS2011071500961  liujinggang 20110715 end > */
		if ((ps_count - ir_count) > err_threshold_value[range_index] || (ps_count - ir_count) < 0 )
			flag = -1;
	    else if( (ps_count - ir_count) > high_threshold )
/* DTS2010100800714 liugaofei 20101008 end */			
	     flag = 0;
	    else if( (ps_count - ir_count) < low_threshold )
	    	flag = 1;
	    else{
		    PROXIMITY_DEBUG("the value is in the threshold, do not report. \n");
	    }
/* < DTS2010102103994 zhangtao 20101112 begin */
        APS_DBG("the ps -ir is %d,the ps is %d,the ir is %d,the range_index is %d!\n",ps_count - ir_count,ps_count,ir_count,range_index);
/* DTS2010102103994 zhangtao 20101112 end > */
/* DTS2010072801000 zhangtao 20100728 end > */
/* <DTS2010100800714 liugaofei 20101008 begin */
		/* skip invalid event */
		if(-1 != flag)
		{
			if(1 == flag)
			{
				/* report far event immediately */
				/* 0 is close, 1 is far */
				input_report_abs(aps->input_dev, ABS_DISTANCE, flag);
				input_sync(aps->input_dev);
			}
			else if(last_event != flag)
			{
				PROXIMITY_DEBUG("NOTE: skip unstable data: %s !!!\n", flag ? "far" : "close");
				last_event = flag;
				goto er_adjust;
			}
			else
			{
				PROXIMITY_DEBUG("report distance flag=%d \n", flag);
				/* 0 is close, 1 is far */
				input_report_abs(aps->input_dev, ABS_DISTANCE, flag);
				input_sync(aps->input_dev);
			}
		}

		/* save the last event */
		last_event = flag;

		/*
		 * reset the sensor range to 1000.
		 */
		if(0 != range_index)
		{
			aps_i2c_reg_write(aps, APS_12D_REG_CMD2, \
/* < DTS2010102103994 zhangtao 20101112 begin */
					(uint8_t)(APS_12D_IRDR_SEL_50MA << 6 | \
						APS_12D_FREQ_SEL_DC << 4 | \
						APS_12D_RES_SEL_12 << 2 | \
						APS_12D_RANGE_SEL_ALS_1000));
/* DTS2010102103994 zhangtao 20101112 end > */
		}
	}
/* DTS2010100800714 liugaofei 20101008 end */

	if (atomic_read(&l_flag)) 
		{
		ret = aps_i2c_reg_write(aps, APS_12D_REG_CMD1, APS_12D_ALS_ONCE);
/* < DTS2010102103994 zhangtao 20101112 begin */
		msleep(45);
/* DTS2010102103994 zhangtao 20101112 end > */
		reg_val_lsb = aps_i2c_reg_read(aps, APS_12D_DATA_LSB);
		reg_val_msb = aps_i2c_reg_read(aps, APS_12D_DATA_MSB);
		als_count = ((uint16_t)reg_val_msb << 8) + (uint16_t)reg_val_lsb;
		PROXIMITY_DEBUG("ALS once lsb=%d; msb=%d; als_count=%d \n", reg_val_lsb, reg_val_msb, als_count);

/* < DTS2010072801000 zhangtao 20100728 begin */
		if (als_count > 0xFFF){
			PROXIMITY_DEBUG("get wrong als value, als_count=%d \n", als_count);
			als_count = 0xFFF;
		}

		als_level = LSENSOR_MAX_LEVEL - 1;
		for (i = 0; i < ARRAY_SIZE(lsensor_adc_table); i++){
			if (als_count < lsensor_adc_table[i]){
				als_level = i;
				break;
			}
		}
		PROXIMITY_DEBUG("report adc level=%d \n", als_level);
		
		if(aps_first_read)
		{
			/* report a invalid key first */
			aps_first_read = 0;
			/* < DTS2011010500959 zhangtao 20110119 begin */
			/* < DTS2011030404089 zhangtao 20110314 begin */
			/*changge the report event as -1 so the app will not changge anything*/
			input_report_abs(aps->input_dev, ABS_LIGHT, -1);
			/* DTS2011030404089 zhangtao 20110314 end > */
			/* DTS2011010500959 zhangtao 20110119 end > */
			input_sync(aps->input_dev);
		}
		else
		{
			/* < DTS2011042705601 zhangtao 20110427 begin */
			input_report_abs(aps->input_dev, ABS_LIGHT, als_level);
			/* DTS2011042705601 zhangtao 20110427 end > */
			input_sync(aps->input_dev);
/* DTS2010072801000 zhangtao 20100728 end > */
		}
	}
	
     if (atomic_read(&p_flag) || atomic_read(&l_flag))
		hrtimer_start(&aps->timer, ktime_set(sesc, nsesc), HRTIMER_MODE_REL);
	
}