Re: [PATCH] Input: add driver for TouchNetix aXiom touchscreen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Le Mon, Sep 11, 2023 at 08:59:21AM +0200, Krzysztof Kozlowski a écrit :
> On 08/09/2023 17:32, Kamel Bouhara wrote:
> > Add a new driver for the TouchNetix's aXiom family of
> > multi-touch controller. This driver only support i2c
> > and can be later adapted for SPI and USB support.
> >
> > Signed-off-by: Kamel Bouhara <kamel.bouhara@xxxxxxxxxxx>
> > ---
> >  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>
>
> Thank you for your patch. There is something to discuss/improve.
>
> 1. Bindings are separate patches.
>
> I am surprised that you did not send this through your collegagues at
> Bootlin for some internal review. It would spot such easy things to fix.
>
> 2. Please use subject prefixes matching the subsystem. You can get them
> for example with `git log --oneline -- DIRECTORY_OR_FILE` on the
> directory your patch is touching.
>
> 3. Please run scripts/checkpatch.pl and fix reported warnings. Some
> warnings can be ignored, but the code here looks like it needs a fix.
> Feel free to get in touch if the warning is not clear.
>
> 4. Please use scripts/get_maintainers.pl to get a list of necessary
> people and lists to CC. It might happen, that command when run on an
> older kernel, gives you outdated entries. Therefore please be sure you
> base your patches on recent Linux kernel.
>
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time, thus I will skip this patch entirely till you follow
> the process allowing the patch to be tested.
>
> Please kindly resend and include all necessary To/Cc entries.
>
> Limited review follows.

Hello Krzysztof,

Sorry for this late answer  and thanks for this not so limited review,
much appreciate :) !

