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