lis3lv02d.c revision 05faadcf59507e8eea57ffbeea9cbb14c9a2ab3d
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 */ 37805faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai if (lis3->pdata) { 37905faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai lis3->read(lis3, CTRL_REG2, ®); 38005faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai if (lis3->whoami == WAI_12B) 38105faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai reg |= CTRL2_BDU | CTRL2_BOOT; 38205faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai else 38305faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai reg |= CTRL2_BOOT_8B; 38405faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai lis3->write(lis3, CTRL_REG2, reg); 38505faadcf59507e8eea57ffbeea9cbb14c9a2ab3dTakashi Iwai } 3862a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo 3872a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo /* LIS3 power on delay is quite long */ 3882a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo msleep(lis3->pwron_delay / lis3lv02d_get_odr()); 3892a7fade7e03a7c773f91e2e5ff26ad6fafda5a9fSamu Onkalo 390f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (lis3->reg_ctrl) 391f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo lis3_context_restore(lis3); 392455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 393a002ee896dfd08ce9fba44e9ae513c9094699a27Eric PielEXPORT_SYMBOL_GPL(lis3lv02d_poweron); 394a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel 395455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 3966d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) 3976d94d4081048756df78444a07201156f4930fe48Samu Onkalo{ 3986d94d4081048756df78444a07201156f4930fe48Samu Onkalo int x, y, z; 3996d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4006d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3_dev.mutex); 4016d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 4026d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_X, x); 4036d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_Y, y); 4046d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_abs(pidev->input, ABS_Z, z); 4056d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_sync(pidev->input); 4066d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3_dev.mutex); 4076d94d4081048756df78444a07201156f4930fe48Samu Onkalo} 4086d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4092a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_open(struct input_polled_dev *pidev) 4102a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 4112a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 4122a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3_dev.pm_dev); 413e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo 414e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev) 415e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&lis3_dev.wake_thread, 1); 416821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo /* 417821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo * Update coordinates for the case where poll interval is 0 and 418821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo * the chip in running purely under interrupt control 419821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo */ 420821f664644c2da9e1a51e36751abedf49d4332e0Samu Onkalo lis3lv02d_joystick_poll(pidev); 4212a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 4222a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 4232a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_joystick_close(struct input_polled_dev *pidev) 4242a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 425e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&lis3_dev.wake_thread, 0); 4262a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 4272a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put(lis3_dev.pm_dev); 4282a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 4292a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 430ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic irqreturn_t lis302dl_interrupt(int irq, void *dummy) 431ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 43292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (!test_bit(0, &lis3_dev.misc_opened)) 43392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo goto out; 43492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 435ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek /* 436ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * Be careful: on some HP laptops the bios force DD when on battery and 437ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * the lid is closed. This leads to interrupts as soon as a little move 438ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * is done. 439ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek */ 440be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek atomic_inc(&lis3_dev.count); 441ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 442be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek wake_up_interruptible(&lis3_dev.misc_wait); 443be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); 44492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkaloout: 445e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo if (atomic_read(&lis3_dev.wake_thread)) 44692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_WAKE_THREAD; 447ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return IRQ_HANDLED; 448ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 449ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 4506d94d4081048756df78444a07201156f4930fe48Samu Onkalostatic void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) 4516d94d4081048756df78444a07201156f4930fe48Samu Onkalo{ 4526d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct input_dev *dev = lis3->idev->input; 4536d94d4081048756df78444a07201156f4930fe48Samu Onkalo u8 click_src; 4546d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4556d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3->mutex); 4566d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3->read(lis3, CLICK_SRC, &click_src); 4576d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4586d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_X) { 4596d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[0], 1); 4606d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[0], 0); 4616d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4626d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4636d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_Y) { 4646d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[1], 1); 4656d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[1], 0); 4666d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4676d94d4081048756df78444a07201156f4930fe48Samu Onkalo 4686d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (click_src & CLICK_SINGLE_Z) { 4696d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[2], 1); 4706d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_report_key(dev, lis3->mapped_btns[2], 0); 4716d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 4726d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_sync(dev); 4736d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3->mutex); 4746d94d4081048756df78444a07201156f4930fe48Samu Onkalo} 4756d94d4081048756df78444a07201156f4930fe48Samu Onkalo 476029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) 477ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 478029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo int dummy; 479029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 480029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo /* Dummy read to ack interrupt */ 481029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); 482029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis3->data_ready_count[index]++; 483029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo} 4846d94d4081048756df78444a07201156f4930fe48Samu Onkalo 485029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalostatic irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) 486029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo{ 4876d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct lis3lv02d *lis3 = data; 488029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; 4896d94d4081048756df78444a07201156f4930fe48Samu Onkalo 490029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (irq_cfg == LIS3_IRQ1_CLICK) 4916d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis302dl_interrupt_handle_click(lis3); 492029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) 493029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis302dl_data_ready(lis3, IRQ_LINE0); 4946d94d4081048756df78444a07201156f4930fe48Samu Onkalo else 495e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo lis3lv02d_joystick_poll(lis3->idev); 4966d94d4081048756df78444a07201156f4930fe48Samu Onkalo 49792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_HANDLED; 49892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo} 499ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 50092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) 50192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{ 5026d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct lis3lv02d *lis3 = data; 503029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; 5046d94d4081048756df78444a07201156f4930fe48Samu Onkalo 505029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo if (irq_cfg == LIS3_IRQ2_CLICK) 5066d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis302dl_interrupt_handle_click(lis3); 507029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) 508029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo lis302dl_data_ready(lis3, IRQ_LINE1); 5096d94d4081048756df78444a07201156f4930fe48Samu Onkalo else 510e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo lis3lv02d_joystick_poll(lis3->idev); 5116d94d4081048756df78444a07201156f4930fe48Samu Onkalo 51292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo return IRQ_HANDLED; 51392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo} 51492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 51592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalostatic int lis3lv02d_misc_open(struct inode *inode, struct file *file) 51692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo{ 517be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (test_and_set_bit(0, &lis3_dev.misc_opened)) 518ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return -EBUSY; /* already open */ 519ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 5202a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 5212a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3_dev.pm_dev); 5222a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 523be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek atomic_set(&lis3_dev.count, 0); 524ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 525ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 526ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 527ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_release(struct inode *inode, struct file *file) 528ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 529be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek fasync_helper(-1, file, 0, &lis3_dev.async_queue); 530be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek clear_bit(0, &lis3_dev.misc_opened); /* release the device */ 5312a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3_dev.pm_dev) 5322a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put(lis3_dev.pm_dev); 533ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 534ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 535ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 536ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, 537ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek size_t count, loff_t *pos) 538ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 539ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek DECLARE_WAITQUEUE(wait, current); 540ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek u32 data; 541ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek unsigned char byte_data; 542ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek ssize_t retval = 1; 543ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 544ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (count < 1) 545ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return -EINVAL; 546ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 547be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek add_wait_queue(&lis3_dev.misc_wait, &wait); 548ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek while (true) { 549ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek set_current_state(TASK_INTERRUPTIBLE); 550be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek data = atomic_xchg(&lis3_dev.count, 0); 551ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (data) 552ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek break; 553ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 554ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (file->f_flags & O_NONBLOCK) { 555ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -EAGAIN; 556ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek goto out; 557ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 558ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 559ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (signal_pending(current)) { 560ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -ERESTARTSYS; 561ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek goto out; 562ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 563ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 564ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek schedule(); 565ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek } 566ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 567ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (data < 255) 568ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek byte_data = data; 569ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek else 570ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek byte_data = 255; 571ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 572ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek /* make sure we are not going into copy_to_user() with 573ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek * TASK_INTERRUPTIBLE state */ 574ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek set_current_state(TASK_RUNNING); 575ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek if (copy_to_user(buf, &byte_data, sizeof(byte_data))) 576ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek retval = -EFAULT; 577ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 578ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekout: 579ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek __set_current_state(TASK_RUNNING); 580be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek remove_wait_queue(&lis3_dev.misc_wait, &wait); 581ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 582ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return retval; 583ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 584ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 585ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) 586ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 587be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek poll_wait(file, &lis3_dev.misc_wait, wait); 588be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (atomic_read(&lis3_dev.count)) 589ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return POLLIN | POLLRDNORM; 590ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek return 0; 591ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 592ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 593ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic int lis3lv02d_misc_fasync(int fd, struct file *file, int on) 594ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek{ 595be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek return fasync_helper(fd, file, on, &lis3_dev.async_queue); 596ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek} 597ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 598ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic const struct file_operations lis3lv02d_misc_fops = { 599ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .owner = THIS_MODULE, 600ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .llseek = no_llseek, 601ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .read = lis3lv02d_misc_read, 602ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .open = lis3lv02d_misc_open, 603ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .release = lis3lv02d_misc_release, 604ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .poll = lis3lv02d_misc_poll, 605ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .fasync = lis3lv02d_misc_fasync, 606ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}; 607ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 608ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machekstatic struct miscdevice lis3lv02d_misc_device = { 609ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .minor = MISC_DYNAMIC_MINOR, 610ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .name = "freefall", 611ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek .fops = &lis3lv02d_misc_fops, 612ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek}; 613ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel Machek 614cfce41a6d643c001d416ead960caf04fae2d609aEric Pielint lis3lv02d_joystick_enable(void) 615455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 616dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel struct input_dev *input_dev; 617455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek int err; 61832496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo int max_val, fuzz, flat; 6196d94d4081048756df78444a07201156f4930fe48Samu Onkalo int btns[] = {BTN_X, BTN_Y, BTN_Z}; 620455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 621be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (lis3_dev.idev) 622455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return -EINVAL; 623455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 624dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev = input_allocate_polled_device(); 625be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (!lis3_dev.idev) 626455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return -ENOMEM; 627455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 628dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev->poll = lis3lv02d_joystick_poll; 6292a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3_dev.idev->open = lis3lv02d_joystick_open; 6302a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3_dev.idev->close = lis3lv02d_joystick_close; 631dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; 6324a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; 6334a70a413ccfd1c14ef29a290a4d2dada04ccbefbSamu Onkalo lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; 634dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev = lis3_dev.idev->input; 635dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel 636dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->name = "ST LIS3LV02DL Accelerometer"; 637dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->phys = DRIVER_NAME "/input0"; 638dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->id.bustype = BUS_HOST; 639dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->id.vendor = 0; 640dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_dev->dev.parent = &lis3_dev.pdev->dev; 641455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 642dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel set_bit(EV_ABS, input_dev->evbit); 64332496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY; 644477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo if (lis3_dev.whoami == WAI_12B) { 645477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = LIS3_DEFAULT_FUZZ_12B; 646477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = LIS3_DEFAULT_FLAT_12B; 647477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo } else { 648477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = LIS3_DEFAULT_FUZZ_8B; 649477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = LIS3_DEFAULT_FLAT_8B; 650477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo } 651477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY; 652477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo flat = (flat * lis3_dev.scale) / LIS3_ACCURACY; 653477bc918c2323a51f577cd892ca49376f6feb5d5Samu Onkalo 65432496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat); 65532496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); 65632496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); 657455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 6586d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); 6596d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); 6606d94d4081048756df78444a07201156f4930fe48Samu Onkalo lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); 6616d94d4081048756df78444a07201156f4930fe48Samu Onkalo 662dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel err = input_register_polled_device(lis3_dev.idev); 663455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek if (err) { 664dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_free_polled_device(lis3_dev.idev); 665be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek lis3_dev.idev = NULL; 666455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek } 667455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 668455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return err; 669455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 670cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); 671455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 672cfce41a6d643c001d416ead960caf04fae2d609aEric Pielvoid lis3lv02d_joystick_disable(void) 673455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 67492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (lis3_dev.irq) 67592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo free_irq(lis3_dev.irq, &lis3_dev); 67692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (lis3_dev.pdata && lis3_dev.pdata->irq2) 67792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo free_irq(lis3_dev.pdata->irq2, &lis3_dev); 67892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 679be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek if (!lis3_dev.idev) 680455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return; 681455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 682c28842421cb6a29fd952043381bc5391bdf6be50Eric Piel if (lis3_dev.irq) 683c28842421cb6a29fd952043381bc5391bdf6be50Eric Piel misc_deregister(&lis3lv02d_misc_device); 684dc6ea97bac6b8228c7a69740df35eed2be3407beEric Piel input_unregister_polled_device(lis3_dev.idev); 68566c8569bf990064b3f11e0f211a81a46e0b627ffSamu Onkalo input_free_polled_device(lis3_dev.idev); 686be84cfc588b19f14764d78556dc7b630ee8c914cPavel Machek lis3_dev.idev = NULL; 687455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 688cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 689455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 690455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek/* Sysfs stuff */ 6912a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalostatic void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) 6922a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo{ 6932a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* 6942a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * SYSFS functions are fast visitors so put-call 6952a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * immediately after the get-call. However, keep 6962a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * chip running for a while and schedule delayed 6972a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * suspend. This way periodic sysfs calls doesn't 6982a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo * suffer from relatively long power up time. 6992a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo */ 7002a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 7012a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3->pm_dev) { 7022a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_get_sync(lis3->pm_dev); 7032a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_put_noidle(lis3->pm_dev); 7042a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); 7052a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 7062a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo} 7072a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 7082db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic ssize_t lis3lv02d_selftest_show(struct device *dev, 7092db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo struct device_attribute *attr, char *buf) 7102db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo{ 7112db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo s16 values[3]; 7122db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 713029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char ok[] = "OK"; 714029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char fail[] = "FAIL"; 715029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo static const char irq[] = "FAIL_IRQ"; 716029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo const char *res; 717029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo 7182a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 719029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo switch (lis3lv02d_selftest(&lis3_dev, values)) { 720029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_FAIL: 721029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = fail; 722029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 723029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_IRQ: 724029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = irq; 725029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 726029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo case SELFTEST_OK: 727029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo default: 728029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo res = ok; 729029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo break; 730029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo } 731029756d0b8856f52d83dee81c01dd3af786cadffSamu Onkalo return sprintf(buf, "%s %d %d %d\n", res, 7322db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo values[0], values[1], values[2]); 7332db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo} 7342db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 735455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_position_show(struct device *dev, 736455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek struct device_attribute *attr, char *buf) 737455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 738455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek int x, y, z; 739455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 7402a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 7416d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_lock(&lis3_dev.mutex); 742a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 7436d94d4081048756df78444a07201156f4930fe48Samu Onkalo mutex_unlock(&lis3_dev.mutex); 744455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return sprintf(buf, "(%d,%d,%d)\n", x, y, z); 745455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 746455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 747455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic ssize_t lis3lv02d_rate_show(struct device *dev, 748455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek struct device_attribute *attr, char *buf) 749455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 7502a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 751641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo return sprintf(buf, "%d\n", lis3lv02d_get_odr()); 752455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 753455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 754a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic ssize_t lis3lv02d_rate_set(struct device *dev, 755a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo struct device_attribute *attr, const char *buf, 756a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo size_t count) 757a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo{ 758a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo unsigned long rate; 759a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 760a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo if (strict_strtoul(buf, 0, &rate)) 761a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return -EINVAL; 762a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 7632a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_sysfs_poweron(&lis3_dev); 764a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo if (lis3lv02d_set_odr(rate)) 765a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return -EINVAL; 766a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 767a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo return count; 768a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo} 769a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo 7702db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalostatic DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); 771455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); 772a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalostatic DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, 773a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo lis3lv02d_rate_set); 774455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 775455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute *lis3lv02d_attributes[] = { 7762db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo &dev_attr_selftest.attr, 777455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek &dev_attr_position.attr, 778455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek &dev_attr_rate.attr, 779455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek NULL 780455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}; 781455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 782455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machekstatic struct attribute_group lis3lv02d_attribute_group = { 783455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek .attrs = lis3lv02d_attributes 784455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek}; 785455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 786cfce41a6d643c001d416ead960caf04fae2d609aEric Piel 787a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackstatic int lis3lv02d_add_fs(struct lis3lv02d *lis3) 788455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 789a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); 790a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel if (IS_ERR(lis3->pdev)) 791a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel return PTR_ERR(lis3->pdev); 792455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 793a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); 794455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 795455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 796a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Pielint lis3lv02d_remove_fs(struct lis3lv02d *lis3) 797455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek{ 798a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); 799a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel platform_device_unregister(lis3->pdev); 8002a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (lis3->pm_dev) { 8012a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* Barrier after the sysfs remove */ 8022a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_barrier(lis3->pm_dev); 8032a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 8042a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo /* SYSFS may have left chip running. Turn off if necessary */ 8052a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (!pm_runtime_suspended(lis3->pm_dev)) 8062a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo lis3lv02d_poweroff(&lis3_dev); 8072a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 8082a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_disable(lis3->pm_dev); 8092a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_set_suspended(lis3->pm_dev); 8102a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 811f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo kfree(lis3->reg_cache); 812455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek return 0; 813455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek} 814cfce41a6d643c001d416ead960caf04fae2d609aEric PielEXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); 815455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel Machek 816ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalostatic void lis3lv02d_8b_configure(struct lis3lv02d *dev, 817ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo struct lis3lv02d_platform_data *p) 818ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo{ 81992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo int err; 820342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo int ctrl2 = p->hipass_ctrl; 821342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo 822ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (p->click_flags) { 823ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_CFG, p->click_flags); 824ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); 825ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_LATENCY, p->click_latency); 826ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_WINDOW, p->click_window); 827ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); 828ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, CLICK_THSY_X, 829ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo (p->click_thresh_x & 0xf) | 830ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo (p->click_thresh_y << 4)); 8316d94d4081048756df78444a07201156f4930fe48Samu Onkalo 8326d94d4081048756df78444a07201156f4930fe48Samu Onkalo if (dev->idev) { 8336d94d4081048756df78444a07201156f4930fe48Samu Onkalo struct input_dev *input_dev = lis3_dev.idev->input; 8346d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_X); 8356d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_Y); 8366d94d4081048756df78444a07201156f4930fe48Samu Onkalo input_set_capability(input_dev, EV_KEY, BTN_Z); 8376d94d4081048756df78444a07201156f4930fe48Samu Onkalo } 838ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo } 839ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo 840ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (p->wakeup_flags) { 841ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); 842ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); 843cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo /* pdata value + 1 to keep this backward compatible*/ 844cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1); 845342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ 846342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo } 847342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo 848342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo if (p->wakeup_flags2) { 849342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); 850342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); 851cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo /* pdata value + 1 to keep this backward compatible*/ 852cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1); 853342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ 854ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo } 855342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo /* Configure hipass filters */ 856342c5f128140d54961c435d1702eadcaba97a37aSamu Onkalo dev->write(dev, CTRL_REG2, ctrl2); 85792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 85892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (p->irq2) { 85992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo err = request_threaded_irq(p->irq2, 86092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo NULL, 86192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo lis302dl_interrupt_thread2_8b, 862cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo IRQF_TRIGGER_RISING | IRQF_ONESHOT | 863cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo (p->irq_flags2 & IRQF_TRIGGER_MASK), 86492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo DRIVER_NAME, &lis3_dev); 86592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (err < 0) 86663366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("No second IRQ. Limited functionality\n"); 86792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo } 868ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo} 869ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo 870ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack/* 871ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack * Initialise the accelerometer and the various subsystems. 872bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel * Should be rather independent of the bus system. 873ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack */ 874a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mackint lis3lv02d_init_device(struct lis3lv02d *dev) 875ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack{ 87692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo int err; 87792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo irq_handler_t thread_fn; 878cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo int irq_flags = 0; 87992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 880a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); 881a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 882a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack switch (dev->whoami) { 883bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel case WAI_12B: 88463366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("12 bits sensor found\n"); 885bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel dev->read_data = lis3lv02d_read_12; 886a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->mdps_max_val = 2048; 887641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; 888a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odrs = lis3_12_rates; 889a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odr_mask = CTRL1_DF0 | CTRL1_DF1; 89032496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo dev->scale = LIS3_SENSITIVITY_12B; 891f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs = lis3_wai12_regs; 892f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); 893a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack break; 894bc62c1471773fc32adcfc05100abd16fa2b6e126Éric Piel case WAI_8B: 89563366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("8 bits sensor found\n"); 896a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->read_data = lis3lv02d_read_8; 897a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack dev->mdps_max_val = 128; 898641615abfac0b7c5e6f242a6db77f7690925b443Samu Onkalo dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; 899a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odrs = lis3_8_rates; 900a253aaef60a37bddfa84846353edeb62a6acf5b3Samu Onkalo dev->odr_mask = CTRL1_DR; 90132496c76b777752ba84b125bebfb0cc498f5602cSamu Onkalo dev->scale = LIS3_SENSITIVITY_8B; 902f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs = lis3_wai8_regs; 903f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); 904a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack break; 90578537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai case WAI_3DC: 90663366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_info("8 bits 3DC sensor found\n"); 90778537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->read_data = lis3lv02d_read_8; 90878537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->mdps_max_val = 128; 90978537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; 91078537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->odrs = lis3_3dc_rates; 91178537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; 91278537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai dev->scale = LIS3_SENSITIVITY_8B; 91378537c3b6ffcb69bf4fd43a74ba57928fcefce95Takashi Iwai break; 914a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack default: 91563366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("unknown sensor type 0x%X\n", dev->whoami); 916a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack return -EINVAL; 917a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack } 918a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack 919f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), 920f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo sizeof(lis3_wai12_regs)), GFP_KERNEL); 921f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 922f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo if (dev->reg_cache == NULL) { 923f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo printk(KERN_ERR DRIVER_NAME "out of memory\n"); 924f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo return -ENOMEM; 925f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo } 926f9deb41f91c41d9d91a24c84a555ec7fe82620daSamu Onkalo 9272db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo mutex_init(&dev->mutex); 928e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo atomic_set(&dev->wake_thread, 0); 9292db4a76d5f3554e9e5632c8f91828313318579c8Samu Onkalo 930a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack lis3lv02d_add_fs(dev); 931a002ee896dfd08ce9fba44e9ae513c9094699a27Eric Piel lis3lv02d_poweron(dev); 932ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 9332a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo if (dev->pm_dev) { 9342a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_set_active(dev->pm_dev); 9352a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo pm_runtime_enable(dev->pm_dev); 9362a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo } 9372a346996626ecbb4269c239e9ff7372a182907e9Samu Onkalo 938ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (lis3lv02d_joystick_enable()) 93963366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("joystick initialization failed\n"); 940ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 9418f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack /* passing in platform specific data is purely optional and only 9428f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack * used by the SPI transport layer at the moment */ 9438f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack if (dev->pdata) { 9448f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack struct lis3lv02d_platform_data *p = dev->pdata; 9458f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack 946ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo if (dev->whoami == WAI_8B) 947ecc437aeee65afeea2e1bed963ccf6c384c555eaSamu Onkalo lis3lv02d_8b_configure(dev, p); 9488873c33483e62988ed886230aab71ef4c678f710Daniel Mack 949cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK; 950cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo 951e726111f953f8f5b922b953caf06ba6790c5fbaaSamu Onkalo dev->irq_cfg = p->irq_cfg; 9528f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack if (p->irq_cfg) 9538f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack dev->write(dev, CTRL_REG3, p->irq_cfg); 954cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo 955cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo if (p->default_rate) 956cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo lis3lv02d_set_odr(p->default_rate); 9578f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack } 9588f3128e714ded7cf1e8c786c204a4f253b5d8ff4Daniel Mack 959a38da2ed74f628c1f3e907c772be21a66eccab9cDaniel Mack /* bail if we did not get an IRQ from the bus layer */ 960ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (!dev->irq) { 961a20f0bc10c47fcf62be027e1a50b62791052ab56Kalhan Trisal pr_debug("No IRQ. Disabling /dev/freefall\n"); 962ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack goto out; 963ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack } 964ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 96592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo /* 96692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * The sensor can generate interrupts for free-fall and direction 96792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep 96892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * the things simple and _fast_ we activate it only for free-fall, so 96992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * no need to read register (very slow with ACPI). For the same reason, 97092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * we forbid shared interrupts. 97192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * 97292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * IRQF_TRIGGER_RISING seems pointless on HP laptops because the 97392ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * io-apic is not configurable (and generates a warning) but I keep it 97492ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo * in case of support for other hardware. 97592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo */ 976f7c77a3dc4683659b6f0d1b6cbc82b6253d095e0Takashi Iwai if (dev->pdata && dev->whoami == WAI_8B) 97792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn = lis302dl_interrupt_thread1_8b; 97892ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo else 97992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn = NULL; 98092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 98192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo err = request_threaded_irq(dev->irq, lis302dl_interrupt, 98292ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo thread_fn, 983cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo IRQF_TRIGGER_RISING | IRQF_ONESHOT | 984cc23aa1ce2631b2fe1e3fba82ee444460f5ee3b7Samu Onkalo irq_flags, 98592ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo DRIVER_NAME, &lis3_dev); 98692ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 98792ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo if (err < 0) { 98863366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("Cannot get IRQ\n"); 98992ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo goto out; 99092ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo } 99192ba4fe4b53b4fa5ac71ec4d80572348fca85796Samu Onkalo 992ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack if (misc_register(&lis3lv02d_misc_device)) 99363366d37ad5dbb4f208b517c88ea4bd41738dbf7Joe Perches pr_err("misc_register failed\n"); 994ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mackout: 995ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack return 0; 996ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack} 997ab337a632783c251a3c3852aec0ead8a0281cbddDaniel MackEXPORT_SYMBOL_GPL(lis3lv02d_init_device); 998ab337a632783c251a3c3852aec0ead8a0281cbddDaniel Mack 999455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); 1000ef2cfc790bf5f0ff189b01eabc0f4feb5e8524dfPavel MachekMODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); 1001455fbdd376c3ed3a5be8c039348896fdd87e9930Pavel MachekMODULE_LICENSE("GPL"); 1002