>
>
> >  MAINTAINERS                                   |   7 +
> >  drivers/input/touchscreen/Kconfig             |  11 +
> >  drivers/input/touchscreen/Makefile            |   1 +
> >  drivers/input/touchscreen/axiom_core.c        | 382 ++++++++++++++++++
> >  drivers/input/touchscreen/axiom_core.h        | 140 +++++++
> >  drivers/input/touchscreen/axiom_i2c.c         | 349 ++++++++++++++++
> >  7 files changed, 892 insertions(+)
> >  create mode 100644 drivers/input/touchscreen/axiom_core.c
> >  create mode 100644 drivers/input/touchscreen/axiom_core.h
> >  create mode 100644 drivers/input/touchscreen/axiom_i2c.c
> >
> > diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> > index 573578db9509..b0a3ed451f15 100644
> > --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> > +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> > @@ -175,6 +175,8 @@ patternProperties:
> >    "^awinic,.*":
> >      description: Shanghai Awinic Technology Co., Ltd.
> >    "^axentia,.*":
> > +    description: TouchNetix
> > +  "^axiom,.*":
> >      description: Axentia Technologies AB
> >    "^axis,.*":
> >      description: Axis Communications AB
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 389fe9e38884..43add48257d8 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -3373,6 +3373,13 @@ W:	https://ez.analog.com/linux-software-drivers
> >  F:	Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
> >  F:	drivers/hwmon/axi-fan-control.c
> >
> > +AXIOM I2C TOUCHSCREEN DRIVER
> > +M:	Kamel Bouhara <kamel.bouhara@xxxxxxxxxxx>
> > +L:	linux-input@xxxxxxxxxxxxxxx
> > +S:	Maintained
> > +F:	drivers/input/touchscreen/axiom_core.c
> > +F:	drivers/input/touchscreen/axiom_i2.c
> > +
> >  AXXIA I2C CONTROLLER
> >  M:	Krzysztof Adamski <krzysztof.adamski@xxxxxxxxx>
> >  L:	linux-i2c@xxxxxxxxxxxxxxx
> > diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> > index e3e2324547b9..08a770a0c5e5 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -150,6 +150,17 @@ config TOUCHSCREEN_AUO_PIXCIR
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called auo-pixcir-ts.
> >
> > +config TOUCHSCREEN_AXIOM_I2C
> > +	tristate "AXIOM based multi-touch panel controllers"
> > +	help
> > +	  Say Y here if you have a axiom touchscreen connected to
> > +	  your system.
> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called axiom_i2c.
> > +
> >  config TOUCHSCREEN_BU21013
> >  	tristate "BU21013 based touch panel controllers"
> >  	depends on I2C
> > diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> > index 62bd24f3ac8e..59a3234ddb09 100644
> > --- a/drivers/input/touchscreen/Makefile
> > +++ b/drivers/input/touchscreen/Makefile
> > @@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
> >  obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C)	+= ar1021_i2c.o
> >  obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
> > +obj-$(CONFIG_TOUCHSCREEN_AXIOM_I2C)	+= axiom_core.o axiom_i2c.o
> >  obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_BU21029)	+= bu21029_ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318)	+= chipone_icn8318.o
> > diff --git a/drivers/input/touchscreen/axiom_core.c b/drivers/input/touchscreen/axiom_core.c
> > new file mode 100644
> > index 000000000000..d381afd7fb84
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/axiom_core.c
> > @@ -0,0 +1,382 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * TouchNetix aXiom Touchscreen Driver
> > + *
> > + * Copyright (C) 2020-2023 TouchNetix Ltd.
> > + *
> > + * Author(s): Mark Satterthwaite <mark.satterthwaite@xxxxxxxxxxxxxx>
> > + *            Pedro Torruella <pedro.torruella@xxxxxxxxxxxxxx>
> > + *            Bart Prescott <bartp@xxxxxxxxxxxxxx>
> > + *            Hannah Rossiter <hannah.rossiter@xxxxxxxxxxxxxx>
> > + *
> > + */
> > +
> > +#include <linux/crc16.h>
> > +#include <linux/device.h>
> > +#include <linux/input.h>
> > +#include <linux/input/mt.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/slab.h>
> > +
> > +#include "axiom_core.h"
> > +
> > +/**
> > + * Decodes and populates the local u31 structure.
> > + * Given a buffer of data read from page 0 of u31 in an aXiom device.
> > + */
> > +void axiom_get_dev_info(struct axiom_data *ts, char *info)
> > +{
> > +	struct axiom_devinfo *devinfo = &ts->devinfo;
> > +
> > +	if (devinfo) {
> > +		devinfo->bootloader_mode = ((info[1] & 0x80) != 0) ? 1 : 0;
> > +		devinfo->device_id = ((info[1] & 0x7F) << 8) | info[0];
> > +		devinfo->fw_minor = info[2];
> > +		devinfo->fw_major = info[3];
> > +		devinfo->fw_info_extra = (info[4]) | (info[5] << 8);
> > +		devinfo->bootloader_fw_ver_minor = info[6];
> > +		devinfo->bootloader_fw_ver_major = info[7];
> > +		devinfo->jedec_id = (info[8]) | (info[9] << 8);
> > +		devinfo->num_usages = info[10];
> > +		devinfo->silicon_revision = info[11];
> > +	}
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_get_dev_info);
>
> Nope

I guess this means no need to export the function ?

I agree this is not required currently as we only have support the i2c
variant.

