static ssize_t
proximity_enable_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct gp2a_data *data = dev_get_drvdata(dev);

	int value = 0;
	int err = 0;
	int16_t thrd;
	u8 reg;

	err = kstrtoint(buf, 10, &value);

	if (err) {
		pr_err("%s, kstrtoint failed.", __func__);
		goto done;
	}
	if (value != 0 && value != 1)
		goto done;

        printk(KERN_INFO "[GP2A] proximity_enable_store : value=%d, offset=%d\n", value, data->offset_value);

	if (data->proximity_enabled && !value) {	/* Prox power off */
		data->proximity_enabled = value;
		disable_irq(data->irq);

		proximity_onoff(0, data);
		if (data->pdata->led_on)
			data->pdata->led_on(0);
	}
	if (!data->proximity_enabled && value) {	/* prox power on */
		data->proximity_enabled = value;
		if (data->pdata->led_on)
			data->pdata->led_on(1);
		msleep(5);
		proximity_onoff(1, data);

		thrd = gp2a_reg[3][1]+(data->offset_value);
		THR_REG_LSB(thrd, reg);
		gp2a_i2c_write(gp2a_reg[3][0], &reg);
		THR_REG_MSB(thrd, reg);
		gp2a_i2c_write(gp2a_reg[4][0], &reg);

		thrd = gp2a_reg[5][1]+(data->offset_value);
		THR_REG_LSB(thrd, reg);
		gp2a_i2c_write(gp2a_reg[5][0], &reg);
		THR_REG_MSB(thrd, reg);
		gp2a_i2c_write(gp2a_reg[6][0], &reg);

		input_report_abs(data->proximity_input_dev, ABS_DISTANCE, 1);
		input_sync(data->proximity_input_dev);

		enable_irq(data->irq);
	}
