[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ZoW4_hctu_cSiKA5@google.com>
Date: Wed, 3 Jul 2024 13:47:58 -0700
From: Dmitry Torokhov <dmitry.torokhov@...il.com>
To: Charles Wang <charles.goodix@...il.com>
Cc: dan.carpenter@...aro.org, conor@...nel.org, robh@...nel.org,
dianders@...omium.org, krzk+dt@...nel.org, jikos@...nel.org,
bentiss@...nel.org, hbarnor@...omium.org,
linux-input@...r.kernel.org, devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH v5 1/2] HID: hid-goodix: Add Goodix HID-over-SPI driver
Hi Charles,
On Tue, Jun 18, 2024 at 04:44:53PM +0800, Charles Wang wrote:
> This patch introduces a new driver to support the Goodix GT7986U
> touch controller. This device is not compatible with Microsoft's
> HID-over-SPI protocol and therefore needs to implement its own
> flavor. The data reported is packaged according to the HID
> protocol but uses SPI for communication to improve speed. This
> enables the device to transmit not only coordinate data but also
> corresponding raw data that can be accessed by user-space programs
> through the hidraw interface. The raw data can be utilized for
> functions like palm rejection, thereby improving the touch experience.
>
> Key features:
> - Device connection confirmation and initialization
> - IRQ-based event reporting to the input subsystem
> - Support for HIDRAW operations (GET_REPORT and SET_REPORT)
This looks reasonable good, so:
Reviewed-by: Dmitry Torokhov <dmitry.torokhov@...il.com>
A couple of suggestions/nits below:
> +static int goodix_spi_probe(struct spi_device *spi)
> +{
> + struct device *dev = &spi->dev;
> + struct goodix_ts_data *ts;
> + int error;
> +
> + /* init spi_device */
> + spi->mode = SPI_MODE_0;
> + spi->bits_per_word = 8;
> + error = spi_setup(spi);
> + if (error)
> + return error;
> +
> + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
> + if (!ts)
> + return -ENOMEM;
> +
If you do:
ts->event_buf = devm_kmalloc(dev, <some nominal size>, GFP_KERNEL);
here and use devm_krealloc() once you figure the true size of event
buffer you can stop calling kfree() by hand on remove.
> + mutex_init(&ts->hid_request_lock);
> + spi_set_drvdata(spi, ts);
> + ts->spi = spi;
> + ts->dev = dev;
> + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
> + if (IS_ERR(ts->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(ts->reset_gpio),
> + "failed to request reset gpio\n");
> +
> + error = device_property_read_u32(dev, "goodix,hid-report-addr",
> + &ts->hid_report_addr);
> + if (error)
> + return dev_err_probe(dev, error,
> + "failed get hid report addr\n");
> +
> + error = goodix_dev_confirm(ts);
> + if (error)
> + return error;
> +
> + /* Waits 150ms for firmware to fully boot */
> + msleep(GOODIX_NORMAL_RESET_DELAY_MS);
> +
> + error = goodix_hid_init(ts);
> + if (error) {
> + dev_err(dev, "failed init hid device");
> + return error;
> + }
> +
> + error = devm_request_threaded_irq(&ts->spi->dev, ts->spi->irq,
> + NULL, goodix_hid_irq, IRQF_ONESHOT,
> + "goodix_spi_hid", ts);
> + if (error) {
> + dev_err(ts->dev, "could not register interrupt, irq = %d, %d",
> + ts->spi->irq, error);
> + goto err_destroy_hid;
> + }
> +
> + return 0;
> +
> +err_destroy_hid:
> + hid_destroy_device(ts->hid);
> + return error;
> +}
> +
> +static void goodix_spi_remove(struct spi_device *spi)
> +{
> + struct goodix_ts_data *ts = spi_get_drvdata(spi);
> +
> + disable_irq(spi->irq);
> + hid_destroy_device(ts->hid);
> + kfree(ts->event_buf);
> +}
> +
> +static void goodix_spi_shutdown(struct spi_device *spi)
> +{
> + struct goodix_ts_data *ts = spi_get_drvdata(spi);
> +
> + disable_irq(spi->irq);
> + hid_destroy_device(ts->hid);
Do we really need shutdown() method? It is very rarely that it is
needed.
> +}
> +
> +static int goodix_spi_set_power(struct goodix_ts_data *ts, int power_state)
> +{
> + u8 power_control_cmd[] = {0x00, 0x00, 0x00, 0x87, 0x02, 0x00, 0x08};
> + int error;
> +
> + /* value 0 for power on, 1 for power sleep */
> + power_control_cmd[5] = power_state;
> +
> + guard(mutex)(&ts->hid_request_lock);
> + error = goodix_spi_write(ts, ts->hid_report_addr, power_control_cmd,
> + sizeof(power_control_cmd));
> + if (error) {
> + dev_err(ts->dev, "failed set power mode: %s",
> + power_state == GOODIX_SPI_POWER_ON ? "on" : "sleep");
> + return error;
> + }
> + return 0;
> +}
> +
> +static int goodix_spi_suspend(struct device *dev)
> +{
> + struct goodix_ts_data *ts = dev_get_drvdata(dev);
> + int error;
> +
> + error = goodix_spi_set_power(ts, GOODIX_SPI_POWER_SLEEP);
> + disable_irq(ts->spi->irq);
Can disable_irq() be called first?
Thanks.
--
Dmitry
Powered by blists - more mailing lists