>
> > +
> > +/**
> > + * Decodes and populates the local Usage Table.
> > + * Given a buffer of data read from page 1 onwards of u31 from an aXiom
> > + * device.
> > + */
> > +char axiom_populate_usage_table(struct axiom_data *ts, char *rx_data)
> > +{
> > +	u32 usage_id = 0;
> > +	char max_report_len = 0;
> > +	struct axiom_devinfo *device_info;
> > +	struct usage_entry *usage_table;
> > +
> > +	device_info = &ts->devinfo;
> > +	usage_table = ts->usage_table;
> > +
> > +	for (usage_id = 0; usage_id < device_info->num_usages; usage_id++) {
> > +		u16 offset = (usage_id * U31_BYTES_PER_USAGE);
> > +		char id = rx_data[offset + 0];
> > +		char start_page = rx_data[offset + 1];
> > +		char num_pages = rx_data[offset + 2];
> > +		char max_offset = ((rx_data[offset + 3] & 0x7F) + 1) * 2;
> > +
> > +		/* Store the entry into the usage table */
> > +		usage_table[usage_id].id = id;
> > +		usage_table[usage_id].is_report = ((num_pages == 0) ? 1 : 0);
> > +		usage_table[usage_id].start_page = start_page;
> > +		usage_table[usage_id].num_pages = num_pages;
> > +
> > +		dev_dbg(ts->pdev, "Usage %2u Info: %*ph\n", usage_id,
> > +			U31_BYTES_PER_USAGE, &rx_data[offset]);
> > +
> > +		/* Identify the max report length the module will receive */
> > +		if ((usage_table[usage_id].is_report)
> > +		    && (max_offset > max_report_len))
> > +			max_report_len = max_offset;
> > +	}
> > +	ts->usage_table_populated = true;
> > +
> > +	return max_report_len;
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_populate_usage_table);
> > +
> > +/**
> > + * Translate usage/page/offset triplet into physical address.
> > + *
> > + * @usage: groups of registers
> > + * @page: page to which the usage belongs to offset
> > + * @offset of the usage
> > + */
> > +u16
> > +usage_to_target_address(struct axiom_data *ts, char usage, char page,
> > +			char offset)
> > +{
> > +	struct axiom_devinfo *device_info;
> > +	struct usage_entry *usage_table;
> > +	u16 target_address;
> > +	u32 i;
> > +
> > +	device_info = &ts->devinfo;
> > +	usage_table = ts->usage_table;
> > +
> > +	/* At the moment the convention is that u31 is always at physical address 0x0 */
> > +	if (!ts->usage_table_populated && (usage == DEVINFO_USAGE_ID)) {
> > +		target_address = ((page << 8) + offset);
> > +	} else if (ts->usage_table_populated) {
> > +		for (i = 0; i < device_info->num_usages; i++) {
> > +			if (usage_table[i].id == usage) {
> > +				if (page < usage_table[i].num_pages) {
> > +					target_address =
> > +					    ((usage_table[i].start_page + page) << 8) + offset;
> > +				} else {
> > +					target_address = 0xFFFF;
> > +					dev_err(ts->pdev,
> > +						"Invalid usage table! usage: %u, page: %u, offset: %u\n",
> > +						usage, page, offset);
> > +				}
> > +				break;
> > +			}
> > +		}
> > +	} else {
> > +		target_address = 0xFFFF;
> > +		dev_err(ts->pdev, "Unpopulated usage table for usage: %u\n",
> > +			usage);
> > +	}
> > +
> > +	dev_dbg(ts->pdev, "target_address is 0x%04x for usage: %u page %u\n",
> > +		target_address, usage, page);
> > +
> > +	return target_address;
> > +}
> > +EXPORT_SYMBOL_GPL(usage_to_target_address);
>
> Nope, drop.
>
> > +
> > +void axiom_remove(struct axiom_data *ts)
> > +{
> > +	if (ts->usage_table)
> > +		ts->usage_table_populated = false;
> > +
> > +	if (ts->input_dev)
> > +		input_unregister_device(ts->input_dev);
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_remove);
>
> Nope, drop.
>
> > +
>
>
> > +
> > +/**
> > + * Take a raw buffer with u41 report data and decode it.
> > + * Also generate input events if needed.
> > + * @rx_buf: ptr to a byte array [0]: Usage number [1]: Status LSB [2]: Status MSB
> > + */
> > +void axiom_process_u41_report(struct axiom_data *ts, char *rx_buf)
> > +{
> > +	struct axiom_target_report target;
> > +	struct input_dev *input_dev = ts->input_dev;
> > +	bool update_done = false;
> > +	u16 target_status;
> > +	u32 i;
> > +
> > +	if (rx_buf[0] != 0x41) {
> > +		dev_err(ts->pdev,
> > +			"Data in buffer does not have expected u41 format.\n");
> > +		return;
> > +	}
> > +
> > +	target_status = ((rx_buf[1]) | (rx_buf[2] << 8));
> > +
> > +	for (i = 0; i < U41_MAX_TARGETS; i++) {
> > +		target.index = i;
> > +		target.present = ((target_status & (1 << i)) != 0) ? 1 : 0;
> > +		target.x = (rx_buf[(i * 4) + 3]) | (rx_buf[(i * 4) + 4] << 8);
> > +		target.y = (rx_buf[(i * 4) + 5]) | (rx_buf[(i * 4) + 6] << 8);
> > +		target.z = (s8) (rx_buf[i + 43]);
> > +		update_done |= axiom_process_u41_report_target(ts, &target);
> > +	}
> > +
> > +	if (update_done)
> > +		input_sync(input_dev);
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_process_u41_report);
>
> Nope, drop.
>
> > +
> > +void axiom_process_u46_report(struct axiom_data *ts, char *rx_buf)
> > +{
> > +	struct input_dev *input_dev = ts->input_dev;
> > +	u16 aux_value;
> > +	u32 event_value;
> > +	u32 i = 0;
> > +
> > +	for (i = 0; i < U46_AUX_CHANNELS; i++) {
> > +		aux_value =
> > +		    ((rx_buf[(i * 2) + 2] << 8) | (rx_buf[(i * 2) + 1])) &
> > +		    U46_AUX_MASK;
> > +		event_value = (i << 16) | (aux_value);
> > +		input_event(input_dev, EV_MSC, MSC_RAW, event_value);
> > +	}
> > +
> > +	input_mt_sync(input_dev);
> > +	input_sync(input_dev);
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_process_u46_report);
>
> Nope, drop.
>
> Clean your driver before sending upstream. :(
>
> > +
> > +/**
> > + * Support function to axiom_process_report.
> > + * It validates the crc and multiplexes the axiom reports to the appropriate
> > + * report handler
> > + */
> > +void axiom_process_report(struct axiom_data *ts, char *report_data)
> > +{
> > +	struct device *pdev = ts->pdev;
> > +	char usage = report_data[1];
> > +	u16 crc_report;
> > +	u16 crc_calc;
> > +	char len;
> > +
> > +	if ((report_data[0] & COMMS_OVERFLOW_MSK) != 0)
> > +		ts->report_overflow_counter++;
> > +
> > +	len = (report_data[0] & COMMS_REPORT_LEN_MSK) << 1;
> > +	if (len == 0) {
> > +		dev_err(pdev, "Zero length report discarded.\n");
> > +		return;
> > +	}
> > +
> > +	dev_dbg(pdev, "Payload Data %*ph\n", len, report_data);
> > +
> > +	/* Validate the report CRC */
> > +	crc_report = (report_data[len - 1] << 8) | (report_data[len - 2]);
> > +	/* Length is in 16 bit words and remove the size of the CRC16 itself */
> > +	crc_calc = crc16(0, report_data, (len - 2));
> > +
> > +	if (crc_calc != crc_report) {
> > +		dev_err(pdev,
> > +			"CRC mismatch! Expected: %#x, Calculated CRC: %#x.\n",
> > +			crc_report, crc_calc);
> > +		return;
> > +	}
> > +
> > +	switch (usage) {
> > +	case USAGE_2DCTS_REPORT_ID:
> > +		axiom_process_u41_report(ts, &report_data[1]);
> > +		break;
> > +
> > +	case USAGE_2AUX_REPORT_ID:
> > +		/* This is an aux report (force) */
> > +		axiom_process_u46_report(ts, &report_data[1]);
> > +		break;
> > +
> > +	case USAGE_2HB_REPORT_ID:
> > +		/* This is a heartbeat report */
> > +		break;
> > +
> > +	default:
> > +		break;
> > +	}
> > +
> > +	ts->report_counter++;
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_process_report);
>
> Nope, drop.
>
> > +
> > +MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@xxxxxxxxxxx>");
> > +MODULE_DESCRIPTION("aXiom touchscreen core logic");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("axiom");
>
> ???? How can you have multiple drivers with the same alias? Even if your
> Makefile allowed it (but it doesn't!), it would not make sense.
>
>
> > diff --git a/drivers/input/touchscreen/axiom_core.h b/drivers/input/touchscreen/axiom_core.h
> > new file mode 100644
> > index 000000000000..f129d28671ff
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/axiom_core.h
> > @@ -0,0 +1,140 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * TouchNetix aXiom Touchscreen Driver
> > + *
> > + * Copyright (C) 2020-2023 TouchNetix Ltd.
> > + *
> > + * Author(s): Mark Satterthwaite <mark.satterthwaite@xxxxxxxxxxxxxx>
> > + *            Pedro Torruella <pedro.torruella@xxxxxxxxxxxxxx>
> > + *            Bart Prescott <bartp@xxxxxxxxxxxxxx>
> > + *            Hannah Rossiter <hannah.rossiter@xxxxxxxxxxxxxx>
> > + *
> > + * This program is free software; you can redistribute  it and/or modify it
> > + * under  the terms of  the GNU General  Public License as published by the
> > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > + * option) any later version.
>
> OK, so this is some old, vendor crappy code. We do not have it since
> some years!

Yes :).

