All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Oleh Kuzhylnyi <kuzhylol@gmail.com>
Cc: Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	linux-input@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Conor Dooley <conor.dooley@microchip.com>,
	igor.opaniuk@gmail.com,
	Neil Armstrong <neil.armstrong@linaro.org>,
	Jeff LaBundy <jeff@labundy.com>
Subject: Re: [PATCH v4 2/2] input: add driver for Hynitron CST816X touchscreen
Date: Sat, 31 Aug 2024 21:27:13 -0700	[thread overview]
Message-ID: <ZtPtIdqm4G7SqYvd@google.com> (raw)
In-Reply-To: <20240829212014.111357-2-kuzhylol@gmail.com>

Hi Oleh,

On Thu, Aug 29, 2024 at 11:20:14PM +0200, Oleh Kuzhylnyi wrote:
> Introduce support for the Hynitron CST816X touchscreen controller
> used for 240×240 1.28-inch Round LCD Display Module manufactured
> by Waveshare Electronics. The driver is designed based on an Arduino
> implementation marked as under MIT License. This driver is written
> for a particular round display based on the CST816S controller, which
> is not compatiable with existing driver for Hynitron controllers.
> 
> Signed-off-by: Oleh Kuzhylnyi <kuzhylol@gmail.com>
> ---
> 
> Changes in v4:
> - Update commit based on Dmitry's feedback:
> - Move abs_x and abs_y to u16
> - Remove __packed qualifier for touch_info struct
> - Hide tiny touch irq context to stack
> - Extend cst816x_i2c_read_register() with buf and buf_size
> - Remove loop from event lookup

Thank you for making the changes, a few more comments/suggestions:

> +
> +static const struct cst816x_event_mapping event_map[16] = {
> +	{CST816X_SWIPE_UP, BTN_FORWARD},
> +	{CST816X_SWIPE_DOWN, BTN_BACK},
> +	{CST816X_SWIPE_LEFT, BTN_LEFT},
> +	{CST816X_SWIPE_RIGHT, BTN_RIGHT},
> +	{CST816X_SINGLE_TAP, BTN_TOUCH},
> +	{CST816X_LONG_PRESS, BTN_TOOL_TRIPLETAP},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +	{CST816X_RESERVED, KEY_RESERVED},
> +};
> +
> +static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
> +				     void *buf, size_t len)
> +{
> +	struct i2c_client *client;

Whenever reasonable combine declaration and initialization:

	struct i2c_client *client = priv->client;

> +	struct i2c_msg xfer[2];

	struct i2c_msg xfer[] = {
		{
			.addr = client->addr,
			.buf = &reg,
			.len = sizeof(reg),

		},
		{
			.addr = client->addr,
			.flags = I2C_M_RD,
			.buf = buf,
			.len = len,
		},
	};

> +	int rc;
> +
> +	client = priv->client;
> +
> +	xfer[0].addr = client->addr;
> +	xfer[0].flags = 0;
> +	xfer[0].buf = &reg;
> +	xfer[0].len = sizeof(reg);
> +
> +	xfer[1].addr = client->addr;
> +	xfer[1].flags = I2C_M_RD;
> +	xfer[1].buf = buf;
> +	xfer[1].len = len;
> +
> +	rc = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
> +	if (rc != ARRAY_SIZE(xfer)) {
> +		if (rc >= 0)
> +			rc = -EIO;
		rc = rc < 0 ? rc : -EIO;
		dev_err(...);
		return rc;
> +	} else {
> +		rc = 0;
> +	}
> +
> +	if (rc < 0)
> +		dev_err(&client->dev, "i2c rx err: %d\n", rc);
> +
> +	return rc;

Explicitly returning 0 on success is preferred if code looks reasonable.

	return 0;

> +}
> +
> +static int cst816x_process_touch(struct cst816x_priv *priv,
> +				 struct cst816x_touch_info *info)
> +{
> +	u8 raw[8];
> +	int rc;

	int error;

> +
> +	rc = cst816x_i2c_read_register(priv, CST816X_FRAME, raw, sizeof(raw));
> +	if (!rc) {

	error = cst816x_i2c_read_register(...);
	if (error)
		return error;


> +		info->gesture = raw[0];
> +		info->touch = raw[1];
> +		info->abs_x = ((raw[2] & 0x0F) << 8) | raw[3];

I think it can be written as

	info->abs_x = get_unaligned_le16(&raw[2]) & GENMASK(11, 0);

> +		info->abs_y = ((raw[4] & 0x0F) << 8) | raw[5];
> +
> +		dev_dbg(priv->dev, "x: %d, y: %d, t: %d, g: 0x%x\n",
> +			info->abs_x, info->abs_y, info->touch, info->gesture);
> +	}
> +
> +	return rc;

	return 0;

> +}
> +
> +static int cst816x_register_input(struct cst816x_priv *priv)
> +{
> +	priv->input = devm_input_allocate_device(priv->dev);
> +	if (!priv->input)
> +		return -ENOMEM;
> +
> +	priv->input->name = "Hynitron CST816X Touchscreen";
> +	priv->input->phys = "input/ts";
> +	priv->input->id.bustype = BUS_I2C;
> +	input_set_drvdata(priv->input, priv);
> +
> +	for (unsigned int i = 0; i < ARRAY_SIZE(event_map); i++)
> +		input_set_capability(priv->input, EV_KEY, event_map[i].code);
> +
> +	input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
> +	input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
> +
> +	return input_register_device(priv->input);
> +}
> +
> +static void cst816x_reset(struct cst816x_priv *priv)
> +{

I believe the reset line should be optional, and so check for non-NULL
here before trying to execute the reset sequence.

> +	gpiod_set_value_cansleep(priv->reset, 1);
> +	msleep(50);
> +	gpiod_set_value_cansleep(priv->reset, 0);
> +	msleep(100);
> +}
> +
> +static void report_gesture_event(const struct cst816x_priv *priv,
> +				 enum cst816x_gestures gesture, bool touch)
> +{
> +	u16 key = event_map[gesture & 0x0F].code;
> +
> +	if (key != KEY_RESERVED)
> +		input_report_key(priv->input, key, touch);
> +
> +	if (!touch)
> +		input_report_key(priv->input, BTN_TOUCH, 0);

This chunk does not belong here but rather where you report the rest of
the touch state.

> +}
> +
> +/*
> + * Supports five gestures: TOUCH, LEFT, RIGHT, FORWARD, BACK, and LONG_PRESS.
> + * Reports surface interaction, sliding coordinates and finger detachment.
> + *
> + * 1. TOUCH Gesture Scenario:
> + *
> + * [x/y] [touch] [gesture] [Action] [Report ABS] [Report Key]
> + *  x y   true    0x00      Touch    ABS_X_Y      BTN_TOUCH
> + *  x y   true    0x00      Slide    ABS_X_Y
> + *  x y   false   0x05      Gesture               BTN_TOUCH
> + *
> + * 2. LEFT, RIGHT, FORWARD, BACK, and LONG_PRESS Gestures Scenario:
> + *
> + * [x/y] [touch] [gesture] [Action] [Report ABS] [Report Key]
> + *  x y   true    0x00      Touch    ABS_X_Y      BTN_TOUCH
> + *  x y   true    0x01      Gesture  ABS_X_Y      BTN_FORWARD
> + *  x y   true    0x01      Slide    ABS_X_Y
> + *  x y   false   0x01      Detach                BTN_FORWARD | BTN_TOUCH
> + */
> +static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
> +{
> +	struct cst816x_priv *priv = (struct cst816x_priv *)cookie;

No need to cast void pointers.

> +	struct cst816x_touch_info info;
> +
> +	if (!cst816x_process_touch(priv, &info)) {

This makes it appear cst816x_process_touch() returning boolean.

	error = cst816x_process_touch(priv, &info);
	if (error)
		goto out;

> +		if (info.touch) {
> +			input_report_abs(priv->input, ABS_X, info.abs_x);
> +			input_report_abs(priv->input, ABS_Y, info.abs_y);
> +			input_report_key(priv->input, BTN_TOUCH, 1);
> +		}

		} else {
			input_report_key(priv->input, BTN_TOUCH, 0);
		}

> +
> +		if (info.gesture)
> +			report_gesture_event(priv, info.gesture, info.touch);
> +
> +		input_sync(priv->input);
> +	}