done:
	return count;
}
Beispiel #2
0
static int gp2a_prox_manual_offset(struct gp2a_data  *data, u8 change_on)
{
	struct file *cal_filp;
	int err;
	int16_t thrd;
	u8 reg;
	mm_segment_t old_fs;

	data->offset_value = change_on;
	/* update threshold */
	thrd = gp2a_reg[3][1]+(data->offset_value);
	THR_REG_LSB(thrd, reg);
	gp2a_i2c_write(data, gp2a_reg[3][0], &reg);
	THR_REG_MSB(thrd, reg);
	gp2a_i2c_write(data, gp2a_reg[4][0], &reg);

	thrd = gp2a_reg[5][1]+(data->offset_value);
	THR_REG_LSB(thrd, reg);
	gp2a_i2c_write(data, gp2a_reg[5][0], &reg);
	THR_REG_MSB(thrd, reg);
	gp2a_i2c_write(data, gp2a_reg[6][0], &reg);

	/* calibration result */
	data->cal_result = 1;

	old_fs = get_fs();
	set_fs(KERNEL_DS);

	cal_filp = filp_open(CAL_PATH,
			O_CREAT | O_TRUNC | O_WRONLY,
			S_IRUGO | S_IWUSR | S_IWGRP);
	if (IS_ERR(cal_filp)) {
		pr_err("%s Can't open calibration file\n", __func__);
		set_fs(old_fs);
		err = PTR_ERR(cal_filp);
		goto done;
	}

	err = cal_filp->f_op->write(cal_filp,
		(char *)&data->offset_value, sizeof(int),
			&cal_filp->f_pos);
	if (err != sizeof(int)) {
		pr_err("%s Can't write the cal data to file\n",
			__func__);
		err = -EIO;
	}

	filp_close(cal_filp, current->files);
done:
	set_fs(old_fs);
	return err;
}
static long gp2a_opt_ioctl(struct file *file, unsigned int cmd,  unsigned long arg)
{	
	int ret = 0;
	short data = 0;
	u8 thrd = 0;
	u8 reg;

	switch (cmd)
	{
		case PROX_IOC_SET_CALIBRATION:
		{
			printk(KERN_INFO "[GP2A] PROX_IOC_SET_CALIBRATION\n");                
			if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
				return -EFAULT;

			ret = proximity_open_calibration(gp2a_opt_data);
			if (ret < 0 && ret != -ENOENT)
			{
				printk(KERN_INFO "[GP2A] proximity_open_offset() failed\n");
			}else {
				thrd = gp2a_reg[3][1]+(gp2a_opt_data->offset_value);
				THR_REG_LSB(thrd, reg);
				gp2a_i2c_write(gp2a_reg[3][0], &reg);
				THR_REG_MSB(thrd, reg);
				gp2a_i2c_write(gp2a_reg[4][0], &reg);

				thrd = gp2a_reg[5][1]+(gp2a_opt_data->offset_value);
				THR_REG_LSB(thrd, reg);
				gp2a_i2c_write(gp2a_reg[5][0], &reg);
				THR_REG_MSB(thrd, reg);
				gp2a_i2c_write(gp2a_reg[6][0], &reg);
			}
			break;
		}
		case PROX_IOC_GET_CALIBRATION:
		{
			printk(KERN_INFO "[GP2A] PROX_IOC_GET_CALIBRATION\n");      
			data = gp2a_opt_data->offset_value;
			if (copy_to_user((void __user *)arg, &data, sizeof(data)))
				return -EFAULT;
			break;
		}
		default:
			printk(KERN_ERR "Unknown IOCTL command");
			ret = -ENOTTY;
			break;
	}
	return ret;
}
static ssize_t
proximity_enable_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct gp2a_data *data = dev_get_drvdata(dev);

	int value = 0;
	char input;
	int err = 0;
	int16_t thrd;
	u8 reg;

	err = kstrtoint(buf, 10, &value);

	if (err) {
		pr_err("%s, kstrtoint failed.", __func__);
		goto done;
	}
	if (value != 0 && value != 1)
		goto done;

	pr_info("%s, %d value = %d\n", __func__, __LINE__, value);

	if (data->proximity_enabled && !value) {	/* Prox power off */
		disable_irq(data->irq);

		proximity_onoff(0, data);
		disable_irq_wake(data->irq);
		if (data->pdata->led_on)
			data->pdata->led_on(false);
	}
	if (!data->proximity_enabled && value) {	/* prox power on */
		if (data->pdata->led_on)
			data->pdata->led_on(true);
		usleep_range(1000, 1100);
		proximity_onoff(1, data);

		err = proximity_open_calibration(data);
		if (err < 0 && err != -ENOENT)
			pr_err("%s: proximity_open_offset() failed\n",
				__func__);
		else {
			thrd = gp2a_reg[3][1]+(data->offset_value);
			THR_REG_LSB(thrd, reg);
			gp2a_i2c_write(data, gp2a_reg[3][0], &reg);
			THR_REG_MSB(thrd, reg);
			gp2a_i2c_write(data, gp2a_reg[4][0], &reg);

			thrd = gp2a_reg[5][1]+(data->offset_value);
			THR_REG_LSB(thrd, reg);
			gp2a_i2c_write(data, gp2a_reg[5][0], &reg);
			THR_REG_MSB(thrd, reg);
			gp2a_i2c_write(data, gp2a_reg[6][0], &reg);
		}

		enable_irq_wake(data->irq);
		msleep(160);

		input = gpio_get_value_cansleep(data->pdata->p_out);
		if (input == 0) {
			input_report_abs(data->proximity_input_dev,
					ABS_DISTANCE, 1);
			input_sync(data->proximity_input_dev);
		}

		enable_irq(data->irq);
	}
	data->proximity_enabled = value;
