summaryrefslogtreecommitdiff
path: root/etzkx.txt
blob: 5d2017ca29a1515ef58ea4970aa79e953d8bf8e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
	ETZKX - State Machine Interrupt Driven Accelerometer
	====================================================

Author: Andi Shyti <andi@etezian.com>

The etzkx driver provides support for the programmable state machine interrupt
driven 3-axis accelerometer.
The chip is manifactured by:

	ROHM Semiconductor: kxcnl-1010

Device description
------------------
The kxcnl-1010 accelerometer is an ultra low-power device based on a
differential capacitance arising from acceleration-induced motion of the sensor
element. The device has a dynamically user selectable sensitivity scale of
+-2/+-4/+-6/+-8g. Moreover the user has the possibility to select the sampling
frequency (odr) from 3.125Hz to 1.6kHz.

The X, Y, Z coordinates are accessible by polling the device. Interrupt
generation on data ready is also possible if preferred.

The device is capable of running two state machines for gesture recognition
such as orientation change, shake, tap, etc. Two sets of registers are used to
load the algorithms for the state machine.

The communication with the CPU is done via I2C bus. Two interrupt lines allow
signalling the state machines behavior and possibly the presence of new
data.

The device implements a hardware selftest functionality which allows testing of
the reliability of the device.

The driver
----------
The driver is located under

	driver/misc/etzkx.c
	include/linux/i2c/etzkx.h

and is placed in between the i2c driver and the userspace interfaces

	 __________________________
	|        |        |        |
	| input  | sysfs  |  char  |
	| device |        | device |
	|________|________|________|
	|                          |
	|          etzkx           |
	|__________________________|
	|                          |
	|         i2c smbus        |
	|__________________________|
	|                          |
	|         i2c  xfer        |
	|                          |
	+==========================+
	|                          |
	|        kxcnl-1010        |
	|__________________________|


In the menuconfig the driver is reachable

	Device Drivers  --->
	   [*] Misc devices  --->
	      <*>   ETZKX kxcnl 3d digital accelerometer

The interfaces
--------------
The driver generates three types of interfaces:

 * sysfs: provides information related to the device and sets some basic
   parameters like output data rate (odr) and range.

 * input event: provides the X, Y, Z coordinates.

 * character device: provides state machine related information.

Sysfs interfaces
----------------
Here is a list of all the sysfs interfaces generated by the driver

hwid
	RO - shows the chip installed on the board

enable
	RW - enables/disables the streaming of X, Y, Z coordinates which are
	     readable from the input event file
	     1 enables the the streaming
	     0 disables the streaming

odr
	RW - sets the output data rate of the chip, i.e. sets the frequency of
	     working of the chip. The available data rates are (in Hz) 3.125,
	     6.25, 12.5, 25, 50, 100, 400, 1600. It is possible to write a
	     generic frequency and the driver will normalize it to the closest
	     available. When a state machine is running the user is prevented
	     form changing the odr.

delay
	RW - sets the driver polling rate in ms. Usually is

	                         1
	               delay = -----
	                        odr

	      but depending of some state machine conditions, odr and delay
	      might not be synchronized.

range
	RW - sets the sensitivity measured in g. The available g range are
	     +-2g, +-4g, +-6g, +-8g. When a state machine is running, the user
	     is prevented from changing the range.

self_test
	RW - enables/disables the self-test functionality. When the self_test is
	     enabled the X, Y, Z axes are affected by an offset, that offset
	     allows to evaluate the liability of the device (refer to the
	     datasheets for the self test patterns)
	     1 enables self test
	     0 disables self test

drv_version
	RO - shows the driver version

Input event interface
---------------------
The input event is generated under /dev/input/eventX, where X is an incremental
number chosen by the input driver framework.

To eventX file is associated the 'etzkx' name which is discoverable using an
ioctl function with EVIOCGNAME flag.

    DIR *dir;
    struct dirent *de;
    char *fname;
    [...]

    dir = opendir("/dev/input");
    while ( (de = readdir(dir)) )
    {
        fd = open(de->d_name, O_RDONLY))
        ioctl(fd, EVIOCGNAME(sizeof(fname) - 1), &fname)

        if (!strcmp(fname, "etzkx"))
            /*** found it! ***/

        close (fd);
    }

The driver streams the coordinates every "delay" ms (or "odr" Hz) through this
interface. The input driver sends a struct input_event to the interface buffer,
which has the following structure:

	#include <linux/input.h>

	struct input_event {
		struct timeval time;
		__u16 type;
		__u16 code;
		__s32 value;
	};

where the type event is EV_ABS, the code of the event is ABS_X, ABS_Y, ABS_Z
corresponding to the X, Y, Z coordiantes and in the end the value field is the
specific coordinate value. The driver sends three different events for each
coordinate followed by a synchronization event which has type=0, code=0 and
value=0.

