162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2021 Oleh Kravchenko <oleg@kaa.org.ua>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * SparkFun Qwiic Joystick
662306a36Sopenharmony_ci * Product page:https://www.sparkfun.com/products/15168
762306a36Sopenharmony_ci * Firmware and hardware sources:https://github.com/sparkfun/Qwiic_Joystick
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bits.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/input.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define DRV_NAME "qwiic-joystick"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define QWIIC_JSK_REG_VERS	1
1962306a36Sopenharmony_ci#define QWIIC_JSK_REG_DATA	3
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define QWIIC_JSK_MAX_AXIS	GENMASK(9, 0)
2262306a36Sopenharmony_ci#define QWIIC_JSK_FUZZ		2
2362306a36Sopenharmony_ci#define QWIIC_JSK_FLAT		2
2462306a36Sopenharmony_ci#define QWIIC_JSK_POLL_INTERVAL	16
2562306a36Sopenharmony_ci#define QWIIC_JSK_POLL_MIN	8
2662306a36Sopenharmony_ci#define QWIIC_JSK_POLL_MAX	32
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct qwiic_jsk {
2962306a36Sopenharmony_ci	char phys[32];
3062306a36Sopenharmony_ci	struct input_dev *dev;
3162306a36Sopenharmony_ci	struct i2c_client *client;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct qwiic_ver {
3562306a36Sopenharmony_ci	u8 major;
3662306a36Sopenharmony_ci	u8 minor;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct qwiic_data {
4062306a36Sopenharmony_ci	__be16 x;
4162306a36Sopenharmony_ci	__be16 y;
4262306a36Sopenharmony_ci	u8 thumb;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void qwiic_poll(struct input_dev *input)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct qwiic_jsk *priv = input_get_drvdata(input);
4862306a36Sopenharmony_ci	struct qwiic_data data;
4962306a36Sopenharmony_ci	int err;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	err = i2c_smbus_read_i2c_block_data(priv->client, QWIIC_JSK_REG_DATA,
5262306a36Sopenharmony_ci					    sizeof(data), (u8 *)&data);
5362306a36Sopenharmony_ci	if (err != sizeof(data))
5462306a36Sopenharmony_ci		return;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	input_report_abs(input, ABS_X, be16_to_cpu(data.x) >> 6);
5762306a36Sopenharmony_ci	input_report_abs(input, ABS_Y, be16_to_cpu(data.y) >> 6);
5862306a36Sopenharmony_ci	input_report_key(input, BTN_THUMBL, !data.thumb);
5962306a36Sopenharmony_ci	input_sync(input);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int qwiic_probe(struct i2c_client *client)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct qwiic_jsk *priv;
6562306a36Sopenharmony_ci	struct qwiic_ver vers;
6662306a36Sopenharmony_ci	int err;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	err = i2c_smbus_read_i2c_block_data(client, QWIIC_JSK_REG_VERS,
6962306a36Sopenharmony_ci					    sizeof(vers), (u8 *)&vers);
7062306a36Sopenharmony_ci	if (err < 0)
7162306a36Sopenharmony_ci		return err;
7262306a36Sopenharmony_ci	if (err != sizeof(vers))
7362306a36Sopenharmony_ci		return -EIO;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	dev_dbg(&client->dev, "SparkFun Qwiic Joystick, FW: %u.%u\n",
7662306a36Sopenharmony_ci		vers.major, vers.minor);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
7962306a36Sopenharmony_ci	if (!priv)
8062306a36Sopenharmony_ci		return -ENOMEM;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	priv->client = client;
8362306a36Sopenharmony_ci	snprintf(priv->phys, sizeof(priv->phys),
8462306a36Sopenharmony_ci		 "i2c/%s", dev_name(&client->dev));
8562306a36Sopenharmony_ci	i2c_set_clientdata(client, priv);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	priv->dev = devm_input_allocate_device(&client->dev);
8862306a36Sopenharmony_ci	if (!priv->dev)
8962306a36Sopenharmony_ci		return -ENOMEM;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	priv->dev->id.bustype = BUS_I2C;
9262306a36Sopenharmony_ci	priv->dev->name = "SparkFun Qwiic Joystick";
9362306a36Sopenharmony_ci	priv->dev->phys = priv->phys;
9462306a36Sopenharmony_ci	input_set_drvdata(priv->dev, priv);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	input_set_abs_params(priv->dev, ABS_X, 0, QWIIC_JSK_MAX_AXIS,
9762306a36Sopenharmony_ci			     QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT);
9862306a36Sopenharmony_ci	input_set_abs_params(priv->dev, ABS_Y, 0, QWIIC_JSK_MAX_AXIS,
9962306a36Sopenharmony_ci			     QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT);
10062306a36Sopenharmony_ci	input_set_capability(priv->dev, EV_KEY, BTN_THUMBL);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	err = input_setup_polling(priv->dev, qwiic_poll);
10362306a36Sopenharmony_ci	if (err) {
10462306a36Sopenharmony_ci		dev_err(&client->dev, "failed to set up polling: %d\n", err);
10562306a36Sopenharmony_ci		return err;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	input_set_poll_interval(priv->dev, QWIIC_JSK_POLL_INTERVAL);
10862306a36Sopenharmony_ci	input_set_min_poll_interval(priv->dev, QWIIC_JSK_POLL_MIN);
10962306a36Sopenharmony_ci	input_set_max_poll_interval(priv->dev, QWIIC_JSK_POLL_MAX);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	err = input_register_device(priv->dev);
11262306a36Sopenharmony_ci	if (err) {
11362306a36Sopenharmony_ci		dev_err(&client->dev, "failed to register joystick: %d\n", err);
11462306a36Sopenharmony_ci		return err;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return 0;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#ifdef CONFIG_OF
12162306a36Sopenharmony_cistatic const struct of_device_id of_qwiic_match[] = {
12262306a36Sopenharmony_ci	{ .compatible = "sparkfun,qwiic-joystick", },
12362306a36Sopenharmony_ci	{ },
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_qwiic_match);
12662306a36Sopenharmony_ci#endif /* CONFIG_OF */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const struct i2c_device_id qwiic_id_table[] = {
12962306a36Sopenharmony_ci	{ KBUILD_MODNAME, 0 },
13062306a36Sopenharmony_ci	{ },
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, qwiic_id_table);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic struct i2c_driver qwiic_driver = {
13562306a36Sopenharmony_ci	.driver = {
13662306a36Sopenharmony_ci		.name		= DRV_NAME,
13762306a36Sopenharmony_ci		.of_match_table	= of_match_ptr(of_qwiic_match),
13862306a36Sopenharmony_ci	},
13962306a36Sopenharmony_ci	.id_table	= qwiic_id_table,
14062306a36Sopenharmony_ci	.probe		= qwiic_probe,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_cimodule_i2c_driver(qwiic_driver);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciMODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
14562306a36Sopenharmony_ciMODULE_DESCRIPTION("SparkFun Qwiic Joystick driver");
14662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
147