All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Neil Armstrong <neil.armstrong@linaro.org>
Cc: linux-input@vger.kernel.org, Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Bastien Nocera <hadess@hadess.net>,
	Hans de Goede <hdegoede@redhat.com>,
	Henrik Rydberg <rydberg@bitmath.org>,
	Jeff LaBundy <jeff@labundy.com>,
	linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v9 2/4] Input: add core support for Goodix Berlin Touchscreen IC
Date: Sun, 22 Oct 2023 21:37:08 -0700	[thread overview]
Message-ID: <ZTX4dPa3CxZacDph@google.com> (raw)
In-Reply-To: <20231021-topic-goodix-berlin-upstream-initial-v9-2-13fb4e887156@linaro.org>

Hi Neil,

On Sat, Oct 21, 2023 at 01:09:24PM +0200, Neil Armstrong wrote:
> +static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
> +{
> +	u8 afe_data[GOODIX_BERLIN_IC_INFO_MAX_LEN];

You probably already saw the kernel test robot message, I think we
should allocate this buffer in the heap (and free it once its no longer
needed).

> +	__le16 length_raw;
> +	u16 length;
> +	int error;
> +
> +	error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
> +				&length_raw, sizeof(length_raw));
> +	if (error) {
> +		dev_info(cd->dev, "failed get ic info length, %d\n", error);
> +		return error;
> +	}
> +
> +	length = le16_to_cpu(length_raw);
> +	if (length >= GOODIX_BERLIN_IC_INFO_MAX_LEN) {
> +		dev_info(cd->dev, "invalid ic info length %d\n", length);
> +		return -EINVAL;
> +	}
> +
> +	error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
> +				afe_data, length);
> +	if (error) {
> +		dev_info(cd->dev, "failed get ic info data, %d\n", error);
> +		return error;
> +	}
> +
> +	/* check whether the data is valid (ex. bus default values) */
> +	if (goodix_berlin_is_dummy_data(cd, (const uint8_t *)afe_data, length)) {

This cast is not needed.

> +		dev_err(cd->dev, "fw info data invalid\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!goodix_berlin_checksum_valid((const uint8_t *)afe_data, length)) {

This cast is not needed either.

> +		dev_info(cd->dev, "fw info checksum error\n");
> +		return -EINVAL;
> +	}
> +
> +	error = goodix_berlin_convert_ic_info(cd, afe_data, length);
> +	if (error)
> +		return error;
> +
> +	/* check some key info */
> +	if (!cd->touch_data_addr) {
> +		dev_err(cd->dev, "touch_data_addr is null\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void goodix_berlin_parse_finger(struct goodix_berlin_core *cd,
> +				       const void *buf, int touch_num)
> +{
> +	const struct goodix_berlin_touch_data *touch_data = buf;
> +	int i;
> +
> +	/* Check for data validity */
> +	for (i = 0; i < touch_num; i++) {
> +		unsigned int id;
> +
> +		id = FIELD_GET(GOODIX_BERLIN_TOUCH_ID_MASK, touch_data[i].id);
> +
> +		if (id >= GOODIX_BERLIN_MAX_TOUCH) {
> +			dev_warn(cd->dev, "invalid finger id %d\n", id);
> +			return;

Is it important to abort entire packet if one if the slots has incorrect
data? Can we simply skip over these contacts?

> +		}
> +	}
> +
> +	/* Report finger touches */
> +	for (i = 0; i < touch_num; i++) {
> +		input_mt_slot(cd->input_dev,
> +			      FIELD_GET(GOODIX_BERLIN_TOUCH_ID_MASK,
> +					touch_data[i].id));
> +		input_mt_report_slot_state(cd->input_dev, MT_TOOL_FINGER, true);
> +
> +		touchscreen_report_pos(cd->input_dev, &cd->props,
> +				       __le16_to_cpu(touch_data[i].x),
> +				       __le16_to_cpu(touch_data[i].y),
> +				       true);
> +		input_report_abs(cd->input_dev, ABS_MT_TOUCH_MAJOR,
> +				 __le16_to_cpu(touch_data[i].w));
> +	}
> +
> +	input_mt_sync_frame(cd->input_dev);
> +	input_sync(cd->input_dev);
> +}
> +
> +static void goodix_berlin_touch_handler(struct goodix_berlin_core *cd,
> +					const void *pre_buf, u32 pre_buf_len)
> +{
> +	static u8 buffer[GOODIX_BERLIN_IRQ_READ_LEN(GOODIX_BERLIN_MAX_TOUCH)];

No, please no static data. The drivers should be ready to handle more
than one device on a system. If the buffer is large-ish put it into
goodix_berlin_core.


> +	u8 point_type, touch_num;
> +	int error;
> +
> +	/* copy pre-data to buffer */
> +	memcpy(buffer, pre_buf, pre_buf_len);
> +
> +	touch_num = FIELD_GET(GOODIX_BERLIN_TOUCH_COUNT_MASK,
> +			      buffer[GOODIX_BERLIN_REQUEST_TYPE_OFFSET]);
> +
> +	if (touch_num > GOODIX_BERLIN_MAX_TOUCH) {
> +		dev_warn(cd->dev, "invalid touch num %d\n", touch_num);
> +		return;
> +	}
> +
> +	if (touch_num) {
> +		/* read more data if more than 2 touch events */
> +		if (unlikely(touch_num > 2)) {
> +			error = regmap_raw_read(cd->regmap,
> +						cd->touch_data_addr + pre_buf_len,
> +						&buffer[pre_buf_len],
> +						(touch_num - 2) * GOODIX_BERLIN_BYTES_PER_POINT);
> +			if (error) {
> +				dev_err_ratelimited(cd->dev, "failed to get touch data, %d\n",
> +						    error);
> +				return;
> +			}
> +		}
> +
> +		point_type = FIELD_GET(GOODIX_BERLIN_POINT_TYPE_MASK,
> +				       buffer[GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN]);
> +
> +		if (point_type == GOODIX_BERLIN_POINT_TYPE_STYLUS ||
> +		    point_type == GOODIX_BERLIN_POINT_TYPE_STYLUS_HOVER) {
> +			dev_warn_once(cd->dev, "Stylus event type not handled\n");
> +			return;
> +		}
> +
> +		if (!goodix_berlin_checksum_valid(&buffer[GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN],
> +						  touch_num * GOODIX_BERLIN_BYTES_PER_POINT + 2)) {
> +			dev_err(cd->dev, "touch data checksum error, data: %*ph\n",
> +				touch_num * GOODIX_BERLIN_BYTES_PER_POINT + 2,
> +				&buffer[GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN]);
> +			return;
> +		}
> +	}
> +
> +	goodix_berlin_parse_finger(cd, &buffer[GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN],
> +				   touch_num);
> +}
> +
> +static int goodix_berlin_request_handle_reset(struct goodix_berlin_core *cd)
> +{
> +	gpiod_set_value(cd->reset_gpio, 1);
> +	usleep_range(2000, 2100);
> +	gpiod_set_value(cd->reset_gpio, 0);
> +
> +	msleep(GOODIX_BERLIN_NORMAL_RESET_DELAY_MS);

The reset line handling is optional, we should skip waits if there is
no GPIO defined for the board. 

> +
> +	return 0;
> +}
> +
> +static irqreturn_t goodix_berlin_threadirq_func(int irq, void *data)
> +{
> +	struct goodix_berlin_core *cd = data;
> +	u8 buf[GOODIX_BERLIN_IRQ_READ_LEN(2)];
> +	u8 event_status;
> +	int error;
> +
> +	/* First, read buffer with space for 2 touch events */
> +	error = regmap_raw_read(cd->regmap, cd->touch_data_addr, buf,
> +				GOODIX_BERLIN_IRQ_READ_LEN(2));
> +	if (error) {
> +		dev_err_ratelimited(cd->dev, "failed get event head data, %d\n", error);
> +		return IRQ_HANDLED;
> +	}
> +
> +	if (buf[GOODIX_BERLIN_STATUS_OFFSET] == 0)
> +		return IRQ_HANDLED;
> +
> +	if (!goodix_berlin_checksum_valid(buf, GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN)) {
> +		dev_warn_ratelimited(cd->dev, "touch head checksum err : %*ph\n",
> +				     GOODIX_BERLIN_IRQ_EVENT_HEAD_LEN, buf);
> +		return IRQ_HANDLED;
> +	}
> +
> +	event_status = buf[GOODIX_BERLIN_STATUS_OFFSET];
> +
> +	if (event_status & GOODIX_BERLIN_TOUCH_EVENT)
> +		goodix_berlin_touch_handler(cd, buf, GOODIX_BERLIN_IRQ_READ_LEN(2));
> +
> +	if (event_status & GOODIX_BERLIN_REQUEST_EVENT) {
> +		switch (buf[GOODIX_BERLIN_REQUEST_TYPE_OFFSET]) {
> +		case GOODIX_BERLIN_REQUEST_CODE_RESET:
> +			goodix_berlin_request_handle_reset(cd);
> +			break;
> +
> +		default:
> +			dev_warn(cd->dev, "unsupported request code 0x%x\n",
> +				 buf[GOODIX_BERLIN_REQUEST_TYPE_OFFSET]);
> +		}
> +	}
> +
> +	/* Clear up status field */
> +	regmap_write(cd->regmap, cd->touch_data_addr, 0);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd,
> +					  const struct input_id *id)
> +{
> +	struct input_dev *input_dev;
> +	int error;
> +
> +	input_dev = devm_input_allocate_device(cd->dev);
> +	if (!input_dev)
> +		return -ENOMEM;
> +
> +	cd->input_dev = input_dev;
> +	input_set_drvdata(input_dev, cd);
> +
> +	input_dev->name = "Goodix Berlin Capacitive TouchScreen";
> +	input_dev->phys = "input/ts";
> +
> +	input_dev->id = *id;
> +
> +	input_set_abs_params(cd->input_dev, ABS_MT_POSITION_X, 0, SZ_64K - 1, 0, 0);
> +	input_set_abs_params(cd->input_dev, ABS_MT_POSITION_Y, 0, SZ_64K - 1, 0, 0);
> +	input_set_abs_params(cd->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> +
> +	touchscreen_parse_properties(cd->input_dev, true, &cd->props);
> +
> +	error = input_mt_init_slots(cd->input_dev, GOODIX_BERLIN_MAX_TOUCH,
> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +	if (error)
> +		return error;
> +
> +	return input_register_device(cd->input_dev);

Please in functions with multiple possible failure paths use format

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

	return 0;

Thanks.

-- 
Dmitry

  reply	other threads:[~2023-10-23  4:37 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-21 11:09 [PATCH v9 0/4] Input: add initial support for Goodix Berlin touchscreen IC Neil Armstrong
2023-10-21 11:09 ` [PATCH v9 1/4] dt-bindings: input: document Goodix Berlin Touchscreen IC Neil Armstrong
2023-10-21 11:09 ` [PATCH v9 2/4] Input: add core support for " Neil Armstrong
2023-10-23  4:37   ` Dmitry Torokhov [this message]
2023-10-23 14:04     ` Neil Armstrong
2023-10-21 11:09 ` [PATCH v9 3/4] Input: goodix-berlin - add I2C " Neil Armstrong
2023-10-23  3:24   ` kernel test robot
2023-10-21 11:09 ` [PATCH v9 4/4] Input: goodix-berlin - add SPI " Neil Armstrong

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=ZTX4dPa3CxZacDph@google.com \
    --to=dmitry.torokhov@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=hadess@hadess.net \
    --cc=hdegoede@redhat.com \
    --cc=jeff@labundy.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=robh+dt@kernel.org \
    --cc=rydberg@bitmath.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.