Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fd832b1 authored by Bingzhe Cai's avatar Bingzhe Cai Committed by Sudhakar Manapati
Browse files

input: touchpanel: Add DT support for Goodix touchpanel driver



Add device tree parser to allow Goodix touchpanel driver to get
board dependent configuration from device tree.

  This patch is propagated from 3.4 kernel
    commit: 0c3a9e121cb001a4de9f6bc84df37065dcb999d6
    input: touchpanel: Add DT support for Goodix touchpanel driver

Change-Id: I702400140130fd3b673e0e13a8dbdb7060bba881
Signed-off-by: default avatarBingzhe Cai <bingzhec@codeaurora.org>
Signed-off-by: default avatarSudhakar Manapati <smanap@codeaurora.org>
parent 9ccc3ab1
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
Goodix GT9xx series touch controller

Required properties:

 - compatible		: Should be "goodix,gt9xx"
 - reg			: I2C slave address of the device.
 - interrupt-parent	: Parent of interrupt.
 - interrupts		: Configuration of touch panel controller interrupt
				GPIO.
 - goodix,family-id	: Family identification of the controller.
 - interrupt-gpios	: Interrupt gpio which is to provide interrupts to
				host, same as "interrupts" node.
 - reset-gpios		: Reset gpio to control the reset of chip.
 - goodix,display-coords	: Display coordinates in pixels. It is a four
				tuple consisting of min x, min y, max x and
				max y values.

Optional properties:

 - avdd-supply		: Power supply needed to power up the device, this is
				for fixed voltage external regulator.
 - vdd-supply		: Power supply needed to power up the device, when use
				external regulator, do not add this property.
 - vcc-i2c-supply	: Power source required to power up i2c bus.
				GT9xx series can provide 1.8V from internal
				LDO, add this properties base on hardware
				design.
 - goodix,panel-coords	: Panel coordinates for the chip in pixels.
				It is a four tuple consisting of min x,
				min y, max x and max y values.
 - goodix,i2c-pull-up	: To specify pull up is required.
 - goodix,no-force-update	: To specify force update is allowed.
 - goodix,button-map	: Button map of key codes. The number of key codes
				depend on panel.
 - goodix,cfg-data	: Touchpanel controller configuration data, ask vendor
				to provide that. Default configuration will be
				used if this property is not present.

Example:
i2c@f9927000 {
		goodix@5d {
			compatible = "goodix,gt9xx";
			reg = <0x5d>;
			interrupt-parent = <&msmgpio>;
			interrupts = <17 0x2008>;
			reset-gpios = <&msmgpio 16 0x00>;
			interrupt-gpios = <&msmgpio 17 0x00>;
			avdd-supply = <&tp_power>;
			goodix,panel-coords = <0 0 720 1200>;
			goodix,display-coords = <0 0 720 1080>;
			goodix,button-map= <158 102 139>;
			goodix,family-id = <0x0>;
			goodix,cfg-data = [
		41 D0 02 00 05 0A 05 01 01 08
		12 58 50 41 03 05 00 00 00 00
		00 00 00 00 00 00 00 8C 2E 0E
		28 24 73 13 00 00 00 83 03 1D
		40 02 00 00 00 03 64 32 00 00
		00 1A 38 94 C0 02 00 00 00 04
		9E 1C 00 8D 20 00 7A 26 00 6D
		2C 00 60 34 00 60 10 38 68 00
		F0 50 35 FF FF 27 00 00 00 00
		00 01 1B 14 0C 14 00 00 01 00
		00 00 00 00 00 00 00 00 00 00
		00 00 02 04 06 08 0A 0C 0E 10
		12 14 16 18 1A 1C FF FF FF FF
		FF FF FF FF FF FF FF FF FF FF
		FF FF 00 02 04 06 08 0A 0C 0F
		10 12 13 14 16 18 1C 1D 1E 1F
		20 21 22 24 26 28 29 2A FF FF
		FF FF FF FF FF FF FF 22 22 22
		22 22 22 FF 07 01];
		};
};
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ fairchild Fairchild Semiconductor International, Inc.
focaltech	Focaltech systems
fsl	Freescale Semiconductor
GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
goodix	Goodix. Ltd.
gef	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
geniatech	Geniatech, Inc.
globalscale	Globalscale Technologies, Inc.
+166 −14
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@

