static ssize_t proximity_state_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	u16 ps_data;

	mutex_lock(&cm36686->power_lock);
	if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
		cm36686_leden_gpio_onoff(cm36686, 1);
#else
	prox_led_onoff(cm36686, 1);
#endif
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
			ps_reg_init_setting[PS_CONF1][CMD]);
	}

	mutex_lock(&cm36686->read_lock);
	cm36686_i2c_read_word(cm36686, REG_PS_DATA,
		&ps_data);
	mutex_unlock(&cm36686->read_lock);

	if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
				0x0001);
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
		cm36686_leden_gpio_onoff(cm36686, 0);
#else
	prox_led_onoff(cm36686, 0);
#endif
	}
	mutex_unlock(&cm36686->power_lock);

	return sprintf(buf, "%u\n", ps_data);
}
static ssize_t proximity_state_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	u16 ps_data;

	mutex_lock(&cm36686->power_lock);
	if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
		if (cm36686->pdata->cm36686_led_on) {
			cm36686->pdata->cm36686_led_on(true);
			msleep(20);
		}
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
			ps_reg_init_setting[PS_CONF1][CMD]);
	}

	mutex_lock(&cm36686->read_lock);
	cm36686_i2c_read_word(cm36686, REG_PS_DATA,
		&ps_data);
	mutex_unlock(&cm36686->read_lock);

	if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
				0x0001);
		if (cm36686->pdata->cm36686_led_on)
			cm36686->pdata->cm36686_led_on(false);
	}
	mutex_unlock(&cm36686->power_lock);

	return sprintf(buf, "%u\n", ps_data);
}
Esempio n. 3
0
static int cm36686_setup_reg(struct cm36686_data *cm36686)
{
	int err = 0, i = 0;
	u16 tmp = 0;

	/* ALS initialization */
	err = cm36686_i2c_write_word(cm36686,
			als_reg_setting[0][0],
			als_reg_setting[0][1]);
	if (err < 0) {
		pr_err("%s: cm36686_als_reg is failed. %d\n", __func__,
			err);
		return err;
	}
	/* PS initialization */

	if (cm36686->pdata != NULL) {
		ps_reg_init_setting[PS_THD_LOW][CMD] =
			cm36686->pdata->default_low_thd;
		ps_reg_init_setting[PS_THD_HIGH][CMD] =
			cm36686->pdata->default_hi_thd;
		pr_info("%s - THD_LOW = %u, THD_HIGH = %u\n", __func__,
			ps_reg_init_setting[PS_THD_LOW][CMD],
			ps_reg_init_setting[PS_THD_HIGH][CMD]);
	}
	for (i = 0; i < PS_REG_NUM; i++) {
		err = cm36686_i2c_write_word(cm36686,
			ps_reg_init_setting[i][REG_ADDR],
			ps_reg_init_setting[i][CMD]);
		if (err < 0) {
			pr_err("%s: cm36686_ps_reg is failed. %d\n", __func__,
				err);
			return err;
		}
	}

	/* printing the inital proximity value with no contact */
	msleep(50);
	mutex_lock(&cm36686->read_lock);
	err = cm36686_i2c_read_word(cm36686, REG_PS_DATA, &tmp);
	mutex_unlock(&cm36686->read_lock);
	if (err < 0) {
		pr_err("%s: read ps_data failed\n", __func__);
		err = -EIO;
	}
	pr_err("%s: initial proximity value = %d\n",
		__func__, tmp);

	/* turn off */
	cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001);
	cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001);
	cm36686_i2c_write_word(cm36686, REG_PS_CONF3, 0x0000);

	pr_info("%s is success.", __func__);
	return err;
}
Esempio n. 4
0
static ssize_t proximity_avg_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	bool new_value = false;

	if (sysfs_streq(buf, "1"))
		new_value = true;
	else if (sysfs_streq(buf, "0"))
		new_value = false;
	else {
		pr_err("%s, invalid value %d\n", __func__, *buf);
		return -EINVAL;
	}

	pr_info("%s, average enable = %d\n", __func__, new_value);
	mutex_lock(&cm36686->power_lock);
	if (new_value) {
		if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
			if (cm36686->cm36686_proxi_vddpower)
				cm36686->cm36686_proxi_vddpower(true);

			if (cm36686->pdata->cm36686_led_on) {
				cm36686->pdata->cm36686_led_on(true);
				msleep(20);
			}
			cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
				ps_reg_init_setting[PS_CONF1][CMD]);
		}
		hrtimer_start(&cm36686->prox_timer, cm36686->prox_poll_delay,
			HRTIMER_MODE_REL);
	} else if (!new_value) {
		hrtimer_cancel(&cm36686->prox_timer);
		cancel_work_sync(&cm36686->work_prox);
		if (!(cm36686->power_state & PROXIMITY_ENABLED)) {
			cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
				0x0001);
			if (cm36686->pdata->cm36686_led_on)
				cm36686->pdata->cm36686_led_on(false);

			if (cm36686->cm36686_proxi_vddpower)
				cm36686->cm36686_proxi_vddpower(false);
		}
	}
	mutex_unlock(&cm36686->power_lock);

	return size;
}
static ssize_t proximity_thresh_low_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	u16 thresh_value = ps_reg_init_setting[PS_THD_LOW][CMD];
	int err;

	err = kstrtou16(buf, 10, &thresh_value);
	if (err < 0)
		pr_err("%s, kstrtoint failed.", __func__);

	if (thresh_value > 2) {
		ps_reg_init_setting[PS_THD_LOW][CMD] = thresh_value;
		err = cm36686_i2c_write_word(cm36686, REG_PS_THD_LOW,
			ps_reg_init_setting[PS_THD_LOW][CMD]);
		if (err < 0)
			pr_err("%s: cm36686_ps_low_reg is failed. %d\n", __func__,
				err);
		pr_info("%s, new low threshold = 0x%x\n",
			__func__, thresh_value);
		msleep(150);
	} else
		pr_err("%s, wrong low threshold value(0x%x)!!\n",
			__func__, thresh_value);

	return size;
}
static void cm36686_light_disable(struct cm36686_data *cm36686)
{
	/* disable setting */
	cm36686_i2c_write_word(cm36686, REG_CS_CONF1,
		als_reg_setting[1][1]);
	hrtimer_cancel(&cm36686->light_timer);
	cancel_work_sync(&cm36686->work_light);
}
static void cm36686_light_enable(struct cm36686_data *cm36686)
{
	/* enable setting */
	cm36686_i2c_write_word(cm36686, REG_CS_CONF1,
		als_reg_setting[0][1]);
	hrtimer_start(&cm36686->light_timer, ns_to_ktime(200 * NSEC_PER_MSEC),
		HRTIMER_MODE_REL);
}
static int cm36686_i2c_remove(struct i2c_client *client)
{
	struct cm36686_data *cm36686 = i2c_get_clientdata(client);

	/* free irq */
	if (cm36686->power_state & PROXIMITY_ENABLED) {
		disable_irq_wake(cm36686->irq);
		disable_irq(cm36686->irq);
	}
	free_irq(cm36686->irq, cm36686);
	gpio_free(cm36686->pdata->irq);

	/* device off */
	if (cm36686->power_state & LIGHT_ENABLED)
		cm36686_light_disable(cm36686);
	if (cm36686->power_state & PROXIMITY_ENABLED) {
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
					   0x0001);
	}

	/* destroy workqueue */
	destroy_workqueue(cm36686->light_wq);
	destroy_workqueue(cm36686->prox_wq);

	/* sysfs destroy */
	sensors_unregister(cm36686->light_dev, light_sensor_attrs);
	sensors_unregister(cm36686->proximity_dev, prox_sensor_attrs);
	sensors_remove_symlink(&cm36686->light_input_dev->dev.kobj,
			cm36686->light_input_dev->name);
	sensors_remove_symlink(&cm36686->proximity_input_dev->dev.kobj,
			cm36686->proximity_input_dev->name);

	/* input device destroy */
	sysfs_remove_group(&cm36686->light_input_dev->dev.kobj,
				&light_attribute_group);
	input_unregister_device(cm36686->light_input_dev);
	sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj,
				&proximity_attribute_group);
	input_unregister_device(cm36686->proximity_input_dev);
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
	cm36686_leden_gpio_onoff(cm36686, 0);
	gpio_free(cm36686->pdata->leden_gpio);