>
> > + *
>
> ...
>
> > +
> > +static void axiom_i2c_poll(struct input_dev *input_dev)
> > +{
> > +	struct axiom_data *ts = input_get_drvdata(input_dev);
> > +	char *rx_data = ts->rx_buf;
> > +
> > +	axiom_i2c_read(ts->client, REPORT_USAGE_ID, 0, rx_data,
> > +		       ts->max_report_len);
> > +	axiom_process_report(ts, rx_data);
> > +}
> > +
> > +/**
> > + * Retrieve, store and print the axiom device information
> > + */
> > +int axiom_discover(struct axiom_data *ts)
>
> This has to be static.

ok.

>
> > +{
> > +	char *rx_data = &ts->rx_buf[0];
> > +	struct device *pdev = ts->pdev;
> > +	int ret;
> > +
> > +	/* First the first page of u31 to get the device information and */
> > +	/* the number of usages */
> > +	ret =
> > +	    axiom_i2c_read(ts->client, DEVINFO_USAGE_ID, 0, rx_data,
> > +			   AX_U31_PAGE0_LENGTH);
> > +	if (ret)
> > +		return ret;
> > +
> > +	axiom_get_dev_info(ts, rx_data);
> > +
> > +	dev_dbg(pdev, "Data Decode:\n");
> > +	dev_dbg(pdev, "  Bootloader Mode: %u\n", ts->devinfo.bootloader_mode);
> > +	dev_dbg(pdev, "  Device ID      : %04x\n", ts->devinfo.device_id);
> > +	dev_dbg(pdev, "  Firmware Rev   : %02x.%02x\n", ts->devinfo.fw_major,
> > +		ts->devinfo.fw_minor);
> > +	dev_dbg(pdev, "  Bootloader Rev : %02x.%02x\n",
> > +		ts->devinfo.bootloader_fw_ver_major,
> > +		ts->devinfo.bootloader_fw_ver_minor);
> > +	dev_dbg(pdev, "  FW Extra Info  : %04x\n", ts->devinfo.fw_info_extra);
> > +	dev_dbg(pdev, "  Silicon        : %02x\n", ts->devinfo.jedec_id);
> > +	dev_dbg(pdev, "  Num Usages     : %04x\n", ts->devinfo.num_usages);
> > +
> > +	/* Read the second page of u31 to get the usage table */
> > +	ret = axiom_i2c_read(ts->client, DEVINFO_USAGE_ID, 1, rx_data,
> > +			     (U31_BYTES_PER_USAGE * ts->devinfo.num_usages));
> > +	if (ret)
> > +		return ret;
> > +
> > +	ts->max_report_len = axiom_populate_usage_table(ts, rx_data);
> > +	dev_dbg(pdev, "Max Report Length: %u\n", ts->max_report_len);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_discover);
>
> Nope.
>
> > +
> > +/**
> > + * Rebaseline the touchscreen, effectively zero-ing it
> > + */
> > +void axiom_rebaseline(struct axiom_data *ts)
>
> Missing static.
>
> > +{
> > +	struct device *pdev = ts->pdev;
> > +	char buffer[8] = { 0 };
> > +	int ret;
> > +
> > +	memset(buffer, 0, sizeof(buffer));
> > +
> > +	buffer[0] = REBASELINE_CMD;
> > +
> > +	ret = axiom_i2c_write(ts->client, 0x02, 0, buffer, sizeof(buffer));
> > +	if (ret)
> > +		dev_err(pdev, "Rebaseline failed\n");
> > +
> > +	dev_info(pdev, "Capture Baseline Requested\n");
> > +}
> > +EXPORT_SYMBOL_GPL(axiom_rebaseline);
>
> Nope.
>
> > +
> > +static irqreturn_t axiom_irq(int irq, void *handle)
> > +{
> > +	struct axiom_data *ts = handle;
> > +	u8 *rx_data = &ts->rx_buf[0];
> > +
> > +	axiom_i2c_read(ts->client, REPORT_USAGE_ID, 0, rx_data, ts->max_report_len);
> > +	axiom_process_report(ts, rx_data);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int axiom_i2c_probe(struct i2c_client *client)
> > +{
> > +	struct axiom_data *ts;
> > +	struct device *pdev = &client->dev;
> > +	struct input_dev *input_dev;
> > +	int error;
> > +	int target;
> > +
> > +	ts = devm_kzalloc(pdev, sizeof(*ts), GFP_KERNEL);
> > +	if (!ts)
> > +		return -ENOMEM;
> > +
> > +	ts->irq_gpio = devm_gpiod_get_optional(pdev, "irq", GPIOD_IN);
> > +	if (IS_ERR(ts->irq_gpio)) {
> > +		error = PTR_ERR(ts->irq_gpio);
> > +		dev_err(pdev, "failed to request irq GPIO: %d", error);
>
> Heh... syntax is: return dev_err_probe()
>
> > +		return error;
> > +	}
> > +
> > +	ts->reset_gpio = devm_gpiod_get_optional(pdev, "reset", GPIOD_OUT_HIGH);
>
> You do not use this GPIO at all. Dead code, especially that you keep the
> device in reset. This was absolutely never tested (unless with incorrect
> DTS...).

Actually this has been exclusively tested on a X86 platform with ACPI
overrides however this still need to be fixed indeed.

>
> > +	if (IS_ERR(ts->reset_gpio)) {
> > +		error = PTR_ERR(ts->reset_gpio);
>
> return dev_err_probe()
>
> > +		dev_err(pdev, "failed to request reset GPIO: %d", error);
> > +		return error;
> > +	}
> > +
> > +	if (ts->irq_gpio) {
> > +		error =
> > +		    devm_request_threaded_irq(pdev, client->irq, NULL,
> > +					      axiom_irq,
> > +					      IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> > +					      "axiom_irq", ts);
> > +		if (error != 0) {
> > +			dev_err(pdev, "Failed to request IRQ %u (error: %d)\n",
> > +				client->irq, error);
>
> return dev_err_probe()
>
> > +			return error;
> > +		}
> > +	}
> > +
> > +	ts->client = client;
> > +	ts->pdev = pdev;
> > +	ts->usage_table_populated = false;
> > +
> > +	i2c_set_clientdata(client, ts);
> > +
> > +	axiom_discover(ts);
> > +	axiom_rebaseline(ts);
> > +
> > +	input_dev = devm_input_allocate_device(ts->pdev);
> > +	if (!input_dev) {
> > +		dev_err(pdev, "Failed to allocate input device\n");
>
> I don't think we print memory allocation failures.
>
> > +		return -ENOMEM;
> > +	}
> > +
> > +	input_dev->name = "TouchNetix aXiom Touchscreen";
> > +	input_dev->phys = "input/axiom_ts";
> > +
> > +	/* Single Touch */
> > +	input_set_abs_params(input_dev, ABS_X, 0, 65535, 0, 0);
> > +	input_set_abs_params(input_dev, ABS_Y, 0, 65535, 0, 0);
> > +
> > +	/* Multi Touch */
> > +	/* Min, Max, Fuzz (expected noise in px, try 4?) and Flat */
> > +	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 65535, 0, 0);
> > +	/* Min, Max, Fuzz (expected noise in px, try 4?) and Flat */
> > +	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 65535, 0, 0);
> > +	input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
> > +	input_set_abs_params(input_dev, ABS_MT_DISTANCE, 0, 127, 0, 0);
> > +	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 127, 0, 0);
> > +
> > +	/* Registers the axiom device as a touch screen instead of as a mouse pointer */
> > +	input_mt_init_slots(input_dev, U41_MAX_TARGETS, INPUT_MT_DIRECT);
> > +
> > +	input_set_capability(input_dev, EV_KEY, BTN_LEFT);
> > +
> > +	/* Enables the raw data for up to 4 force channels to be sent to the */
> > +	/* input subsystem */
> > +	set_bit(EV_REL, input_dev->evbit);
> > +	set_bit(EV_MSC, input_dev->evbit);
> > +	/* Declare that we support "RAW" Miscellaneous events */
> > +	set_bit(MSC_RAW, input_dev->mscbit);
> > +
> > +	if (!ts->irq_gpio) {
> > +		error = input_setup_polling(input_dev, axiom_i2c_poll);
> > +		if (error) {
> > +			dev_err(ts->pdev, "Unable to set up polling: %d\n",
> > +				error);
> > +			return error;
> > +		}
> > +		input_set_poll_interval(input_dev, POLL_INTERVAL_DEFAULT_MS);
> > +	}
> > +
> > +	error = input_register_device(input_dev);
> > +	if (error != 0) {
> > +		dev_err(ts->pdev,
> > +			"Could not register with Input Sub-system., error=%d\n",
> > +			error);
> > +		return error;
> > +	}
> > +
> > +	ts->input_dev = input_dev;
> > +	input_set_drvdata(ts->input_dev, ts);
> > +
> > +	dev_info(pdev, "AXIOM: I2C driver registered with Input Sub-System.\n");
>
> Drop silly tracing messages.
>
> > +
> > +	/* Delay just a smidge before enabling the IRQ */
> > +	udelay(10);
>
> ??? So where is the IRQ being enabled? This is confusing.