A possible reading algorithm can be

    struct input_event ev;

    while (1)
    {
        do
        {
            read(fd, &ev, sizeof(struct input_event));

            if (ev.type == EV_ABS)
                switch (ev.code)
                {
                    case ABS_X:
                        X = ev.value;
                        break;
                    case ABS_Y:
                        Y = ev.value;
                        break;
                    case ABS_Z:
                        Z = ev.value;
                        break;
                }
        } while (ev.type != EV_SYN);
    }

Character device
----------------
The character device is used to report to the userspace the running state
machine's outcome. The interface is capable of polling so that it is possible to
use select() or poll() on it. The character interface is generated as

	/dev/etzkx_stm

The driver communicates with userspace by writing 64 bit structure on the
interface

	+-----+--------------------------+
	| 32  | algorithm id             |
	+-----+--------------------------+
	| 32  | specific algorithm data  |
	+-----+--------------------------+

Currently, three algorithms are implemented:

 - algorithm id
	ETZKX_STM_ID_TIMING: timing algorithm used for testing. It sends an interrupt
	every 16 odr.

	ETZKX_STM_ID_ORIENTATION: sends an interrupt every orientation change
	(portrait or landscape)

	ETZKX_STM_ID_DOUBLE_TAP: sends an interrupt every time that a double tap
	is detected

 - specific algorithm data
	timing (bit order)
	32 bit: not relevant, uninitialized

	orientation (bit order)
	16 bit: 1 if portrait, 0 otherwise
	16 bit: 1 if landscape, 0 otherwise

	double tap (bit order)
	8 bit: 1 if +x, 2 if -x, 0 otherwise
	8 bit: 1 if +y, 2 if -y, 0 otherwise
	8 bit: 1 if +z, 2 if -z, 0 otherwise
	8 bit: double tap peak

The /dev/etzkx_stm file is capable of ioctl with the following flags

	ETZKXIO_ENABLE_TIMING: enables timing algorithm
	ETZKXIO_DISABLE_TIMING: disable timing algorithm
	ETZKXIO_ENABLE_ORIENTATION: enables orientation algorithm
	ETZKXIO_DISABLE_ORIENTATION: disables orientation algorithm
	ETZKXIO_ENABLE_DOUBLE_TAP: enables double tap algorithm
	ETZKXIO_DISABLE_DOUBLE_TAP: disables double tap algorithm

	ETZKXIO_WHICH_ORIENTATION: asks to the driver the actual orientation
	status. The driver provides via ioctl an algorithm structure like
	this:

	   32 bit: ETZKX_STM_ID_ORIENTATION
	   16 bit: 1 if portrait, 0 otherwise
	   16 bit: 1 if landscape, 0 otherwise

	ETZKXIO_INSTANT_ORIENTATION: like ETZKXIO_WHICH_ORIENTATION, with the
	difference that the calculation of the orientation is calculated by
	comparing the X and Y coordinates.

	ETZKXIO_RUNNING_ALGO: reports to the userspace the two running
	algorithms for each state machine slot:

	   32 bit: running algorithm id on slot 1
	   32 bit: running algorithm id on slot 2

	if no state machine is loaded, the id is equal to ETZKX_STM_ID_NO_STM

Driver usage
------------
The driver follows a state machine way of working and at any time it tracks the
state which the driver is in.

                     __STRM --- STRM + STM1
                    /       \/              \
                   /        /\               \
   STBY --- ACTIVE --- STM1     STRM + STM2 --- STRM + STM1 + STM2
                   \        \/               /
                    \__     /\              /
                       STM2 --- STM1 + STM2

To reach each driver state, userspace applications have to enable/disable the
available features using the related interfaces.

Enable/disable streaming (STRM state):
	echo 1 > /sys/.../enable
	echo 0 > /sys/.../enable

Enable/disable state machine (STM1/STM2 state):
	ioctl (fd, ETZKXIO_ENABLE_ORIENTATION,  0);
	ioctl (fd, ETZKXIO_ENABLE_DOUBLE_TAP,   0);
	ioctl (fd, ETZKXIO_DISABLE_ORIENTATION, 0);
	ioctl (fd, ETZKXIO_DISABLE_DOUBLE_TAP,  0);

Self test
---------
The self test checks the electromechanical functionality of the sensor. The
driver sets the self test state as a specific branch of the driver state
machine:

                       _
                      /  ST
                     /    ^
   STDBY <---> ACTIVE     |
                     \    |
                      \_  v
                         STRM

To enable/disable the self test

	echo 1 > /sys/.../self_test
	echo 0 > /sys/.../self_test

This applies an extra capacitance to every axes which adds an offset to the X,
Y, Z output, it can be different for each coordinate.

The suppliers provides the minimum Dx, Dy, Dz offset in order to consider the
device reliable. The evaluation should be done like follows:

	|Xst - X| > Dx
	|Yst - Y| > Dy
	|Zst - Z| > Dz

where Xst, Yst and Zst are the coordinates measured after applying the self test
on the accelerometer.