#else
	prox_led_onoff(cm36686, 0);
#endif

	/* lock destroy */
	mutex_destroy(&cm36686->read_lock);
	mutex_destroy(&cm36686->power_lock);
	wake_lock_destroy(&cm36686->prx_wake_lock);

	kfree(cm36686);

	return 0;
}
static ssize_t proximity_enable_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t size)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	bool new_value;

	if (sysfs_streq(buf, "1"))
		new_value = true;
	else if (sysfs_streq(buf, "0"))
		new_value = false;
	else {
		pr_err("[SENSOR] %s: invalid value %d\n", __func__, *buf);
		return -EINVAL;
	}

	mutex_lock(&cm36686->power_lock);
	pr_info("%s, new_value = %d\n", __func__, new_value);
	if (new_value && !(cm36686->power_state & PROXIMITY_ENABLED)) {
		u8 val = 1;
		int i;
#ifdef CM36686_CANCELATION
		int err = 0;
#endif
		cm36686->power_state |= PROXIMITY_ENABLED;
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
		cm36686_leden_gpio_onoff(cm36686, 1);
#else
	prox_led_onoff(cm36686, 1);
#endif
#ifdef CM36686_CANCELATION
		/* open cancelation data */
		err = proximity_open_cancelation(cm36686);
		if (err < 0 && err != -ENOENT)
			pr_err("[SENSOR] %s: proximity_open_cancelation() failed\n",
				__func__);
#endif
		/* enable settings */
		for (i = 0; i < PS_REG_NUM; i++) {
			cm36686_i2c_write_word(cm36686,
				ps_reg_init_setting[i][REG_ADDR],
				ps_reg_init_setting[i][CMD]);
		}

		val = gpio_get_value(cm36686->pdata->irq);
		/* 0 is close, 1 is far */
		input_report_abs(cm36686->proximity_input_dev,
			ABS_DISTANCE, val);
		input_sync(cm36686->proximity_input_dev);

		enable_irq(cm36686->irq);
		enable_irq_wake(cm36686->irq);
	} else if (!new_value && (cm36686->power_state & PROXIMITY_ENABLED)) {
		cm36686->power_state &= ~PROXIMITY_ENABLED;

		disable_irq_wake(cm36686->irq);
		disable_irq(cm36686->irq);
		/* disable settings */
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1, 0x0001);
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
		cm36686_leden_gpio_onoff(cm36686, 0);