This need to move before IRQ is enabled.

>
> > +
> > +	/* Ensure that all reports are initialised to not be present. */
> > +	for (target = 0; target < U41_MAX_TARGETS; target++)
> > +		ts->targets[target].state = TARGET_STATE_NOT_PRESENT;
> > +
> > +	return 0;
> > +}
> > +
> > +static void axiom_i2c_remove(struct i2c_client *client)
> > +{
> > +	struct axiom_data *ts = i2c_get_clientdata(client);
> > +
> > +	axiom_remove(ts);
> > +}
> > +
> > +static const struct i2c_device_id axiom_i2c_id_table[] = {
> > +	{"ax54a"},
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, axiom_i2c_id_table);
> > +
> > +static const struct of_device_id axiom_i2c_dt_ids[] = {
> > +	{
> > +	 .compatible = "axiom,ax54a",
>
> That's not documented. And you would know it if you run basic checks
> before sending patches upstream.
>

I was actually suprised to found not all touchscreen drivers have
a documented binding and I know understand this is bad :) !

> Please run scripts/checkpatch.pl and fix reported warnings. Some
> warnings can be ignored, but the code here looks like it needs a fix.
> Feel free to get in touch if the warning is not clear.

OK, actually those are the only checkpatch warnings reported:

$ ./scripts/checkpatch.pl 0001-Input-add-driver-for-TouchNetix-aXiom-touchscreen.patch
WARNING: DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.rst

WARNING: DT compatible string "axiom,ax54a" appears un-documented -- check ./Documentation/devicetree/bindings/
#954: FILE: drivers/input/touchscreen/axiom_i2c.c:326:
+        .compatible = "axiom,ax54a",

total: 0 errors, 2 warnings, 916 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

>
> > +	 .data = "axiom",
>
> Why?

Actually not used, more clean up required.

>
> That's not readable. Indent it like in other drivers.
>
> > +	 },
> > +	{}
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, axiom_i2c_dt_ids);
> > +
> > +static struct i2c_driver axiom_i2c_driver = {
> > +	.driver = {
> > +		   .name = "axiom_i2c",
> > +		   .of_match_table = of_match_ptr(axiom_i2c_dt_ids),
>
> Drop of_match_ptr(), it causes warnings in your code...

Ok.

>
> > +		   },
> > +	.id_table = axiom_i2c_id_table,
> > +	.probe = axiom_i2c_probe,
> > +	.remove = axiom_i2c_remove,
> > +};
> > +
> > +module_i2c_driver(axiom_i2c_driver);
> > +
> > +MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@xxxxxxxxxxx>");
> > +MODULE_DESCRIPTION("aXiom touchscreen I2C bus driver");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("axiom");
>
> Nope, you cannot have such alias and it is not even needed.

Ack, thanks !

>
>
> Best regards,
> Krzysztof
>

--
Kamel Bouhara, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux