162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ADXL345/346 Three-Axis Digital Accelerometers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Enter bugs at http://blackfin.uclinux.org/ 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/input.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/irq.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/workqueue.h> 1762306a36Sopenharmony_ci#include <linux/input/adxl34x.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "adxl34x.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* ADXL345/6 Register Map */ 2362306a36Sopenharmony_ci#define DEVID 0x00 /* R Device ID */ 2462306a36Sopenharmony_ci#define THRESH_TAP 0x1D /* R/W Tap threshold */ 2562306a36Sopenharmony_ci#define OFSX 0x1E /* R/W X-axis offset */ 2662306a36Sopenharmony_ci#define OFSY 0x1F /* R/W Y-axis offset */ 2762306a36Sopenharmony_ci#define OFSZ 0x20 /* R/W Z-axis offset */ 2862306a36Sopenharmony_ci#define DUR 0x21 /* R/W Tap duration */ 2962306a36Sopenharmony_ci#define LATENT 0x22 /* R/W Tap latency */ 3062306a36Sopenharmony_ci#define WINDOW 0x23 /* R/W Tap window */ 3162306a36Sopenharmony_ci#define THRESH_ACT 0x24 /* R/W Activity threshold */ 3262306a36Sopenharmony_ci#define THRESH_INACT 0x25 /* R/W Inactivity threshold */ 3362306a36Sopenharmony_ci#define TIME_INACT 0x26 /* R/W Inactivity time */ 3462306a36Sopenharmony_ci#define ACT_INACT_CTL 0x27 /* R/W Axis enable control for activity and */ 3562306a36Sopenharmony_ci /* inactivity detection */ 3662306a36Sopenharmony_ci#define THRESH_FF 0x28 /* R/W Free-fall threshold */ 3762306a36Sopenharmony_ci#define TIME_FF 0x29 /* R/W Free-fall time */ 3862306a36Sopenharmony_ci#define TAP_AXES 0x2A /* R/W Axis control for tap/double tap */ 3962306a36Sopenharmony_ci#define ACT_TAP_STATUS 0x2B /* R Source of tap/double tap */ 4062306a36Sopenharmony_ci#define BW_RATE 0x2C /* R/W Data rate and power mode control */ 4162306a36Sopenharmony_ci#define POWER_CTL 0x2D /* R/W Power saving features control */ 4262306a36Sopenharmony_ci#define INT_ENABLE 0x2E /* R/W Interrupt enable control */ 4362306a36Sopenharmony_ci#define INT_MAP 0x2F /* R/W Interrupt mapping control */ 4462306a36Sopenharmony_ci#define INT_SOURCE 0x30 /* R Source of interrupts */ 4562306a36Sopenharmony_ci#define DATA_FORMAT 0x31 /* R/W Data format control */ 4662306a36Sopenharmony_ci#define DATAX0 0x32 /* R X-Axis Data 0 */ 4762306a36Sopenharmony_ci#define DATAX1 0x33 /* R X-Axis Data 1 */ 4862306a36Sopenharmony_ci#define DATAY0 0x34 /* R Y-Axis Data 0 */ 4962306a36Sopenharmony_ci#define DATAY1 0x35 /* R Y-Axis Data 1 */ 5062306a36Sopenharmony_ci#define DATAZ0 0x36 /* R Z-Axis Data 0 */ 5162306a36Sopenharmony_ci#define DATAZ1 0x37 /* R Z-Axis Data 1 */ 5262306a36Sopenharmony_ci#define FIFO_CTL 0x38 /* R/W FIFO control */ 5362306a36Sopenharmony_ci#define FIFO_STATUS 0x39 /* R FIFO status */ 5462306a36Sopenharmony_ci#define TAP_SIGN 0x3A /* R Sign and source for tap/double tap */ 5562306a36Sopenharmony_ci/* Orientation ADXL346 only */ 5662306a36Sopenharmony_ci#define ORIENT_CONF 0x3B /* R/W Orientation configuration */ 5762306a36Sopenharmony_ci#define ORIENT 0x3C /* R Orientation status */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* DEVIDs */ 6062306a36Sopenharmony_ci#define ID_ADXL345 0xE5 6162306a36Sopenharmony_ci#define ID_ADXL346 0xE6 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */ 6462306a36Sopenharmony_ci#define DATA_READY (1 << 7) 6562306a36Sopenharmony_ci#define SINGLE_TAP (1 << 6) 6662306a36Sopenharmony_ci#define DOUBLE_TAP (1 << 5) 6762306a36Sopenharmony_ci#define ACTIVITY (1 << 4) 6862306a36Sopenharmony_ci#define INACTIVITY (1 << 3) 6962306a36Sopenharmony_ci#define FREE_FALL (1 << 2) 7062306a36Sopenharmony_ci#define WATERMARK (1 << 1) 7162306a36Sopenharmony_ci#define OVERRUN (1 << 0) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* ACT_INACT_CONTROL Bits */ 7462306a36Sopenharmony_ci#define ACT_ACDC (1 << 7) 7562306a36Sopenharmony_ci#define ACT_X_EN (1 << 6) 7662306a36Sopenharmony_ci#define ACT_Y_EN (1 << 5) 7762306a36Sopenharmony_ci#define ACT_Z_EN (1 << 4) 7862306a36Sopenharmony_ci#define INACT_ACDC (1 << 3) 7962306a36Sopenharmony_ci#define INACT_X_EN (1 << 2) 8062306a36Sopenharmony_ci#define INACT_Y_EN (1 << 1) 8162306a36Sopenharmony_ci#define INACT_Z_EN (1 << 0) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* TAP_AXES Bits */ 8462306a36Sopenharmony_ci#define SUPPRESS (1 << 3) 8562306a36Sopenharmony_ci#define TAP_X_EN (1 << 2) 8662306a36Sopenharmony_ci#define TAP_Y_EN (1 << 1) 8762306a36Sopenharmony_ci#define TAP_Z_EN (1 << 0) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* ACT_TAP_STATUS Bits */ 9062306a36Sopenharmony_ci#define ACT_X_SRC (1 << 6) 9162306a36Sopenharmony_ci#define ACT_Y_SRC (1 << 5) 9262306a36Sopenharmony_ci#define ACT_Z_SRC (1 << 4) 9362306a36Sopenharmony_ci#define ASLEEP (1 << 3) 9462306a36Sopenharmony_ci#define TAP_X_SRC (1 << 2) 9562306a36Sopenharmony_ci#define TAP_Y_SRC (1 << 1) 9662306a36Sopenharmony_ci#define TAP_Z_SRC (1 << 0) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* BW_RATE Bits */ 9962306a36Sopenharmony_ci#define LOW_POWER (1 << 4) 10062306a36Sopenharmony_ci#define RATE(x) ((x) & 0xF) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* POWER_CTL Bits */ 10362306a36Sopenharmony_ci#define PCTL_LINK (1 << 5) 10462306a36Sopenharmony_ci#define PCTL_AUTO_SLEEP (1 << 4) 10562306a36Sopenharmony_ci#define PCTL_MEASURE (1 << 3) 10662306a36Sopenharmony_ci#define PCTL_SLEEP (1 << 2) 10762306a36Sopenharmony_ci#define PCTL_WAKEUP(x) ((x) & 0x3) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* DATA_FORMAT Bits */ 11062306a36Sopenharmony_ci#define SELF_TEST (1 << 7) 11162306a36Sopenharmony_ci#define SPI (1 << 6) 11262306a36Sopenharmony_ci#define INT_INVERT (1 << 5) 11362306a36Sopenharmony_ci#define FULL_RES (1 << 3) 11462306a36Sopenharmony_ci#define JUSTIFY (1 << 2) 11562306a36Sopenharmony_ci#define RANGE(x) ((x) & 0x3) 11662306a36Sopenharmony_ci#define RANGE_PM_2g 0 11762306a36Sopenharmony_ci#define RANGE_PM_4g 1 11862306a36Sopenharmony_ci#define RANGE_PM_8g 2 11962306a36Sopenharmony_ci#define RANGE_PM_16g 3 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Maximum value our axis may get in full res mode for the input device 12362306a36Sopenharmony_ci * (signed 13 bits) 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci#define ADXL_FULLRES_MAX_VAL 4096 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* 12862306a36Sopenharmony_ci * Maximum value our axis may get in fixed res mode for the input device 12962306a36Sopenharmony_ci * (signed 10 bits) 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci#define ADXL_FIXEDRES_MAX_VAL 512 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* FIFO_CTL Bits */ 13462306a36Sopenharmony_ci#define FIFO_MODE(x) (((x) & 0x3) << 6) 13562306a36Sopenharmony_ci#define FIFO_BYPASS 0 13662306a36Sopenharmony_ci#define FIFO_FIFO 1 13762306a36Sopenharmony_ci#define FIFO_STREAM 2 13862306a36Sopenharmony_ci#define FIFO_TRIGGER 3 13962306a36Sopenharmony_ci#define TRIGGER (1 << 5) 14062306a36Sopenharmony_ci#define SAMPLES(x) ((x) & 0x1F) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* FIFO_STATUS Bits */ 14362306a36Sopenharmony_ci#define FIFO_TRIG (1 << 7) 14462306a36Sopenharmony_ci#define ENTRIES(x) ((x) & 0x3F) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* TAP_SIGN Bits ADXL346 only */ 14762306a36Sopenharmony_ci#define XSIGN (1 << 6) 14862306a36Sopenharmony_ci#define YSIGN (1 << 5) 14962306a36Sopenharmony_ci#define ZSIGN (1 << 4) 15062306a36Sopenharmony_ci#define XTAP (1 << 3) 15162306a36Sopenharmony_ci#define YTAP (1 << 2) 15262306a36Sopenharmony_ci#define ZTAP (1 << 1) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* ORIENT_CONF ADXL346 only */ 15562306a36Sopenharmony_ci#define ORIENT_DEADZONE(x) (((x) & 0x7) << 4) 15662306a36Sopenharmony_ci#define ORIENT_DIVISOR(x) ((x) & 0x7) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* ORIENT ADXL346 only */ 15962306a36Sopenharmony_ci#define ADXL346_2D_VALID (1 << 6) 16062306a36Sopenharmony_ci#define ADXL346_2D_ORIENT(x) (((x) & 0x30) >> 4) 16162306a36Sopenharmony_ci#define ADXL346_3D_VALID (1 << 3) 16262306a36Sopenharmony_ci#define ADXL346_3D_ORIENT(x) ((x) & 0x7) 16362306a36Sopenharmony_ci#define ADXL346_2D_PORTRAIT_POS 0 /* +X */ 16462306a36Sopenharmony_ci#define ADXL346_2D_PORTRAIT_NEG 1 /* -X */ 16562306a36Sopenharmony_ci#define ADXL346_2D_LANDSCAPE_POS 2 /* +Y */ 16662306a36Sopenharmony_ci#define ADXL346_2D_LANDSCAPE_NEG 3 /* -Y */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#define ADXL346_3D_FRONT 3 /* +X */ 16962306a36Sopenharmony_ci#define ADXL346_3D_BACK 4 /* -X */ 17062306a36Sopenharmony_ci#define ADXL346_3D_RIGHT 2 /* +Y */ 17162306a36Sopenharmony_ci#define ADXL346_3D_LEFT 5 /* -Y */ 17262306a36Sopenharmony_ci#define ADXL346_3D_TOP 1 /* +Z */ 17362306a36Sopenharmony_ci#define ADXL346_3D_BOTTOM 6 /* -Z */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#undef ADXL_DEBUG 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci#define ADXL_X_AXIS 0 17862306a36Sopenharmony_ci#define ADXL_Y_AXIS 1 17962306a36Sopenharmony_ci#define ADXL_Z_AXIS 2 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define AC_READ(ac, reg) ((ac)->bops->read((ac)->dev, reg)) 18262306a36Sopenharmony_ci#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val)) 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistruct axis_triple { 18562306a36Sopenharmony_ci int x; 18662306a36Sopenharmony_ci int y; 18762306a36Sopenharmony_ci int z; 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistruct adxl34x { 19162306a36Sopenharmony_ci struct device *dev; 19262306a36Sopenharmony_ci struct input_dev *input; 19362306a36Sopenharmony_ci struct mutex mutex; /* reentrant protection for struct */ 19462306a36Sopenharmony_ci struct adxl34x_platform_data pdata; 19562306a36Sopenharmony_ci struct axis_triple swcal; 19662306a36Sopenharmony_ci struct axis_triple hwcal; 19762306a36Sopenharmony_ci struct axis_triple saved; 19862306a36Sopenharmony_ci char phys[32]; 19962306a36Sopenharmony_ci unsigned orient2d_saved; 20062306a36Sopenharmony_ci unsigned orient3d_saved; 20162306a36Sopenharmony_ci bool disabled; /* P: mutex */ 20262306a36Sopenharmony_ci bool opened; /* P: mutex */ 20362306a36Sopenharmony_ci bool suspended; /* P: mutex */ 20462306a36Sopenharmony_ci bool fifo_delay; 20562306a36Sopenharmony_ci int irq; 20662306a36Sopenharmony_ci unsigned model; 20762306a36Sopenharmony_ci unsigned int_mask; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci const struct adxl34x_bus_ops *bops; 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic const struct adxl34x_platform_data adxl34x_default_init = { 21362306a36Sopenharmony_ci .tap_threshold = 35, 21462306a36Sopenharmony_ci .tap_duration = 3, 21562306a36Sopenharmony_ci .tap_latency = 20, 21662306a36Sopenharmony_ci .tap_window = 20, 21762306a36Sopenharmony_ci .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN, 21862306a36Sopenharmony_ci .act_axis_control = 0xFF, 21962306a36Sopenharmony_ci .activity_threshold = 6, 22062306a36Sopenharmony_ci .inactivity_threshold = 4, 22162306a36Sopenharmony_ci .inactivity_time = 3, 22262306a36Sopenharmony_ci .free_fall_threshold = 8, 22362306a36Sopenharmony_ci .free_fall_time = 0x20, 22462306a36Sopenharmony_ci .data_rate = 8, 22562306a36Sopenharmony_ci .data_range = ADXL_FULL_RES, 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci .ev_type = EV_ABS, 22862306a36Sopenharmony_ci .ev_code_x = ABS_X, /* EV_REL */ 22962306a36Sopenharmony_ci .ev_code_y = ABS_Y, /* EV_REL */ 23062306a36Sopenharmony_ci .ev_code_z = ABS_Z, /* EV_REL */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci .ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */ 23362306a36Sopenharmony_ci .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK, 23462306a36Sopenharmony_ci .fifo_mode = ADXL_FIFO_STREAM, 23562306a36Sopenharmony_ci .watermark = 0, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci __le16 buf[3]; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci mutex_lock(&ac->mutex); 24562306a36Sopenharmony_ci ac->saved.x = (s16) le16_to_cpu(buf[0]); 24662306a36Sopenharmony_ci axis->x = ac->saved.x; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ac->saved.y = (s16) le16_to_cpu(buf[1]); 24962306a36Sopenharmony_ci axis->y = ac->saved.y; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ac->saved.z = (s16) le16_to_cpu(buf[2]); 25262306a36Sopenharmony_ci axis->z = ac->saved.z; 25362306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void adxl34x_service_ev_fifo(struct adxl34x *ac) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct adxl34x_platform_data *pdata = &ac->pdata; 25962306a36Sopenharmony_ci struct axis_triple axis; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci adxl34x_get_triple(ac, &axis); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_x, 26462306a36Sopenharmony_ci axis.x - ac->swcal.x); 26562306a36Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_y, 26662306a36Sopenharmony_ci axis.y - ac->swcal.y); 26762306a36Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_z, 26862306a36Sopenharmony_ci axis.z - ac->swcal.z); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void adxl34x_report_key_single(struct input_dev *input, int key) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci input_report_key(input, key, true); 27462306a36Sopenharmony_ci input_sync(input); 27562306a36Sopenharmony_ci input_report_key(input, key, false); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void adxl34x_send_key_events(struct adxl34x *ac, 27962306a36Sopenharmony_ci struct adxl34x_platform_data *pdata, int status, int press) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci int i; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) { 28462306a36Sopenharmony_ci if (status & (1 << (ADXL_Z_AXIS - i))) 28562306a36Sopenharmony_ci input_report_key(ac->input, 28662306a36Sopenharmony_ci pdata->ev_code_tap[i], press); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void adxl34x_do_tap(struct adxl34x *ac, 29162306a36Sopenharmony_ci struct adxl34x_platform_data *pdata, int status) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci adxl34x_send_key_events(ac, pdata, status, true); 29462306a36Sopenharmony_ci input_sync(ac->input); 29562306a36Sopenharmony_ci adxl34x_send_key_events(ac, pdata, status, false); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic irqreturn_t adxl34x_irq(int irq, void *handle) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct adxl34x *ac = handle; 30162306a36Sopenharmony_ci struct adxl34x_platform_data *pdata = &ac->pdata; 30262306a36Sopenharmony_ci int int_stat, tap_stat, samples, orient, orient_code; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * ACT_TAP_STATUS should be read before clearing the interrupt 30662306a36Sopenharmony_ci * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN)) 31062306a36Sopenharmony_ci tap_stat = AC_READ(ac, ACT_TAP_STATUS); 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci tap_stat = 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci int_stat = AC_READ(ac, INT_SOURCE); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (int_stat & FREE_FALL) 31762306a36Sopenharmony_ci adxl34x_report_key_single(ac->input, pdata->ev_code_ff); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (int_stat & OVERRUN) 32062306a36Sopenharmony_ci dev_dbg(ac->dev, "OVERRUN\n"); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) { 32362306a36Sopenharmony_ci adxl34x_do_tap(ac, pdata, tap_stat); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (int_stat & DOUBLE_TAP) 32662306a36Sopenharmony_ci adxl34x_do_tap(ac, pdata, tap_stat); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (pdata->ev_code_act_inactivity) { 33062306a36Sopenharmony_ci if (int_stat & ACTIVITY) 33162306a36Sopenharmony_ci input_report_key(ac->input, 33262306a36Sopenharmony_ci pdata->ev_code_act_inactivity, 1); 33362306a36Sopenharmony_ci if (int_stat & INACTIVITY) 33462306a36Sopenharmony_ci input_report_key(ac->input, 33562306a36Sopenharmony_ci pdata->ev_code_act_inactivity, 0); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * ORIENTATION SENSING ADXL346 only 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci if (pdata->orientation_enable) { 34262306a36Sopenharmony_ci orient = AC_READ(ac, ORIENT); 34362306a36Sopenharmony_ci if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) && 34462306a36Sopenharmony_ci (orient & ADXL346_2D_VALID)) { 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci orient_code = ADXL346_2D_ORIENT(orient); 34762306a36Sopenharmony_ci /* Report orientation only when it changes */ 34862306a36Sopenharmony_ci if (ac->orient2d_saved != orient_code) { 34962306a36Sopenharmony_ci ac->orient2d_saved = orient_code; 35062306a36Sopenharmony_ci adxl34x_report_key_single(ac->input, 35162306a36Sopenharmony_ci pdata->ev_codes_orient_2d[orient_code]); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) && 35662306a36Sopenharmony_ci (orient & ADXL346_3D_VALID)) { 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci orient_code = ADXL346_3D_ORIENT(orient) - 1; 35962306a36Sopenharmony_ci /* Report orientation only when it changes */ 36062306a36Sopenharmony_ci if (ac->orient3d_saved != orient_code) { 36162306a36Sopenharmony_ci ac->orient3d_saved = orient_code; 36262306a36Sopenharmony_ci adxl34x_report_key_single(ac->input, 36362306a36Sopenharmony_ci pdata->ev_codes_orient_3d[orient_code]); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (int_stat & (DATA_READY | WATERMARK)) { 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (pdata->fifo_mode) 37162306a36Sopenharmony_ci samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1; 37262306a36Sopenharmony_ci else 37362306a36Sopenharmony_ci samples = 1; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (; samples > 0; samples--) { 37662306a36Sopenharmony_ci adxl34x_service_ev_fifo(ac); 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * To ensure that the FIFO has 37962306a36Sopenharmony_ci * completely popped, there must be at least 5 us between 38062306a36Sopenharmony_ci * the end of reading the data registers, signified by the 38162306a36Sopenharmony_ci * transition to register 0x38 from 0x37 or the CS pin 38262306a36Sopenharmony_ci * going high, and the start of new reads of the FIFO or 38362306a36Sopenharmony_ci * reading the FIFO_STATUS register. For SPI operation at 38462306a36Sopenharmony_ci * 1.5 MHz or lower, the register addressing portion of the 38562306a36Sopenharmony_ci * transmission is sufficient delay to ensure the FIFO has 38662306a36Sopenharmony_ci * completely popped. It is necessary for SPI operation 38762306a36Sopenharmony_ci * greater than 1.5 MHz to de-assert the CS pin to ensure a 38862306a36Sopenharmony_ci * total of 5 us, which is at most 3.4 us at 5 MHz 38962306a36Sopenharmony_ci * operation. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci if (ac->fifo_delay && (samples > 1)) 39262306a36Sopenharmony_ci udelay(3); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci input_sync(ac->input); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return IRQ_HANDLED; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void __adxl34x_disable(struct adxl34x *ac) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * A '0' places the ADXL34x into standby mode 40562306a36Sopenharmony_ci * with minimum power consumption. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci AC_WRITE(ac, POWER_CTL, 0); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void __adxl34x_enable(struct adxl34x *ac) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int adxl34x_suspend(struct device *dev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci mutex_lock(&ac->mutex); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!ac->suspended && !ac->disabled && ac->opened) 42262306a36Sopenharmony_ci __adxl34x_disable(ac); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ac->suspended = true; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int adxl34x_resume(struct device *dev) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci mutex_lock(&ac->mutex); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (ac->suspended && !ac->disabled && ac->opened) 43862306a36Sopenharmony_ci __adxl34x_enable(ac); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ac->suspended = false; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic ssize_t adxl34x_disable_show(struct device *dev, 44862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return sprintf(buf, "%u\n", ac->disabled); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic ssize_t adxl34x_disable_store(struct device *dev, 45662306a36Sopenharmony_ci struct device_attribute *attr, 45762306a36Sopenharmony_ci const char *buf, size_t count) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 46062306a36Sopenharmony_ci unsigned int val; 46162306a36Sopenharmony_ci int error; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci error = kstrtouint(buf, 10, &val); 46462306a36Sopenharmony_ci if (error) 46562306a36Sopenharmony_ci return error; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mutex_lock(&ac->mutex); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!ac->suspended && ac->opened) { 47062306a36Sopenharmony_ci if (val) { 47162306a36Sopenharmony_ci if (!ac->disabled) 47262306a36Sopenharmony_ci __adxl34x_disable(ac); 47362306a36Sopenharmony_ci } else { 47462306a36Sopenharmony_ci if (ac->disabled) 47562306a36Sopenharmony_ci __adxl34x_enable(ac); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ac->disabled = !!val; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return count; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic ssize_t adxl34x_calibrate_show(struct device *dev, 48962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 49262306a36Sopenharmony_ci ssize_t count; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci mutex_lock(&ac->mutex); 49562306a36Sopenharmony_ci count = sprintf(buf, "%d,%d,%d\n", 49662306a36Sopenharmony_ci ac->hwcal.x * 4 + ac->swcal.x, 49762306a36Sopenharmony_ci ac->hwcal.y * 4 + ac->swcal.y, 49862306a36Sopenharmony_ci ac->hwcal.z * 4 + ac->swcal.z); 49962306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return count; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic ssize_t adxl34x_calibrate_store(struct device *dev, 50562306a36Sopenharmony_ci struct device_attribute *attr, 50662306a36Sopenharmony_ci const char *buf, size_t count) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * Hardware offset calibration has a resolution of 15.6 mg/LSB. 51262306a36Sopenharmony_ci * We use HW calibration and handle the remaining bits in SW. (4mg/LSB) 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci mutex_lock(&ac->mutex); 51662306a36Sopenharmony_ci ac->hwcal.x -= (ac->saved.x / 4); 51762306a36Sopenharmony_ci ac->swcal.x = ac->saved.x % 4; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci ac->hwcal.y -= (ac->saved.y / 4); 52062306a36Sopenharmony_ci ac->swcal.y = ac->saved.y % 4; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci ac->hwcal.z -= (ac->saved.z / 4); 52362306a36Sopenharmony_ci ac->swcal.z = ac->saved.z % 4; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci AC_WRITE(ac, OFSX, (s8) ac->hwcal.x); 52662306a36Sopenharmony_ci AC_WRITE(ac, OFSY, (s8) ac->hwcal.y); 52762306a36Sopenharmony_ci AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z); 52862306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return count; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic DEVICE_ATTR(calibrate, 0664, 53462306a36Sopenharmony_ci adxl34x_calibrate_show, adxl34x_calibrate_store); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic ssize_t adxl34x_rate_show(struct device *dev, 53762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate)); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic ssize_t adxl34x_rate_store(struct device *dev, 54562306a36Sopenharmony_ci struct device_attribute *attr, 54662306a36Sopenharmony_ci const char *buf, size_t count) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 54962306a36Sopenharmony_ci unsigned char val; 55062306a36Sopenharmony_ci int error; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci error = kstrtou8(buf, 10, &val); 55362306a36Sopenharmony_ci if (error) 55462306a36Sopenharmony_ci return error; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci mutex_lock(&ac->mutex); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ac->pdata.data_rate = RATE(val); 55962306a36Sopenharmony_ci AC_WRITE(ac, BW_RATE, 56062306a36Sopenharmony_ci ac->pdata.data_rate | 56162306a36Sopenharmony_ci (ac->pdata.low_power_mode ? LOW_POWER : 0)); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return count; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic ssize_t adxl34x_autosleep_show(struct device *dev, 57162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return sprintf(buf, "%u\n", 57662306a36Sopenharmony_ci ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic ssize_t adxl34x_autosleep_store(struct device *dev, 58062306a36Sopenharmony_ci struct device_attribute *attr, 58162306a36Sopenharmony_ci const char *buf, size_t count) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 58462306a36Sopenharmony_ci unsigned int val; 58562306a36Sopenharmony_ci int error; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci error = kstrtouint(buf, 10, &val); 58862306a36Sopenharmony_ci if (error) 58962306a36Sopenharmony_ci return error; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci mutex_lock(&ac->mutex); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (val) 59462306a36Sopenharmony_ci ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK); 59562306a36Sopenharmony_ci else 59662306a36Sopenharmony_ci ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (!ac->disabled && !ac->suspended && ac->opened) 59962306a36Sopenharmony_ci AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return count; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic DEVICE_ATTR(autosleep, 0664, 60762306a36Sopenharmony_ci adxl34x_autosleep_show, adxl34x_autosleep_store); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic ssize_t adxl34x_position_show(struct device *dev, 61062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 61362306a36Sopenharmony_ci ssize_t count; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci mutex_lock(&ac->mutex); 61662306a36Sopenharmony_ci count = sprintf(buf, "(%d, %d, %d)\n", 61762306a36Sopenharmony_ci ac->saved.x, ac->saved.y, ac->saved.z); 61862306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return count; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci#ifdef ADXL_DEBUG 62662306a36Sopenharmony_cistatic ssize_t adxl34x_write_store(struct device *dev, 62762306a36Sopenharmony_ci struct device_attribute *attr, 62862306a36Sopenharmony_ci const char *buf, size_t count) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 63162306a36Sopenharmony_ci unsigned int val; 63262306a36Sopenharmony_ci int error; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* 63562306a36Sopenharmony_ci * This allows basic ADXL register write access for debug purposes. 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci error = kstrtouint(buf, 16, &val); 63862306a36Sopenharmony_ci if (error) 63962306a36Sopenharmony_ci return error; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mutex_lock(&ac->mutex); 64262306a36Sopenharmony_ci AC_WRITE(ac, val >> 8, val & 0xFF); 64362306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return count; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store); 64962306a36Sopenharmony_ci#endif 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic struct attribute *adxl34x_attributes[] = { 65262306a36Sopenharmony_ci &dev_attr_disable.attr, 65362306a36Sopenharmony_ci &dev_attr_calibrate.attr, 65462306a36Sopenharmony_ci &dev_attr_rate.attr, 65562306a36Sopenharmony_ci &dev_attr_autosleep.attr, 65662306a36Sopenharmony_ci &dev_attr_position.attr, 65762306a36Sopenharmony_ci#ifdef ADXL_DEBUG 65862306a36Sopenharmony_ci &dev_attr_write.attr, 65962306a36Sopenharmony_ci#endif 66062306a36Sopenharmony_ci NULL 66162306a36Sopenharmony_ci}; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic const struct attribute_group adxl34x_attr_group = { 66462306a36Sopenharmony_ci .attrs = adxl34x_attributes, 66562306a36Sopenharmony_ci}; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic int adxl34x_input_open(struct input_dev *input) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct adxl34x *ac = input_get_drvdata(input); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci mutex_lock(&ac->mutex); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!ac->suspended && !ac->disabled) 67462306a36Sopenharmony_ci __adxl34x_enable(ac); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ac->opened = true; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void adxl34x_input_close(struct input_dev *input) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct adxl34x *ac = input_get_drvdata(input); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci mutex_lock(&ac->mutex); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (!ac->suspended && !ac->disabled) 69062306a36Sopenharmony_ci __adxl34x_disable(ac); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ac->opened = false; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci mutex_unlock(&ac->mutex); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistruct adxl34x *adxl34x_probe(struct device *dev, int irq, 69862306a36Sopenharmony_ci bool fifo_delay_default, 69962306a36Sopenharmony_ci const struct adxl34x_bus_ops *bops) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct adxl34x *ac; 70262306a36Sopenharmony_ci struct input_dev *input_dev; 70362306a36Sopenharmony_ci const struct adxl34x_platform_data *pdata; 70462306a36Sopenharmony_ci int err, range, i; 70562306a36Sopenharmony_ci int revid; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (!irq) { 70862306a36Sopenharmony_ci dev_err(dev, "no IRQ?\n"); 70962306a36Sopenharmony_ci err = -ENODEV; 71062306a36Sopenharmony_ci goto err_out; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci ac = kzalloc(sizeof(*ac), GFP_KERNEL); 71462306a36Sopenharmony_ci input_dev = input_allocate_device(); 71562306a36Sopenharmony_ci if (!ac || !input_dev) { 71662306a36Sopenharmony_ci err = -ENOMEM; 71762306a36Sopenharmony_ci goto err_free_mem; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ac->fifo_delay = fifo_delay_default; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci pdata = dev_get_platdata(dev); 72362306a36Sopenharmony_ci if (!pdata) { 72462306a36Sopenharmony_ci dev_dbg(dev, 72562306a36Sopenharmony_ci "No platform data: Using default initialization\n"); 72662306a36Sopenharmony_ci pdata = &adxl34x_default_init; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ac->pdata = *pdata; 73062306a36Sopenharmony_ci pdata = &ac->pdata; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci ac->input = input_dev; 73362306a36Sopenharmony_ci ac->dev = dev; 73462306a36Sopenharmony_ci ac->irq = irq; 73562306a36Sopenharmony_ci ac->bops = bops; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mutex_init(&ac->mutex); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci input_dev->name = "ADXL34x accelerometer"; 74062306a36Sopenharmony_ci revid = AC_READ(ac, DEVID); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci switch (revid) { 74362306a36Sopenharmony_ci case ID_ADXL345: 74462306a36Sopenharmony_ci ac->model = 345; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case ID_ADXL346: 74762306a36Sopenharmony_ci ac->model = 346; 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci default: 75062306a36Sopenharmony_ci dev_err(dev, "Failed to probe %s\n", input_dev->name); 75162306a36Sopenharmony_ci err = -ENODEV; 75262306a36Sopenharmony_ci goto err_free_mem; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev)); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci input_dev->phys = ac->phys; 75862306a36Sopenharmony_ci input_dev->dev.parent = dev; 75962306a36Sopenharmony_ci input_dev->id.product = ac->model; 76062306a36Sopenharmony_ci input_dev->id.bustype = bops->bustype; 76162306a36Sopenharmony_ci input_dev->open = adxl34x_input_open; 76262306a36Sopenharmony_ci input_dev->close = adxl34x_input_close; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci input_set_drvdata(input_dev, ac); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci __set_bit(ac->pdata.ev_type, input_dev->evbit); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (ac->pdata.ev_type == EV_REL) { 76962306a36Sopenharmony_ci __set_bit(REL_X, input_dev->relbit); 77062306a36Sopenharmony_ci __set_bit(REL_Y, input_dev->relbit); 77162306a36Sopenharmony_ci __set_bit(REL_Z, input_dev->relbit); 77262306a36Sopenharmony_ci } else { 77362306a36Sopenharmony_ci /* EV_ABS */ 77462306a36Sopenharmony_ci __set_bit(ABS_X, input_dev->absbit); 77562306a36Sopenharmony_ci __set_bit(ABS_Y, input_dev->absbit); 77662306a36Sopenharmony_ci __set_bit(ABS_Z, input_dev->absbit); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (pdata->data_range & FULL_RES) 77962306a36Sopenharmony_ci range = ADXL_FULLRES_MAX_VAL; /* Signed 13-bit */ 78062306a36Sopenharmony_ci else 78162306a36Sopenharmony_ci range = ADXL_FIXEDRES_MAX_VAL; /* Signed 10-bit */ 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3); 78462306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3); 78562306a36Sopenharmony_ci input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci __set_bit(EV_KEY, input_dev->evbit); 78962306a36Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit); 79062306a36Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit); 79162306a36Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (pdata->ev_code_ff) { 79462306a36Sopenharmony_ci ac->int_mask = FREE_FALL; 79562306a36Sopenharmony_ci __set_bit(pdata->ev_code_ff, input_dev->keybit); 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (pdata->ev_code_act_inactivity) 79962306a36Sopenharmony_ci __set_bit(pdata->ev_code_act_inactivity, input_dev->keybit); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ac->int_mask |= ACTIVITY | INACTIVITY; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (pdata->watermark) { 80462306a36Sopenharmony_ci ac->int_mask |= WATERMARK; 80562306a36Sopenharmony_ci if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS) 80662306a36Sopenharmony_ci ac->pdata.fifo_mode |= FIFO_STREAM; 80762306a36Sopenharmony_ci } else { 80862306a36Sopenharmony_ci ac->int_mask |= DATA_READY; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN)) 81262306a36Sopenharmony_ci ac->int_mask |= SINGLE_TAP | DOUBLE_TAP; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS) 81562306a36Sopenharmony_ci ac->fifo_delay = false; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci AC_WRITE(ac, POWER_CTL, 0); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci err = request_threaded_irq(ac->irq, NULL, adxl34x_irq, 82062306a36Sopenharmony_ci IRQF_ONESHOT, dev_name(dev), ac); 82162306a36Sopenharmony_ci if (err) { 82262306a36Sopenharmony_ci dev_err(dev, "irq %d busy?\n", ac->irq); 82362306a36Sopenharmony_ci goto err_free_mem; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group); 82762306a36Sopenharmony_ci if (err) 82862306a36Sopenharmony_ci goto err_free_irq; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci err = input_register_device(input_dev); 83162306a36Sopenharmony_ci if (err) 83262306a36Sopenharmony_ci goto err_remove_attr; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci AC_WRITE(ac, OFSX, pdata->x_axis_offset); 83562306a36Sopenharmony_ci ac->hwcal.x = pdata->x_axis_offset; 83662306a36Sopenharmony_ci AC_WRITE(ac, OFSY, pdata->y_axis_offset); 83762306a36Sopenharmony_ci ac->hwcal.y = pdata->y_axis_offset; 83862306a36Sopenharmony_ci AC_WRITE(ac, OFSZ, pdata->z_axis_offset); 83962306a36Sopenharmony_ci ac->hwcal.z = pdata->z_axis_offset; 84062306a36Sopenharmony_ci AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold); 84162306a36Sopenharmony_ci AC_WRITE(ac, DUR, pdata->tap_duration); 84262306a36Sopenharmony_ci AC_WRITE(ac, LATENT, pdata->tap_latency); 84362306a36Sopenharmony_ci AC_WRITE(ac, WINDOW, pdata->tap_window); 84462306a36Sopenharmony_ci AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold); 84562306a36Sopenharmony_ci AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold); 84662306a36Sopenharmony_ci AC_WRITE(ac, TIME_INACT, pdata->inactivity_time); 84762306a36Sopenharmony_ci AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold); 84862306a36Sopenharmony_ci AC_WRITE(ac, TIME_FF, pdata->free_fall_time); 84962306a36Sopenharmony_ci AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control); 85062306a36Sopenharmony_ci AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control); 85162306a36Sopenharmony_ci AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) | 85262306a36Sopenharmony_ci (pdata->low_power_mode ? LOW_POWER : 0)); 85362306a36Sopenharmony_ci AC_WRITE(ac, DATA_FORMAT, pdata->data_range); 85462306a36Sopenharmony_ci AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) | 85562306a36Sopenharmony_ci SAMPLES(pdata->watermark)); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (pdata->use_int2) { 85862306a36Sopenharmony_ci /* Map all INTs to INT2 */ 85962306a36Sopenharmony_ci AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN); 86062306a36Sopenharmony_ci } else { 86162306a36Sopenharmony_ci /* Map all INTs to INT1 */ 86262306a36Sopenharmony_ci AC_WRITE(ac, INT_MAP, 0); 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (ac->model == 346 && ac->pdata.orientation_enable) { 86662306a36Sopenharmony_ci AC_WRITE(ac, ORIENT_CONF, 86762306a36Sopenharmony_ci ORIENT_DEADZONE(ac->pdata.deadzone_angle) | 86862306a36Sopenharmony_ci ORIENT_DIVISOR(ac->pdata.divisor_length)); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ac->orient2d_saved = 1234; 87162306a36Sopenharmony_ci ac->orient3d_saved = 1234; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) 87462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++) 87562306a36Sopenharmony_ci __set_bit(pdata->ev_codes_orient_3d[i], 87662306a36Sopenharmony_ci input_dev->keybit); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) 87962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++) 88062306a36Sopenharmony_ci __set_bit(pdata->ev_codes_orient_2d[i], 88162306a36Sopenharmony_ci input_dev->keybit); 88262306a36Sopenharmony_ci } else { 88362306a36Sopenharmony_ci ac->pdata.orientation_enable = 0; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci return ac; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci err_remove_attr: 89362306a36Sopenharmony_ci sysfs_remove_group(&dev->kobj, &adxl34x_attr_group); 89462306a36Sopenharmony_ci err_free_irq: 89562306a36Sopenharmony_ci free_irq(ac->irq, ac); 89662306a36Sopenharmony_ci err_free_mem: 89762306a36Sopenharmony_ci input_free_device(input_dev); 89862306a36Sopenharmony_ci kfree(ac); 89962306a36Sopenharmony_ci err_out: 90062306a36Sopenharmony_ci return ERR_PTR(err); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_probe); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_civoid adxl34x_remove(struct adxl34x *ac) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group); 90762306a36Sopenharmony_ci free_irq(ac->irq, ac); 90862306a36Sopenharmony_ci input_unregister_device(ac->input); 90962306a36Sopenharmony_ci dev_dbg(ac->dev, "unregistered accelerometer\n"); 91062306a36Sopenharmony_ci kfree(ac); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_remove); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ciEXPORT_GPL_SIMPLE_DEV_PM_OPS(adxl34x_pm, adxl34x_suspend, adxl34x_resume); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 91762306a36Sopenharmony_ciMODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver"); 91862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 919