#else
	prox_led_onoff(cm36686, 0);
#endif
	}
	mutex_unlock(&cm36686->power_lock);
	return size;
}
static int proximity_store_cancelation(struct device *dev, bool do_calib)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	struct file *cancel_filp = NULL;
	mm_segment_t old_fs;
	int err = 0;
	u16 ps_data = 0;

	if (do_calib) {
		mutex_lock(&cm36686->read_lock);
		cm36686_i2c_read_word(cm36686,
			REG_PS_DATA, &ps_data);
		ps_reg_init_setting[PS_CANCEL][CMD] = ps_data;
		mutex_unlock(&cm36686->read_lock);

		err = get_proximity_threshold(cm36686);
		if(err != ERROR) {
			if (cm36686->pdata->cancel_hi_thd) {
				ps_reg_init_setting[PS_THD_HIGH][CMD] =
					cm36686->pdata->cancel_hi_thd;
			} else
				ps_reg_init_setting[PS_THD_HIGH][CMD] = CANCEL_HI_THD;

			if (cm36686->pdata->cancel_low_thd) {
				ps_reg_init_setting[PS_THD_LOW][CMD] =
					cm36686->pdata->cancel_low_thd;
			} else
				ps_reg_init_setting[PS_THD_LOW][CMD] = DEFUALT_LOW_THD;
		} else {
			set_default_proximity_threshold(cm36686);
		}
	} else { /* reset */
		ps_reg_init_setting[PS_CANCEL][CMD] = 0;
		set_default_proximity_threshold(cm36686);
	}

	err = cm36686_i2c_write_word(cm36686, REG_PS_CANC,
		ps_reg_init_setting[PS_CANCEL][CMD]);
	if (err < 0)
		pr_err("%s: cm36686_ps_canc_reg is failed. %d\n", __func__,
			err);
	err = cm36686_i2c_write_word(cm36686, REG_PS_THD_HIGH,
		ps_reg_init_setting[PS_THD_HIGH][CMD]);
	if (err < 0)
		pr_err("%s: cm36686_ps_high_reg is failed. %d\n", __func__,
			err);
	err = cm36686_i2c_write_word(cm36686, REG_PS_THD_LOW,
		ps_reg_init_setting[PS_THD_LOW][CMD]);
	if (err < 0)
		pr_err("%s: cm36686_ps_low_reg is failed. %d\n", __func__,
			err);

	pr_info("%s: prox_cal = 0x%x, ps_high_thresh = 0x%x, ps_low_thresh = 0x%x\n",
		__func__, ps_reg_init_setting[PS_CANCEL][CMD],
		ps_reg_init_setting[PS_THD_HIGH][CMD], ps_reg_init_setting[PS_THD_LOW][CMD]);

	old_fs = get_fs();
	set_fs(KERNEL_DS);

	cancel_filp = filp_open(CANCELATION_FILE_PATH,
			O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666);
	if (IS_ERR(cancel_filp)) {
		pr_err("[SENSOR] %s: Can't open cancelation file\n", __func__);
		set_fs(old_fs);
		err = PTR_ERR(cancel_filp);
		return err;
	}

	err = cancel_filp->f_op->write(cancel_filp,
		(char *)&ps_reg_init_setting[PS_CANCEL][CMD],
		sizeof(u16), &cancel_filp->f_pos);
	if (err != sizeof(u16)) {
		pr_err("%s: Can't write the cancel data to file\n", __func__);
		err = -EIO;
	}

	filp_close(cancel_filp, current->files);
	set_fs(old_fs);

	if (!do_calib) /* delay for clearing */
		msleep(150);

	return err;
}
static int cm36686_i2c_probe(struct i2c_client *client,
				const struct i2c_device_id *id)
{
	int ret = -ENODEV;
	struct cm36686_data *cm36686 = NULL;
	struct cm36686_platform_data *pdata = NULL;
	int err;

	pr_info("[SENSOR] %s: Probe Start!\n", __func__);
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		pr_err("[SENSOR] %s: i2c functionality check failed!\n", __func__);
		return ret;
	}

	cm36686 = kzalloc(sizeof(struct cm36686_data), GFP_KERNEL);
	if (!cm36686) {
		pr_err
		    ("[SENSOR] %s: failed to alloc memory for RGB sensor module data\n",
			__func__);
		return -ENOMEM;
	}

		if(client->dev.of_node) {
		pdata = devm_kzalloc (&client->dev ,
			sizeof(struct cm36686_platform_data ), GFP_KERNEL);
		if(!pdata) {
		dev_err(&client->dev, "Failed to allocate memory\n");
			if(cm36686)
				kfree(cm36686);
		return -ENOMEM;
		}
		err = cm36686_parse_dt(&client->dev, pdata);
		if(err)
			goto err_devicetree;
	} else
		pdata = client->dev.platform_data;
    if (!pdata) {
		pr_err("%s: missing pdata!\n", __func__);
		if(cm36686)
			kfree(cm36686);
		return ret;
	}

	prox_regulator_onoff(&client->dev,1);

	cm36686->pdata = pdata;
	cm36686->i2c_client = client;
	i2c_set_clientdata(client, cm36686);

	mutex_init(&cm36686->power_lock);
	mutex_init(&cm36686->read_lock);

	/* wake lock init for proximity sensor */
	wake_lock_init(&cm36686->prx_wake_lock, WAKE_LOCK_SUSPEND,
			"prx_wake_lock");

