162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Kionix, Inc.
462306a36Sopenharmony_ci * Written by Chris Hudson <chudson@kionix.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/i2c.h>
962306a36Sopenharmony_ci#include <linux/input.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/input/kxtj9.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define NAME			"kxtj9"
1662306a36Sopenharmony_ci#define G_MAX			8000
1762306a36Sopenharmony_ci/* OUTPUT REGISTERS */
1862306a36Sopenharmony_ci#define XOUT_L			0x06
1962306a36Sopenharmony_ci#define WHO_AM_I		0x0F
2062306a36Sopenharmony_ci/* CONTROL REGISTERS */
2162306a36Sopenharmony_ci#define INT_REL			0x1A
2262306a36Sopenharmony_ci#define CTRL_REG1		0x1B
2362306a36Sopenharmony_ci#define INT_CTRL1		0x1E
2462306a36Sopenharmony_ci#define DATA_CTRL		0x21
2562306a36Sopenharmony_ci/* CONTROL REGISTER 1 BITS */
2662306a36Sopenharmony_ci#define PC1_OFF			0x7F
2762306a36Sopenharmony_ci#define PC1_ON			(1 << 7)
2862306a36Sopenharmony_ci/* Data ready funtion enable bit: set during probe if using irq mode */
2962306a36Sopenharmony_ci#define DRDYE			(1 << 5)
3062306a36Sopenharmony_ci/* DATA CONTROL REGISTER BITS */
3162306a36Sopenharmony_ci#define ODR12_5F		0
3262306a36Sopenharmony_ci#define ODR25F			1
3362306a36Sopenharmony_ci#define ODR50F			2
3462306a36Sopenharmony_ci#define ODR100F		3
3562306a36Sopenharmony_ci#define ODR200F		4
3662306a36Sopenharmony_ci#define ODR400F		5
3762306a36Sopenharmony_ci#define ODR800F		6
3862306a36Sopenharmony_ci/* INTERRUPT CONTROL REGISTER 1 BITS */
3962306a36Sopenharmony_ci/* Set these during probe if using irq mode */
4062306a36Sopenharmony_ci#define KXTJ9_IEL		(1 << 3)
4162306a36Sopenharmony_ci#define KXTJ9_IEA		(1 << 4)
4262306a36Sopenharmony_ci#define KXTJ9_IEN		(1 << 5)
4362306a36Sopenharmony_ci/* INPUT_ABS CONSTANTS */
4462306a36Sopenharmony_ci#define FUZZ			3
4562306a36Sopenharmony_ci#define FLAT			3
4662306a36Sopenharmony_ci/* RESUME STATE INDICES */
4762306a36Sopenharmony_ci#define RES_DATA_CTRL		0
4862306a36Sopenharmony_ci#define RES_CTRL_REG1		1
4962306a36Sopenharmony_ci#define RES_INT_CTRL1		2
5062306a36Sopenharmony_ci#define RESUME_ENTRIES		3
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * The following table lists the maximum appropriate poll interval for each
5462306a36Sopenharmony_ci * available output data rate.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_cistatic const struct {
5762306a36Sopenharmony_ci	unsigned int cutoff;
5862306a36Sopenharmony_ci	u8 mask;
5962306a36Sopenharmony_ci} kxtj9_odr_table[] = {
6062306a36Sopenharmony_ci	{ 3,	ODR800F },
6162306a36Sopenharmony_ci	{ 5,	ODR400F },
6262306a36Sopenharmony_ci	{ 10,	ODR200F },
6362306a36Sopenharmony_ci	{ 20,	ODR100F },
6462306a36Sopenharmony_ci	{ 40,	ODR50F  },
6562306a36Sopenharmony_ci	{ 80,	ODR25F  },
6662306a36Sopenharmony_ci	{ 0,	ODR12_5F},
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct kxtj9_data {
7062306a36Sopenharmony_ci	struct i2c_client *client;
7162306a36Sopenharmony_ci	struct kxtj9_platform_data pdata;
7262306a36Sopenharmony_ci	struct input_dev *input_dev;
7362306a36Sopenharmony_ci	unsigned int last_poll_interval;
7462306a36Sopenharmony_ci	u8 shift;
7562306a36Sopenharmony_ci	u8 ctrl_reg1;
7662306a36Sopenharmony_ci	u8 data_ctrl;
7762306a36Sopenharmony_ci	u8 int_ctrl;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct i2c_msg msgs[] = {
8362306a36Sopenharmony_ci		{
8462306a36Sopenharmony_ci			.addr = tj9->client->addr,
8562306a36Sopenharmony_ci			.flags = tj9->client->flags,
8662306a36Sopenharmony_ci			.len = 1,
8762306a36Sopenharmony_ci			.buf = &addr,
8862306a36Sopenharmony_ci		},
8962306a36Sopenharmony_ci		{
9062306a36Sopenharmony_ci			.addr = tj9->client->addr,
9162306a36Sopenharmony_ci			.flags = tj9->client->flags | I2C_M_RD,
9262306a36Sopenharmony_ci			.len = len,
9362306a36Sopenharmony_ci			.buf = data,
9462306a36Sopenharmony_ci		},
9562306a36Sopenharmony_ci	};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return i2c_transfer(tj9->client->adapter, msgs, 2);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void kxtj9_report_acceleration_data(struct kxtj9_data *tj9)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */
10362306a36Sopenharmony_ci	s16 x, y, z;
10462306a36Sopenharmony_ci	int err;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6);
10762306a36Sopenharmony_ci	if (err < 0)
10862306a36Sopenharmony_ci		dev_err(&tj9->client->dev, "accelerometer data read failed\n");
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]);
11162306a36Sopenharmony_ci	y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
11262306a36Sopenharmony_ci	z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	x >>= tj9->shift;
11562306a36Sopenharmony_ci	y >>= tj9->shift;
11662306a36Sopenharmony_ci	z >>= tj9->shift;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
11962306a36Sopenharmony_ci	input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
12062306a36Sopenharmony_ci	input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z);
12162306a36Sopenharmony_ci	input_sync(tj9->input_dev);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic irqreturn_t kxtj9_isr(int irq, void *dev)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct kxtj9_data *tj9 = dev;
12762306a36Sopenharmony_ci	int err;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* data ready is the only possible interrupt type */
13062306a36Sopenharmony_ci	kxtj9_report_acceleration_data(tj9);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
13362306a36Sopenharmony_ci	if (err < 0)
13462306a36Sopenharmony_ci		dev_err(&tj9->client->dev,
13562306a36Sopenharmony_ci			"error clearing interrupt status: %d\n", err);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return IRQ_HANDLED;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	switch (new_g_range) {
14362306a36Sopenharmony_ci	case KXTJ9_G_2G:
14462306a36Sopenharmony_ci		tj9->shift = 4;
14562306a36Sopenharmony_ci		break;
14662306a36Sopenharmony_ci	case KXTJ9_G_4G:
14762306a36Sopenharmony_ci		tj9->shift = 3;
14862306a36Sopenharmony_ci		break;
14962306a36Sopenharmony_ci	case KXTJ9_G_8G:
15062306a36Sopenharmony_ci		tj9->shift = 2;
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	default:
15362306a36Sopenharmony_ci		return -EINVAL;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	tj9->ctrl_reg1 &= 0xe7;
15762306a36Sopenharmony_ci	tj9->ctrl_reg1 |= new_g_range;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int err;
16562306a36Sopenharmony_ci	int i;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Use the lowest ODR that can support the requested poll interval */
16862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) {
16962306a36Sopenharmony_ci		tj9->data_ctrl = kxtj9_odr_table[i].mask;
17062306a36Sopenharmony_ci		if (poll_interval < kxtj9_odr_table[i].cutoff)
17162306a36Sopenharmony_ci			break;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
17562306a36Sopenharmony_ci	if (err < 0)
17662306a36Sopenharmony_ci		return err;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl);
17962306a36Sopenharmony_ci	if (err < 0)
18062306a36Sopenharmony_ci		return err;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
18362306a36Sopenharmony_ci	if (err < 0)
18462306a36Sopenharmony_ci		return err;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int kxtj9_device_power_on(struct kxtj9_data *tj9)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if (tj9->pdata.power_on)
19262306a36Sopenharmony_ci		return tj9->pdata.power_on();
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void kxtj9_device_power_off(struct kxtj9_data *tj9)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	int err;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	tj9->ctrl_reg1 &= PC1_OFF;
20262306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
20362306a36Sopenharmony_ci	if (err < 0)
20462306a36Sopenharmony_ci		dev_err(&tj9->client->dev, "soft power off failed\n");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (tj9->pdata.power_off)
20762306a36Sopenharmony_ci		tj9->pdata.power_off();
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int kxtj9_enable(struct kxtj9_data *tj9)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	int err;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	err = kxtj9_device_power_on(tj9);
21562306a36Sopenharmony_ci	if (err < 0)
21662306a36Sopenharmony_ci		return err;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* ensure that PC1 is cleared before updating control registers */
21962306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
22062306a36Sopenharmony_ci	if (err < 0)
22162306a36Sopenharmony_ci		return err;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* only write INT_CTRL_REG1 if in irq mode */
22462306a36Sopenharmony_ci	if (tj9->client->irq) {
22562306a36Sopenharmony_ci		err = i2c_smbus_write_byte_data(tj9->client,
22662306a36Sopenharmony_ci						INT_CTRL1, tj9->int_ctrl);
22762306a36Sopenharmony_ci		if (err < 0)
22862306a36Sopenharmony_ci			return err;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	err = kxtj9_update_g_range(tj9, tj9->pdata.g_range);
23262306a36Sopenharmony_ci	if (err < 0)
23362306a36Sopenharmony_ci		return err;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* turn on outputs */
23662306a36Sopenharmony_ci	tj9->ctrl_reg1 |= PC1_ON;
23762306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
23862306a36Sopenharmony_ci	if (err < 0)
23962306a36Sopenharmony_ci		return err;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	err = kxtj9_update_odr(tj9, tj9->last_poll_interval);
24262306a36Sopenharmony_ci	if (err < 0)
24362306a36Sopenharmony_ci		return err;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* clear initial interrupt if in irq mode */
24662306a36Sopenharmony_ci	if (tj9->client->irq) {
24762306a36Sopenharmony_ci		err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
24862306a36Sopenharmony_ci		if (err < 0) {
24962306a36Sopenharmony_ci			dev_err(&tj9->client->dev,
25062306a36Sopenharmony_ci				"error clearing interrupt: %d\n", err);
25162306a36Sopenharmony_ci			goto fail;
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cifail:
25862306a36Sopenharmony_ci	kxtj9_device_power_off(tj9);
25962306a36Sopenharmony_ci	return err;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void kxtj9_disable(struct kxtj9_data *tj9)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	kxtj9_device_power_off(tj9);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int kxtj9_input_open(struct input_dev *input)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct kxtj9_data *tj9 = input_get_drvdata(input);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return kxtj9_enable(tj9);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void kxtj9_input_close(struct input_dev *dev)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct kxtj9_data *tj9 = input_get_drvdata(dev);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	kxtj9_disable(tj9);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * When IRQ mode is selected, we need to provide an interface to allow the user
28362306a36Sopenharmony_ci * to change the output data rate of the part.  For consistency, we are using
28462306a36Sopenharmony_ci * the set_poll method, which accepts a poll interval in milliseconds, and then
28562306a36Sopenharmony_ci * calls update_odr() while passing this value as an argument.  In IRQ mode, the
28662306a36Sopenharmony_ci * data outputs will not be read AT the requested poll interval, rather, the
28762306a36Sopenharmony_ci * lowest ODR that can support the requested interval.  The client application
28862306a36Sopenharmony_ci * will be responsible for retrieving data from the input node at the desired
28962306a36Sopenharmony_ci * interval.
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/* Returns currently selected poll interval (in ms) */
29362306a36Sopenharmony_cistatic ssize_t kxtj9_get_poll(struct device *dev,
29462306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
29762306a36Sopenharmony_ci	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return sprintf(buf, "%d\n", tj9->last_poll_interval);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* Allow users to select a new poll interval (in ms) */
30362306a36Sopenharmony_cistatic ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
30462306a36Sopenharmony_ci						const char *buf, size_t count)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
30762306a36Sopenharmony_ci	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
30862306a36Sopenharmony_ci	struct input_dev *input_dev = tj9->input_dev;
30962306a36Sopenharmony_ci	unsigned int interval;
31062306a36Sopenharmony_ci	int error;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	error = kstrtouint(buf, 10, &interval);
31362306a36Sopenharmony_ci	if (error < 0)
31462306a36Sopenharmony_ci		return error;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* Lock the device to prevent races with open/close (and itself) */
31762306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	disable_irq(client->irq);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/*
32262306a36Sopenharmony_ci	 * Set current interval to the greater of the minimum interval or
32362306a36Sopenharmony_ci	 * the requested interval
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci	tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	kxtj9_update_odr(tj9, tj9->last_poll_interval);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	enable_irq(client->irq);
33062306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return count;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic struct attribute *kxtj9_attributes[] = {
33862306a36Sopenharmony_ci	&dev_attr_poll.attr,
33962306a36Sopenharmony_ci	NULL
34062306a36Sopenharmony_ci};
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic struct attribute_group kxtj9_attribute_group = {
34362306a36Sopenharmony_ci	.attrs = kxtj9_attributes
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void kxtj9_poll(struct input_dev *input)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct kxtj9_data *tj9 = input_get_drvdata(input);
34962306a36Sopenharmony_ci	unsigned int poll_interval = input_get_poll_interval(input);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	kxtj9_report_acceleration_data(tj9);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (poll_interval != tj9->last_poll_interval) {
35462306a36Sopenharmony_ci		kxtj9_update_odr(tj9, poll_interval);
35562306a36Sopenharmony_ci		tj9->last_poll_interval = poll_interval;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void kxtj9_platform_exit(void *data)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct kxtj9_data *tj9 = data;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (tj9->pdata.exit)
36462306a36Sopenharmony_ci		tj9->pdata.exit();
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int kxtj9_verify(struct kxtj9_data *tj9)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	int retval;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	retval = kxtj9_device_power_on(tj9);
37262306a36Sopenharmony_ci	if (retval < 0)
37362306a36Sopenharmony_ci		return retval;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);
37662306a36Sopenharmony_ci	if (retval < 0) {
37762306a36Sopenharmony_ci		dev_err(&tj9->client->dev, "read err int source\n");
37862306a36Sopenharmony_ci		goto out;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	retval = (retval != 0x07 && retval != 0x08) ? -EIO : 0;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciout:
38462306a36Sopenharmony_ci	kxtj9_device_power_off(tj9);
38562306a36Sopenharmony_ci	return retval;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int kxtj9_probe(struct i2c_client *client)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	const struct kxtj9_platform_data *pdata =
39162306a36Sopenharmony_ci			dev_get_platdata(&client->dev);
39262306a36Sopenharmony_ci	struct kxtj9_data *tj9;
39362306a36Sopenharmony_ci	struct input_dev *input_dev;
39462306a36Sopenharmony_ci	int err;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
39762306a36Sopenharmony_ci				I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
39862306a36Sopenharmony_ci		dev_err(&client->dev, "client is not i2c capable\n");
39962306a36Sopenharmony_ci		return -ENXIO;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (!pdata) {
40362306a36Sopenharmony_ci		dev_err(&client->dev, "platform data is NULL; exiting\n");
40462306a36Sopenharmony_ci		return -EINVAL;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	tj9 = devm_kzalloc(&client->dev, sizeof(*tj9), GFP_KERNEL);
40862306a36Sopenharmony_ci	if (!tj9) {
40962306a36Sopenharmony_ci		dev_err(&client->dev,
41062306a36Sopenharmony_ci			"failed to allocate memory for module data\n");
41162306a36Sopenharmony_ci		return -ENOMEM;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	tj9->client = client;
41562306a36Sopenharmony_ci	tj9->pdata = *pdata;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (pdata->init) {
41862306a36Sopenharmony_ci		err = pdata->init();
41962306a36Sopenharmony_ci		if (err < 0)
42062306a36Sopenharmony_ci			return err;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	err = devm_add_action_or_reset(&client->dev, kxtj9_platform_exit, tj9);
42462306a36Sopenharmony_ci	if (err)
42562306a36Sopenharmony_ci		return err;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	err = kxtj9_verify(tj9);
42862306a36Sopenharmony_ci	if (err < 0) {
42962306a36Sopenharmony_ci		dev_err(&client->dev, "device not recognized\n");
43062306a36Sopenharmony_ci		return err;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	i2c_set_clientdata(client, tj9);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
43662306a36Sopenharmony_ci	tj9->last_poll_interval = tj9->pdata.init_interval;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	input_dev = devm_input_allocate_device(&client->dev);
43962306a36Sopenharmony_ci	if (!input_dev) {
44062306a36Sopenharmony_ci		dev_err(&client->dev, "input device allocate failed\n");
44162306a36Sopenharmony_ci		return -ENOMEM;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	input_set_drvdata(input_dev, tj9);
44562306a36Sopenharmony_ci	tj9->input_dev = input_dev;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	input_dev->name = "kxtj9_accel";
44862306a36Sopenharmony_ci	input_dev->id.bustype = BUS_I2C;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	input_dev->open = kxtj9_input_open;
45162306a36Sopenharmony_ci	input_dev->close = kxtj9_input_close;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT);
45462306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT);
45562306a36Sopenharmony_ci	input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (client->irq <= 0) {
45862306a36Sopenharmony_ci		err = input_setup_polling(input_dev, kxtj9_poll);
45962306a36Sopenharmony_ci		if (err)
46062306a36Sopenharmony_ci			return err;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	err = input_register_device(input_dev);
46462306a36Sopenharmony_ci	if (err) {
46562306a36Sopenharmony_ci		dev_err(&client->dev,
46662306a36Sopenharmony_ci			"unable to register input polled device %s: %d\n",
46762306a36Sopenharmony_ci			input_dev->name, err);
46862306a36Sopenharmony_ci		return err;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (client->irq) {
47262306a36Sopenharmony_ci		/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
47362306a36Sopenharmony_ci		tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
47462306a36Sopenharmony_ci		tj9->ctrl_reg1 |= DRDYE;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		err = devm_request_threaded_irq(&client->dev, client->irq,
47762306a36Sopenharmony_ci						NULL, kxtj9_isr,
47862306a36Sopenharmony_ci						IRQF_TRIGGER_RISING |
47962306a36Sopenharmony_ci							IRQF_ONESHOT,
48062306a36Sopenharmony_ci						"kxtj9-irq", tj9);
48162306a36Sopenharmony_ci		if (err) {
48262306a36Sopenharmony_ci			dev_err(&client->dev, "request irq failed: %d\n", err);
48362306a36Sopenharmony_ci			return err;
48462306a36Sopenharmony_ci		}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		err = devm_device_add_group(&client->dev,
48762306a36Sopenharmony_ci					    &kxtj9_attribute_group);
48862306a36Sopenharmony_ci		if (err) {
48962306a36Sopenharmony_ci			dev_err(&client->dev, "sysfs create failed: %d\n", err);
49062306a36Sopenharmony_ci			return err;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic int kxtj9_suspend(struct device *dev)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
50062306a36Sopenharmony_ci	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
50162306a36Sopenharmony_ci	struct input_dev *input_dev = tj9->input_dev;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (input_device_enabled(input_dev))
50662306a36Sopenharmony_ci		kxtj9_disable(tj9);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int kxtj9_resume(struct device *dev)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
51562306a36Sopenharmony_ci	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
51662306a36Sopenharmony_ci	struct input_dev *input_dev = tj9->input_dev;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	mutex_lock(&input_dev->mutex);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (input_device_enabled(input_dev))
52162306a36Sopenharmony_ci		kxtj9_enable(tj9);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	mutex_unlock(&input_dev->mutex);
52462306a36Sopenharmony_ci	return 0;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic const struct i2c_device_id kxtj9_id[] = {
53062306a36Sopenharmony_ci	{ NAME, 0 },
53162306a36Sopenharmony_ci	{ },
53262306a36Sopenharmony_ci};
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, kxtj9_id);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic struct i2c_driver kxtj9_driver = {
53762306a36Sopenharmony_ci	.driver = {
53862306a36Sopenharmony_ci		.name	= NAME,
53962306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&kxtj9_pm_ops),
54062306a36Sopenharmony_ci	},
54162306a36Sopenharmony_ci	.probe		= kxtj9_probe,
54262306a36Sopenharmony_ci	.id_table	= kxtj9_id,
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cimodule_i2c_driver(kxtj9_driver);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ciMODULE_DESCRIPTION("KXTJ9 accelerometer driver");
54862306a36Sopenharmony_ciMODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
54962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
550