diff mbox

[v8,2/9] Input: goodix - reset device at init

Message ID 1444314231-19206-3-git-send-email-irina.tirdea@intel.com (mailing list archive)
State Superseded
Headers show

Commit Message

tip-bot for Irina Tirdea Oct. 8, 2015, 2:23 p.m. UTC
After power on, it is recommended that the driver resets the device.
The reset procedure timing is described in the datasheet and is used
at device init (before writing device configuration) and
for power management. It is a sequence of setting the interrupt
and reset pins high/low at specific timing intervals. This procedure
also includes setting the slave address to the one specified in the
ACPI/device tree.

This is based on Goodix datasheets for GT911 and GT9271 and on Goodix
driver gt9xx.c for Android (publicly available in Android kernel
trees for various devices).

For reset the driver needs to control the interrupt and
reset gpio pins (configured through ACPI/device tree). For devices
that do not have the gpio pins properly declared, the functionality
depending on these pins will not be available, but the device can still
be used with basic functionality.

For both device tree and ACPI, the interrupt gpio pin configuration is
read from the "irq-gpio" property and the reset pin configuration is
read from the "reset-gpio" property. For ACPI 5.1, named properties
can be specified using the _DSD section. This functionality will not be
available for devices that use indexed gpio pins declared in the _CRS
section (we need to provide backward compatibility with devices
that do not support using the interrupt gpio pin as output).