#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
	/* setup leden_gpio */
	ret = cm36686_setup_leden_gpio(cm36686);
	if (ret) {
		pr_err("%s: could not setup leden_gpio\n", __func__);
		goto err_setup_leden_gpio;
	}
	cm36686_leden_gpio_onoff(cm36686, 1);
#else
	prox_led_onoff(cm36686, 1);
#endif

	/* Check if the device is there or not. */
	ret = cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001);
	if (ret < 0) {
		pr_err("[SENSOR] %s: cm36686 is not connected.(%d)\n", __func__, ret);
		goto err_setup_reg;
	}

	/* setup initial registers */
	ret = cm36686_setup_reg(cm36686);
	if (ret < 0) {
		pr_err("[SENSOR] %s: could not setup regs\n", __func__);
		goto err_setup_reg;
	}
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
	cm36686_leden_gpio_onoff(cm36686, 0);
#else
	prox_led_onoff(cm36686, 0);
#endif

	/* allocate proximity input_device */
	cm36686->proximity_input_dev = input_allocate_device();
	if (!cm36686->proximity_input_dev) {
		pr_err("%s: could not allocate proximity input device\n",
			__func__);
		goto err_input_allocate_device_proximity;
	}

	input_set_drvdata(cm36686->proximity_input_dev, cm36686);
	cm36686->proximity_input_dev->name = "proximity_sensor";
	input_set_capability(cm36686->proximity_input_dev, EV_ABS,
			ABS_DISTANCE);
	input_set_abs_params(cm36686->proximity_input_dev, ABS_DISTANCE, 0, 1,
			0, 0);

	ret = input_register_device(cm36686->proximity_input_dev);
	if (ret < 0) {
		input_free_device(cm36686->proximity_input_dev);
		pr_err("[SENSOR] %s: could not register input device\n", __func__);
		goto err_input_register_device_proximity;
	}

	ret = sensors_create_symlink(&cm36686->proximity_input_dev->dev.kobj,
					cm36686->proximity_input_dev->name);
	if (ret < 0) {
		pr_err("[SENSOR] %s: create_symlink error\n", __func__);
		goto err_sensors_create_symlink_prox;
	}

	ret = sysfs_create_group(&cm36686->proximity_input_dev->dev.kobj,
				 &proximity_attribute_group);
	if (ret) {
		pr_err("[SENSOR] %s: could not create sysfs group\n", __func__);
		goto err_sysfs_create_group_proximity;
	}

	/* setup irq */
	ret = cm36686_setup_irq(cm36686);
	if (ret) {
		pr_err("%s: could not setup irq\n", __func__);
		goto err_setup_irq;
	}

	/* For factory test mode, we use timer to get average proximity data. */
	/* prox_timer settings. we poll for light values using a timer. */
	hrtimer_init(&cm36686->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	cm36686->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC);/*2 sec*/
	cm36686->prox_timer.function = cm36686_prox_timer_func;

	/* the timer just fires off a work queue request.  we need a thread
	   to read the i2c (can be slow and blocking). */
	cm36686->prox_wq = create_singlethread_workqueue("cm36686_prox_wq");
	if (!cm36686->prox_wq) {
		ret = -ENOMEM;
		pr_err("[SENSOR] %s: could not create prox workqueue\n", __func__);
		goto err_create_prox_workqueue;
	}
	/* this is the thread function we run on the work queue */
	INIT_WORK(&cm36686->work_prox, cm36686_work_func_prox);

	/* allocate lightsensor input_device */
	cm36686->light_input_dev = input_allocate_device();
	if (!cm36686->light_input_dev) {
		pr_err("%s: could not allocate light input device\n", __func__);
		goto err_input_allocate_device_light;
	}

	input_set_drvdata(cm36686->light_input_dev, cm36686);
	cm36686->light_input_dev->name = "light_sensor";
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_MISC);
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_DIAL);
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_WHEEL);

	ret = input_register_device(cm36686->light_input_dev);
	if (ret < 0) {
		input_free_device(cm36686->light_input_dev);
		pr_err("%s: could not register input device\n", __func__);
		goto err_input_register_device_light;
	}

	ret = sensors_create_symlink(&cm36686->light_input_dev->dev.kobj,
					cm36686->light_input_dev->name);
	if (ret < 0) {
		pr_err("[SENSOR] %s: create_symlink error\n", __func__);
		goto err_sensors_create_symlink_light;
	}

	ret = sysfs_create_group(&cm36686->light_input_dev->dev.kobj,
				 &light_attribute_group);
	if (ret) {
		pr_err("[SENSOR] %s: could not create sysfs group\n", __func__);
		goto err_sysfs_create_group_light;
	}

	/* light_timer settings. we poll for light values using a timer. */
	hrtimer_init(&cm36686->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	cm36686->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC);
	cm36686->light_timer.function = cm36686_light_timer_func;

	/* the timer just fires off a work queue request.  we need a thread
	   to read the i2c (can be slow and blocking). */
	cm36686->light_wq = create_singlethread_workqueue("cm36686_light_wq");
	if (!cm36686->light_wq) {
		ret = -ENOMEM;
		pr_err("[SENSOR] %s: could not create light workqueue\n", __func__);
		goto err_create_light_workqueue;
	}

	/* this is the thread function we run on the work queue */
	INIT_WORK(&cm36686->work_light, cm36686_work_func_light);

	/* set sysfs for proximity sensor */
	ret = sensors_register(cm36686->proximity_dev,
		cm36686, prox_sensor_attrs,
			"proximity_sensor");
	if (ret) {
		pr_err("[SENSOR] %s: cound not register\
			proximity sensor device(%d).\n",
			__func__, ret);
		goto prox_sensor_register_failed;
	}

	/* set sysfs for light sensor */
	ret = sensors_register(cm36686->light_dev,
		cm36686, light_sensor_attrs,
			"light_sensor");
	if (ret) {
		pr_err("[SENSOR] %s: cound not register\
			light sensor device(%d).\n",
			__func__, ret);
		goto light_sensor_register_failed;
	}

	pr_info("[SENSOR] %s is success.\n", __func__);
	goto done;

