aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
diff options
context:
space:
mode:
authorsrinivas pandruvada <srinivas.pandruvada@intel.com>2012-09-05 08:56:00 -0400
committerJonathan Cameron <jic23@kernel.org>2012-09-06 14:20:11 -0400
commit73c6768b710a1621903f2bc179ae9c7789d41e9f (patch)
treee486fe76c5fa4ba4a5cd61124b52689510169385 /drivers/iio/common/hid-sensors/hid-sensor-attributes.c
parent401ca24fb34aee0cedf9c4fef361e533224f15a1 (diff)
iio: hid-sensors: Common attribute and trigger
This patch contains the common code, which is used by all HID sensors. There are some common set of attributes, which every hid sensor needs it. This patch contains all such attributes processing. Also the trigger interface is common among all HID sensors. This patch contains common trigger functions utilized by all HID sensors. Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/common/hid-sensors/hid-sensor-attributes.c')
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
new file mode 100644
index 000000000000..75374955caba
--- /dev/null
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -0,0 +1,250 @@
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/sysfs.h>
28#include "hid-sensor-attributes.h"
29
30static int pow_10(unsigned power)
31{
32 int i;
33 int ret = 1;
34 for (i = 0; i < power; ++i)
35 ret = ret * 10;
36
37 return ret;
38}
39
40static void simple_div(int dividend, int divisor, int *whole,
41 int *micro_frac)
42{
43 int rem;
44 int exp = 0;
45
46 *micro_frac = 0;
47 if (divisor == 0) {
48 *whole = 0;
49 return;
50 }
51 *whole = dividend/divisor;
52 rem = dividend % divisor;
53 if (rem) {
54 while (rem <= divisor) {
55 rem *= 10;
56 exp++;
57 }
58 *micro_frac = (rem / divisor) * pow_10(6-exp);
59 }
60}
61
62static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
63{
64 *val1 = no/pow_10(exp);
65 *val2 = no%pow_10(exp) * pow_10(6-exp);
66}
67
68/*
69VTF format uses exponent and variable size format.
70For example if the size is 2 bytes
710x0067 with VTF16E14 format -> +1.03
72To convert just change to 0x67 to decimal and use two decimal as E14 stands
73for 10^-2.
74Negative numbers are 2's complement
75*/
76static void convert_from_vtf_format(u32 value, int size, int exp,
77 int *val1, int *val2)
78{
79 int sign = 1;
80
81 if (value & BIT(size*8 - 1)) {
82 value = ((1LL << (size * 8)) - value);
83 sign = -1;
84 }
85 exp = hid_sensor_convert_exponent(exp);
86 if (exp >= 0) {
87 *val1 = sign * value * pow_10(exp);
88 *val2 = 0;
89 } else {
90 split_micro_fraction(value, -exp, val1, val2);
91 if (*val1)
92 *val1 = sign * (*val1);
93 else
94 *val2 = sign * (*val2);
95 }
96}
97
98static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
99{
100 u32 value;
101 int sign = 1;
102
103 if (val1 < 0 || val2 < 0)
104 sign = -1;
105 exp = hid_sensor_convert_exponent(exp);
106 if (exp < 0) {
107 value = abs(val1) * pow_10(-exp);
108 value += abs(val2) / pow_10(6+exp);
109 } else
110 value = abs(val1) / pow_10(exp);
111 if (sign < 0)
112 value = ((1LL << (size * 8)) - value);
113
114 return value;
115}
116
117int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
118 int *val1, int *val2)
119{
120 s32 value;
121 int ret;
122
123 ret = sensor_hub_get_feature(st->hsdev,
124 st->poll.report_id,
125 st->poll.index, &value);
126 if (ret < 0 || value < 0) {
127 *val1 = *val2 = 0;
128 return -EINVAL;
129 } else {
130 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
131 simple_div(1000, value, val1, val2);
132 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
133 simple_div(1, value, val1, val2);
134 else {
135 *val1 = *val2 = 0;
136 return -EINVAL;
137 }
138 }
139
140 return IIO_VAL_INT_PLUS_MICRO;
141}
142EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
143
144int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
145 int val1, int val2)
146{
147 s32 value;
148 int ret;
149
150 if (val1 < 0 || val2 < 0)
151 ret = -EINVAL;
152
153 value = val1 * pow_10(6) + val2;
154 if (value) {
155 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
156 value = pow_10(9)/value;
157 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
158 value = pow_10(6)/value;
159 else
160 value = 0;
161 }
162 ret = sensor_hub_set_feature(st->hsdev,
163 st->poll.report_id,
164 st->poll.index, value);
165 if (ret < 0 || value < 0)
166 ret = -EINVAL;
167
168 return ret;
169}
170EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
171
172int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
173 int *val1, int *val2)
174{
175 s32 value;
176 int ret;
177
178 ret = sensor_hub_get_feature(st->hsdev,
179 st->sensitivity.report_id,
180 st->sensitivity.index, &value);
181 if (ret < 0 || value < 0) {
182 *val1 = *val2 = 0;
183 return -EINVAL;
184 } else {
185 convert_from_vtf_format(value, st->sensitivity.size,
186 st->sensitivity.unit_expo,
187 val1, val2);
188 }
189
190 return IIO_VAL_INT_PLUS_MICRO;
191}
192EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
193
194int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
195 int val1, int val2)
196{
197 s32 value;
198 int ret;
199
200 value = convert_to_vtf_format(st->sensitivity.size,
201 st->sensitivity.unit_expo,
202 val1, val2);
203 ret = sensor_hub_set_feature(st->hsdev,
204 st->sensitivity.report_id,
205 st->sensitivity.index, value);
206 if (ret < 0 || value < 0)
207 ret = -EINVAL;
208
209 return ret;
210}
211EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
212
213int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
214 u32 usage_id,
215 struct hid_sensor_iio_common *st)
216{
217
218 sensor_hub_input_get_attribute_info(hsdev,
219 HID_FEATURE_REPORT, usage_id,
220 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
221 &st->poll);
222
223 sensor_hub_input_get_attribute_info(hsdev,
224 HID_FEATURE_REPORT, usage_id,
225 HID_USAGE_SENSOR_PROP_REPORT_STATE,
226 &st->report_state);
227
228 sensor_hub_input_get_attribute_info(hsdev,
229 HID_FEATURE_REPORT, usage_id,
230 HID_USAGE_SENSOR_PROY_POWER_STATE,
231 &st->power_state);
232
233 sensor_hub_input_get_attribute_info(hsdev,
234 HID_FEATURE_REPORT, usage_id,
235 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
236 &st->sensitivity);
237
238 hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
239 st->poll.index, st->poll.report_id,
240 st->report_state.index, st->report_state.report_id,
241 st->power_state.index, st->power_state.report_id,
242 st->sensitivity.index, st->sensitivity.report_id);
243
244 return 0;
245}
246EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
247
248MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
249MODULE_DESCRIPTION("HID Sensor common attribute processing");
250MODULE_LICENSE("GPL");