18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADXL345/346 Three-Axis Digital Accelerometers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Enter bugs at http://blackfin.uclinux.org/ 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/input.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci#include <linux/input/adxl34x.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "adxl34x.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* ADXL345/6 Register Map */ 238c2ecf20Sopenharmony_ci#define DEVID 0x00 /* R Device ID */ 248c2ecf20Sopenharmony_ci#define THRESH_TAP 0x1D /* R/W Tap threshold */ 258c2ecf20Sopenharmony_ci#define OFSX 0x1E /* R/W X-axis offset */ 268c2ecf20Sopenharmony_ci#define OFSY 0x1F /* R/W Y-axis offset */ 278c2ecf20Sopenharmony_ci#define OFSZ 0x20 /* R/W Z-axis offset */ 288c2ecf20Sopenharmony_ci#define DUR 0x21 /* R/W Tap duration */ 298c2ecf20Sopenharmony_ci#define LATENT 0x22 /* R/W Tap latency */ 308c2ecf20Sopenharmony_ci#define WINDOW 0x23 /* R/W Tap window */ 318c2ecf20Sopenharmony_ci#define THRESH_ACT 0x24 /* R/W Activity threshold */ 328c2ecf20Sopenharmony_ci#define THRESH_INACT 0x25 /* R/W Inactivity threshold */ 338c2ecf20Sopenharmony_ci#define TIME_INACT 0x26 /* R/W Inactivity time */ 348c2ecf20Sopenharmony_ci#define ACT_INACT_CTL 0x27 /* R/W Axis enable control for activity and */ 358c2ecf20Sopenharmony_ci /* inactivity detection */ 368c2ecf20Sopenharmony_ci#define THRESH_FF 0x28 /* R/W Free-fall threshold */ 378c2ecf20Sopenharmony_ci#define TIME_FF 0x29 /* R/W Free-fall time */ 388c2ecf20Sopenharmony_ci#define TAP_AXES 0x2A /* R/W Axis control for tap/double tap */ 398c2ecf20Sopenharmony_ci#define ACT_TAP_STATUS 0x2B /* R Source of tap/double tap */ 408c2ecf20Sopenharmony_ci#define BW_RATE 0x2C /* R/W Data rate and power mode control */ 418c2ecf20Sopenharmony_ci#define POWER_CTL 0x2D /* R/W Power saving features control */ 428c2ecf20Sopenharmony_ci#define INT_ENABLE 0x2E /* R/W Interrupt enable control */ 438c2ecf20Sopenharmony_ci#define INT_MAP 0x2F /* R/W Interrupt mapping control */ 448c2ecf20Sopenharmony_ci#define INT_SOURCE 0x30 /* R Source of interrupts */ 458c2ecf20Sopenharmony_ci#define DATA_FORMAT 0x31 /* R/W Data format control */ 468c2ecf20Sopenharmony_ci#define DATAX0 0x32 /* R X-Axis Data 0 */ 478c2ecf20Sopenharmony_ci#define DATAX1 0x33 /* R X-Axis Data 1 */ 488c2ecf20Sopenharmony_ci#define DATAY0 0x34 /* R Y-Axis Data 0 */ 498c2ecf20Sopenharmony_ci#define DATAY1 0x35 /* R Y-Axis Data 1 */ 508c2ecf20Sopenharmony_ci#define DATAZ0 0x36 /* R Z-Axis Data 0 */ 518c2ecf20Sopenharmony_ci#define DATAZ1 0x37 /* R Z-Axis Data 1 */ 528c2ecf20Sopenharmony_ci#define FIFO_CTL 0x38 /* R/W FIFO control */ 538c2ecf20Sopenharmony_ci#define FIFO_STATUS 0x39 /* R FIFO status */ 548c2ecf20Sopenharmony_ci#define TAP_SIGN 0x3A /* R Sign and source for tap/double tap */ 558c2ecf20Sopenharmony_ci/* Orientation ADXL346 only */ 568c2ecf20Sopenharmony_ci#define ORIENT_CONF 0x3B /* R/W Orientation configuration */ 578c2ecf20Sopenharmony_ci#define ORIENT 0x3C /* R Orientation status */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* DEVIDs */ 608c2ecf20Sopenharmony_ci#define ID_ADXL345 0xE5 618c2ecf20Sopenharmony_ci#define ID_ADXL346 0xE6 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */ 648c2ecf20Sopenharmony_ci#define DATA_READY (1 << 7) 658c2ecf20Sopenharmony_ci#define SINGLE_TAP (1 << 6) 668c2ecf20Sopenharmony_ci#define DOUBLE_TAP (1 << 5) 678c2ecf20Sopenharmony_ci#define ACTIVITY (1 << 4) 688c2ecf20Sopenharmony_ci#define INACTIVITY (1 << 3) 698c2ecf20Sopenharmony_ci#define FREE_FALL (1 << 2) 708c2ecf20Sopenharmony_ci#define WATERMARK (1 << 1) 718c2ecf20Sopenharmony_ci#define OVERRUN (1 << 0) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* ACT_INACT_CONTROL Bits */ 748c2ecf20Sopenharmony_ci#define ACT_ACDC (1 << 7) 758c2ecf20Sopenharmony_ci#define ACT_X_EN (1 << 6) 768c2ecf20Sopenharmony_ci#define ACT_Y_EN (1 << 5) 778c2ecf20Sopenharmony_ci#define ACT_Z_EN (1 << 4) 788c2ecf20Sopenharmony_ci#define INACT_ACDC (1 << 3) 798c2ecf20Sopenharmony_ci#define INACT_X_EN (1 << 2) 808c2ecf20Sopenharmony_ci#define INACT_Y_EN (1 << 1) 818c2ecf20Sopenharmony_ci#define INACT_Z_EN (1 << 0) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* TAP_AXES Bits */ 848c2ecf20Sopenharmony_ci#define SUPPRESS (1 << 3) 858c2ecf20Sopenharmony_ci#define TAP_X_EN (1 << 2) 868c2ecf20Sopenharmony_ci#define TAP_Y_EN (1 << 1) 878c2ecf20Sopenharmony_ci#define TAP_Z_EN (1 << 0) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* ACT_TAP_STATUS Bits */ 908c2ecf20Sopenharmony_ci#define ACT_X_SRC (1 << 6) 918c2ecf20Sopenharmony_ci#define ACT_Y_SRC (1 << 5) 928c2ecf20Sopenharmony_ci#define ACT_Z_SRC (1 << 4) 938c2ecf20Sopenharmony_ci#define ASLEEP (1 << 3) 948c2ecf20Sopenharmony_ci#define TAP_X_SRC (1 << 2) 958c2ecf20Sopenharmony_ci#define TAP_Y_SRC (1 << 1) 968c2ecf20Sopenharmony_ci#define TAP_Z_SRC (1 << 0) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* BW_RATE Bits */ 998c2ecf20Sopenharmony_ci#define LOW_POWER (1 << 4) 1008c2ecf20Sopenharmony_ci#define RATE(x) ((x) & 0xF) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* POWER_CTL Bits */ 1038c2ecf20Sopenharmony_ci#define PCTL_LINK (1 << 5) 1048c2ecf20Sopenharmony_ci#define PCTL_AUTO_SLEEP (1 << 4) 1058c2ecf20Sopenharmony_ci#define PCTL_MEASURE (1 << 3) 1068c2ecf20Sopenharmony_ci#define PCTL_SLEEP (1 << 2) 1078c2ecf20Sopenharmony_ci#define PCTL_WAKEUP(x) ((x) & 0x3) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* DATA_FORMAT Bits */ 1108c2ecf20Sopenharmony_ci#define SELF_TEST (1 << 7) 1118c2ecf20Sopenharmony_ci#define SPI (1 << 6) 1128c2ecf20Sopenharmony_ci#define INT_INVERT (1 << 5) 1138c2ecf20Sopenharmony_ci#define FULL_RES (1 << 3) 1148c2ecf20Sopenharmony_ci#define JUSTIFY (1 << 2) 1158c2ecf20Sopenharmony_ci#define RANGE(x) ((x) & 0x3) 1168c2ecf20Sopenharmony_ci#define RANGE_PM_2g 0 1178c2ecf20Sopenharmony_ci#define RANGE_PM_4g 1 1188c2ecf20Sopenharmony_ci#define RANGE_PM_8g 2 1198c2ecf20Sopenharmony_ci#define RANGE_PM_16g 3 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * Maximum value our axis may get in full res mode for the input device 1238c2ecf20Sopenharmony_ci * (signed 13 bits) 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci#define ADXL_FULLRES_MAX_VAL 4096 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * Maximum value our axis may get in fixed res mode for the input device 1298c2ecf20Sopenharmony_ci * (signed 10 bits) 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci#define ADXL_FIXEDRES_MAX_VAL 512 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* FIFO_CTL Bits */ 1348c2ecf20Sopenharmony_ci#define FIFO_MODE(x) (((x) & 0x3) << 6) 1358c2ecf20Sopenharmony_ci#define FIFO_BYPASS 0 1368c2ecf20Sopenharmony_ci#define FIFO_FIFO 1 1378c2ecf20Sopenharmony_ci#define FIFO_STREAM 2 1388c2ecf20Sopenharmony_ci#define FIFO_TRIGGER 3 1398c2ecf20Sopenharmony_ci#define TRIGGER (1 << 5) 1408c2ecf20Sopenharmony_ci#define SAMPLES(x) ((x) & 0x1F) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* FIFO_STATUS Bits */ 1438c2ecf20Sopenharmony_ci#define FIFO_TRIG (1 << 7) 1448c2ecf20Sopenharmony_ci#define ENTRIES(x) ((x) & 0x3F) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* TAP_SIGN Bits ADXL346 only */ 1478c2ecf20Sopenharmony_ci#define XSIGN (1 << 6) 1488c2ecf20Sopenharmony_ci#define YSIGN (1 << 5) 1498c2ecf20Sopenharmony_ci#define ZSIGN (1 << 4) 1508c2ecf20Sopenharmony_ci#define XTAP (1 << 3) 1518c2ecf20Sopenharmony_ci#define YTAP (1 << 2) 1528c2ecf20Sopenharmony_ci#define ZTAP (1 << 1) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* ORIENT_CONF ADXL346 only */ 1558c2ecf20Sopenharmony_ci#define ORIENT_DEADZONE(x) (((x) & 0x7) << 4) 1568c2ecf20Sopenharmony_ci#define ORIENT_DIVISOR(x) ((x) & 0x7) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* ORIENT ADXL346 only */ 1598c2ecf20Sopenharmony_ci#define ADXL346_2D_VALID (1 << 6) 1608c2ecf20Sopenharmony_ci#define ADXL346_2D_ORIENT(x) (((x) & 0x30) >> 4) 1618c2ecf20Sopenharmony_ci#define ADXL346_3D_VALID (1 << 3) 1628c2ecf20Sopenharmony_ci#define ADXL346_3D_ORIENT(x) ((x) & 0x7) 1638c2ecf20Sopenharmony_ci#define ADXL346_2D_PORTRAIT_POS 0 /* +X */ 1648c2ecf20Sopenharmony_ci#define ADXL346_2D_PORTRAIT_NEG 1 /* -X */ 1658c2ecf20Sopenharmony_ci#define ADXL346_2D_LANDSCAPE_POS 2 /* +Y */ 1668c2ecf20Sopenharmony_ci#define ADXL346_2D_LANDSCAPE_NEG 3 /* -Y */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define ADXL346_3D_FRONT 3 /* +X */ 1698c2ecf20Sopenharmony_ci#define ADXL346_3D_BACK 4 /* -X */ 1708c2ecf20Sopenharmony_ci#define ADXL346_3D_RIGHT 2 /* +Y */ 1718c2ecf20Sopenharmony_ci#define ADXL346_3D_LEFT 5 /* -Y */ 1728c2ecf20Sopenharmony_ci#define ADXL346_3D_TOP 1 /* +Z */ 1738c2ecf20Sopenharmony_ci#define ADXL346_3D_BOTTOM 6 /* -Z */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#undef ADXL_DEBUG 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define ADXL_X_AXIS 0 1788c2ecf20Sopenharmony_ci#define ADXL_Y_AXIS 1 1798c2ecf20Sopenharmony_ci#define ADXL_Z_AXIS 2 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define AC_READ(ac, reg) ((ac)->bops->read((ac)->dev, reg)) 1828c2ecf20Sopenharmony_ci#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val)) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistruct axis_triple { 1858c2ecf20Sopenharmony_ci int x; 1868c2ecf20Sopenharmony_ci int y; 1878c2ecf20Sopenharmony_ci int z; 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistruct adxl34x { 1918c2ecf20Sopenharmony_ci struct device *dev; 1928c2ecf20Sopenharmony_ci struct input_dev *input; 1938c2ecf20Sopenharmony_ci struct mutex mutex; /* reentrant protection for struct */ 1948c2ecf20Sopenharmony_ci struct adxl34x_platform_data pdata; 1958c2ecf20Sopenharmony_ci struct axis_triple swcal; 1968c2ecf20Sopenharmony_ci struct axis_triple hwcal; 1978c2ecf20Sopenharmony_ci struct axis_triple saved; 1988c2ecf20Sopenharmony_ci char phys[32]; 1998c2ecf20Sopenharmony_ci unsigned orient2d_saved; 2008c2ecf20Sopenharmony_ci unsigned orient3d_saved; 2018c2ecf20Sopenharmony_ci bool disabled; /* P: mutex */ 2028c2ecf20Sopenharmony_ci bool opened; /* P: mutex */ 2038c2ecf20Sopenharmony_ci bool suspended; /* P: mutex */ 2048c2ecf20Sopenharmony_ci bool fifo_delay; 2058c2ecf20Sopenharmony_ci int irq; 2068c2ecf20Sopenharmony_ci unsigned model; 2078c2ecf20Sopenharmony_ci unsigned int_mask; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci const struct adxl34x_bus_ops *bops; 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct adxl34x_platform_data adxl34x_default_init = { 2138c2ecf20Sopenharmony_ci .tap_threshold = 35, 2148c2ecf20Sopenharmony_ci .tap_duration = 3, 2158c2ecf20Sopenharmony_ci .tap_latency = 20, 2168c2ecf20Sopenharmony_ci .tap_window = 20, 2178c2ecf20Sopenharmony_ci .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN, 2188c2ecf20Sopenharmony_ci .act_axis_control = 0xFF, 2198c2ecf20Sopenharmony_ci .activity_threshold = 6, 2208c2ecf20Sopenharmony_ci .inactivity_threshold = 4, 2218c2ecf20Sopenharmony_ci .inactivity_time = 3, 2228c2ecf20Sopenharmony_ci .free_fall_threshold = 8, 2238c2ecf20Sopenharmony_ci .free_fall_time = 0x20, 2248c2ecf20Sopenharmony_ci .data_rate = 8, 2258c2ecf20Sopenharmony_ci .data_range = ADXL_FULL_RES, 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci .ev_type = EV_ABS, 2288c2ecf20Sopenharmony_ci .ev_code_x = ABS_X, /* EV_REL */ 2298c2ecf20Sopenharmony_ci .ev_code_y = ABS_Y, /* EV_REL */ 2308c2ecf20Sopenharmony_ci .ev_code_z = ABS_Z, /* EV_REL */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci .ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */ 2338c2ecf20Sopenharmony_ci .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK, 2348c2ecf20Sopenharmony_ci .fifo_mode = ADXL_FIFO_STREAM, 2358c2ecf20Sopenharmony_ci .watermark = 0, 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci short buf[3]; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 2458c2ecf20Sopenharmony_ci ac->saved.x = (s16) le16_to_cpu(buf[0]); 2468c2ecf20Sopenharmony_ci axis->x = ac->saved.x; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ac->saved.y = (s16) le16_to_cpu(buf[1]); 2498c2ecf20Sopenharmony_ci axis->y = ac->saved.y; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ac->saved.z = (s16) le16_to_cpu(buf[2]); 2528c2ecf20Sopenharmony_ci axis->z = ac->saved.z; 2538c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void adxl34x_service_ev_fifo(struct adxl34x *ac) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct adxl34x_platform_data *pdata = &ac->pdata; 2598c2ecf20Sopenharmony_ci struct axis_triple axis; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci adxl34x_get_triple(ac, &axis); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_x, 2648c2ecf20Sopenharmony_ci axis.x - ac->swcal.x); 2658c2ecf20Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_y, 2668c2ecf20Sopenharmony_ci axis.y - ac->swcal.y); 2678c2ecf20Sopenharmony_ci input_event(ac->input, pdata->ev_type, pdata->ev_code_z, 2688c2ecf20Sopenharmony_ci axis.z - ac->swcal.z); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void adxl34x_report_key_single(struct input_dev *input, int key) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci input_report_key(input, key, true); 2748c2ecf20Sopenharmony_ci input_sync(input); 2758c2ecf20Sopenharmony_ci input_report_key(input, key, false); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void adxl34x_send_key_events(struct adxl34x *ac, 2798c2ecf20Sopenharmony_ci struct adxl34x_platform_data *pdata, int status, int press) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci int i; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) { 2848c2ecf20Sopenharmony_ci if (status & (1 << (ADXL_Z_AXIS - i))) 2858c2ecf20Sopenharmony_ci input_report_key(ac->input, 2868c2ecf20Sopenharmony_ci pdata->ev_code_tap[i], press); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void adxl34x_do_tap(struct adxl34x *ac, 2918c2ecf20Sopenharmony_ci struct adxl34x_platform_data *pdata, int status) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci adxl34x_send_key_events(ac, pdata, status, true); 2948c2ecf20Sopenharmony_ci input_sync(ac->input); 2958c2ecf20Sopenharmony_ci adxl34x_send_key_events(ac, pdata, status, false); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic irqreturn_t adxl34x_irq(int irq, void *handle) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct adxl34x *ac = handle; 3018c2ecf20Sopenharmony_ci struct adxl34x_platform_data *pdata = &ac->pdata; 3028c2ecf20Sopenharmony_ci int int_stat, tap_stat, samples, orient, orient_code; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * ACT_TAP_STATUS should be read before clearing the interrupt 3068c2ecf20Sopenharmony_ci * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN)) 3108c2ecf20Sopenharmony_ci tap_stat = AC_READ(ac, ACT_TAP_STATUS); 3118c2ecf20Sopenharmony_ci else 3128c2ecf20Sopenharmony_ci tap_stat = 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci int_stat = AC_READ(ac, INT_SOURCE); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (int_stat & FREE_FALL) 3178c2ecf20Sopenharmony_ci adxl34x_report_key_single(ac->input, pdata->ev_code_ff); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (int_stat & OVERRUN) 3208c2ecf20Sopenharmony_ci dev_dbg(ac->dev, "OVERRUN\n"); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) { 3238c2ecf20Sopenharmony_ci adxl34x_do_tap(ac, pdata, tap_stat); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (int_stat & DOUBLE_TAP) 3268c2ecf20Sopenharmony_ci adxl34x_do_tap(ac, pdata, tap_stat); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pdata->ev_code_act_inactivity) { 3308c2ecf20Sopenharmony_ci if (int_stat & ACTIVITY) 3318c2ecf20Sopenharmony_ci input_report_key(ac->input, 3328c2ecf20Sopenharmony_ci pdata->ev_code_act_inactivity, 1); 3338c2ecf20Sopenharmony_ci if (int_stat & INACTIVITY) 3348c2ecf20Sopenharmony_ci input_report_key(ac->input, 3358c2ecf20Sopenharmony_ci pdata->ev_code_act_inactivity, 0); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * ORIENTATION SENSING ADXL346 only 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci if (pdata->orientation_enable) { 3428c2ecf20Sopenharmony_ci orient = AC_READ(ac, ORIENT); 3438c2ecf20Sopenharmony_ci if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) && 3448c2ecf20Sopenharmony_ci (orient & ADXL346_2D_VALID)) { 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci orient_code = ADXL346_2D_ORIENT(orient); 3478c2ecf20Sopenharmony_ci /* Report orientation only when it changes */ 3488c2ecf20Sopenharmony_ci if (ac->orient2d_saved != orient_code) { 3498c2ecf20Sopenharmony_ci ac->orient2d_saved = orient_code; 3508c2ecf20Sopenharmony_ci adxl34x_report_key_single(ac->input, 3518c2ecf20Sopenharmony_ci pdata->ev_codes_orient_2d[orient_code]); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) && 3568c2ecf20Sopenharmony_ci (orient & ADXL346_3D_VALID)) { 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci orient_code = ADXL346_3D_ORIENT(orient) - 1; 3598c2ecf20Sopenharmony_ci /* Report orientation only when it changes */ 3608c2ecf20Sopenharmony_ci if (ac->orient3d_saved != orient_code) { 3618c2ecf20Sopenharmony_ci ac->orient3d_saved = orient_code; 3628c2ecf20Sopenharmony_ci adxl34x_report_key_single(ac->input, 3638c2ecf20Sopenharmony_ci pdata->ev_codes_orient_3d[orient_code]); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (int_stat & (DATA_READY | WATERMARK)) { 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (pdata->fifo_mode) 3718c2ecf20Sopenharmony_ci samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1; 3728c2ecf20Sopenharmony_ci else 3738c2ecf20Sopenharmony_ci samples = 1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci for (; samples > 0; samples--) { 3768c2ecf20Sopenharmony_ci adxl34x_service_ev_fifo(ac); 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * To ensure that the FIFO has 3798c2ecf20Sopenharmony_ci * completely popped, there must be at least 5 us between 3808c2ecf20Sopenharmony_ci * the end of reading the data registers, signified by the 3818c2ecf20Sopenharmony_ci * transition to register 0x38 from 0x37 or the CS pin 3828c2ecf20Sopenharmony_ci * going high, and the start of new reads of the FIFO or 3838c2ecf20Sopenharmony_ci * reading the FIFO_STATUS register. For SPI operation at 3848c2ecf20Sopenharmony_ci * 1.5 MHz or lower, the register addressing portion of the 3858c2ecf20Sopenharmony_ci * transmission is sufficient delay to ensure the FIFO has 3868c2ecf20Sopenharmony_ci * completely popped. It is necessary for SPI operation 3878c2ecf20Sopenharmony_ci * greater than 1.5 MHz to de-assert the CS pin to ensure a 3888c2ecf20Sopenharmony_ci * total of 5 us, which is at most 3.4 us at 5 MHz 3898c2ecf20Sopenharmony_ci * operation. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci if (ac->fifo_delay && (samples > 1)) 3928c2ecf20Sopenharmony_ci udelay(3); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci input_sync(ac->input); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void __adxl34x_disable(struct adxl34x *ac) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci /* 4048c2ecf20Sopenharmony_ci * A '0' places the ADXL34x into standby mode 4058c2ecf20Sopenharmony_ci * with minimum power consumption. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ci AC_WRITE(ac, POWER_CTL, 0); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void __adxl34x_enable(struct adxl34x *ac) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_civoid adxl34x_suspend(struct adxl34x *ac) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!ac->suspended && !ac->disabled && ac->opened) 4208c2ecf20Sopenharmony_ci __adxl34x_disable(ac); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ac->suspended = true; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_suspend); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_civoid adxl34x_resume(struct adxl34x *ac) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (ac->suspended && !ac->disabled && ac->opened) 4338c2ecf20Sopenharmony_ci __adxl34x_enable(ac); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ac->suspended = false; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_resume); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic ssize_t adxl34x_disable_show(struct device *dev, 4428c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", ac->disabled); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic ssize_t adxl34x_disable_store(struct device *dev, 4508c2ecf20Sopenharmony_ci struct device_attribute *attr, 4518c2ecf20Sopenharmony_ci const char *buf, size_t count) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 4548c2ecf20Sopenharmony_ci unsigned int val; 4558c2ecf20Sopenharmony_ci int error; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 4588c2ecf20Sopenharmony_ci if (error) 4598c2ecf20Sopenharmony_ci return error; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (!ac->suspended && ac->opened) { 4648c2ecf20Sopenharmony_ci if (val) { 4658c2ecf20Sopenharmony_ci if (!ac->disabled) 4668c2ecf20Sopenharmony_ci __adxl34x_disable(ac); 4678c2ecf20Sopenharmony_ci } else { 4688c2ecf20Sopenharmony_ci if (ac->disabled) 4698c2ecf20Sopenharmony_ci __adxl34x_enable(ac); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ac->disabled = !!val; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return count; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic ssize_t adxl34x_calibrate_show(struct device *dev, 4838c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 4868c2ecf20Sopenharmony_ci ssize_t count; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 4898c2ecf20Sopenharmony_ci count = sprintf(buf, "%d,%d,%d\n", 4908c2ecf20Sopenharmony_ci ac->hwcal.x * 4 + ac->swcal.x, 4918c2ecf20Sopenharmony_ci ac->hwcal.y * 4 + ac->swcal.y, 4928c2ecf20Sopenharmony_ci ac->hwcal.z * 4 + ac->swcal.z); 4938c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return count; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic ssize_t adxl34x_calibrate_store(struct device *dev, 4998c2ecf20Sopenharmony_ci struct device_attribute *attr, 5008c2ecf20Sopenharmony_ci const char *buf, size_t count) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* 5058c2ecf20Sopenharmony_ci * Hardware offset calibration has a resolution of 15.6 mg/LSB. 5068c2ecf20Sopenharmony_ci * We use HW calibration and handle the remaining bits in SW. (4mg/LSB) 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 5108c2ecf20Sopenharmony_ci ac->hwcal.x -= (ac->saved.x / 4); 5118c2ecf20Sopenharmony_ci ac->swcal.x = ac->saved.x % 4; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ac->hwcal.y -= (ac->saved.y / 4); 5148c2ecf20Sopenharmony_ci ac->swcal.y = ac->saved.y % 4; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ac->hwcal.z -= (ac->saved.z / 4); 5178c2ecf20Sopenharmony_ci ac->swcal.z = ac->saved.z % 4; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSX, (s8) ac->hwcal.x); 5208c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSY, (s8) ac->hwcal.y); 5218c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z); 5228c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return count; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic DEVICE_ATTR(calibrate, 0664, 5288c2ecf20Sopenharmony_ci adxl34x_calibrate_show, adxl34x_calibrate_store); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic ssize_t adxl34x_rate_show(struct device *dev, 5318c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate)); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic ssize_t adxl34x_rate_store(struct device *dev, 5398c2ecf20Sopenharmony_ci struct device_attribute *attr, 5408c2ecf20Sopenharmony_ci const char *buf, size_t count) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 5438c2ecf20Sopenharmony_ci unsigned char val; 5448c2ecf20Sopenharmony_ci int error; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci error = kstrtou8(buf, 10, &val); 5478c2ecf20Sopenharmony_ci if (error) 5488c2ecf20Sopenharmony_ci return error; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ac->pdata.data_rate = RATE(val); 5538c2ecf20Sopenharmony_ci AC_WRITE(ac, BW_RATE, 5548c2ecf20Sopenharmony_ci ac->pdata.data_rate | 5558c2ecf20Sopenharmony_ci (ac->pdata.low_power_mode ? LOW_POWER : 0)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return count; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic ssize_t adxl34x_autosleep_show(struct device *dev, 5658c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", 5708c2ecf20Sopenharmony_ci ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic ssize_t adxl34x_autosleep_store(struct device *dev, 5748c2ecf20Sopenharmony_ci struct device_attribute *attr, 5758c2ecf20Sopenharmony_ci const char *buf, size_t count) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 5788c2ecf20Sopenharmony_ci unsigned int val; 5798c2ecf20Sopenharmony_ci int error; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 5828c2ecf20Sopenharmony_ci if (error) 5838c2ecf20Sopenharmony_ci return error; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (val) 5888c2ecf20Sopenharmony_ci ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK); 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (!ac->disabled && !ac->suspended && ac->opened) 5938c2ecf20Sopenharmony_ci AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return count; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(autosleep, 0664, 6018c2ecf20Sopenharmony_ci adxl34x_autosleep_show, adxl34x_autosleep_store); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic ssize_t adxl34x_position_show(struct device *dev, 6048c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 6078c2ecf20Sopenharmony_ci ssize_t count; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 6108c2ecf20Sopenharmony_ci count = sprintf(buf, "(%d, %d, %d)\n", 6118c2ecf20Sopenharmony_ci ac->saved.x, ac->saved.y, ac->saved.z); 6128c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return count; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci#ifdef ADXL_DEBUG 6208c2ecf20Sopenharmony_cistatic ssize_t adxl34x_write_store(struct device *dev, 6218c2ecf20Sopenharmony_ci struct device_attribute *attr, 6228c2ecf20Sopenharmony_ci const char *buf, size_t count) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct adxl34x *ac = dev_get_drvdata(dev); 6258c2ecf20Sopenharmony_ci unsigned int val; 6268c2ecf20Sopenharmony_ci int error; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * This allows basic ADXL register write access for debug purposes. 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci error = kstrtouint(buf, 16, &val); 6328c2ecf20Sopenharmony_ci if (error) 6338c2ecf20Sopenharmony_ci return error; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 6368c2ecf20Sopenharmony_ci AC_WRITE(ac, val >> 8, val & 0xFF); 6378c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return count; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store); 6438c2ecf20Sopenharmony_ci#endif 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic struct attribute *adxl34x_attributes[] = { 6468c2ecf20Sopenharmony_ci &dev_attr_disable.attr, 6478c2ecf20Sopenharmony_ci &dev_attr_calibrate.attr, 6488c2ecf20Sopenharmony_ci &dev_attr_rate.attr, 6498c2ecf20Sopenharmony_ci &dev_attr_autosleep.attr, 6508c2ecf20Sopenharmony_ci &dev_attr_position.attr, 6518c2ecf20Sopenharmony_ci#ifdef ADXL_DEBUG 6528c2ecf20Sopenharmony_ci &dev_attr_write.attr, 6538c2ecf20Sopenharmony_ci#endif 6548c2ecf20Sopenharmony_ci NULL 6558c2ecf20Sopenharmony_ci}; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic const struct attribute_group adxl34x_attr_group = { 6588c2ecf20Sopenharmony_ci .attrs = adxl34x_attributes, 6598c2ecf20Sopenharmony_ci}; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int adxl34x_input_open(struct input_dev *input) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct adxl34x *ac = input_get_drvdata(input); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (!ac->suspended && !ac->disabled) 6688c2ecf20Sopenharmony_ci __adxl34x_enable(ac); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci ac->opened = true; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic void adxl34x_input_close(struct input_dev *input) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct adxl34x *ac = input_get_drvdata(input); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci mutex_lock(&ac->mutex); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (!ac->suspended && !ac->disabled) 6848c2ecf20Sopenharmony_ci __adxl34x_disable(ac); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ac->opened = false; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci mutex_unlock(&ac->mutex); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistruct adxl34x *adxl34x_probe(struct device *dev, int irq, 6928c2ecf20Sopenharmony_ci bool fifo_delay_default, 6938c2ecf20Sopenharmony_ci const struct adxl34x_bus_ops *bops) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct adxl34x *ac; 6968c2ecf20Sopenharmony_ci struct input_dev *input_dev; 6978c2ecf20Sopenharmony_ci const struct adxl34x_platform_data *pdata; 6988c2ecf20Sopenharmony_ci int err, range, i; 6998c2ecf20Sopenharmony_ci int revid; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!irq) { 7028c2ecf20Sopenharmony_ci dev_err(dev, "no IRQ?\n"); 7038c2ecf20Sopenharmony_ci err = -ENODEV; 7048c2ecf20Sopenharmony_ci goto err_out; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ac = kzalloc(sizeof(*ac), GFP_KERNEL); 7088c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 7098c2ecf20Sopenharmony_ci if (!ac || !input_dev) { 7108c2ecf20Sopenharmony_ci err = -ENOMEM; 7118c2ecf20Sopenharmony_ci goto err_free_mem; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci ac->fifo_delay = fifo_delay_default; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pdata = dev_get_platdata(dev); 7178c2ecf20Sopenharmony_ci if (!pdata) { 7188c2ecf20Sopenharmony_ci dev_dbg(dev, 7198c2ecf20Sopenharmony_ci "No platform data: Using default initialization\n"); 7208c2ecf20Sopenharmony_ci pdata = &adxl34x_default_init; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ac->pdata = *pdata; 7248c2ecf20Sopenharmony_ci pdata = &ac->pdata; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci ac->input = input_dev; 7278c2ecf20Sopenharmony_ci ac->dev = dev; 7288c2ecf20Sopenharmony_ci ac->irq = irq; 7298c2ecf20Sopenharmony_ci ac->bops = bops; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci mutex_init(&ac->mutex); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci input_dev->name = "ADXL34x accelerometer"; 7348c2ecf20Sopenharmony_ci revid = AC_READ(ac, DEVID); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci switch (revid) { 7378c2ecf20Sopenharmony_ci case ID_ADXL345: 7388c2ecf20Sopenharmony_ci ac->model = 345; 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci case ID_ADXL346: 7418c2ecf20Sopenharmony_ci ac->model = 346; 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci default: 7448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to probe %s\n", input_dev->name); 7458c2ecf20Sopenharmony_ci err = -ENODEV; 7468c2ecf20Sopenharmony_ci goto err_free_mem; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev)); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci input_dev->phys = ac->phys; 7528c2ecf20Sopenharmony_ci input_dev->dev.parent = dev; 7538c2ecf20Sopenharmony_ci input_dev->id.product = ac->model; 7548c2ecf20Sopenharmony_ci input_dev->id.bustype = bops->bustype; 7558c2ecf20Sopenharmony_ci input_dev->open = adxl34x_input_open; 7568c2ecf20Sopenharmony_ci input_dev->close = adxl34x_input_close; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, ac); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci __set_bit(ac->pdata.ev_type, input_dev->evbit); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (ac->pdata.ev_type == EV_REL) { 7638c2ecf20Sopenharmony_ci __set_bit(REL_X, input_dev->relbit); 7648c2ecf20Sopenharmony_ci __set_bit(REL_Y, input_dev->relbit); 7658c2ecf20Sopenharmony_ci __set_bit(REL_Z, input_dev->relbit); 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci /* EV_ABS */ 7688c2ecf20Sopenharmony_ci __set_bit(ABS_X, input_dev->absbit); 7698c2ecf20Sopenharmony_ci __set_bit(ABS_Y, input_dev->absbit); 7708c2ecf20Sopenharmony_ci __set_bit(ABS_Z, input_dev->absbit); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (pdata->data_range & FULL_RES) 7738c2ecf20Sopenharmony_ci range = ADXL_FULLRES_MAX_VAL; /* Signed 13-bit */ 7748c2ecf20Sopenharmony_ci else 7758c2ecf20Sopenharmony_ci range = ADXL_FIXEDRES_MAX_VAL; /* Signed 10-bit */ 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3); 7788c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3); 7798c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci __set_bit(EV_KEY, input_dev->evbit); 7838c2ecf20Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit); 7848c2ecf20Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit); 7858c2ecf20Sopenharmony_ci __set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (pdata->ev_code_ff) { 7888c2ecf20Sopenharmony_ci ac->int_mask = FREE_FALL; 7898c2ecf20Sopenharmony_ci __set_bit(pdata->ev_code_ff, input_dev->keybit); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (pdata->ev_code_act_inactivity) 7938c2ecf20Sopenharmony_ci __set_bit(pdata->ev_code_act_inactivity, input_dev->keybit); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci ac->int_mask |= ACTIVITY | INACTIVITY; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (pdata->watermark) { 7988c2ecf20Sopenharmony_ci ac->int_mask |= WATERMARK; 7998c2ecf20Sopenharmony_ci if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS) 8008c2ecf20Sopenharmony_ci ac->pdata.fifo_mode |= FIFO_STREAM; 8018c2ecf20Sopenharmony_ci } else { 8028c2ecf20Sopenharmony_ci ac->int_mask |= DATA_READY; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN)) 8068c2ecf20Sopenharmony_ci ac->int_mask |= SINGLE_TAP | DOUBLE_TAP; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS) 8098c2ecf20Sopenharmony_ci ac->fifo_delay = false; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci AC_WRITE(ac, POWER_CTL, 0); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci err = request_threaded_irq(ac->irq, NULL, adxl34x_irq, 8148c2ecf20Sopenharmony_ci IRQF_ONESHOT, dev_name(dev), ac); 8158c2ecf20Sopenharmony_ci if (err) { 8168c2ecf20Sopenharmony_ci dev_err(dev, "irq %d busy?\n", ac->irq); 8178c2ecf20Sopenharmony_ci goto err_free_mem; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group); 8218c2ecf20Sopenharmony_ci if (err) 8228c2ecf20Sopenharmony_ci goto err_free_irq; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci err = input_register_device(input_dev); 8258c2ecf20Sopenharmony_ci if (err) 8268c2ecf20Sopenharmony_ci goto err_remove_attr; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSX, pdata->x_axis_offset); 8298c2ecf20Sopenharmony_ci ac->hwcal.x = pdata->x_axis_offset; 8308c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSY, pdata->y_axis_offset); 8318c2ecf20Sopenharmony_ci ac->hwcal.y = pdata->y_axis_offset; 8328c2ecf20Sopenharmony_ci AC_WRITE(ac, OFSZ, pdata->z_axis_offset); 8338c2ecf20Sopenharmony_ci ac->hwcal.z = pdata->z_axis_offset; 8348c2ecf20Sopenharmony_ci AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold); 8358c2ecf20Sopenharmony_ci AC_WRITE(ac, DUR, pdata->tap_duration); 8368c2ecf20Sopenharmony_ci AC_WRITE(ac, LATENT, pdata->tap_latency); 8378c2ecf20Sopenharmony_ci AC_WRITE(ac, WINDOW, pdata->tap_window); 8388c2ecf20Sopenharmony_ci AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold); 8398c2ecf20Sopenharmony_ci AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold); 8408c2ecf20Sopenharmony_ci AC_WRITE(ac, TIME_INACT, pdata->inactivity_time); 8418c2ecf20Sopenharmony_ci AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold); 8428c2ecf20Sopenharmony_ci AC_WRITE(ac, TIME_FF, pdata->free_fall_time); 8438c2ecf20Sopenharmony_ci AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control); 8448c2ecf20Sopenharmony_ci AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control); 8458c2ecf20Sopenharmony_ci AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) | 8468c2ecf20Sopenharmony_ci (pdata->low_power_mode ? LOW_POWER : 0)); 8478c2ecf20Sopenharmony_ci AC_WRITE(ac, DATA_FORMAT, pdata->data_range); 8488c2ecf20Sopenharmony_ci AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) | 8498c2ecf20Sopenharmony_ci SAMPLES(pdata->watermark)); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (pdata->use_int2) { 8528c2ecf20Sopenharmony_ci /* Map all INTs to INT2 */ 8538c2ecf20Sopenharmony_ci AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN); 8548c2ecf20Sopenharmony_ci } else { 8558c2ecf20Sopenharmony_ci /* Map all INTs to INT1 */ 8568c2ecf20Sopenharmony_ci AC_WRITE(ac, INT_MAP, 0); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (ac->model == 346 && ac->pdata.orientation_enable) { 8608c2ecf20Sopenharmony_ci AC_WRITE(ac, ORIENT_CONF, 8618c2ecf20Sopenharmony_ci ORIENT_DEADZONE(ac->pdata.deadzone_angle) | 8628c2ecf20Sopenharmony_ci ORIENT_DIVISOR(ac->pdata.divisor_length)); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci ac->orient2d_saved = 1234; 8658c2ecf20Sopenharmony_ci ac->orient3d_saved = 1234; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) 8688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++) 8698c2ecf20Sopenharmony_ci __set_bit(pdata->ev_codes_orient_3d[i], 8708c2ecf20Sopenharmony_ci input_dev->keybit); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) 8738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++) 8748c2ecf20Sopenharmony_ci __set_bit(pdata->ev_codes_orient_2d[i], 8758c2ecf20Sopenharmony_ci input_dev->keybit); 8768c2ecf20Sopenharmony_ci } else { 8778c2ecf20Sopenharmony_ci ac->pdata.orientation_enable = 0; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return ac; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci err_remove_attr: 8878c2ecf20Sopenharmony_ci sysfs_remove_group(&dev->kobj, &adxl34x_attr_group); 8888c2ecf20Sopenharmony_ci err_free_irq: 8898c2ecf20Sopenharmony_ci free_irq(ac->irq, ac); 8908c2ecf20Sopenharmony_ci err_free_mem: 8918c2ecf20Sopenharmony_ci input_free_device(input_dev); 8928c2ecf20Sopenharmony_ci kfree(ac); 8938c2ecf20Sopenharmony_ci err_out: 8948c2ecf20Sopenharmony_ci return ERR_PTR(err); 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_probe); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ciint adxl34x_remove(struct adxl34x *ac) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group); 9018c2ecf20Sopenharmony_ci free_irq(ac->irq, ac); 9028c2ecf20Sopenharmony_ci input_unregister_device(ac->input); 9038c2ecf20Sopenharmony_ci dev_dbg(ac->dev, "unregistered accelerometer\n"); 9048c2ecf20Sopenharmony_ci kfree(ac); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adxl34x_remove); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 9118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver"); 9128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 913