err_devicetree:
printk("\n error in device tree");

/* error, unwind it all */
light_sensor_register_failed:
	sensors_unregister(cm36686->proximity_dev, prox_sensor_attrs);
prox_sensor_register_failed:
	destroy_workqueue(cm36686->light_wq);
err_create_light_workqueue:
	sysfs_remove_group(&cm36686->light_input_dev->dev.kobj,
			   &light_attribute_group);
err_sysfs_create_group_light:
	sensors_remove_symlink(&cm36686->light_input_dev->dev.kobj,
			cm36686->light_input_dev->name);
err_sensors_create_symlink_light:
	input_unregister_device(cm36686->light_input_dev);
err_input_register_device_light:
err_input_allocate_device_light:
	destroy_workqueue(cm36686->prox_wq);
err_create_prox_workqueue:
	free_irq(cm36686->irq, cm36686);
	gpio_free(cm36686->pdata->irq);
err_setup_irq:
	sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj,
			   &proximity_attribute_group);
err_sysfs_create_group_proximity:
	sensors_remove_symlink(&cm36686->proximity_input_dev->dev.kobj,
			cm36686->proximity_input_dev->name);
err_sensors_create_symlink_prox:
	input_unregister_device(cm36686->proximity_input_dev);
err_input_register_device_proximity:
err_input_allocate_device_proximity:
err_setup_reg:
#if defined(CONFIG_SENSORS_CM36686_LEDA_EN_GPIO)
	cm36686_leden_gpio_onoff(cm36686, 0);
	gpio_free(cm36686->pdata->leden_gpio);
err_setup_leden_gpio:
#else
	prox_led_onoff(cm36686, 0);
#endif
	wake_lock_destroy(&cm36686->prx_wake_lock);
	mutex_destroy(&cm36686->read_lock);
	mutex_destroy(&cm36686->power_lock);


	kfree(cm36686);
	prox_regulator_onoff(&client->dev,0);