For ACPI, the pins can be specified using ACPI 5.1:
Device (STAC)
{
    Name (_HID, "GDIX1001")
    ...

    Method (_CRS, 0, Serialized)
    {
        Name (RBUF, ResourceTemplate ()
        {
            I2cSerialBus (0x0014, ControllerInitiated, 0x00061A80,
                AddressingMode7Bit, "\\I2C0",
                0x00, ResourceConsumer, ,
                )

            GpioInt (Edge, ActiveHigh, Exclusive, PullNone, 0x0000,
                "\\I2C0", 0x00, ResourceConsumer, ,
                 )
                 {   // Pin list
                     0
                 }

            GpioIo (Exclusive, PullDown, 0x0000, 0x0000,
                IoRestrictionOutputOnly, "\\I2C0", 0x00,
                ResourceConsumer, ,
                )
                {
                     1
                }
        })
        Return (RBUF)
    }

    Name (_DSD,  Package ()
    {
        ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
        Package ()
        {
            Package (2) {"irq-gpio", Package() {^STAC, 0, 0, 0 }},
            Package (2) {"reset-gpio", Package() {^STAC, 1, 0, 0 }},
            ...
        }
    }

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 .../bindings/input/touchscreen/goodix.txt          |   5 +
 drivers/input/touchscreen/goodix.c                 | 101 +++++++++++++++++++++
 2 files changed, 106 insertions(+)

Comments

Bastien Nocera Oct. 9, 2015, 2:22 p.m. UTC | #1
On Thu, 2015-10-08 at 17:23 +0300, Irina Tirdea wrote:
> After power on, it is recommended that the driver resets the device.
> The reset procedure timing is described in the datasheet and is used
> at device init (before writing device configuration) and
> for power management. It is a sequence of setting the interrupt
> and reset pins high/low at specific timing intervals. This procedure
> also includes setting the slave address to the one specified in the
> ACPI/device tree.
> 
> This is based on Goodix datasheets for GT911 and GT9271 and on Goodix
> driver gt9xx.c for Android (publicly available in Android kernel
> trees for various devices).
> 
> For reset the driver needs to control the interrupt and
> reset gpio pins (configured through ACPI/device tree). For devices
> that do not have the gpio pins properly declared, the functionality
> depending on these pins will not be available, but the device can
> still
> be used with basic functionality.
> 
> For both device tree and ACPI, the interrupt gpio pin configuration
> is
> read from the "irq-gpio" property and the reset pin configuration is
> read from the "reset-gpio" property. For ACPI 5.1, named properties
> can be specified using the _DSD section. This functionality will not
> be
> available for devices that use indexed gpio pins declared in the _CRS
> section (we need to provide backward compatibility with devices
> that do not support using the interrupt gpio pin as output).
> 
> For ACPI, the pins can be specified using ACPI 5.1:
> Device (STAC)
> {
>     Name (_HID, "GDIX1001")
>     ...
> 
>     Method (_CRS, 0, Serialized)
>     {
>         Name (RBUF, ResourceTemplate ()
>         {
>             I2cSerialBus (0x0014, ControllerInitiated, 0x00061A80,
>                 AddressingMode7Bit, "\\I2C0",
>                 0x00, ResourceConsumer, ,
>                 )
> 
>             GpioInt (Edge, ActiveHigh, Exclusive, PullNone, 0x0000,
>                 "\\I2C0", 0x00, ResourceConsumer, ,
>                  )
>                  {   // Pin list
>                      0
>                  }
> 
>             GpioIo (Exclusive, PullDown, 0x0000, 0x0000,
>                 IoRestrictionOutputOnly, "\\I2C0", 0x00,
>                 ResourceConsumer, ,
>                 )
>                 {
>                      1
>                 }
>         })
>         Return (RBUF)
>     }
> 
>     Name (_DSD,  Package ()
>     {
>         ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>         Package ()
>         {
>             Package (2) {"irq-gpio", Package() {^STAC, 0, 0, 0 }},
>             Package (2) {"reset-gpio", Package() {^STAC, 1, 0, 0 }},
>             ...
>         }
>     }
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>

Didn't actually cause problems on my system, and the documentation
looks good.

Acked-by: Bastien Nocera <hadess@hadess.net>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
kernel test robot Oct. 10, 2015, 11:35 p.m. UTC | #2
Hi Irina,

[auto build test ERROR on v4.3-rc4 -- if it's inappropriate base, please ignore]

config: x86_64-randconfig-h0-10110617 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/input/touchscreen/goodix.c: In function 'goodix_int_sync':
>> drivers/input/touchscreen/goodix.c:250:10: error: implicit declaration of function 'gpiod_direction_output' [-Werror=implicit-function-declaration]
     error = gpiod_direction_output(ts->gpiod_int, 0);
             ^
>> drivers/input/touchscreen/goodix.c:255:9: error: implicit declaration of function 'gpiod_direction_input' [-Werror=implicit-function-declaration]
     return gpiod_direction_input(ts->gpiod_int);
            ^
   drivers/input/touchscreen/goodix.c: In function 'goodix_get_gpio_config':
>> drivers/input/touchscreen/goodix.c:304:10: error: implicit declaration of function 'devm_gpiod_get' [-Werror=implicit-function-declaration]
     gpiod = devm_gpiod_get(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
             ^
>> drivers/input/touchscreen/goodix.c:304:52: error: 'GPIOD_IN' undeclared (first use in this function)
     gpiod = devm_gpiod_get(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
                                                       ^
   drivers/input/touchscreen/goodix.c:304:52: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors

vim +/gpiod_direction_output +250 drivers/input/touchscreen/goodix.c

   244	}
   245	
   246	static int goodix_int_sync(struct goodix_ts_data *ts)
   247	{
   248		int error;
   249	
 > 250		error = gpiod_direction_output(ts->gpiod_int, 0);
   251		if (error)
   252			return error;
   253		msleep(50);				/* T5: 50ms */
   254	
 > 255		return gpiod_direction_input(ts->gpiod_int);
   256	}
   257	
   258	/**
   259	 * goodix_reset - Reset device during power on
   260	 *
   261	 * @ts: goodix_ts_data pointer
   262	 */
   263	static int goodix_reset(struct goodix_ts_data *ts)
   264	{
   265		int error;
   266	
   267		/* begin select I2C slave addr */
   268		error = gpiod_direction_output(ts->gpiod_rst, 0);
   269		if (error)
   270			return error;
   271		msleep(20);				/* T2: > 10ms */
   272		/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
   273		error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
   274		if (error)
   275			return error;
   276		usleep_range(100, 2000);		/* T3: > 100us */
   277		error = gpiod_direction_output(ts->gpiod_rst, 1);
   278		if (error)
   279			return error;
   280		usleep_range(6000, 10000);		/* T4: > 5ms */
   281		/* end select I2C slave addr */
   282		error = gpiod_direction_input(ts->gpiod_rst);
   283		if (error)
   284			return error;
   285		return goodix_int_sync(ts);
   286	}
   287	
   288	/**
   289	 * goodix_get_gpio_config - Get GPIO config from ACPI/DT
   290	 *
   291	 * @ts: goodix_ts_data pointer
   292	 */
   293	static int goodix_get_gpio_config(struct goodix_ts_data *ts)
   294	{
   295		int error;
   296		struct device *dev;
   297		struct gpio_desc *gpiod;
   298	
   299		if (!ts->client)
   300			return -EINVAL;
   301		dev = &ts->client->dev;
   302	
   303		/* Get the interrupt GPIO pin number */
 > 304		gpiod = devm_gpiod_get(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
   305		if (IS_ERR(gpiod)) {
   306			error = PTR_ERR(gpiod);
   307			if (error != -EPROBE_DEFER)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
index 8ba98ee..7137881 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
@@ -12,6 +12,8 @@  Required properties:
  - reg			: I2C address of the chip. Should be 0x5d or 0x14
  - interrupt-parent	: Interrupt controller to which the chip is connected
  - interrupts		: Interrupt to which the chip is connected
+ - irq-gpio		: GPIO pin used for IRQ
+ - reset-gpio		: GPIO pin used for reset
 
 Example:
 
@@ -23,6 +25,9 @@  Example:
 			reg = <0x5d>;
 			interrupt-parent = <&gpio>;
 			interrupts = <0 0>;
+
+			irq-gpio = <&gpio1 0 0>;
+			reset-gpio = <&gpio1 1 0>;
 		};
 
 		/* ... */
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 56d0330..87304ac 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -16,6 +16,7 @@ 
 
 #include <linux/kernel.h>
 #include <linux/dmi.h>
+#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
@@ -37,8 +38,13 @@  struct goodix_ts_data {
 	unsigned int int_trigger_type;
 	bool rotated_screen;
 	int cfg_len;
+	struct gpio_desc *gpiod_int;
+	struct gpio_desc *gpiod_rst;
 };
 
+#define GOODIX_GPIO_INT_NAME		"irq"
+#define GOODIX_GPIO_RST_NAME		"reset"
+
 #define GOODIX_MAX_HEIGHT		4096
 #define GOODIX_MAX_WIDTH		4096
 #define GOODIX_INT_TRIGGER		1
@@ -237,6 +243,88 @@  static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int goodix_int_sync(struct goodix_ts_data *ts)
+{
+	int error;
+
+	error = gpiod_direction_output(ts->gpiod_int, 0);
+	if (error)
+		return error;
+	msleep(50);				/* T5: 50ms */
+
+	return gpiod_direction_input(ts->gpiod_int);
+}
+
+/**
+ * goodix_reset - Reset device during power on
+ *
+ * @ts: goodix_ts_data pointer
+ */
+static int goodix_reset(struct goodix_ts_data *ts)
+{
+	int error;
+
+	/* begin select I2C slave addr */
+	error = gpiod_direction_output(ts->gpiod_rst, 0);
+	if (error)
+		return error;
+	msleep(20);				/* T2: > 10ms */
+	/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+	error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
+	if (error)
+		return error;
+	usleep_range(100, 2000);		/* T3: > 100us */
+	error = gpiod_direction_output(ts->gpiod_rst, 1);
+	if (error)
+		return error;
+	usleep_range(6000, 10000);		/* T4: > 5ms */
+	/* end select I2C slave addr */
+	error = gpiod_direction_input(ts->gpiod_rst);
+	if (error)
+		return error;
+	return goodix_int_sync(ts);
+}
+
+/**
+ * goodix_get_gpio_config - Get GPIO config from ACPI/DT
+ *
+ * @ts: goodix_ts_data pointer
+ */
+static int goodix_get_gpio_config(struct goodix_ts_data *ts)
+{
+	int error;
+	struct device *dev;
+	struct gpio_desc *gpiod;
+
+	if (!ts->client)
+		return -EINVAL;
+	dev = &ts->client->dev;
+
+	/* Get the interrupt GPIO pin number */
+	gpiod = devm_gpiod_get(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
+	if (IS_ERR(gpiod)) {
+		error = PTR_ERR(gpiod);
+		if (error != -EPROBE_DEFER)
+			dev_dbg(dev, "Failed to get %s GPIO: %d\n",
+				GOODIX_GPIO_INT_NAME, error);
+		return error;
+	}
+	ts->gpiod_int = gpiod;
+
+	/* Get the reset line GPIO pin number */
+	gpiod = devm_gpiod_get(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
+	if (IS_ERR(gpiod)) {
+		error = PTR_ERR(gpiod);
+		if (error != -EPROBE_DEFER)
+			dev_dbg(dev, "Failed to get %s GPIO: %d\n",
+				GOODIX_GPIO_RST_NAME, error);
+		return error;
+	}
+	ts->gpiod_rst = gpiod;
+
+	return 0;
+}
+
 /**
  * goodix_read_config - Read the embedded configuration of the panel
  *
@@ -405,6 +493,19 @@  static int goodix_ts_probe(struct i2c_client *client,
 	ts->client = client;
 	i2c_set_clientdata(client, ts);
 
+	error = goodix_get_gpio_config(ts);
+	if (error == -EPROBE_DEFER)
+		return error;
+
+	if (ts->gpiod_int && ts->gpiod_rst) {
+		/* reset the controller */
+		error = goodix_reset(ts);
+		if (error) {
+			dev_err(&client->dev, "Controller reset failed.\n");
+			return error;
+		}
+	}
+
 	error = goodix_i2c_test(client);
 	if (error) {
 		dev_err(&client->dev, "I2C communication failure: %d\n", error);