1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * lis3lv02d.h - ST LIS3LV02DL accelerometer driver 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Copyright (C) 2007-2008 Yan Burman 6*4882a593Smuzhiyun * Copyright (C) 2008-2009 Eric Piel 7*4882a593Smuzhiyun */ 8*4882a593Smuzhiyun #include <linux/platform_device.h> 9*4882a593Smuzhiyun #include <linux/input.h> 10*4882a593Smuzhiyun #include <linux/regulator/consumer.h> 11*4882a593Smuzhiyun #include <linux/miscdevice.h> 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun /* 14*4882a593Smuzhiyun * This driver tries to support the "digital" accelerometer chips from 15*4882a593Smuzhiyun * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, 16*4882a593Smuzhiyun * LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of 17*4882a593Smuzhiyun * programming, with almost the same registers. In addition to differing 18*4882a593Smuzhiyun * on physical properties, they differ on the number of axes (2/3), 19*4882a593Smuzhiyun * precision (8/12 bits), and special features (freefall detection, 20*4882a593Smuzhiyun * click...). Unfortunately, not all the differences can be probed via 21*4882a593Smuzhiyun * a register. They can be connected either via I²C or SPI. 22*4882a593Smuzhiyun */ 23*4882a593Smuzhiyun 24*4882a593Smuzhiyun #include <linux/lis3lv02d.h> 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun enum lis3_reg { 27*4882a593Smuzhiyun WHO_AM_I = 0x0F, 28*4882a593Smuzhiyun OFFSET_X = 0x16, 29*4882a593Smuzhiyun OFFSET_Y = 0x17, 30*4882a593Smuzhiyun OFFSET_Z = 0x18, 31*4882a593Smuzhiyun GAIN_X = 0x19, 32*4882a593Smuzhiyun GAIN_Y = 0x1A, 33*4882a593Smuzhiyun GAIN_Z = 0x1B, 34*4882a593Smuzhiyun CTRL_REG1 = 0x20, 35*4882a593Smuzhiyun CTRL_REG2 = 0x21, 36*4882a593Smuzhiyun CTRL_REG3 = 0x22, 37*4882a593Smuzhiyun CTRL_REG4 = 0x23, 38*4882a593Smuzhiyun HP_FILTER_RESET = 0x23, 39*4882a593Smuzhiyun STATUS_REG = 0x27, 40*4882a593Smuzhiyun OUTX_L = 0x28, 41*4882a593Smuzhiyun OUTX_H = 0x29, 42*4882a593Smuzhiyun OUTX = 0x29, 43*4882a593Smuzhiyun OUTY_L = 0x2A, 44*4882a593Smuzhiyun OUTY_H = 0x2B, 45*4882a593Smuzhiyun OUTY = 0x2B, 46*4882a593Smuzhiyun OUTZ_L = 0x2C, 47*4882a593Smuzhiyun OUTZ_H = 0x2D, 48*4882a593Smuzhiyun OUTZ = 0x2D, 49*4882a593Smuzhiyun }; 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun enum lis302d_reg { 52*4882a593Smuzhiyun FF_WU_CFG_1 = 0x30, 53*4882a593Smuzhiyun FF_WU_SRC_1 = 0x31, 54*4882a593Smuzhiyun FF_WU_THS_1 = 0x32, 55*4882a593Smuzhiyun FF_WU_DURATION_1 = 0x33, 56*4882a593Smuzhiyun FF_WU_CFG_2 = 0x34, 57*4882a593Smuzhiyun FF_WU_SRC_2 = 0x35, 58*4882a593Smuzhiyun FF_WU_THS_2 = 0x36, 59*4882a593Smuzhiyun FF_WU_DURATION_2 = 0x37, 60*4882a593Smuzhiyun CLICK_CFG = 0x38, 61*4882a593Smuzhiyun CLICK_SRC = 0x39, 62*4882a593Smuzhiyun CLICK_THSY_X = 0x3B, 63*4882a593Smuzhiyun CLICK_THSZ = 0x3C, 64*4882a593Smuzhiyun CLICK_TIMELIMIT = 0x3D, 65*4882a593Smuzhiyun CLICK_LATENCY = 0x3E, 66*4882a593Smuzhiyun CLICK_WINDOW = 0x3F, 67*4882a593Smuzhiyun }; 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun enum lis3lv02d_reg { 70*4882a593Smuzhiyun FF_WU_CFG = 0x30, 71*4882a593Smuzhiyun FF_WU_SRC = 0x31, 72*4882a593Smuzhiyun FF_WU_ACK = 0x32, 73*4882a593Smuzhiyun FF_WU_THS_L = 0x34, 74*4882a593Smuzhiyun FF_WU_THS_H = 0x35, 75*4882a593Smuzhiyun FF_WU_DURATION = 0x36, 76*4882a593Smuzhiyun DD_CFG = 0x38, 77*4882a593Smuzhiyun DD_SRC = 0x39, 78*4882a593Smuzhiyun DD_ACK = 0x3A, 79*4882a593Smuzhiyun DD_THSI_L = 0x3C, 80*4882a593Smuzhiyun DD_THSI_H = 0x3D, 81*4882a593Smuzhiyun DD_THSE_L = 0x3E, 82*4882a593Smuzhiyun DD_THSE_H = 0x3F, 83*4882a593Smuzhiyun }; 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun enum lis3_who_am_i { 86*4882a593Smuzhiyun WAI_3DLH = 0x32, /* 16 bits: LIS331DLH */ 87*4882a593Smuzhiyun WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ 88*4882a593Smuzhiyun WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ 89*4882a593Smuzhiyun WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ 90*4882a593Smuzhiyun WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ 91*4882a593Smuzhiyun }; 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun enum lis3_type { 94*4882a593Smuzhiyun LIS3LV02D, 95*4882a593Smuzhiyun LIS3DC, 96*4882a593Smuzhiyun HP3DC, 97*4882a593Smuzhiyun LIS2302D, 98*4882a593Smuzhiyun LIS331DLF, 99*4882a593Smuzhiyun LIS331DLH, 100*4882a593Smuzhiyun }; 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun enum lis3lv02d_ctrl1_12b { 103*4882a593Smuzhiyun CTRL1_Xen = 0x01, 104*4882a593Smuzhiyun CTRL1_Yen = 0x02, 105*4882a593Smuzhiyun CTRL1_Zen = 0x04, 106*4882a593Smuzhiyun CTRL1_ST = 0x08, 107*4882a593Smuzhiyun CTRL1_DF0 = 0x10, 108*4882a593Smuzhiyun CTRL1_DF1 = 0x20, 109*4882a593Smuzhiyun CTRL1_PD0 = 0x40, 110*4882a593Smuzhiyun CTRL1_PD1 = 0x80, 111*4882a593Smuzhiyun }; 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun /* Delta to ctrl1_12b version */ 114*4882a593Smuzhiyun enum lis3lv02d_ctrl1_8b { 115*4882a593Smuzhiyun CTRL1_STM = 0x08, 116*4882a593Smuzhiyun CTRL1_STP = 0x10, 117*4882a593Smuzhiyun CTRL1_FS = 0x20, 118*4882a593Smuzhiyun CTRL1_PD = 0x40, 119*4882a593Smuzhiyun CTRL1_DR = 0x80, 120*4882a593Smuzhiyun }; 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun enum lis3lv02d_ctrl1_3dc { 123*4882a593Smuzhiyun CTRL1_ODR0 = 0x10, 124*4882a593Smuzhiyun CTRL1_ODR1 = 0x20, 125*4882a593Smuzhiyun CTRL1_ODR2 = 0x40, 126*4882a593Smuzhiyun CTRL1_ODR3 = 0x80, 127*4882a593Smuzhiyun }; 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun enum lis331dlh_ctrl1 { 130*4882a593Smuzhiyun CTRL1_DR0 = 0x08, 131*4882a593Smuzhiyun CTRL1_DR1 = 0x10, 132*4882a593Smuzhiyun CTRL1_PM0 = 0x20, 133*4882a593Smuzhiyun CTRL1_PM1 = 0x40, 134*4882a593Smuzhiyun CTRL1_PM2 = 0x80, 135*4882a593Smuzhiyun }; 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun enum lis331dlh_ctrl2 { 138*4882a593Smuzhiyun CTRL2_HPEN1 = 0x04, 139*4882a593Smuzhiyun CTRL2_HPEN2 = 0x08, 140*4882a593Smuzhiyun CTRL2_FDS_3DLH = 0x10, 141*4882a593Smuzhiyun CTRL2_BOOT_3DLH = 0x80, 142*4882a593Smuzhiyun }; 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun enum lis331dlh_ctrl4 { 145*4882a593Smuzhiyun CTRL4_STSIGN = 0x08, 146*4882a593Smuzhiyun CTRL4_BLE = 0x40, 147*4882a593Smuzhiyun CTRL4_BDU = 0x80, 148*4882a593Smuzhiyun }; 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun enum lis3lv02d_ctrl2 { 151*4882a593Smuzhiyun CTRL2_DAS = 0x01, 152*4882a593Smuzhiyun CTRL2_SIM = 0x02, 153*4882a593Smuzhiyun CTRL2_DRDY = 0x04, 154*4882a593Smuzhiyun CTRL2_IEN = 0x08, 155*4882a593Smuzhiyun CTRL2_BOOT = 0x10, 156*4882a593Smuzhiyun CTRL2_BLE = 0x20, 157*4882a593Smuzhiyun CTRL2_BDU = 0x40, /* Block Data Update */ 158*4882a593Smuzhiyun CTRL2_FS = 0x80, /* Full Scale selection */ 159*4882a593Smuzhiyun }; 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun enum lis3lv02d_ctrl4_3dc { 162*4882a593Smuzhiyun CTRL4_SIM = 0x01, 163*4882a593Smuzhiyun CTRL4_ST0 = 0x02, 164*4882a593Smuzhiyun CTRL4_ST1 = 0x04, 165*4882a593Smuzhiyun CTRL4_FS0 = 0x10, 166*4882a593Smuzhiyun CTRL4_FS1 = 0x20, 167*4882a593Smuzhiyun }; 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun enum lis302d_ctrl2 { 170*4882a593Smuzhiyun HP_FF_WU2 = 0x08, 171*4882a593Smuzhiyun HP_FF_WU1 = 0x04, 172*4882a593Smuzhiyun CTRL2_BOOT_8B = 0x40, 173*4882a593Smuzhiyun }; 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun enum lis3lv02d_ctrl3 { 176*4882a593Smuzhiyun CTRL3_CFS0 = 0x01, 177*4882a593Smuzhiyun CTRL3_CFS1 = 0x02, 178*4882a593Smuzhiyun CTRL3_FDS = 0x10, 179*4882a593Smuzhiyun CTRL3_HPFF = 0x20, 180*4882a593Smuzhiyun CTRL3_HPDD = 0x40, 181*4882a593Smuzhiyun CTRL3_ECK = 0x80, 182*4882a593Smuzhiyun }; 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun enum lis3lv02d_status_reg { 185*4882a593Smuzhiyun STATUS_XDA = 0x01, 186*4882a593Smuzhiyun STATUS_YDA = 0x02, 187*4882a593Smuzhiyun STATUS_ZDA = 0x04, 188*4882a593Smuzhiyun STATUS_XYZDA = 0x08, 189*4882a593Smuzhiyun STATUS_XOR = 0x10, 190*4882a593Smuzhiyun STATUS_YOR = 0x20, 191*4882a593Smuzhiyun STATUS_ZOR = 0x40, 192*4882a593Smuzhiyun STATUS_XYZOR = 0x80, 193*4882a593Smuzhiyun }; 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun enum lis3lv02d_ff_wu_cfg { 196*4882a593Smuzhiyun FF_WU_CFG_XLIE = 0x01, 197*4882a593Smuzhiyun FF_WU_CFG_XHIE = 0x02, 198*4882a593Smuzhiyun FF_WU_CFG_YLIE = 0x04, 199*4882a593Smuzhiyun FF_WU_CFG_YHIE = 0x08, 200*4882a593Smuzhiyun FF_WU_CFG_ZLIE = 0x10, 201*4882a593Smuzhiyun FF_WU_CFG_ZHIE = 0x20, 202*4882a593Smuzhiyun FF_WU_CFG_LIR = 0x40, 203*4882a593Smuzhiyun FF_WU_CFG_AOI = 0x80, 204*4882a593Smuzhiyun }; 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun enum lis3lv02d_ff_wu_src { 207*4882a593Smuzhiyun FF_WU_SRC_XL = 0x01, 208*4882a593Smuzhiyun FF_WU_SRC_XH = 0x02, 209*4882a593Smuzhiyun FF_WU_SRC_YL = 0x04, 210*4882a593Smuzhiyun FF_WU_SRC_YH = 0x08, 211*4882a593Smuzhiyun FF_WU_SRC_ZL = 0x10, 212*4882a593Smuzhiyun FF_WU_SRC_ZH = 0x20, 213*4882a593Smuzhiyun FF_WU_SRC_IA = 0x40, 214*4882a593Smuzhiyun }; 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun enum lis3lv02d_dd_cfg { 217*4882a593Smuzhiyun DD_CFG_XLIE = 0x01, 218*4882a593Smuzhiyun DD_CFG_XHIE = 0x02, 219*4882a593Smuzhiyun DD_CFG_YLIE = 0x04, 220*4882a593Smuzhiyun DD_CFG_YHIE = 0x08, 221*4882a593Smuzhiyun DD_CFG_ZLIE = 0x10, 222*4882a593Smuzhiyun DD_CFG_ZHIE = 0x20, 223*4882a593Smuzhiyun DD_CFG_LIR = 0x40, 224*4882a593Smuzhiyun DD_CFG_IEND = 0x80, 225*4882a593Smuzhiyun }; 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun enum lis3lv02d_dd_src { 228*4882a593Smuzhiyun DD_SRC_XL = 0x01, 229*4882a593Smuzhiyun DD_SRC_XH = 0x02, 230*4882a593Smuzhiyun DD_SRC_YL = 0x04, 231*4882a593Smuzhiyun DD_SRC_YH = 0x08, 232*4882a593Smuzhiyun DD_SRC_ZL = 0x10, 233*4882a593Smuzhiyun DD_SRC_ZH = 0x20, 234*4882a593Smuzhiyun DD_SRC_IA = 0x40, 235*4882a593Smuzhiyun }; 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun enum lis3lv02d_click_src_8b { 238*4882a593Smuzhiyun CLICK_SINGLE_X = 0x01, 239*4882a593Smuzhiyun CLICK_DOUBLE_X = 0x02, 240*4882a593Smuzhiyun CLICK_SINGLE_Y = 0x04, 241*4882a593Smuzhiyun CLICK_DOUBLE_Y = 0x08, 242*4882a593Smuzhiyun CLICK_SINGLE_Z = 0x10, 243*4882a593Smuzhiyun CLICK_DOUBLE_Z = 0x20, 244*4882a593Smuzhiyun CLICK_IA = 0x40, 245*4882a593Smuzhiyun }; 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun enum lis3lv02d_reg_state { 248*4882a593Smuzhiyun LIS3_REG_OFF = 0x00, 249*4882a593Smuzhiyun LIS3_REG_ON = 0x01, 250*4882a593Smuzhiyun }; 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun union axis_conversion { 253*4882a593Smuzhiyun struct { 254*4882a593Smuzhiyun int x, y, z; 255*4882a593Smuzhiyun }; 256*4882a593Smuzhiyun int as_array[3]; 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun }; 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun struct lis3lv02d { 261*4882a593Smuzhiyun void *bus_priv; /* used by the bus layer only */ 262*4882a593Smuzhiyun struct device *pm_dev; /* for pm_runtime purposes */ 263*4882a593Smuzhiyun int (*init) (struct lis3lv02d *lis3); 264*4882a593Smuzhiyun int (*write) (struct lis3lv02d *lis3, int reg, u8 val); 265*4882a593Smuzhiyun int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); 266*4882a593Smuzhiyun int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret); 267*4882a593Smuzhiyun int (*reg_ctrl) (struct lis3lv02d *lis3, bool state); 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun int *odrs; /* Supported output data rates */ 270*4882a593Smuzhiyun u8 *regs; /* Regs to store / restore */ 271*4882a593Smuzhiyun int regs_size; 272*4882a593Smuzhiyun u8 *reg_cache; 273*4882a593Smuzhiyun bool regs_stored; 274*4882a593Smuzhiyun bool init_required; 275*4882a593Smuzhiyun u8 odr_mask; /* ODR bit mask */ 276*4882a593Smuzhiyun u8 whoami; /* indicates measurement precision */ 277*4882a593Smuzhiyun s16 (*read_data) (struct lis3lv02d *lis3, int reg); 278*4882a593Smuzhiyun int mdps_max_val; 279*4882a593Smuzhiyun int pwron_delay; 280*4882a593Smuzhiyun int scale; /* 281*4882a593Smuzhiyun * relationship between 1 LBS and mG 282*4882a593Smuzhiyun * (1/1000th of earth gravity) 283*4882a593Smuzhiyun */ 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun struct input_dev *idev; /* input device */ 286*4882a593Smuzhiyun struct platform_device *pdev; /* platform device */ 287*4882a593Smuzhiyun struct regulator_bulk_data regulators[2]; 288*4882a593Smuzhiyun atomic_t count; /* interrupt count after last read */ 289*4882a593Smuzhiyun union axis_conversion ac; /* hw -> logical axis */ 290*4882a593Smuzhiyun int mapped_btns[3]; 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun u32 irq; /* IRQ number */ 293*4882a593Smuzhiyun struct fasync_struct *async_queue; /* queue for the misc device */ 294*4882a593Smuzhiyun wait_queue_head_t misc_wait; /* Wait queue for the misc device */ 295*4882a593Smuzhiyun unsigned long misc_opened; /* bit0: whether the device is open */ 296*4882a593Smuzhiyun struct miscdevice miscdev; 297*4882a593Smuzhiyun 298*4882a593Smuzhiyun int data_ready_count[2]; 299*4882a593Smuzhiyun atomic_t wake_thread; 300*4882a593Smuzhiyun unsigned char irq_cfg; 301*4882a593Smuzhiyun unsigned int shift_adj; 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun struct lis3lv02d_platform_data *pdata; /* for passing board config */ 304*4882a593Smuzhiyun struct mutex mutex; /* Serialize poll and selftest */ 305*4882a593Smuzhiyun 306*4882a593Smuzhiyun #ifdef CONFIG_OF 307*4882a593Smuzhiyun struct device_node *of_node; 308*4882a593Smuzhiyun #endif 309*4882a593Smuzhiyun }; 310*4882a593Smuzhiyun 311*4882a593Smuzhiyun int lis3lv02d_init_device(struct lis3lv02d *lis3); 312*4882a593Smuzhiyun int lis3lv02d_joystick_enable(struct lis3lv02d *lis3); 313*4882a593Smuzhiyun void lis3lv02d_joystick_disable(struct lis3lv02d *lis3); 314*4882a593Smuzhiyun void lis3lv02d_poweroff(struct lis3lv02d *lis3); 315*4882a593Smuzhiyun int lis3lv02d_poweron(struct lis3lv02d *lis3); 316*4882a593Smuzhiyun int lis3lv02d_remove_fs(struct lis3lv02d *lis3); 317*4882a593Smuzhiyun int lis3lv02d_init_dt(struct lis3lv02d *lis3); 318*4882a593Smuzhiyun 319*4882a593Smuzhiyun extern struct lis3lv02d lis3_dev; 320