done:
	return ret;
}
Esempio n. 12
0
static int cm36686_i2c_remove(struct i2c_client *client)
{
	struct cm36686_data *cm36686 = i2c_get_clientdata(client);

	/* free irq */
	if (cm36686->power_state & PROXIMITY_ENABLED) {
		disable_irq_wake(cm36686->irq);
		disable_irq(cm36686->irq);
	}
	free_irq(cm36686->irq, cm36686);
	gpio_free(cm36686->pdata->irq);

	/* device off */
	if (cm36686->power_state & LIGHT_ENABLED)
		cm36686_light_disable(cm36686);
	if (cm36686->power_state & PROXIMITY_ENABLED) {
		cm36686_i2c_write_word(cm36686, REG_PS_CONF1,
					   0x0001);
		if (cm36686->pdata->cm36686_led_on)
			cm36686->pdata->cm36686_led_on(false);

		if (cm36686->cm36686_light_vddpower)
			cm36686->cm36686_light_vddpower(false);

		if (cm36686->cm36686_proxi_vddpower)
			cm36686->cm36686_proxi_vddpower(false);
	}

	/* destroy workqueue */
	destroy_workqueue(cm36686->light_wq);
	destroy_workqueue(cm36686->prox_wq);

	/* sysfs destroy */
	device_remove_file(cm36686->light_dev, &dev_attr_name);
	device_remove_file(cm36686->light_dev, &dev_attr_vendor);
	device_remove_file(cm36686->light_dev, &dev_attr_raw_data);
	device_remove_file(cm36686->light_dev, &dev_attr_lux);
	sensors_classdev_unregister(cm36686->light_dev);

	device_remove_file(cm36686->proximity_dev, &dev_attr_name);
	device_remove_file(cm36686->proximity_dev, &dev_attr_vendor);
	device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_high);
	device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_low);

	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_avg);
#ifdef CM36686_CANCELATION
	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_cal);
	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_offset_pass);
#endif
	device_remove_file(cm36686->proximity_dev, &attr_prox_raw);
	device_remove_file(cm36686->proximity_dev, &dev_attr_state);
	sensors_classdev_unregister(cm36686->proximity_dev);

	/* input device destroy */
	sysfs_remove_group(&cm36686->light_input_dev->dev.kobj,
				&light_attribute_group);
	input_unregister_device(cm36686->light_input_dev);
	sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj,
				&proximity_attribute_group);
	input_unregister_device(cm36686->proximity_input_dev);

	/* lock destroy */
	mutex_destroy(&cm36686->read_lock);
	mutex_destroy(&cm36686->power_lock);
	wake_lock_destroy(&cm36686->prx_wake_lock);

	kfree(cm36686);

	return 0;
}
Esempio n. 13
0
static int cm36686_i2c_probe(struct i2c_client *client,
				const struct i2c_device_id *id)
{
	int ret = -ENODEV;
	struct cm36686_data *cm36686 = NULL;

	pr_info("%s is called.\n", __func__);
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		pr_err("%s: i2c functionality check failed!\n", __func__);
		return ret;
	}

	cm36686 = kzalloc(sizeof(struct cm36686_data), GFP_KERNEL);
	if (!cm36686) {
		pr_err("%s: failed to alloc memory for cm36686 module data\n",
			__func__);
		return -ENOMEM;
	}

	cm36686->pdata = client->dev.platform_data;
	cm36686->i2c_client = client;
	i2c_set_clientdata(client, cm36686);
	mutex_init(&cm36686->power_lock);
	mutex_init(&cm36686->read_lock);

	if(cm36686->pdata->cm36686_light_power != NULL) {
		cm36686->cm36686_light_vddpower = cm36686->pdata->cm36686_light_power;
		if (cm36686->cm36686_light_vddpower)
			cm36686->cm36686_light_vddpower(true);
	}

	if(cm36686->pdata->cm36686_proxi_power != NULL) {
		cm36686->cm36686_proxi_vddpower = cm36686->pdata->cm36686_proxi_power;
		if (cm36686->cm36686_proxi_vddpower)
			cm36686->cm36686_proxi_vddpower(true);
	}

	/* wake lock init for proximity sensor */
	wake_lock_init(&cm36686->prx_wake_lock, WAKE_LOCK_SUSPEND,
			"prx_wake_lock");
	if (cm36686->pdata->cm36686_led_on) {
		cm36686->pdata->cm36686_led_on(true);
		msleep(20);
	}
	/* Check if the device is there or not. */
	ret = cm36686_i2c_write_word(cm36686, REG_CS_CONF1, 0x0001);
	if (ret < 0) {
		pr_err("%s: cm36686 is not connected.(%d)\n", __func__, ret);
		goto err_setup_reg;
	}

	/* setup initial registers */
	ret = cm36686_setup_reg(cm36686);
	if (ret < 0) {
		pr_err("%s: could not setup regs\n", __func__);
		goto err_setup_reg;
	}

	if (cm36686->pdata->cm36686_led_on)
		cm36686->pdata->cm36686_led_on(false);

	if (cm36686->cm36686_light_vddpower)
		cm36686->cm36686_light_vddpower(false);

	if (cm36686->cm36686_proxi_vddpower)
		cm36686->cm36686_proxi_vddpower(false);

	/* allocate proximity input_device */
	cm36686->proximity_input_dev = input_allocate_device();
	if (!cm36686->proximity_input_dev) {
		pr_err("%s: could not allocate proximity input device\n",
			__func__);
		goto err_input_allocate_device_proximity;
	}

	input_set_drvdata(cm36686->proximity_input_dev, cm36686);
	cm36686->proximity_input_dev->name = "proximity_sensor";
	input_set_capability(cm36686->proximity_input_dev, EV_ABS,
			ABS_DISTANCE);
	input_set_abs_params(cm36686->proximity_input_dev, ABS_DISTANCE, 0, 1,
			0, 0);

	ret = input_register_device(cm36686->proximity_input_dev);
	if (ret < 0) {
		input_free_device(cm36686->proximity_input_dev);
		pr_err("%s: could not register input device\n", __func__);
		goto err_input_register_device_proximity;
	}

	ret = sysfs_create_group(&cm36686->proximity_input_dev->dev.kobj,
				 &proximity_attribute_group);
	if (ret) {
		pr_err("%s: could not create sysfs group\n", __func__);
		goto err_sysfs_create_group_proximity;
	}