out:

> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int cst816x_probe(struct i2c_client *client)
> +{
> +	struct cst816x_priv *priv;
> +	struct device *dev = &client->dev;
> +	int rc;

	int error;

> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	priv->client = client;
> +
> +	priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);

Please make reset optional, it does not have to be handled by the driver
if something else (firmware) will be doing power sequencing.

> +	if (IS_ERR(priv->reset))
> +		return dev_err_probe(dev, PTR_ERR(priv->reset),
> +				     "reset gpio not found\n");
> +
> +	cst816x_reset(priv);
> +
> +	rc = cst816x_register_input(priv);
> +	if (rc)
> +		return dev_err_probe(dev, rc, "input register failed\n");
> +
> +	rc = devm_request_threaded_irq(dev, client->irq, NULL, cst816x_irq_cb,
> +				       IRQF_ONESHOT, dev->driver->name, priv);
> +	if (rc)
> +		return dev_err_probe(dev, rc, "irq request failed\n");
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id cst816x_id[] = {
> +	{ .name = "cst816s", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, cst816x_id);
> +
> +static const struct of_device_id cst816x_of_match[] = {
> +	{ .compatible = "hynitron,cst816s", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, cst816x_of_match);
> +
> +static struct i2c_driver cst816x_driver = {
> +	.driver = {
> +		.name = "cst816x",
> +		.of_match_table = cst816x_of_match,
> +	},
> +	.id_table = cst816x_id,
> +	.probe = cst816x_probe,
> +};
> +
> +module_i2c_driver(cst816x_driver);
> +
> +MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>");
> +MODULE_DESCRIPTION("Hynitron CST816X Touchscreen Driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.34.1
> 

Thanks.

-- 
Dmitry

      reply	other threads:[~2024-09-01  4:27 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-29 21:20 [PATCH v4 1/2] dt-bindings: input: touchscreen: add Hynitron CST816X Oleh Kuzhylnyi
2024-08-29 21:20 ` [PATCH v4 2/2] input: add driver for Hynitron CST816X touchscreen Oleh Kuzhylnyi
2024-09-01  4:27   ` Dmitry Torokhov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZtPtIdqm4G7SqYvd@google.com \
    --to=dmitry.torokhov@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=conor.dooley@microchip.com \
    --cc=devicetree@vger.kernel.org \
    --cc=igor.opaniuk@gmail.com \
    --cc=jeff@labundy.com \
    --cc=krzk+dt@kernel.org \
    --cc=kuzhylol@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.