done:
	return count;
}
static int proximity_do_calibrate(struct gp2a_data  *data,
			bool do_calib, bool thresh_set)
{
	struct file *cal_filp;
	int err;
	int xtalk_avg = 0;
	int offset_change = 0;
	uint16_t thrd = 0;
	u8 reg;
	mm_segment_t old_fs;

	if (do_calib) {
		if (thresh_set) {
			/* for proximity_thresh_store */
			data->offset_value =
				data->threshold_high -
				(gp2a_reg[6][1] << 8 | gp2a_reg[5][1]);
		} else {
			/* tap offset button */
			/* get offset value */
			xtalk_avg = proximity_adc_read(data);
			offset_change =
				(gp2a_reg[6][1] << 8 | gp2a_reg[5][1])
				- DEFAULT_HI_THR;
			if (xtalk_avg < offset_change) {
				/* do not need calibration */
				data->cal_result = 0;
				err = 0;
				goto no_cal;
			}
			data->offset_value = xtalk_avg - offset_change;
		}
		/* update threshold */
		thrd = (gp2a_reg[4][1] << 8 | gp2a_reg[3][1])
			+ (data->offset_value);
		THR_REG_LSB(thrd, reg);
		gp2a_i2c_write(data, gp2a_reg[3][0], &reg);
		THR_REG_MSB(thrd, reg);
		gp2a_i2c_write(data, gp2a_reg[4][0], &reg);

		thrd = (gp2a_reg[4][1] << 8 | gp2a_reg[5][1])
			+(data->offset_value);
		THR_REG_LSB(thrd, reg);
		gp2a_i2c_write(data, gp2a_reg[5][0], &reg);
		THR_REG_MSB(thrd, reg);
		gp2a_i2c_write(data, gp2a_reg[6][0], &reg);

		/* calibration result */
		if (!thresh_set)
			data->cal_result = 1;
	} else {
		/* tap reset button */
		data->offset_value = 0;
		/* update threshold */
		gp2a_i2c_write(data, gp2a_reg[3][0], &gp2a_reg[3][1]);
		gp2a_i2c_write(data, gp2a_reg[4][0], &gp2a_reg[4][1]);
		gp2a_i2c_write(data, gp2a_reg[5][0], &gp2a_reg[5][1]);
		gp2a_i2c_write(data, gp2a_reg[6][0], &gp2a_reg[6][1]);
		/* calibration result */
		data->cal_result = 2;
	}

	old_fs = get_fs();
	set_fs(KERNEL_DS);

	cal_filp = filp_open(data->pdata->prox_cal_path,
			O_CREAT | O_TRUNC | O_WRONLY,
			S_IRUGO | S_IWUSR | S_IWGRP);
	if (IS_ERR(cal_filp)) {
		pr_err("%s: Can't open calibration file\n", __func__);
		set_fs(old_fs);
		err = PTR_ERR(cal_filp);
		goto done;
	}

	err = cal_filp->f_op->write(cal_filp,
		(char *)&data->offset_value, sizeof(int),
			&cal_filp->f_pos);
	if (err != sizeof(int)) {
		pr_err("%s: Can't write the cal data to file\n", __func__);
		err = -EIO;
	}

	filp_close(cal_filp, current->files);
done:
	set_fs(old_fs);
no_cal:
	return err;
}
static ssize_t gp2a_prox_enable_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct gp2a_data *data = dev_get_drvdata(dev);

	int value;
	int err = 0;

	err = kstrtoint(buf, 10, &value);

	if (err) {
		pr_err("%s kstrtoint failed.", __func__);
		goto done;
	}
	pr_info("%s %d value = %d\n", __func__, __LINE__, value);

	if (value != SENSOR_DISABLE && value != SENSOR_ENABLE)
		goto done;

	if (value) {

		if (data->prox_enabled == SENSOR_DISABLE) {
			uint16_t thrd = 0;
			u8 reg;

			gp2a_prox_onoff(1, data);

			err = gp2a_prox_open_calibration(data);
			if (err < 0 && err != -ENOENT)
				pr_err("%s gp2a_prox_open_offset() failed\n",
					__func__);
			else {
				thrd = gp2a_reg[3][1]+(data->offset_value);
				THR_REG_LSB(thrd, reg);
				gp2a_i2c_write(data, gp2a_reg[3][0], &reg);
				THR_REG_MSB(thrd, reg);
				gp2a_i2c_write(data, gp2a_reg[4][0], &reg);

				thrd = gp2a_reg[5][1]+(data->offset_value);
				THR_REG_LSB(thrd, reg);
				gp2a_i2c_write(data, gp2a_reg[5][0], &reg);
				THR_REG_MSB(thrd, reg);
				gp2a_i2c_write(data, gp2a_reg[6][0], &reg);
			}

			enable_irq_wake(data->irq);
			enable_irq(data->irq);

			input_report_abs(data->prox_input_dev, ABS_DISTANCE, 1);
			input_sync(data->prox_input_dev);

			data->prox_enabled = SENSOR_ENABLE;
		} else {
			pr_err("%s already enabled\n", __func__);
		}
	} else {

		if (data->prox_enabled == SENSOR_ENABLE) {
			disable_irq(data->irq);
			disable_irq_wake(data->irq);
			gp2a_prox_onoff(0, data);
			data->prox_enabled = SENSOR_DISABLE;
		} else {
			pr_err("%s already disabled\n", __func__);
		}
	}

done:
	return count;
}