#if defined(CONFIG_SENSOR_USE_SYMLINK)
	ret =  sensors_initialize_symlink(cm36686->proximity_input_dev);
	if (ret < 0) {
		pr_err("%s - proximity_sensors_initialize_symlink error(%d).\n",
                        __func__, ret);
		goto err_setup_irq;
	}
#endif
	/* setup irq */
	ret = cm36686_setup_irq(cm36686);
	if (ret) {
		pr_err("%s: could not setup irq\n", __func__);
		goto err_setup_irq;
	}

	/* For factory test mode, we use timer to get average proximity data. */
	/* prox_timer settings. we poll for light values using a timer. */
	hrtimer_init(&cm36686->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	cm36686->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC);/*2 sec*/
	cm36686->prox_timer.function = cm36686_prox_timer_func;

	/* the timer just fires off a work queue request.  we need a thread
	   to read the i2c (can be slow and blocking). */
	cm36686->prox_wq = create_singlethread_workqueue("cm36686_prox_wq");
	if (!cm36686->prox_wq) {
		ret = -ENOMEM;
		pr_err("%s: could not create prox workqueue\n", __func__);
		goto err_create_prox_workqueue;
	}
	/* this is the thread function we run on the work queue */
	INIT_WORK(&cm36686->work_prox, cm36686_work_func_prox);

	/* allocate lightsensor input_device */
	cm36686->light_input_dev = input_allocate_device();
	if (!cm36686->light_input_dev) {
		pr_err("%s: could not allocate light input device\n", __func__);
		goto err_input_allocate_device_light;
	}

	input_set_drvdata(cm36686->light_input_dev, cm36686);
	cm36686->light_input_dev->name = "light_sensor";
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_MISC);
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_DIAL);
	input_set_capability(cm36686->light_input_dev, EV_REL, REL_WHEEL);

	ret = input_register_device(cm36686->light_input_dev);
	if (ret < 0) {
		input_free_device(cm36686->light_input_dev);
		pr_err("%s: could not register input device\n", __func__);
		goto err_input_register_device_light;
	}

	ret = sysfs_create_group(&cm36686->light_input_dev->dev.kobj,
				 &light_attribute_group);
	if (ret) {
		pr_err("%s: could not create sysfs group\n", __func__);
		goto err_sysfs_create_group_light;
	}
#if defined(CONFIG_SENSOR_USE_SYMLINK)
	ret =  sensors_initialize_symlink(cm36686->light_input_dev);
	if (ret < 0) {
		pr_err("%s - light_sensors_initialize_symlink error(%d).\n",
                        __func__, ret);
		goto err_create_light_workqueue;
	}
#endif
	/* light_timer settings. we poll for light values using a timer. */
	hrtimer_init(&cm36686->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	cm36686->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC);
	cm36686->light_timer.function = cm36686_light_timer_func;

	/* the timer just fires off a work queue request.  we need a thread
	   to read the i2c (can be slow and blocking). */
	cm36686->light_wq = create_singlethread_workqueue("cm36686_light_wq");
	if (!cm36686->light_wq) {
		ret = -ENOMEM;
		pr_err("%s: could not create light workqueue\n", __func__);
		goto err_create_light_workqueue;
	}

	/* this is the thread function we run on the work queue */
	INIT_WORK(&cm36686->work_light, cm36686_work_func_light);

	/* set sysfs for proximity sensor */
	cm36686->proximity_dev = sensors_classdev_register("proximity_sensor");
	if (IS_ERR(cm36686->proximity_dev)) {
		pr_err("%s: could not create proximity_dev\n", __func__);
		goto err_proximity_device_create;
	}

	if (device_create_file(cm36686->proximity_dev, &dev_attr_state) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_state.attr.name);
		goto err_proximity_device_create_file1;
	}

	if (device_create_file(cm36686->proximity_dev, &attr_prox_raw) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			attr_prox_raw.attr.name);
		goto err_proximity_device_create_file2;
	}

