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