lis3lv02d.c revision ff606677f6a47c63329cf8e6c7cf978c29f2d736
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 1142ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwaimodule_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); 1152ee321440e3a594dcdd9981e68e5e302447047a2Takashi IwaiMODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); 1162ee321440e3a594dcdd9981e68e5e302447047a2Takashi Iwai 117a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) 118a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack{ 119a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack s8 lo; 120a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack if (lis3->read(lis3, reg, &lo) < 0) 121a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack return 0; 122a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 123a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack return lo; 124a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack} 125a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 126bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Pielstatic s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) 127be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek{ 128be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek u8 lo, hi; 129be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek 130a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3->read(lis3, reg - 1, &lo); 131a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3->read(lis3, reg, &hi); 132be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ 133be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek return (s16)((hi << 8) | lo); 134be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek} 135be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek 136455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/** 137455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * lis3lv02d_get_axis - For the given axis, give the value converted 138455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * @axis: 1,2,3 - can also be negative 139455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * @hw_values: raw values returned by the hardware 140455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * 141455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * Returns the converted value. 142455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */ 143455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) 144455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 145455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek if (axis > 0) 146455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return hw_values[axis - 1]; 147455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek else 148455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return -hw_values[-axis - 1]; 149455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 150455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 151455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/** 152455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer 153a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @lis3: pointer to the device struct 154a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @x: where to store the X axis value 155a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @y: where to store the Y axis value 156a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack * @z: where to store the Z axis value 157455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * 158455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek * Note that 40Hz input device can eat up about 10% CPU at 800MHZ 159455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek */ 160a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) 161455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 162455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek int position[3]; 16332496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo int i; 164455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 165f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo if (lis3->blkread) { 166f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo if (lis3_dev.whoami == WAI_12B) { 167f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo u16 data[3]; 168f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo lis3->blkread(lis3, OUTX_L, 6, (u8 *)data); 169f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo for (i = 0; i < 3; i++) 170f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo position[i] = (s16)le16_to_cpu(data[i]); 171f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo } else { 172f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo u8 data[5]; 173f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo /* Data: x, dummy, y, dummy, z */ 174f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo lis3->blkread(lis3, OUTX, 5, data); 175f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo for (i = 0; i < 3; i++) 176f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo position[i] = (s8)data[i * 2]; 177f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo } 178f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo } else { 179f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo position[0] = lis3->read_data(lis3, OUTX); 180f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo position[1] = lis3->read_data(lis3, OUTY); 181f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo position[2] = lis3->read_data(lis3, OUTZ); 182f10a5407b58603fb3b084d7fbdbd50f47d010c82Samu Onkalo } 183455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 18432496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo for (i = 0; i < 3; i++) 18532496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; 18632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo 187a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel *x = lis3lv02d_get_axis(lis3->ac.x, position); 188a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel *y = lis3lv02d_get_axis(lis3->ac.y, position); 189a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel *z = lis3lv02d_get_axis(lis3->ac.z, position); 190455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 191455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 192641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo/* conversion btw sampling rate and the register values */ 193641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalostatic int lis3_12_rates[4] = {40, 160, 640, 2560}; 194641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalostatic int lis3_8_rates[2] = {100, 400}; 19578537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwaistatic int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; 196641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo 197a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo/* ODR is Output Data Rate */ 198641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalostatic int lis3lv02d_get_odr(void) 199641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo{ 200641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo u8 ctrl; 201a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo int shift; 202641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo 203641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); 204a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo ctrl &= lis3_dev.odr_mask; 205a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo shift = ffs(lis3_dev.odr_mask) - 1; 206a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return lis3_dev.odrs[(ctrl >> shift)]; 207a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo} 208641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo 209a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic int lis3lv02d_set_odr(int rate) 210a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo{ 211a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo u8 ctrl; 212a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo int i, len, shift; 213a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 21478537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai if (!rate) 21578537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai return -EINVAL; 21678537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai 217a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); 218a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo ctrl &= ~lis3_dev.odr_mask; 219a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */ 220a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo shift = ffs(lis3_dev.odr_mask) - 1; 221a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 222a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo for (i = 0; i < len; i++) 223a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo if (lis3_dev.odrs[i] == rate) { 224a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo lis3_dev.write(&lis3_dev, CTRL_REG1, 225a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo ctrl | (i << shift)); 226a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return 0; 227a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo } 228a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return -EINVAL; 229641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo} 230641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo 2312db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) 2322db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo{ 23378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai u8 ctlreg, reg; 2342db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo s16 x, y, z; 2352db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo u8 selftest; 2362db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo int ret; 237029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo u8 ctrl_reg_data; 238029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo unsigned char irq_cfg; 2392db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 2402db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo mutex_lock(&lis3->mutex); 241029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 242029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo irq_cfg = lis3->irq_cfg; 243029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (lis3_dev.whoami == WAI_8B) { 244029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[IRQ_LINE0] = 0; 245029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[IRQ_LINE1] = 0; 246029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 247029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo /* Change interrupt cfg to data ready for selftest */ 248029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo atomic_inc(&lis3_dev.wake_thread); 249029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY; 250029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->read(lis3, CTRL_REG3, &ctrl_reg_data); 251029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->write(lis3, CTRL_REG3, (ctrl_reg_data & 252029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) | 253029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); 254029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 255029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 25678537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai if (lis3_dev.whoami == WAI_3DC) { 25778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai ctlreg = CTRL_REG4; 25878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai selftest = CTRL4_ST0; 25978537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai } else { 26078537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai ctlreg = CTRL_REG1; 26178537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai if (lis3_dev.whoami == WAI_12B) 26278537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai selftest = CTRL1_ST; 26378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai else 26478537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai selftest = CTRL1_STP; 26578537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai } 2662db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 26778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai lis3->read(lis3, ctlreg, ®); 26878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai lis3->write(lis3, ctlreg, (reg | selftest)); 2692db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo msleep(lis3->pwron_delay / lis3lv02d_get_odr()); 2702db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 2712db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo /* Read directly to avoid axis remap */ 2722db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo x = lis3->read_data(lis3, OUTX); 2732db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo y = lis3->read_data(lis3, OUTY); 2742db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo z = lis3->read_data(lis3, OUTZ); 2752db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 2762db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo /* back to normal settings */ 27778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai lis3->write(lis3, ctlreg, reg); 2782db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo msleep(lis3->pwron_delay / lis3lv02d_get_odr()); 2792db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 2802db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo results[0] = x - lis3->read_data(lis3, OUTX); 2812db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo results[1] = y - lis3->read_data(lis3, OUTY); 2822db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo results[2] = z - lis3->read_data(lis3, OUTZ); 2832db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 2842db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo ret = 0; 285029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 286029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (lis3_dev.whoami == WAI_8B) { 287029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo /* Restore original interrupt configuration */ 288029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo atomic_dec(&lis3_dev.wake_thread); 289029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->write(lis3, CTRL_REG3, ctrl_reg_data); 290029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->irq_cfg = irq_cfg; 291029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 292029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if ((irq_cfg & LIS3_IRQ1_MASK) && 293029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[IRQ_LINE0] < 2) { 294029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo ret = SELFTEST_IRQ; 295029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo goto fail; 296029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 297029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 298029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if ((irq_cfg & LIS3_IRQ2_MASK) && 299029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[IRQ_LINE1] < 2) { 300029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo ret = SELFTEST_IRQ; 301029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo goto fail; 302029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 303029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 304029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 3052db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo if (lis3->pdata) { 3062db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo int i; 3072db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo for (i = 0; i < 3; i++) { 3082db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo /* Check against selftest acceptance limits */ 3092db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo if ((results[i] < lis3->pdata->st_min_limits[i]) || 3102db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo (results[i] > lis3->pdata->st_max_limits[i])) { 311029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo ret = SELFTEST_FAIL; 3122db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo goto fail; 3132db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo } 3142db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo } 3152db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo } 3162db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 3172db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo /* test passed */ 3182db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalofail: 3192db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo mutex_unlock(&lis3->mutex); 3202db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo return ret; 3212db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo} 3222db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 323f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo/* 324f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * Order of registers in the list affects to order of the restore process. 325f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * Perhaps it is a good idea to set interrupt enable register as a last one 326f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo * after all other configurations 327f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo */ 328f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1, 329f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2, 330f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ, 331f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW, 332f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo CTRL_REG1, CTRL_REG2, CTRL_REG3}; 333f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 334f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H, 335f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H, 336f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo DD_THSE_L, DD_THSE_H, 337f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo CTRL_REG1, CTRL_REG3, CTRL_REG2}; 338f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 339f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic inline void lis3_context_save(struct lis3lv02d *lis3) 340f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo{ 341f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo int i; 342f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo for (i = 0; i < lis3->regs_size; i++) 343f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]); 344f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3->regs_stored = true; 345f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo} 346f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 347f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalostatic inline void lis3_context_restore(struct lis3lv02d *lis3) 348f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo{ 349f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo int i; 350f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (lis3->regs_stored) 351f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo for (i = 0; i < lis3->regs_size; i++) 352f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]); 353f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo} 354f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 355a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackvoid lis3lv02d_poweroff(struct lis3lv02d *lis3) 356455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 357f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (lis3->reg_ctrl) 358f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3_context_save(lis3); 359a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel /* disable X,Y,Z axis and power down */ 360a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3->write(lis3, CTRL_REG1, 0x00); 361f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (lis3->reg_ctrl) 362f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3->reg_ctrl(lis3, LIS3_REG_OFF); 363455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 364cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_poweroff); 365455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 366a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackvoid lis3lv02d_poweron(struct lis3lv02d *lis3) 367455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 368a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel u8 reg; 369455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 370a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3->init(lis3); 371455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 372a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel /* 373a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel * Common configuration 3744b5d95b3809bcd77599122494aa3f575cd6ab1b9Éric Piel * BDU: (12 bits sensors only) LSB and MSB values are not updated until 3754b5d95b3809bcd77599122494aa3f575cd6ab1b9Éric Piel * both have been read. So the value read will always be correct. 3762a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo * Set BOOT bit to refresh factory tuning values. 377a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel */ 3782a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo lis3->read(lis3, CTRL_REG2, ®); 3792a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo if (lis3->whoami == WAI_12B) 3802a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo reg |= CTRL2_BDU | CTRL2_BOOT; 3812a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo else 3822a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo reg |= CTRL2_BOOT_8B; 3832a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo lis3->write(lis3, CTRL_REG2, reg); 3842a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo 3852a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo /* LIS3 power on delay is quite long */ 3862a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo msleep(lis3->pwron_delay / lis3lv02d_get_odr()); 3872a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo 388f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (lis3->reg_ctrl) 389f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3_context_restore(lis3); 390455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 391a002ee896dfd08ce9fba44e9ae513c9094699a27Eric PielEXPORT_SYMBOL_GPL(lis3lv02d_poweron); 392a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel 393455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 3946d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) 3956d94d4081048756df78444a07201156f4930fe48Samu Onkalo{ 3966d94d4081048756df78444a07201156f4930fe48Samu Onkalo int x, y, z; 3976d94d4081048756df78444a07201156f4930fe48Samu Onkalo 3986d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3_dev.mutex); 3996d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 4006d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_X, x); 4016d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_Y, y); 4026d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_Z, z); 4036d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_sync(pidev->input); 4046d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3_dev.mutex); 4056d94d4081048756df78444a07201156f4930fe48Samu Onkalo} 4066d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4072a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_open(struct input_polled_dev *pidev) 4082a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 4092a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 4102a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3_dev.pm_dev); 411e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo 412e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev) 413e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&lis3_dev.wake_thread, 1); 414821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo /* 415821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo * Update coordinates for the case where poll interval is 0 and 416821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo * the chip in running purely under interrupt control 417821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo */ 418821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo lis3lv02d_joystick_poll(pidev); 4192a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 4202a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 4212a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_close(struct input_polled_dev *pidev) 4222a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 423e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&lis3_dev.wake_thread, 0); 4242a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 4252a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put(lis3_dev.pm_dev); 4262a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 4272a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 428ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic irqreturn_t lis302dl_interrupt(int irq, void *dummy) 429ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 43092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (!test_bit(0, &lis3_dev.misc_opened)) 43192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo goto out; 43292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 433ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek /* 434ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * Be careful: on some HP laptops the bios force DD when on battery and 435ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * the lid is closed. This leads to interrupts as soon as a little move 436ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * is done. 437ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek */ 438be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek atomic_inc(&lis3_dev.count); 439ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 440be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek wake_up_interruptible(&lis3_dev.misc_wait); 441be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); 44292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkaloout: 443e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo if (atomic_read(&lis3_dev.wake_thread)) 44492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_WAKE_THREAD; 445ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return IRQ_HANDLED; 446ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 447ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 4486d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) 4496d94d4081048756df78444a07201156f4930fe48Samu Onkalo{ 4506d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct input_dev *dev = lis3->idev->input; 4516d94d4081048756df78444a07201156f4930fe48Samu Onkalo u8 click_src; 4526d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4536d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3->mutex); 4546d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3->read(lis3, CLICK_SRC, &click_src); 4556d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4566d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_X) { 4576d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[0], 1); 4586d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[0], 0); 4596d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4606d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4616d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_Y) { 4626d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[1], 1); 4636d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[1], 0); 4646d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4656d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4666d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_Z) { 4676d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[2], 1); 4686d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[2], 0); 4696d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4706d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_sync(dev); 4716d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3->mutex); 4726d94d4081048756df78444a07201156f4930fe48Samu Onkalo} 4736d94d4081048756df78444a07201156f4930fe48Samu Onkalo 474029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) 475ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 476029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo int dummy; 477029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 478029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo /* Dummy read to ack interrupt */ 479029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); 480029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[index]++; 481029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo} 4826d94d4081048756df78444a07201156f4930fe48Samu Onkalo 483029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) 484029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo{ 4856d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct lis3lv02d *lis3 = data; 486029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; 4876d94d4081048756df78444a07201156f4930fe48Samu Onkalo 488029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (irq_cfg == LIS3_IRQ1_CLICK) 4896d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis302dl_interrupt_handle_click(lis3); 490029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) 491029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis302dl_data_ready(lis3, IRQ_LINE0); 4926d94d4081048756df78444a07201156f4930fe48Samu Onkalo else 493e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo lis3lv02d_joystick_poll(lis3->idev); 4946d94d4081048756df78444a07201156f4930fe48Samu Onkalo 49592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_HANDLED; 49692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo} 497ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 49892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) 49992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{ 5006d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct lis3lv02d *lis3 = data; 501029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; 5026d94d4081048756df78444a07201156f4930fe48Samu Onkalo 503029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (irq_cfg == LIS3_IRQ2_CLICK) 5046d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis302dl_interrupt_handle_click(lis3); 505029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) 506029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis302dl_data_ready(lis3, IRQ_LINE1); 5076d94d4081048756df78444a07201156f4930fe48Samu Onkalo else 508e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo lis3lv02d_joystick_poll(lis3->idev); 5096d94d4081048756df78444a07201156f4930fe48Samu Onkalo 51092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_HANDLED; 51192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo} 51292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 51392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic int lis3lv02d_misc_open(struct inode *inode, struct file *file) 51492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{ 515be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (test_and_set_bit(0, &lis3_dev.misc_opened)) 516ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return -EBUSY; /* already open */ 517ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 5182a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 5192a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3_dev.pm_dev); 5202a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 521be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek atomic_set(&lis3_dev.count, 0); 522ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 523ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 524ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 525ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_release(struct inode *inode, struct file *file) 526ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 527be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek fasync_helper(-1, file, 0, &lis3_dev.async_queue); 528be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek clear_bit(0, &lis3_dev.misc_opened); /* release the device */ 5292a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 5302a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put(lis3_dev.pm_dev); 531ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 532ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 533ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 534ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, 535ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek size_t count, loff_t *pos) 536ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 537ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek DECLARE_WAITQUEUE(wait, current); 538ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek u32 data; 539ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek unsigned char byte_data; 540ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek ssize_t retval = 1; 541ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 542ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (count < 1) 543ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return -EINVAL; 544ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 545be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek add_wait_queue(&lis3_dev.misc_wait, &wait); 546ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek while (true) { 547ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek set_current_state(TASK_INTERRUPTIBLE); 548be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek data = atomic_xchg(&lis3_dev.count, 0); 549ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (data) 550ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek break; 551ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 552ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (file->f_flags & O_NONBLOCK) { 553ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -EAGAIN; 554ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek goto out; 555ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 556ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 557ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (signal_pending(current)) { 558ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -ERESTARTSYS; 559ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek goto out; 560ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 561ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 562ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek schedule(); 563ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 564ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 565ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (data < 255) 566ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek byte_data = data; 567ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek else 568ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek byte_data = 255; 569ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 570ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek /* make sure we are not going into copy_to_user() with 571ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * TASK_INTERRUPTIBLE state */ 572ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek set_current_state(TASK_RUNNING); 573ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (copy_to_user(buf, &byte_data, sizeof(byte_data))) 574ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -EFAULT; 575ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 576ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekout: 577ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek __set_current_state(TASK_RUNNING); 578be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek remove_wait_queue(&lis3_dev.misc_wait, &wait); 579ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 580ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return retval; 581ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 582ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 583ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) 584ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 585be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek poll_wait(file, &lis3_dev.misc_wait, wait); 586be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (atomic_read(&lis3_dev.count)) 587ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return POLLIN | POLLRDNORM; 588ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 589ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 590ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 591ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_fasync(int fd, struct file *file, int on) 592ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 593be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek return fasync_helper(fd, file, on, &lis3_dev.async_queue); 594ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 595ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 596ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic const struct file_operations lis3lv02d_misc_fops = { 597ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .owner = THIS_MODULE, 598ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .llseek = no_llseek, 599ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .read = lis3lv02d_misc_read, 600ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .open = lis3lv02d_misc_open, 601ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .release = lis3lv02d_misc_release, 602ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .poll = lis3lv02d_misc_poll, 603ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .fasync = lis3lv02d_misc_fasync, 604ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}; 605ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 606ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic struct miscdevice lis3lv02d_misc_device = { 607ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .minor = MISC_DYNAMIC_MINOR, 608ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .name = "freefall", 609ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .fops = &lis3lv02d_misc_fops, 610ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}; 611ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 612cfce41a6d643c001d416ead960caf04fae2d609aEric Pielint lis3lv02d_joystick_enable(void) 613455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 614dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel struct input_dev *input_dev; 615455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek int err; 61632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo int max_val, fuzz, flat; 6176d94d4081048756df78444a07201156f4930fe48Samu Onkalo int btns[] = {BTN_X, BTN_Y, BTN_Z}; 618455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 619be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (lis3_dev.idev) 620455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return -EINVAL; 621455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 622dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev = input_allocate_polled_device(); 623be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (!lis3_dev.idev) 624455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return -ENOMEM; 625455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 626dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev->poll = lis3lv02d_joystick_poll; 6272a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3_dev.idev->open = lis3lv02d_joystick_open; 6282a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3_dev.idev->close = lis3lv02d_joystick_close; 629dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; 6304a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; 6314a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; 632dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev = lis3_dev.idev->input; 633dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel 634dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->name = "ST LIS3LV02DL Accelerometer"; 635dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->phys = DRIVER_NAME "/input0"; 636dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->id.bustype = BUS_HOST; 637dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->id.vendor = 0; 638dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->dev.parent = &lis3_dev.pdev->dev; 639455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 640dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel set_bit(EV_ABS, input_dev->evbit); 64132496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY; 642477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo if (lis3_dev.whoami == WAI_12B) { 643477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = LIS3_DEFAULT_FUZZ_12B; 644477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = LIS3_DEFAULT_FLAT_12B; 645477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo } else { 646477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = LIS3_DEFAULT_FUZZ_8B; 647477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = LIS3_DEFAULT_FLAT_8B; 648477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo } 649477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY; 650477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = (flat * lis3_dev.scale) / LIS3_ACCURACY; 651477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo 65232496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat); 65332496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); 65432496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); 655455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 6566d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); 6576d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); 6586d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); 6596d94d4081048756df78444a07201156f4930fe48Samu Onkalo 660dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel err = input_register_polled_device(lis3_dev.idev); 661455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek if (err) { 662dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_free_polled_device(lis3_dev.idev); 663be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek lis3_dev.idev = NULL; 664455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek } 665455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 666455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return err; 667455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 668cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); 669455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 670cfce41a6d643c001d416ead960caf04fae2d609aEric Pielvoid lis3lv02d_joystick_disable(void) 671455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 67292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (lis3_dev.irq) 67392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo free_irq(lis3_dev.irq, &lis3_dev); 67492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (lis3_dev.pdata && lis3_dev.pdata->irq2) 67592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo free_irq(lis3_dev.pdata->irq2, &lis3_dev); 67692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 677be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (!lis3_dev.idev) 678455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return; 679455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 680c28842421cb6a29fd952043381bc5391bdf6be50Eric Piel if (lis3_dev.irq) 681c28842421cb6a29fd952043381bc5391bdf6be50Eric Piel misc_deregister(&lis3lv02d_misc_device); 682dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_unregister_polled_device(lis3_dev.idev); 68366c8569bf990064b3f11e0f211a81a46e0b627ffSamu Onkalo input_free_polled_device(lis3_dev.idev); 684be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek lis3_dev.idev = NULL; 685455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 686cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 687455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 688455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/* Sysfs stuff */ 6892a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) 6902a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 6912a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* 6922a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * SYSFS functions are fast visitors so put-call 6932a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * immediately after the get-call. However, keep 6942a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * chip running for a while and schedule delayed 6952a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * suspend. This way periodic sysfs calls doesn't 6962a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * suffer from relatively long power up time. 6972a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo */ 6982a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 6992a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3->pm_dev) { 7002a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3->pm_dev); 7012a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put_noidle(lis3->pm_dev); 7022a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); 7032a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 7042a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 7052a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 7062db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic ssize_t lis3lv02d_selftest_show(struct device *dev, 7072db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo struct device_attribute *attr, char *buf) 7082db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo{ 7092db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo s16 values[3]; 7102db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 711029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char ok[] = "OK"; 712029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char fail[] = "FAIL"; 713029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char irq[] = "FAIL_IRQ"; 714029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo const char *res; 715029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 7162a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 717029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo switch (lis3lv02d_selftest(&lis3_dev, values)) { 718029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_FAIL: 719029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = fail; 720029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 721029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_IRQ: 722029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = irq; 723029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 724029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_OK: 725029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo default: 726029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = ok; 727029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 728029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 729029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo return sprintf(buf, "%s %d %d %d\n", res, 7302db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo values[0], values[1], values[2]); 7312db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo} 7322db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 733455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_position_show(struct device *dev, 734455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek struct device_attribute *attr, char *buf) 735455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 736455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek int x, y, z; 737455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 7382a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 7396d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3_dev.mutex); 740a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 7416d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3_dev.mutex); 742455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return sprintf(buf, "(%d,%d,%d)\n", x, y, z); 743455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 744455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 745455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_rate_show(struct device *dev, 746455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek struct device_attribute *attr, char *buf) 747455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 7482a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 749641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo return sprintf(buf, "%d\n", lis3lv02d_get_odr()); 750455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 751455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 752a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic ssize_t lis3lv02d_rate_set(struct device *dev, 753a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo struct device_attribute *attr, const char *buf, 754a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo size_t count) 755a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo{ 756a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo unsigned long rate; 757a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 758a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo if (strict_strtoul(buf, 0, &rate)) 759a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return -EINVAL; 760a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 7612a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 762a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo if (lis3lv02d_set_odr(rate)) 763a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return -EINVAL; 764a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 765a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return count; 766a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo} 767a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 7682db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); 769455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); 770a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, 771a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo lis3lv02d_rate_set); 772455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 773455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute *lis3lv02d_attributes[] = { 7742db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo &dev_attr_selftest.attr, 775455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek &dev_attr_position.attr, 776455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek &dev_attr_rate.attr, 777455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek NULL 778455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}; 779455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 780455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute_group lis3lv02d_attribute_group = { 781455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek .attrs = lis3lv02d_attributes 782455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}; 783455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 784cfce41a6d643c001d416ead960caf04fae2d609aEric Piel 785a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic int lis3lv02d_add_fs(struct lis3lv02d *lis3) 786455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 787a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); 788a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel if (IS_ERR(lis3->pdev)) 789a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel return PTR_ERR(lis3->pdev); 790455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 791a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); 792455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 793455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 794a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Pielint lis3lv02d_remove_fs(struct lis3lv02d *lis3) 795455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 796a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); 797a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel platform_device_unregister(lis3->pdev); 7982a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3->pm_dev) { 7992a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* Barrier after the sysfs remove */ 8002a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_barrier(lis3->pm_dev); 8012a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 8022a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* SYSFS may have left chip running. Turn off if necessary */ 8032a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (!pm_runtime_suspended(lis3->pm_dev)) 8042a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_poweroff(&lis3_dev); 8052a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 8062a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_disable(lis3->pm_dev); 8072a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_set_suspended(lis3->pm_dev); 8082a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 809f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo kfree(lis3->reg_cache); 810455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return 0; 811455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 812cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); 813455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 814ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalostatic void lis3lv02d_8b_configure(struct lis3lv02d *dev, 815ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo struct lis3lv02d_platform_data *p) 816ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo{ 81792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo int err; 818342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo int ctrl2 = p->hipass_ctrl; 819342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo 820ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (p->click_flags) { 821ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_CFG, p->click_flags); 822ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); 823ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_LATENCY, p->click_latency); 824ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_WINDOW, p->click_window); 825ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); 826ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_THSY_X, 827ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo (p->click_thresh_x & 0xf) | 828ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo (p->click_thresh_y << 4)); 8296d94d4081048756df78444a07201156f4930fe48Samu Onkalo 8306d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (dev->idev) { 8316d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct input_dev *input_dev = lis3_dev.idev->input; 8326d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_X); 8336d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_Y); 8346d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_Z); 8356d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 836ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo } 837ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo 838ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (p->wakeup_flags) { 839ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); 840ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); 841cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo /* pdata value + 1 to keep this backward compatible*/ 842cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1); 843342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ 844342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo } 845342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo 846342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo if (p->wakeup_flags2) { 847342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); 848342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); 849cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo /* pdata value + 1 to keep this backward compatible*/ 850cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1); 851342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ 852ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo } 853342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo /* Configure hipass filters */ 854342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, CTRL_REG2, ctrl2); 85592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 85692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (p->irq2) { 85792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo err = request_threaded_irq(p->irq2, 85892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo NULL, 85992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo lis302dl_interrupt_thread2_8b, 860cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo IRQF_TRIGGER_RISING | IRQF_ONESHOT | 861cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo (p->irq_flags2 & IRQF_TRIGGER_MASK), 86292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo DRIVER_NAME, &lis3_dev); 86392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (err < 0) 86463366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("No second IRQ. Limited functionality\n"); 86592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo } 866ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo} 867ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo 868ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack/* 869ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack * Initialise the accelerometer and the various subsystems. 870bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel * Should be rather independent of the bus system. 871ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack */ 872a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackint lis3lv02d_init_device(struct lis3lv02d *dev) 873ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack{ 87492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo int err; 87592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo irq_handler_t thread_fn; 876cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo int irq_flags = 0; 87792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 878a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); 879a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 880a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack switch (dev->whoami) { 881bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel case WAI_12B: 88263366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("12 bits sensor found\n"); 883bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel dev->read_data = lis3lv02d_read_12; 884a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->mdps_max_val = 2048; 885641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; 886a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odrs = lis3_12_rates; 887a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odr_mask = CTRL1_DF0 | CTRL1_DF1; 88832496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo dev->scale = LIS3_SENSITIVITY_12B; 889f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs = lis3_wai12_regs; 890f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); 891a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack break; 892bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel case WAI_8B: 89363366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("8 bits sensor found\n"); 894a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->read_data = lis3lv02d_read_8; 895a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->mdps_max_val = 128; 896641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; 897a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odrs = lis3_8_rates; 898a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odr_mask = CTRL1_DR; 89932496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo dev->scale = LIS3_SENSITIVITY_8B; 900f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs = lis3_wai8_regs; 901f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); 902a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack break; 90378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai case WAI_3DC: 90463366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("8 bits 3DC sensor found\n"); 90578537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->read_data = lis3lv02d_read_8; 90678537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->mdps_max_val = 128; 90778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; 90878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->odrs = lis3_3dc_rates; 90978537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; 91078537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->scale = LIS3_SENSITIVITY_8B; 91178537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai break; 912a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack default: 91363366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("unknown sensor type 0x%X\n", dev->whoami); 914a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack return -EINVAL; 915a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack } 916a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 917f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), 918f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo sizeof(lis3_wai12_regs)), GFP_KERNEL); 919f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 920f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (dev->reg_cache == NULL) { 921f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo printk(KERN_ERR DRIVER_NAME "out of memory\n"); 922f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo return -ENOMEM; 923f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo } 924f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 9252db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo mutex_init(&dev->mutex); 926e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&dev->wake_thread, 0); 9272db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 928a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3lv02d_add_fs(dev); 929a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3lv02d_poweron(dev); 930ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 9312a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (dev->pm_dev) { 9322a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_set_active(dev->pm_dev); 9332a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_enable(dev->pm_dev); 9342a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 9352a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 936ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (lis3lv02d_joystick_enable()) 93763366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("joystick initialization failed\n"); 938ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 9398f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack /* passing in platform specific data is purely optional and only 9408f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack * used by the SPI transport layer at the moment */ 9418f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack if (dev->pdata) { 9428f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack struct lis3lv02d_platform_data *p = dev->pdata; 9438f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack 944ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (dev->whoami == WAI_8B) 945ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo lis3lv02d_8b_configure(dev, p); 9468873c33483e62988ed886230aab71ef4c678f710Daniel Mack 947cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK; 948cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo 949e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo dev->irq_cfg = p->irq_cfg; 9508f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack if (p->irq_cfg) 9518f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack dev->write(dev, CTRL_REG3, p->irq_cfg); 952cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo 953cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo if (p->default_rate) 954cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo lis3lv02d_set_odr(p->default_rate); 9558f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack } 9568f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack 957a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack /* bail if we did not get an IRQ from the bus layer */ 958ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (!dev->irq) { 959a20f0bc10c47fcf62be027e1a50b62791052ab56Kalhan Trisal pr_debug("No IRQ. Disabling /dev/freefall\n"); 960ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack goto out; 961ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack } 962ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 96392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo /* 96492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * The sensor can generate interrupts for free-fall and direction 96592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep 96692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * the things simple and _fast_ we activate it only for free-fall, so 96792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * no need to read register (very slow with ACPI). For the same reason, 96892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * we forbid shared interrupts. 96992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * 97092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * IRQF_TRIGGER_RISING seems pointless on HP laptops because the 97192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * io-apic is not configurable (and generates a warning) but I keep it 97292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * in case of support for other hardware. 97392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo */ 974f7c77a3dc4683659b6f0d1b6cbc82b6253d095e0Takashi Iwai if (dev->pdata && dev->whoami == WAI_8B) 97592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn = lis302dl_interrupt_thread1_8b; 97692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo else 97792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn = NULL; 97892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 97992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo err = request_threaded_irq(dev->irq, lis302dl_interrupt, 98092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn, 981cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo IRQF_TRIGGER_RISING | IRQF_ONESHOT | 982cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo irq_flags, 98392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo DRIVER_NAME, &lis3_dev); 98492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 98592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (err < 0) { 98663366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("Cannot get IRQ\n"); 98792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo goto out; 98892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo } 98992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 990ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (misc_register(&lis3lv02d_misc_device)) 99163366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("misc_register failed\n"); 992ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mackout: 993ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack return 0; 994ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack} 995ab337a632783c251a3c3852aec0ead8a0281cbddDaniel MackEXPORT_SYMBOL_GPL(lis3lv02d_init_device); 996ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 997455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); 998ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel MachekMODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); 999455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_LICENSE("GPL"); 1000