static ssize_t light_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("[SENSOR] %s,new_value=%d\n", __func__, new_value);
	if (new_value && !(cm36686->power_state & LIGHT_ENABLED)) {
		cm36686->power_state |= LIGHT_ENABLED;
		cm36686_light_enable(cm36686);
	} else if (!new_value && (cm36686->power_state & LIGHT_ENABLED)) {
		cm36686_light_disable(cm36686);
		cm36686->power_state &= ~LIGHT_ENABLED;
	}
	mutex_unlock(&cm36686->power_lock);
	return size;
}
static ssize_t cm36686_poll_delay_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t size)
{
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);
	int64_t new_delay;
	int err;

	err = strict_strtoll(buf, 10, &new_delay);
	if (err < 0)
		return err;

	mutex_lock(&cm36686->power_lock);
	if (new_delay != ktime_to_ns(cm36686->light_poll_delay)) {
		cm36686->light_poll_delay = ns_to_ktime(new_delay);
		if (cm36686->power_state & LIGHT_ENABLED) {
			cm36686_light_disable(cm36686);
			cm36686_light_enable(cm36686);
		}
		pr_info("[SENSOR] %s, poll_delay = %lld\n", __func__, new_delay);
	}
	mutex_unlock(&cm36686->power_lock);

	return size;
}
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 int cm36686_suspend(struct device *dev)
{
	/* We disable power only if proximity is disabled.  If proximity
	   is enabled, we leave power on because proximity is allowed
	   to wake up device.  We remove power without changing
	   cm36686->power_state because we use that state in resume.
	 */
	struct cm36686_data *cm36686 = dev_get_drvdata(dev);

	if (cm36686->power_state & LIGHT_ENABLED)
		cm36686_light_disable(cm36686);

	return 0;
}
Beispiel #5
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;
}