1455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/*
2455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver
3455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
4455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  Copyright (C) 2007-2008 Yan Burman
5455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  Copyright (C) 2008 Eric Piel
6ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek *  Copyright (C) 2008-2009 Pavel Machek
7455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
8455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  This program is free software; you can redistribute it and/or modify
9455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  it under the terms of the GNU General Public License as published by
10455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  the Free Software Foundation; either version 2 of the License, or
11455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  (at your option) any later version.
12455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
13455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  This program is distributed in the hope that it will be useful,
14455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  GNU General Public License for more details.
17455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
18455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  You should have received a copy of the GNU General Public License
19455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  along with this program; if not, write to the Free Software
20455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */
22455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
2363366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2463366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches
25455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/kernel.h>
26455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/init.h>
27455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/dmi.h>
28455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/module.h>
29455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/types.h>
30455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/platform_device.h>
31455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/interrupt.h>
32dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel#include <linux/input-polldev.h>
33455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/delay.h>
34455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/wait.h>
35455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/poll.h>
36f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo#include <linux/slab.h>
37455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/freezer.h>
38455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include <linux/uaccess.h>
39ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek#include <linux/miscdevice.h>
402a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo#include <linux/pm_runtime.h>
41ff606677f6a47c63329cf8e6c7cf978c29f2d736Jean Delvare#include <linux/atomic.h>
42455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#include "lis3lv02d.h"
43455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
44455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#define DRIVER_NAME     "lis3lv02d"
45455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
46455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/* joystick device poll interval in milliseconds */
47455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek#define MDPS_POLL_INTERVAL 50
484a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo#define MDPS_POLL_MIN	   0
494a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo#define MDPS_POLL_MAX	   2000
502a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
512a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
522a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
53029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo#define SELFTEST_OK	       0
54029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo#define SELFTEST_FAIL	       -1
55029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo#define SELFTEST_IRQ	       -2
56029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
57029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo#define IRQ_LINE0	       0
58029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo#define IRQ_LINE1	       1
59029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
60455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/*
61455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * The sensor can also generate interrupts (DRDY) but it's pretty pointless
62bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel * because they are generated even if the data do not change. So it's better
63455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * to keep the interrupt for the free-fall event. The values are updated at
64455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
65455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * some low processor, we poll the sensor only at 20Hz... enough for the
66455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * joystick.
67455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */
68455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
69641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo#define LIS3_PWRON_DELAY_WAI_12B	(5000)
70641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo#define LIS3_PWRON_DELAY_WAI_8B		(3000)
71641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo
7232496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo/*
7332496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG
7432496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo * LIS302D spec says: 18 mG / digit
7532496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo * LIS3_ACCURACY is used to increase accuracy of the intermediate
7632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo * calculation results.
7732496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo */
7832496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo#define LIS3_ACCURACY			1024
7932496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo/* Sensitivity values for -2G +2G scale */
8032496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo#define LIS3_SENSITIVITY_12B		((LIS3_ACCURACY * 1000) / 1024)
8132496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo#define LIS3_SENSITIVITY_8B		(18 * LIS3_ACCURACY)
8232496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo
83477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo#define LIS3_DEFAULT_FUZZ_12B		3
84477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo#define LIS3_DEFAULT_FLAT_12B		3
85477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo#define LIS3_DEFAULT_FUZZ_8B		1
86477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo#define LIS3_DEFAULT_FLAT_8B		1
8732496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo
88a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstruct lis3lv02d lis3_dev = {
89be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek	.misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
90ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek};
91be84cfc588b19f14764d78556dc7b630ee8c914cPavel MachekEXPORT_SYMBOL_GPL(lis3_dev);
92455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
932ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai/* just like param_set_int() but does sanity-check so that it won't point
942ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai * over the axis array size
952ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai */
962ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwaistatic int param_set_axis(const char *val, const struct kernel_param *kp)
972ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai{
982ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	int ret = param_set_int(val, kp);
992ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	if (!ret) {
1002ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai		int val = *(int *)kp->arg;
1012ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai		if (val < 0)
1022ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai			val = -val;
1032ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai		if (!val || val > 3)
1042ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai			return -EINVAL;
1052ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	}
1062ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	return ret;
1072ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai}
1082ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai
1092ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwaistatic struct kernel_param_ops param_ops_axis = {
1102ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	.set = param_set_axis,
1112ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai	.get = param_get_int,
1122ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai};
1132ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai
114bafeafeab94b8d3019aac15c2df2ce47b08a6363Rusty Russell#define param_check_axis(name, p) param_check_int(name, p)
115bafeafeab94b8d3019aac15c2df2ce47b08a6363Rusty Russell
1162ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwaimodule_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
1172ee321440e3a594dcdd9981e68e5e302447047a2Takashi IwaiMODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
1182ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai
119a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
120a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack{
121a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	s8 lo;
122a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	if (lis3->read(lis3, reg, &lo) < 0)
123a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack		return 0;
124a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack
125a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	return lo;
126a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack}
127a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack
128bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Pielstatic s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
129be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek{
130be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek	u8 lo, hi;
131be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek
132a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	lis3->read(lis3, reg - 1, &lo);
133a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	lis3->read(lis3, reg, &hi);
134be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek	/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
135be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek	return (s16)((hi << 8) | lo);
136be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek}
137be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek
138455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/**
139455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * lis3lv02d_get_axis - For the given axis, give the value converted
140455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * @axis:      1,2,3 - can also be negative
141455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * @hw_values: raw values returned by the hardware
142455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
143455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * Returns the converted value.
144455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */
145455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
146455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
147455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	if (axis > 0)
148455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek		return hw_values[axis - 1];
149455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	else
150455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek		return -hw_values[-axis - 1];
151455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
152455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
153455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/**
154455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
155a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @lis3: pointer to the device struct
156a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @x:    where to store the X axis value
157a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @y:    where to store the Y axis value
158a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @z:    where to store the Z axis value
159455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek *
160455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
161455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */
162a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
163455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
164455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	int position[3];
16532496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	int i;
166455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
167f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo	if (lis3->blkread) {
168895c156c044a736d8dc2239020f4530bb6245675Éric Piel		if (lis3->whoami == WAI_12B) {
169f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			u16 data[3];
170f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
171f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			for (i = 0; i < 3; i++)
172f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo				position[i] = (s16)le16_to_cpu(data[i]);
173f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo		} else {
174f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			u8 data[5];
175f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			/* Data: x, dummy, y, dummy, z */
176f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			lis3->blkread(lis3, OUTX, 5, data);
177f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo			for (i = 0; i < 3; i++)
178f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo				position[i] = (s8)data[i * 2];
179f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo		}
180f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo	} else {
181f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo		position[0] = lis3->read_data(lis3, OUTX);
182f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo		position[1] = lis3->read_data(lis3, OUTY);
183f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo		position[2] = lis3->read_data(lis3, OUTZ);
184f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo	}
185455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
18632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	for (i = 0; i < 3; i++)
18732496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo		position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
18832496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo
189a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	*x = lis3lv02d_get_axis(lis3->ac.x, position);
190a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	*y = lis3lv02d_get_axis(lis3->ac.y, position);
191a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	*z = lis3lv02d_get_axis(lis3->ac.z, position);
192455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
193455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
194641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo/* conversion btw sampling rate and the register values */
195641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalostatic int lis3_12_rates[4] = {40, 160, 640, 2560};
196641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalostatic int lis3_8_rates[2] = {100, 400};
19778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwaistatic int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
198641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo
199a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo/* ODR is Output Data Rate */
200895c156c044a736d8dc2239020f4530bb6245675Éric Pielstatic int lis3lv02d_get_odr(struct lis3lv02d *lis3)
201641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo{
202641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo	u8 ctrl;
203a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	int shift;
204641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo
205895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->read(lis3, CTRL_REG1, &ctrl);
206895c156c044a736d8dc2239020f4530bb6245675Éric Piel	ctrl &= lis3->odr_mask;
207895c156c044a736d8dc2239020f4530bb6245675Éric Piel	shift = ffs(lis3->odr_mask) - 1;
208895c156c044a736d8dc2239020f4530bb6245675Éric Piel	return lis3->odrs[(ctrl >> shift)];
209a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo}
210641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo
2111510dd5954be5070e46b155eb32362dc73d9e9cbÉric Pielstatic int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3)
2121510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel{
213895c156c044a736d8dc2239020f4530bb6245675Éric Piel	int div = lis3lv02d_get_odr(lis3);
2141510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel
2151510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	if (WARN_ONCE(div == 0, "device returned spurious data"))
2161510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel		return -ENXIO;
2171510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel
2181510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	/* LIS3 power on delay is quite long */
2191510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	msleep(lis3->pwron_delay / div);
2201510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	return 0;
2211510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel}
2221510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel
223895c156c044a736d8dc2239020f4530bb6245675Éric Pielstatic int lis3lv02d_set_odr(struct lis3lv02d *lis3, int rate)
224a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo{
225a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	u8 ctrl;
226a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	int i, len, shift;
227a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
22878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	if (!rate)
22978537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		return -EINVAL;
23078537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai
231895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->read(lis3, CTRL_REG1, &ctrl);
232895c156c044a736d8dc2239020f4530bb6245675Éric Piel	ctrl &= ~lis3->odr_mask;
233895c156c044a736d8dc2239020f4530bb6245675Éric Piel	len = 1 << hweight_long(lis3->odr_mask); /* # of possible values */
234895c156c044a736d8dc2239020f4530bb6245675Éric Piel	shift = ffs(lis3->odr_mask) - 1;
235a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
236a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	for (i = 0; i < len; i++)
237895c156c044a736d8dc2239020f4530bb6245675Éric Piel		if (lis3->odrs[i] == rate) {
238895c156c044a736d8dc2239020f4530bb6245675Éric Piel			lis3->write(lis3, CTRL_REG1,
239a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo					ctrl | (i << shift));
240a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo			return 0;
241a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo		}
242a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	return -EINVAL;
243641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo}
244641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo
2452db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
2462db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo{
24778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	u8 ctlreg, reg;
2482db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	s16 x, y, z;
2492db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	u8 selftest;
2502db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	int ret;
251029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	u8 ctrl_reg_data;
252029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	unsigned char irq_cfg;
2532db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
2542db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	mutex_lock(&lis3->mutex);
255029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
256029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	irq_cfg = lis3->irq_cfg;
257895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->whoami == WAI_8B) {
258029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->data_ready_count[IRQ_LINE0] = 0;
259029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->data_ready_count[IRQ_LINE1] = 0;
260029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
261029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		/* Change interrupt cfg to data ready for selftest */
262895c156c044a736d8dc2239020f4530bb6245675Éric Piel		atomic_inc(&lis3->wake_thread);
263029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
264029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
265029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
266029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo				~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
267029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo				(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
268029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	}
269029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
270895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->whoami == WAI_3DC) {
27178537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		ctlreg = CTRL_REG4;
27278537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		selftest = CTRL4_ST0;
27378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	} else {
27478537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		ctlreg = CTRL_REG1;
275895c156c044a736d8dc2239020f4530bb6245675Éric Piel		if (lis3->whoami == WAI_12B)
27678537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai			selftest = CTRL1_ST;
27778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		else
27878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai			selftest = CTRL1_STP;
27978537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	}
2802db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
28178537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	lis3->read(lis3, ctlreg, &reg);
28278537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	lis3->write(lis3, ctlreg, (reg | selftest));
2831510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	ret = lis3lv02d_get_pwron_wait(lis3);
2841510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	if (ret)
2851510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel		goto fail;
2862db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
2872db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	/* Read directly to avoid axis remap */
2882db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	x = lis3->read_data(lis3, OUTX);
2892db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	y = lis3->read_data(lis3, OUTY);
2902db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	z = lis3->read_data(lis3, OUTZ);
2912db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
2922db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	/* back to normal settings */
29378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	lis3->write(lis3, ctlreg, reg);
2941510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	ret = lis3lv02d_get_pwron_wait(lis3);
2951510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	if (ret)
2961510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel		goto fail;
2972db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
2982db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	results[0] = x - lis3->read_data(lis3, OUTX);
2992db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	results[1] = y - lis3->read_data(lis3, OUTY);
3002db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	results[2] = z - lis3->read_data(lis3, OUTZ);
3012db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
3022db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	ret = 0;
303029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
304895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->whoami == WAI_8B) {
305029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		/* Restore original interrupt configuration */
306895c156c044a736d8dc2239020f4530bb6245675Éric Piel		atomic_dec(&lis3->wake_thread);
307029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
308029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis3->irq_cfg = irq_cfg;
309029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
310029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		if ((irq_cfg & LIS3_IRQ1_MASK) &&
311029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			lis3->data_ready_count[IRQ_LINE0] < 2) {
312029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			ret = SELFTEST_IRQ;
313029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			goto fail;
314029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		}
315029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
316029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		if ((irq_cfg & LIS3_IRQ2_MASK) &&
317029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			lis3->data_ready_count[IRQ_LINE1] < 2) {
318029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			ret = SELFTEST_IRQ;
319029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo			goto fail;
320029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		}
321029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	}
322029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
3232db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	if (lis3->pdata) {
3242db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo		int i;
3252db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo		for (i = 0; i < 3; i++) {
3262db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo			/* Check against selftest acceptance limits */
3272db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo			if ((results[i] < lis3->pdata->st_min_limits[i]) ||
3282db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo			    (results[i] > lis3->pdata->st_max_limits[i])) {
329029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo				ret = SELFTEST_FAIL;
3302db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo				goto fail;
3312db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo			}
3322db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo		}
3332db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	}
3342db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
3352db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	/* test passed */
3362db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalofail:
3372db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	mutex_unlock(&lis3->mutex);
3382db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	return ret;
3392db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo}
3402db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
341f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo/*
342f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * Order of registers in the list affects to order of the restore process.
343f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * Perhaps it is a good idea to set interrupt enable register as a last one
344f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * after all other configurations
345f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo */
346f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
347f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
348f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
349f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
350f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       CTRL_REG1, CTRL_REG2, CTRL_REG3};
351f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
352f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
353f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
354f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       DD_THSE_L, DD_THSE_H,
355f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			       CTRL_REG1, CTRL_REG3, CTRL_REG2};
356f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
357f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic inline void lis3_context_save(struct lis3lv02d *lis3)
358f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo{
359f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	int i;
360f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	for (i = 0; i < lis3->regs_size; i++)
361f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
362f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	lis3->regs_stored = true;
363f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo}
364f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
365f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic inline void lis3_context_restore(struct lis3lv02d *lis3)
366f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo{
367f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	int i;
368f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	if (lis3->regs_stored)
369f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		for (i = 0; i < lis3->regs_size; i++)
370f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo			lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
371f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo}
372f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
373a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackvoid lis3lv02d_poweroff(struct lis3lv02d *lis3)
374455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
375f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	if (lis3->reg_ctrl)
376f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		lis3_context_save(lis3);
377a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	/* disable X,Y,Z axis and power down */
378a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	lis3->write(lis3, CTRL_REG1, 0x00);
379f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	if (lis3->reg_ctrl)
380f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		lis3->reg_ctrl(lis3, LIS3_REG_OFF);
381455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
382cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
383455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
3841510dd5954be5070e46b155eb32362dc73d9e9cbÉric Pielint lis3lv02d_poweron(struct lis3lv02d *lis3)
385455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
3861510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	int err;
387a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	u8 reg;
388455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
389a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	lis3->init(lis3);
390455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
391a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	/*
392a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	 * Common configuration
3934b5d95b3809bcd77599122494aa3f575cd6ab1b9Éric Piel	 * BDU: (12 bits sensors only) LSB and MSB values are not updated until
3944b5d95b3809bcd77599122494aa3f575cd6ab1b9Éric Piel	 *      both have been read. So the value read will always be correct.
3952a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo	 * Set BOOT bit to refresh factory tuning values.
396a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	 */
39705faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai	if (lis3->pdata) {
39805faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai		lis3->read(lis3, CTRL_REG2, &reg);
39905faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai		if (lis3->whoami ==  WAI_12B)
40005faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai			reg |= CTRL2_BDU | CTRL2_BOOT;
40105faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai		else
40205faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai			reg |= CTRL2_BOOT_8B;
40305faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai		lis3->write(lis3, CTRL_REG2, reg);
40405faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai	}
4052a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo
4061510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	err = lis3lv02d_get_pwron_wait(lis3);
4071510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	if (err)
4081510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel		return err;
4092a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo
410f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	if (lis3->reg_ctrl)
411f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		lis3_context_restore(lis3);
4121510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel
4131510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	return 0;
414455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
415a002ee896dfd08ce9fba44e9ae513c9094699a27Eric PielEXPORT_SYMBOL_GPL(lis3lv02d_poweron);
416a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel
417455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
4186d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
4196d94d4081048756df78444a07201156f4930fe48Samu Onkalo{
420895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = pidev->private;
4216d94d4081048756df78444a07201156f4930fe48Samu Onkalo	int x, y, z;
4226d94d4081048756df78444a07201156f4930fe48Samu Onkalo
423895c156c044a736d8dc2239020f4530bb6245675Éric Piel	mutex_lock(&lis3->mutex);
424895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_get_xyz(lis3, &x, &y, &z);
4256d94d4081048756df78444a07201156f4930fe48Samu Onkalo	input_report_abs(pidev->input, ABS_X, x);
4266d94d4081048756df78444a07201156f4930fe48Samu Onkalo	input_report_abs(pidev->input, ABS_Y, y);
4276d94d4081048756df78444a07201156f4930fe48Samu Onkalo	input_report_abs(pidev->input, ABS_Z, z);
4286d94d4081048756df78444a07201156f4930fe48Samu Onkalo	input_sync(pidev->input);
429895c156c044a736d8dc2239020f4530bb6245675Éric Piel	mutex_unlock(&lis3->mutex);
4306d94d4081048756df78444a07201156f4930fe48Samu Onkalo}
4316d94d4081048756df78444a07201156f4930fe48Samu Onkalo
4322a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
4332a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{
434895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = pidev->private;
435e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo
436895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pm_dev)
437895c156c044a736d8dc2239020f4530bb6245675Éric Piel		pm_runtime_get_sync(lis3->pm_dev);
438895c156c044a736d8dc2239020f4530bb6245675Éric Piel
439895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pdata && lis3->whoami == WAI_8B && lis3->idev)
440895c156c044a736d8dc2239020f4530bb6245675Éric Piel		atomic_set(&lis3->wake_thread, 1);
441821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo	/*
442821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo	 * Update coordinates for the case where poll interval is 0 and
443821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo	 * the chip in running purely under interrupt control
444821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo	 */
445821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo	lis3lv02d_joystick_poll(pidev);
4462a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo}
4472a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
4482a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
4492a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{
450895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = pidev->private;
451895c156c044a736d8dc2239020f4530bb6245675Éric Piel
452895c156c044a736d8dc2239020f4530bb6245675Éric Piel	atomic_set(&lis3->wake_thread, 0);
453895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pm_dev)
454895c156c044a736d8dc2239020f4530bb6245675Éric Piel		pm_runtime_put(lis3->pm_dev);
4552a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo}
4562a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
457895c156c044a736d8dc2239020f4530bb6245675Éric Pielstatic irqreturn_t lis302dl_interrupt(int irq, void *data)
458ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
459895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = data;
460895c156c044a736d8dc2239020f4530bb6245675Éric Piel
461895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (!test_bit(0, &lis3->misc_opened))
46292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		goto out;
46392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
464ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	/*
465ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	 * Be careful: on some HP laptops the bios force DD when on battery and
466ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	 * the lid is closed. This leads to interrupts as soon as a little move
467ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	 * is done.
468ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	 */
469895c156c044a736d8dc2239020f4530bb6245675Éric Piel	atomic_inc(&lis3->count);
470ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
471895c156c044a736d8dc2239020f4530bb6245675Éric Piel	wake_up_interruptible(&lis3->misc_wait);
472895c156c044a736d8dc2239020f4530bb6245675Éric Piel	kill_fasync(&lis3->async_queue, SIGIO, POLL_IN);
47392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkaloout:
474895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (atomic_read(&lis3->wake_thread))
47592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		return IRQ_WAKE_THREAD;
476ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	return IRQ_HANDLED;
477ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
478ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
4796d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
4806d94d4081048756df78444a07201156f4930fe48Samu Onkalo{
4816d94d4081048756df78444a07201156f4930fe48Samu Onkalo	struct input_dev *dev = lis3->idev->input;
4826d94d4081048756df78444a07201156f4930fe48Samu Onkalo	u8 click_src;
4836d94d4081048756df78444a07201156f4930fe48Samu Onkalo
4846d94d4081048756df78444a07201156f4930fe48Samu Onkalo	mutex_lock(&lis3->mutex);
4856d94d4081048756df78444a07201156f4930fe48Samu Onkalo	lis3->read(lis3, CLICK_SRC, &click_src);
4866d94d4081048756df78444a07201156f4930fe48Samu Onkalo
4876d94d4081048756df78444a07201156f4930fe48Samu Onkalo	if (click_src & CLICK_SINGLE_X) {
4886d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[0], 1);
4896d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[0], 0);
4906d94d4081048756df78444a07201156f4930fe48Samu Onkalo	}
4916d94d4081048756df78444a07201156f4930fe48Samu Onkalo
4926d94d4081048756df78444a07201156f4930fe48Samu Onkalo	if (click_src & CLICK_SINGLE_Y) {
4936d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[1], 1);
4946d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[1], 0);
4956d94d4081048756df78444a07201156f4930fe48Samu Onkalo	}
4966d94d4081048756df78444a07201156f4930fe48Samu Onkalo
4976d94d4081048756df78444a07201156f4930fe48Samu Onkalo	if (click_src & CLICK_SINGLE_Z) {
4986d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[2], 1);
4996d94d4081048756df78444a07201156f4930fe48Samu Onkalo		input_report_key(dev, lis3->mapped_btns[2], 0);
5006d94d4081048756df78444a07201156f4930fe48Samu Onkalo	}
5016d94d4081048756df78444a07201156f4930fe48Samu Onkalo	input_sync(dev);
5026d94d4081048756df78444a07201156f4930fe48Samu Onkalo	mutex_unlock(&lis3->mutex);
5036d94d4081048756df78444a07201156f4930fe48Samu Onkalo}
5046d94d4081048756df78444a07201156f4930fe48Samu Onkalo
505029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
506ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
507029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	int dummy;
508029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
509029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	/* Dummy read to ack interrupt */
510029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
511029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	lis3->data_ready_count[index]++;
512029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo}
5136d94d4081048756df78444a07201156f4930fe48Samu Onkalo
514029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
515029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo{
5166d94d4081048756df78444a07201156f4930fe48Samu Onkalo	struct lis3lv02d *lis3 = data;
517029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
5186d94d4081048756df78444a07201156f4930fe48Samu Onkalo
519029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	if (irq_cfg == LIS3_IRQ1_CLICK)
5206d94d4081048756df78444a07201156f4930fe48Samu Onkalo		lis302dl_interrupt_handle_click(lis3);
521029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
522029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis302dl_data_ready(lis3, IRQ_LINE0);
5236d94d4081048756df78444a07201156f4930fe48Samu Onkalo	else
524e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo		lis3lv02d_joystick_poll(lis3->idev);
5256d94d4081048756df78444a07201156f4930fe48Samu Onkalo
52692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	return IRQ_HANDLED;
52792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo}
528ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
52992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
53092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{
5316d94d4081048756df78444a07201156f4930fe48Samu Onkalo	struct lis3lv02d *lis3 = data;
532029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
5336d94d4081048756df78444a07201156f4930fe48Samu Onkalo
534029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	if (irq_cfg == LIS3_IRQ2_CLICK)
5356d94d4081048756df78444a07201156f4930fe48Samu Onkalo		lis302dl_interrupt_handle_click(lis3);
536029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
537029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		lis302dl_data_ready(lis3, IRQ_LINE1);
5386d94d4081048756df78444a07201156f4930fe48Samu Onkalo	else
539e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo		lis3lv02d_joystick_poll(lis3->idev);
5406d94d4081048756df78444a07201156f4930fe48Samu Onkalo
54192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	return IRQ_HANDLED;
54292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo}
54392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
54492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic int lis3lv02d_misc_open(struct inode *inode, struct file *file)
54592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{
546895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = container_of(file->private_data,
547895c156c044a736d8dc2239020f4530bb6245675Éric Piel					      struct lis3lv02d, miscdev);
548895c156c044a736d8dc2239020f4530bb6245675Éric Piel
549895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (test_and_set_bit(0, &lis3->misc_opened))
550ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		return -EBUSY; /* already open */
551ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
552895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pm_dev)
553895c156c044a736d8dc2239020f4530bb6245675Éric Piel		pm_runtime_get_sync(lis3->pm_dev);
5542a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
555895c156c044a736d8dc2239020f4530bb6245675Éric Piel	atomic_set(&lis3->count, 0);
556ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	return 0;
557ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
558ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
559ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_release(struct inode *inode, struct file *file)
560ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
561895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = container_of(file->private_data,
562895c156c044a736d8dc2239020f4530bb6245675Éric Piel					      struct lis3lv02d, miscdev);
563895c156c044a736d8dc2239020f4530bb6245675Éric Piel
564895c156c044a736d8dc2239020f4530bb6245675Éric Piel	fasync_helper(-1, file, 0, &lis3->async_queue);
565895c156c044a736d8dc2239020f4530bb6245675Éric Piel	clear_bit(0, &lis3->misc_opened); /* release the device */
566895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pm_dev)
567895c156c044a736d8dc2239020f4530bb6245675Éric Piel		pm_runtime_put(lis3->pm_dev);
568ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	return 0;
569ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
570ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
571ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
572ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek				size_t count, loff_t *pos)
573ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
574895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = container_of(file->private_data,
575895c156c044a736d8dc2239020f4530bb6245675Éric Piel					      struct lis3lv02d, miscdev);
576895c156c044a736d8dc2239020f4530bb6245675Éric Piel
577ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	DECLARE_WAITQUEUE(wait, current);
578ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	u32 data;
579ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	unsigned char byte_data;
580ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	ssize_t retval = 1;
581ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
582ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	if (count < 1)
583ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		return -EINVAL;
584ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
585895c156c044a736d8dc2239020f4530bb6245675Éric Piel	add_wait_queue(&lis3->misc_wait, &wait);
586ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	while (true) {
587ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		set_current_state(TASK_INTERRUPTIBLE);
588895c156c044a736d8dc2239020f4530bb6245675Éric Piel		data = atomic_xchg(&lis3->count, 0);
589ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		if (data)
590ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek			break;
591ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
592ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		if (file->f_flags & O_NONBLOCK) {
593ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek			retval = -EAGAIN;
594ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek			goto out;
595ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		}
596ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
597ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		if (signal_pending(current)) {
598ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek			retval = -ERESTARTSYS;
599ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek			goto out;
600ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		}
601ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
602ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		schedule();
603ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	}
604ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
605ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	if (data < 255)
606ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		byte_data = data;
607ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	else
608ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		byte_data = 255;
609ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
610ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	/* make sure we are not going into copy_to_user() with
611ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	 * TASK_INTERRUPTIBLE state */
612ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	set_current_state(TASK_RUNNING);
613ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	if (copy_to_user(buf, &byte_data, sizeof(byte_data)))
614ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		retval = -EFAULT;
615ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
616ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekout:
617ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	__set_current_state(TASK_RUNNING);
618895c156c044a736d8dc2239020f4530bb6245675Éric Piel	remove_wait_queue(&lis3->misc_wait, &wait);
619ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
620ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	return retval;
621ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
622ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
623ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
624ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
625895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = container_of(file->private_data,
626895c156c044a736d8dc2239020f4530bb6245675Éric Piel					      struct lis3lv02d, miscdev);
627895c156c044a736d8dc2239020f4530bb6245675Éric Piel
628895c156c044a736d8dc2239020f4530bb6245675Éric Piel	poll_wait(file, &lis3->misc_wait, wait);
629895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (atomic_read(&lis3->count))
630ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek		return POLLIN | POLLRDNORM;
631ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	return 0;
632ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
633ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
634ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
635ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{
636895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = container_of(file->private_data,
637895c156c044a736d8dc2239020f4530bb6245675Éric Piel					      struct lis3lv02d, miscdev);
638895c156c044a736d8dc2239020f4530bb6245675Éric Piel
639895c156c044a736d8dc2239020f4530bb6245675Éric Piel	return fasync_helper(fd, file, on, &lis3->async_queue);
640ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}
641ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
642ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic const struct file_operations lis3lv02d_misc_fops = {
643ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.owner   = THIS_MODULE,
644ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.llseek  = no_llseek,
645ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.read    = lis3lv02d_misc_read,
646ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.open    = lis3lv02d_misc_open,
647ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.release = lis3lv02d_misc_release,
648ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.poll    = lis3lv02d_misc_poll,
649ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek	.fasync  = lis3lv02d_misc_fasync,
650ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek};
651ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek
652e1e5687d75ef0ea5cbae63df48ff2fdcb5306f66Éric Pielint lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
653455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
654dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	struct input_dev *input_dev;
655455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	int err;
65632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	int max_val, fuzz, flat;
6576d94d4081048756df78444a07201156f4930fe48Samu Onkalo	int btns[] = {BTN_X, BTN_Y, BTN_Z};
658455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
659895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->idev)
660455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek		return -EINVAL;
661455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
662895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev = input_allocate_polled_device();
663895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (!lis3->idev)
664455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek		return -ENOMEM;
665455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
666895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->poll = lis3lv02d_joystick_poll;
667895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->open = lis3lv02d_joystick_open;
668895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->close = lis3lv02d_joystick_close;
669895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->poll_interval = MDPS_POLL_INTERVAL;
670895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->poll_interval_min = MDPS_POLL_MIN;
671895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->poll_interval_max = MDPS_POLL_MAX;
672895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev->private = lis3;
673895c156c044a736d8dc2239020f4530bb6245675Éric Piel	input_dev = lis3->idev->input;
674dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel
675dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	input_dev->name       = "ST LIS3LV02DL Accelerometer";
676dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	input_dev->phys       = DRIVER_NAME "/input0";
677dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	input_dev->id.bustype = BUS_HOST;
678dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	input_dev->id.vendor  = 0;
679895c156c044a736d8dc2239020f4530bb6245675Éric Piel	input_dev->dev.parent = &lis3->pdev->dev;
680455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
681dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel	set_bit(EV_ABS, input_dev->evbit);
682895c156c044a736d8dc2239020f4530bb6245675Éric Piel	max_val = (lis3->mdps_max_val * lis3->scale) / LIS3_ACCURACY;
683895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->whoami == WAI_12B) {
684477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo		fuzz = LIS3_DEFAULT_FUZZ_12B;
685477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo		flat = LIS3_DEFAULT_FLAT_12B;
686477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo	} else {
687477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo		fuzz = LIS3_DEFAULT_FUZZ_8B;
688477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo		flat = LIS3_DEFAULT_FLAT_8B;
689477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo	}
690895c156c044a736d8dc2239020f4530bb6245675Éric Piel	fuzz = (fuzz * lis3->scale) / LIS3_ACCURACY;
691895c156c044a736d8dc2239020f4530bb6245675Éric Piel	flat = (flat * lis3->scale) / LIS3_ACCURACY;
692477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo
69332496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
69432496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
69532496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo	input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
696455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
697895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->mapped_btns[0] = lis3lv02d_get_axis(abs(lis3->ac.x), btns);
698895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->mapped_btns[1] = lis3lv02d_get_axis(abs(lis3->ac.y), btns);
699895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->mapped_btns[2] = lis3lv02d_get_axis(abs(lis3->ac.z), btns);
7006d94d4081048756df78444a07201156f4930fe48Samu Onkalo
701895c156c044a736d8dc2239020f4530bb6245675Éric Piel	err = input_register_polled_device(lis3->idev);
702455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	if (err) {
703895c156c044a736d8dc2239020f4530bb6245675Éric Piel		input_free_polled_device(lis3->idev);
704895c156c044a736d8dc2239020f4530bb6245675Éric Piel		lis3->idev = NULL;
705455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	}
706455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
707455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	return err;
708455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
709cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
710455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
711e1e5687d75ef0ea5cbae63df48ff2fdcb5306f66Éric Pielvoid lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
712455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
713895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->irq)
714895c156c044a736d8dc2239020f4530bb6245675Éric Piel		free_irq(lis3->irq, lis3);
715895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->pdata && lis3->pdata->irq2)
716895c156c044a736d8dc2239020f4530bb6245675Éric Piel		free_irq(lis3->pdata->irq2, lis3);
71792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
718895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (!lis3->idev)
719455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek		return;
720455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
721895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3->irq)
722895c156c044a736d8dc2239020f4530bb6245675Éric Piel		misc_deregister(&lis3->miscdev);
723895c156c044a736d8dc2239020f4530bb6245675Éric Piel	input_unregister_polled_device(lis3->idev);
724895c156c044a736d8dc2239020f4530bb6245675Éric Piel	input_free_polled_device(lis3->idev);
725895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->idev = NULL;
726455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
727cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
728455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
729455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/* Sysfs stuff */
7302a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
7312a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{
7322a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	/*
7332a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 * SYSFS functions are fast visitors so put-call
7342a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 * immediately after the get-call. However, keep
7352a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 * chip running for a while and schedule delayed
7362a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 * suspend. This way periodic sysfs calls doesn't
7372a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 * suffer from relatively long power up time.
7382a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	 */
7392a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
7402a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	if (lis3->pm_dev) {
7412a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_runtime_get_sync(lis3->pm_dev);
7422a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_runtime_put_noidle(lis3->pm_dev);
7432a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
7442a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	}
7452a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo}
7462a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
7472db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic ssize_t lis3lv02d_selftest_show(struct device *dev,
7482db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo				struct device_attribute *attr, char *buf)
7492db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo{
750895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
7512db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	s16 values[3];
7522db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
753029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	static const char ok[] = "OK";
754029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	static const char fail[] = "FAIL";
755029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	static const char irq[] = "FAIL_IRQ";
756029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	const char *res;
757029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo
758895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_sysfs_poweron(lis3);
759895c156c044a736d8dc2239020f4530bb6245675Éric Piel	switch (lis3lv02d_selftest(lis3, values)) {
760029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	case SELFTEST_FAIL:
761029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		res = fail;
762029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		break;
763029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	case SELFTEST_IRQ:
764029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		res = irq;
765029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		break;
766029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	case SELFTEST_OK:
767029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	default:
768029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		res = ok;
769029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo		break;
770029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	}
771029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo	return sprintf(buf, "%s %d %d %d\n", res,
7722db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo		values[0], values[1], values[2]);
7732db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo}
7742db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
775455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_position_show(struct device *dev,
776455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek				struct device_attribute *attr, char *buf)
777455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
778895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
779455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	int x, y, z;
780455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
781895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_sysfs_poweron(lis3);
782895c156c044a736d8dc2239020f4530bb6245675Éric Piel	mutex_lock(&lis3->mutex);
783895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_get_xyz(lis3, &x, &y, &z);
784895c156c044a736d8dc2239020f4530bb6245675Éric Piel	mutex_unlock(&lis3->mutex);
785455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
786455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
787455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
788455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_rate_show(struct device *dev,
789455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek			struct device_attribute *attr, char *buf)
790455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
791895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
792895c156c044a736d8dc2239020f4530bb6245675Éric Piel
793895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_sysfs_poweron(lis3);
794895c156c044a736d8dc2239020f4530bb6245675Éric Piel	return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
795455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
796455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
797a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic ssize_t lis3lv02d_rate_set(struct device *dev,
798a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo				struct device_attribute *attr, const char *buf,
799a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo				size_t count)
800a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo{
801895c156c044a736d8dc2239020f4530bb6245675Éric Piel	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
802a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	unsigned long rate;
803a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
804a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	if (strict_strtoul(buf, 0, &rate))
805a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo		return -EINVAL;
806a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
807895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3lv02d_sysfs_poweron(lis3);
808895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (lis3lv02d_set_odr(lis3, rate))
809a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo		return -EINVAL;
810a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
811a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo	return count;
812a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo}
813a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo
8142db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
815455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
816a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
817a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo					    lis3lv02d_rate_set);
818455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
819455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute *lis3lv02d_attributes[] = {
8202db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo	&dev_attr_selftest.attr,
821455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	&dev_attr_position.attr,
822455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	&dev_attr_rate.attr,
823455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	NULL
824455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek};
825455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
826455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute_group lis3lv02d_attribute_group = {
827455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	.attrs = lis3lv02d_attributes
828455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek};
829455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
830cfce41a6d643c001d416ead960caf04fae2d609aEric Piel
831a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic int lis3lv02d_add_fs(struct lis3lv02d *lis3)
832455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
833a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
834a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	if (IS_ERR(lis3->pdev))
835a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel		return PTR_ERR(lis3->pdev);
836455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
837895c156c044a736d8dc2239020f4530bb6245675Éric Piel	platform_set_drvdata(lis3->pdev, lis3);
838a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
839455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
840455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
841a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Pielint lis3lv02d_remove_fs(struct lis3lv02d *lis3)
842455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{
843a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
844a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel	platform_device_unregister(lis3->pdev);
8452a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	if (lis3->pm_dev) {
8462a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		/* Barrier after the sysfs remove */
8472a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_runtime_barrier(lis3->pm_dev);
8482a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
8492a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		/* SYSFS may have left chip running. Turn off if necessary */
8502a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		if (!pm_runtime_suspended(lis3->pm_dev))
851895c156c044a736d8dc2239020f4530bb6245675Éric Piel			lis3lv02d_poweroff(lis3);
8522a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
8532a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_runtime_disable(lis3->pm_dev);
8542a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo		pm_runtime_set_suspended(lis3->pm_dev);
8552a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	}
856f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	kfree(lis3->reg_cache);
857455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek	return 0;
858455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}
859cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
860455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek
861d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Pielstatic void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
862ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo				struct lis3lv02d_platform_data *p)
863ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo{
86492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	int err;
865342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo	int ctrl2 = p->hipass_ctrl;
866342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo
867ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo	if (p->click_flags) {
868d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_CFG, p->click_flags);
869d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_TIMELIMIT, p->click_time_limit);
870d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_LATENCY, p->click_latency);
871d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_WINDOW, p->click_window);
872d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_THSZ, p->click_thresh_z & 0xf);
873d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, CLICK_THSY_X,
874ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo			(p->click_thresh_x & 0xf) |
875ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo			(p->click_thresh_y << 4));
8766d94d4081048756df78444a07201156f4930fe48Samu Onkalo
877d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		if (lis3->idev) {
878895c156c044a736d8dc2239020f4530bb6245675Éric Piel			struct input_dev *input_dev = lis3->idev->input;
8796d94d4081048756df78444a07201156f4930fe48Samu Onkalo			input_set_capability(input_dev, EV_KEY, BTN_X);
8806d94d4081048756df78444a07201156f4930fe48Samu Onkalo			input_set_capability(input_dev, EV_KEY, BTN_Y);
8816d94d4081048756df78444a07201156f4930fe48Samu Onkalo			input_set_capability(input_dev, EV_KEY, BTN_Z);
8826d94d4081048756df78444a07201156f4930fe48Samu Onkalo		}
883ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo	}
884ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo
885ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo	if (p->wakeup_flags) {
886d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_CFG_1, p->wakeup_flags);
887d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
888cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo		/* pdata value + 1 to keep this backward compatible*/
889d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_DURATION_1, p->duration1 + 1);
890342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo		ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
891342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo	}
892342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo
893342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo	if (p->wakeup_flags2) {
894d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_CFG_2, p->wakeup_flags2);
895d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
896cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo		/* pdata value + 1 to keep this backward compatible*/
897d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->write(lis3, FF_WU_DURATION_2, p->duration2 + 1);
898342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo		ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
899ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo	}
900342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo	/* Configure hipass filters */
901d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	lis3->write(lis3, CTRL_REG2, ctrl2);
90292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
90392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	if (p->irq2) {
90492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		err = request_threaded_irq(p->irq2,
90592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo					NULL,
90692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo					lis302dl_interrupt_thread2_8b,
907cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo					IRQF_TRIGGER_RISING | IRQF_ONESHOT |
908cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo					(p->irq_flags2 & IRQF_TRIGGER_MASK),
909895c156c044a736d8dc2239020f4530bb6245675Éric Piel					DRIVER_NAME, lis3);
91092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		if (err < 0)
91163366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches			pr_err("No second IRQ. Limited functionality\n");
91292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	}
913ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo}
914ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo
915ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack/*
916ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack * Initialise the accelerometer and the various subsystems.
917bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel * Should be rather independent of the bus system.
918ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack */
919d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Pielint lis3lv02d_init_device(struct lis3lv02d *lis3)
920ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack{
92192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	int err;
92292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	irq_handler_t thread_fn;
923cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo	int irq_flags = 0;
92492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
925d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	lis3->whoami = lis3lv02d_read_8(lis3, WHO_AM_I);
926a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack
927d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	switch (lis3->whoami) {
928bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel	case WAI_12B:
92963366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_info("12 bits sensor found\n");
930d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->read_data = lis3lv02d_read_12;
931d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->mdps_max_val = 2048;
932d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
933d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odrs = lis3_12_rates;
934d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odr_mask = CTRL1_DF0 | CTRL1_DF1;
935d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->scale = LIS3_SENSITIVITY_12B;
936d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->regs = lis3_wai12_regs;
937d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->regs_size = ARRAY_SIZE(lis3_wai12_regs);
938a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack		break;
939bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel	case WAI_8B:
94063366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_info("8 bits sensor found\n");
941d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->read_data = lis3lv02d_read_8;
942d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->mdps_max_val = 128;
943d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
944d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odrs = lis3_8_rates;
945d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odr_mask = CTRL1_DR;
946d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->scale = LIS3_SENSITIVITY_8B;
947d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->regs = lis3_wai8_regs;
948d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->regs_size = ARRAY_SIZE(lis3_wai8_regs);
949a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack		break;
95078537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai	case WAI_3DC:
95163366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_info("8 bits 3DC sensor found\n");
952d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->read_data = lis3lv02d_read_8;
953d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->mdps_max_val = 128;
954d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
955d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odrs = lis3_3dc_rates;
956d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
957d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->scale = LIS3_SENSITIVITY_8B;
95878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai		break;
959a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	default:
960d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		pr_err("unknown sensor type 0x%X\n", lis3->whoami);
961a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack		return -EINVAL;
962a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	}
963a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack
964d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
965f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo				     sizeof(lis3_wai12_regs)), GFP_KERNEL);
966f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
967d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	if (lis3->reg_cache == NULL) {
968f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		printk(KERN_ERR DRIVER_NAME "out of memory\n");
969f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo		return -ENOMEM;
970f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo	}
971f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo
972d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	mutex_init(&lis3->mutex);
973d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	atomic_set(&lis3->wake_thread, 0);
9742db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo
975d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	lis3lv02d_add_fs(lis3);
976d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	err = lis3lv02d_poweron(lis3);
9771510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	if (err) {
978d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3lv02d_remove_fs(lis3);
9791510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel		return err;
9801510dd5954be5070e46b155eb32362dc73d9e9cbÉric Piel	}
981ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack
982d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	if (lis3->pm_dev) {
983d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		pm_runtime_set_active(lis3->pm_dev);
984d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		pm_runtime_enable(lis3->pm_dev);
9852a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo	}
9862a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo
987e1e5687d75ef0ea5cbae63df48ff2fdcb5306f66Éric Piel	if (lis3lv02d_joystick_enable(lis3))
98863366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_err("joystick initialization failed\n");
989ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack
9908f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack	/* passing in platform specific data is purely optional and only
9918f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack	 * used by the SPI transport layer at the moment */
992d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	if (lis3->pdata) {
993d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		struct lis3lv02d_platform_data *p = lis3->pdata;
9948f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack
995d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		if (lis3->whoami == WAI_8B)
996d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel			lis3lv02d_8b_configure(lis3, p);
9978873c33483e62988ed886230aab71ef4c678f710Daniel Mack
998cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo		irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
999cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo
1000d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel		lis3->irq_cfg = p->irq_cfg;
10018f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack		if (p->irq_cfg)
1002d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel			lis3->write(lis3, CTRL_REG3, p->irq_cfg);
1003cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo
1004cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo		if (p->default_rate)
1005895c156c044a736d8dc2239020f4530bb6245675Éric Piel			lis3lv02d_set_odr(lis3, p->default_rate);
10068f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack	}
10078f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack
1008a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack	/* bail if we did not get an IRQ from the bus layer */
1009d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	if (!lis3->irq) {
1010a20f0bc10c47fcf62be027e1a50b62791052ab56Kalhan Trisal		pr_debug("No IRQ. Disabling /dev/freefall\n");
1011ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack		goto out;
1012ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack	}
1013ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack
101492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	/*
101592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * The sensor can generate interrupts for free-fall and direction
101692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
101792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * the things simple and _fast_ we activate it only for free-fall, so
101892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * no need to read register (very slow with ACPI). For the same reason,
101992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * we forbid shared interrupts.
102092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 *
102192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
102292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * io-apic is not configurable (and generates a warning) but I keep it
102392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 * in case of support for other hardware.
102492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	 */
1025d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	if (lis3->pdata && lis3->whoami == WAI_8B)
102692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		thread_fn = lis302dl_interrupt_thread1_8b;
102792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	else
102892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		thread_fn = NULL;
102992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
1030d7f81d4299cdc8cf06fc9562ec3dafce528bd6ffÉric Piel	err = request_threaded_irq(lis3->irq, lis302dl_interrupt,
103192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo				thread_fn,
1032cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
1033cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo				irq_flags,
1034895c156c044a736d8dc2239020f4530bb6245675Éric Piel				DRIVER_NAME, lis3);
103592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
103692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	if (err < 0) {
103763366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_err("Cannot get IRQ\n");
103892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo		goto out;
103992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo	}
104092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo
1041895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
1042895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->miscdev.name	= "freefall";
1043895c156c044a736d8dc2239020f4530bb6245675Éric Piel	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
1044895c156c044a736d8dc2239020f4530bb6245675Éric Piel
1045895c156c044a736d8dc2239020f4530bb6245675Éric Piel	if (misc_register(&lis3->miscdev))
104663366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches		pr_err("misc_register failed\n");
1047ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mackout:
1048ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack	return 0;
1049ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack}
1050ab337a632783c251a3c3852aec0ead8a0281cbddDaniel MackEXPORT_SYMBOL_GPL(lis3lv02d_init_device);
1051ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack
1052455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
1053ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel MachekMODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
1054455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_LICENSE("GPL");
1055