#ifdef CM36686_CANCELATION
	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_prox_cal) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_prox_cal.attr.name);
		goto err_proximity_device_create_file3;
	}

	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_prox_offset_pass) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_prox_offset_pass.attr.name);
		goto err_proximity_device_create_file4;
	}
#endif
	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_prox_avg) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_prox_avg.attr.name);
		goto err_proximity_device_create_file5;
	}

	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_thresh_high) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_thresh_high.attr.name);
		goto err_proximity_device_create_file6;
	}

	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_vendor) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_vendor.attr.name);
		goto err_proximity_device_create_file7;
	}

	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_name) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_name.attr.name);
		goto err_proximity_device_create_file8;
	}

	if (device_create_file(cm36686->proximity_dev,
		&dev_attr_thresh_low) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_thresh_low.attr.name);
		goto err_proximity_device_create_file9;
	}

	dev_set_drvdata(cm36686->proximity_dev, cm36686);

	/* set sysfs for light sensor */
	cm36686->light_dev = sensors_classdev_register("light_sensor");
	if (IS_ERR(cm36686->light_dev)) {
		pr_err("%s: could not create light_dev\n", __func__);
		goto err_light_device_create;
	}

	if (device_create_file(cm36686->light_dev, &dev_attr_lux) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_lux.attr.name);
		goto err_light_device_create_file1;
	}

	if (device_create_file(cm36686->light_dev, &dev_attr_raw_data) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_raw_data.attr.name);
		goto err_light_device_create_file2;
	}

	if (device_create_file(cm36686->light_dev, &dev_attr_vendor) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_vendor.attr.name);
		goto err_light_device_create_file3;
	}

	if (device_create_file(cm36686->light_dev, &dev_attr_name) < 0) {
		pr_err("%s: could not create device file(%s)!\n", __func__,
			dev_attr_name.attr.name);
		goto err_light_device_create_file4;
	}

	dev_set_drvdata(cm36686->light_dev, cm36686);

	pr_info("%s is success.\n", __func__);
	goto done;

/* error, unwind it all */
err_light_device_create_file4:
	device_remove_file(cm36686->light_dev, &dev_attr_vendor);
err_light_device_create_file3:
	device_remove_file(cm36686->light_dev, &dev_attr_raw_data);
err_light_device_create_file2:
	device_remove_file(cm36686->light_dev, &dev_attr_lux);
err_light_device_create_file1:
	sensors_classdev_unregister(cm36686->light_dev);
err_light_device_create:
	device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_low);
err_proximity_device_create_file9:
	device_remove_file(cm36686->proximity_dev, &dev_attr_name);
err_proximity_device_create_file8:
	device_remove_file(cm36686->proximity_dev, &dev_attr_vendor);
err_proximity_device_create_file7:
	device_remove_file(cm36686->proximity_dev, &dev_attr_thresh_high);
err_proximity_device_create_file6:
	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_avg);
err_proximity_device_create_file5:
#ifdef CM36686_CANCELATION
	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_offset_pass);
err_proximity_device_create_file4:
	device_remove_file(cm36686->proximity_dev, &dev_attr_prox_cal);
err_proximity_device_create_file3:
#endif
	device_remove_file(cm36686->proximity_dev, &attr_prox_raw);
err_proximity_device_create_file2:
	device_remove_file(cm36686->proximity_dev, &dev_attr_state);
err_proximity_device_create_file1:
	sensors_classdev_unregister(cm36686->proximity_dev);
err_proximity_device_create:
	destroy_workqueue(cm36686->light_wq);
err_create_light_workqueue:
	sysfs_remove_group(&cm36686->light_input_dev->dev.kobj,
			   &light_attribute_group);
err_sysfs_create_group_light:
	input_unregister_device(cm36686->light_input_dev);
err_input_register_device_light:
err_input_allocate_device_light:
	destroy_workqueue(cm36686->prox_wq);
err_create_prox_workqueue:
	free_irq(cm36686->irq, cm36686);
	gpio_free(cm36686->pdata->irq);
err_setup_irq:
	sysfs_remove_group(&cm36686->proximity_input_dev->dev.kobj,
			   &proximity_attribute_group);
err_sysfs_create_group_proximity:
	input_unregister_device(cm36686->proximity_input_dev);
err_input_register_device_proximity:
err_input_allocate_device_proximity:
err_setup_reg:
	if (cm36686->pdata->cm36686_led_on)
		cm36686->pdata->cm36686_led_on(false);

	if (cm36686->cm36686_light_vddpower)
		cm36686->cm36686_light_vddpower(false);

	if (cm36686->cm36686_proxi_vddpower)
		cm36686->cm36686_proxi_vddpower(false);

	wake_lock_destroy(&cm36686->prx_wake_lock);
	mutex_destroy(&cm36686->read_lock);
	mutex_destroy(&cm36686->power_lock);
	kfree(cm36686);
done:
	return ret;
}