1/*
2 * HID Sensors Driver
3 * Copyright (c) 2012, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 */
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/module.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
24#include <linux/slab.h>
25#include <linux/hid-sensor-hub.h>
26#include <linux/iio/iio.h>
27#include <linux/iio/trigger.h>
28#include <linux/iio/sysfs.h>
29#include "hid-sensor-trigger.h"
30
31int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
32{
33	int state_val;
34	int report_val;
35
36	if (state) {
37		if (sensor_hub_device_open(st->hsdev))
38			return -EIO;
39
40		atomic_inc(&st->data_ready);
41
42		state_val = hid_sensor_get_usage_index(st->hsdev,
43			st->power_state.report_id,
44			st->power_state.index,
45			HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM);
46		report_val = hid_sensor_get_usage_index(st->hsdev,
47			st->report_state.report_id,
48			st->report_state.index,
49			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
50	} else {
51		if (!atomic_dec_and_test(&st->data_ready))
52			return 0;
53		sensor_hub_device_close(st->hsdev);
54		state_val = hid_sensor_get_usage_index(st->hsdev,
55			st->power_state.report_id,
56			st->power_state.index,
57			HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM);
58		report_val = hid_sensor_get_usage_index(st->hsdev,
59			st->report_state.report_id,
60			st->report_state.index,
61			HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
62	}
63
64	if (state_val >= 0) {
65		state_val += st->power_state.logical_minimum;
66		sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
67					st->power_state.index,
68					(s32)state_val);
69	}
70
71	if (report_val >= 0) {
72		report_val += st->report_state.logical_minimum;
73		sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
74					st->report_state.index,
75					(s32)report_val);
76	}
77
78	sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
79					st->power_state.index,
80					&state_val);
81	return 0;
82}
83EXPORT_SYMBOL(hid_sensor_power_state);
84
85static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
86						bool state)
87{
88	return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
89}
90
91void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
92{
93	iio_trigger_unregister(attrb->trigger);
94	iio_trigger_free(attrb->trigger);
95}
96EXPORT_SYMBOL(hid_sensor_remove_trigger);
97
98static const struct iio_trigger_ops hid_sensor_trigger_ops = {
99	.owner = THIS_MODULE,
100	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
101};
102
103int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
104				struct hid_sensor_common *attrb)
105{
106	int ret;
107	struct iio_trigger *trig;
108
109	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
110	if (trig == NULL) {
111		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
112		ret = -ENOMEM;
113		goto error_ret;
114	}
115
116	trig->dev.parent = indio_dev->dev.parent;
117	iio_trigger_set_drvdata(trig, attrb);
118	trig->ops = &hid_sensor_trigger_ops;
119	ret = iio_trigger_register(trig);
120
121	if (ret) {
122		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
123		goto error_free_trig;
124	}
125	attrb->trigger = trig;
126	indio_dev->trig = iio_trigger_get(trig);
127
128	return ret;
129
130error_free_trig:
131	iio_trigger_free(trig);
132error_ret:
133	return ret;
134}
135EXPORT_SYMBOL(hid_sensor_setup_trigger);
136
137MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
138MODULE_DESCRIPTION("HID Sensor trigger processing");
139MODULE_LICENSE("GPL");
140