#include "gt9xx.h"

#include <linux/of_gpio.h>

#if GTP_ICS_SLOT_REPORT
#include <linux/input/mt.h>
#endif
@@ -1019,6 +1021,11 @@ static int gtp_init_panel(struct goodix_ts_data *ts)
		return -EINVAL;
	}

	if (ts->pdata->gtp_cfg_len) {
		config_data = ts->pdata->config_data;
		ts->config_data = ts->pdata->config_data;
		ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
	} else {
		config_data = devm_kzalloc(&client->dev,
			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
				GFP_KERNEL);
@@ -1034,6 +1041,7 @@ static int gtp_init_panel(struct goodix_ts_data *ts)
		memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
		memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
				ts->gtp_cfg_len);
	}

#if GTP_CUSTOM_CFG
	config_data[RESOLUTION_LOC] =
@@ -1350,6 +1358,120 @@ exit_free_inputdev:
	return ret;
}

static int goodix_ts_get_dt_coords(struct device *dev, char *name,
				struct goodix_ts_platform_data *pdata)
{
	struct property *prop;
	struct device_node *np = dev->of_node;
	int rc;
	u32 coords[GOODIX_COORDS_ARR_SIZE];

	prop = of_find_property(np, name, NULL);
	if (!prop)
		return -EINVAL;
	if (!prop->value)
		return -ENODATA;

	rc = of_property_read_u32_array(np, name, coords,
		GOODIX_COORDS_ARR_SIZE);
	if (rc && (rc != -EINVAL)) {
		dev_err(dev, "Unable to read %s\n", name);
		return rc;
	}

	if (!strcmp(name, "goodix,panel-coords")) {
		pdata->panel_minx = coords[0];
		pdata->panel_miny = coords[1];
		pdata->panel_maxx = coords[2];
		pdata->panel_maxy = coords[3];
	} else if (!strcmp(name, "goodix,display-coords")) {
		pdata->x_min = coords[0];
		pdata->y_min = coords[1];
		pdata->x_max = coords[2];
		pdata->y_max = coords[3];
	} else {
		dev_err(dev, "unsupported property %s\n", name);
		return -EINVAL;
	}

	return 0;
}

static int goodix_parse_dt(struct device *dev,
			struct goodix_ts_platform_data *pdata)
{
	int rc;
	struct device_node *np = dev->of_node;
	struct property *prop;
	u32 temp_val, num_buttons;
	u32 button_map[MAX_BUTTONS];

	rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
	if (rc && (rc != -EINVAL))
		return rc;

	rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata);
	if (rc)
		return rc;

	pdata->i2c_pull_up = of_property_read_bool(np,
						"goodix,i2c-pull-up");

	pdata->no_force_update = of_property_read_bool(np,
						"goodix,no-force-update");
	/* reset, irq gpio info */
	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
				0, &pdata->reset_gpio_flags);
	if (pdata->reset_gpio < 0)
		return pdata->reset_gpio;

	pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios",
				0, &pdata->irq_gpio_flags);
	if (pdata->irq_gpio < 0)
		return pdata->irq_gpio;

	rc = of_property_read_u32(np, "goodix,family-id", &temp_val);
	if (!rc)
		pdata->family_id = temp_val;
	else
		return rc;

	prop = of_find_property(np, "goodix,button-map", NULL);
	if (prop) {
		num_buttons = prop->length / sizeof(temp_val);
		if (num_buttons > MAX_BUTTONS)
			return -EINVAL;

		rc = of_property_read_u32_array(np,
			"goodix,button-map", button_map,
			num_buttons);
		if (rc) {
			dev_err(dev, "Unable to read key codes\n");
			return rc;
		}
	}

	prop = of_find_property(np, "goodix,cfg-data", &pdata->gtp_cfg_len);
	if (prop && prop->value) {
		pdata->config_data = devm_kzalloc(dev,
			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, GFP_KERNEL);
		if (!pdata->config_data)
			return -ENOMEM;

		pdata->config_data[0] = GTP_REG_CONFIG_DATA >> 8;
		pdata->config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
		memset(&pdata->config_data[GTP_ADDR_LENGTH], 0,
					GTP_CONFIG_MAX_LENGTH);
		memcpy(&pdata->config_data[GTP_ADDR_LENGTH],
				prop->value, pdata->gtp_cfg_len);
	} else {
		dev_err(dev,
			"Unable to get configure data, default will be used.\n");
		pdata->gtp_cfg_len = 0;
	}

	return 0;
}
/*******************************************************
Function:
	I2c probe.
@@ -1364,15 +1486,34 @@ Output:
static int goodix_ts_probe(struct i2c_client *client,
			   const struct i2c_device_id *id)
{
	struct goodix_ts_platform_data *pdata;
	struct goodix_ts_data *ts;
	u16 version_info;
	int ret;

	dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
	if (client->dev.of_node) {
		pdata = devm_kzalloc(&client->dev,
			sizeof(struct goodix_ts_platform_data), GFP_KERNEL);
		if (!pdata)
			return -ENOMEM;

		ret = goodix_parse_dt(&client->dev, pdata);
		if (ret)
			return ret;
	} else {
		pdata = client->dev.platform_data;
	}

	if (!pdata) {
		dev_err(&client->dev, "GTP invalid pdata\n");
		return -EINVAL;
	}

#if GTP_ESD_PROTECT
	i2c_connect_client = client;
#endif

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		dev_err(&client->dev, "GTP I2C not supported\n");
		return -ENODEV;
@@ -1384,7 +1525,8 @@ static int goodix_ts_probe(struct i2c_client *client,

	memset(ts, 0, sizeof(*ts));
	ts->client = client;
	/* For kernel 2.6.39 later we spin_lock_init(&ts->irq_lock)
	ts->pdata = pdata;
	/* For 2.6.39 & later use spin_lock_init(&ts->irq_lock)
	 * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED
	 */
	spin_lock_init(&ts->irq_lock);
@@ -1472,6 +1614,10 @@ exit_free_irq:
exit_free_inputdev:
	kfree(ts->config_data);
exit_free_io_port:
	if (gpio_is_valid(pdata->reset_gpio))
		gpio_free(pdata->reset_gpio);
	if (gpio_is_valid(pdata->irq_gpio))
		gpio_free(pdata->irq_gpio);
exit_power_off:
	i2c_set_clientdata(client, NULL);
	kfree(ts);
@@ -1754,6 +1900,11 @@ static const struct i2c_device_id goodix_ts_id[] = {
	{ }
};

static struct of_device_id goodix_match_table[] = {
	{ .compatible = "goodix,gt9xx", },
	{ },
};

static struct i2c_driver goodix_ts_driver = {
	.probe      = goodix_ts_probe,
	.remove     = goodix_ts_remove,
@@ -1765,6 +1916,7 @@ static struct i2c_driver goodix_ts_driver = {
	.driver = {
		.name     = GTP_I2C_NAME,
		.owner    = THIS_MODULE,
		.of_match_table = goodix_match_table,
	},
};

+2 −2
Original line number Diff line number Diff line
@@ -46,8 +46,6 @@ struct goodix_ts_platform_data {
	u32 irq_gpio_flags;
	int reset_gpio;
	u32 reset_gpio_flags;
	int ldo_en_gpio;
	u32 ldo_en_gpio_flags;
	u32 family_id;
	u32 x_max;
	u32 y_max;
@@ -59,6 +57,8 @@ struct goodix_ts_platform_data {
	u32 panel_maxy;
	bool no_force_update;
	bool i2c_pull_up;
	int gtp_cfg_len;
	u8 *config_data;
};
struct goodix_ts_data {
	spinlock_t irq_lock;