input: atmel_mxt_ts: Add device tree support

Parse the device tree elements and fill platform
data structure.

Signed-off-by: Mohan Pallaka <mpallaka@codeaurora.org>
(cherry picked from commit d96f5032cd8b73450886262fe193d1531038c0f0)

Conflicts:

	drivers/input/touchscreen/atmel_mxt_ts.c

Change-Id: I551dadffaa84c991abbe964bfb9f72b7fd11dfee
Signed-off-by: Sudhir Sharma <sudsha@codeaurora.org>
(cherry picked from commit 368b8d73bbda62f6ab217ef06019b685636fc3ba)
This commit is contained in:
Mohan Pallaka 2012-06-18 22:49:10 +05:30 committed by Stephen Boyd
parent e55483ad0e
commit 915eaefb52
3 changed files with 366 additions and 19 deletions

View file

@ -0,0 +1,128 @@
Atmel touch controller
Required properties:
- compatible : should be "atmel,mxt-ts"
- reg : i2c slave address of the device
- interrupt-parent : parent of interrupt
- interrupts : touch sample interrupt to indicate presense or release
of fingers on the panel.
- atmel,panel-coords : touch panel minimum x, minimum y, maximum x and
maximum y resolution
- atmel,display-coords : LCD display minimum x, minimum y, maximum x and
maximum y resolution
- vdd_ana-supply : Analog power supply needed to power device
- atmel,irq-gpio : irq gpio
- atmel,reset-gpio : reset gpio
- atmel,family-id : family identification of the controller
- atmel,variant-id : variant identification of the controller
- atmel,version : firmware version of the controller
- atmel,build i : firmware build number of the controller
- atmel,bootldr-id : bootloader identification of the controller
- atmel,fw-name : firmware name to used for flashing firmware
Optional property:
- atmel,config : configuration parameter for the controller
- atmel,i2c-pull-up : specify to indicate pull up is needed
- vcc_i2c-supply : Power source required to pull up i2c bus
- atmel,dig-reg-support : specify to indicate digital regulator is
needed
Example:
i2c@f9966000 {
cell-index = <3>;
compatible = "qcom,i2c-qup";
reg = <0xf9966000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
interrupts = <0 104 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <24000000>;
atmel_mxt_ts@4a {
compatible = "atmel,mxt-ts";
reg = <0x4a>
interrupt-parent = <&msmgpio>
interrupts = <48 0x0>;
vdd_ana-supply = <&pm8941_l18>;
vcc_i2c-supply = <&pm8941_lvs1>;
atmel,panel-coords = <0 0 479 799>;
atmel,display-coords = <0 0 479 799>;
atmel,i2c-pull-up = <1>;
atmel,dig-reg-support;
atmel,key-codes = <
102 139 0 0 0 0 0 0
0 158 217 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 >;
atmel,irq-gpio = <&msmgpio 48 0>;
atmel,reset-gpio = <&msmgpio 26 0>;
atmel,cfg_1 {
atmel,family-id = <0x81>;
atmel,variant-id = <0x01>;
atmel,version = <0x10>;
atmel,build = <0xaa>;
atmel,config = [
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
15 00 02 10 08 0C 00 00
/* Object 7, Instance = 0 */
FF FF 32 03
/* Object 8, Instance = 0 */
0F 00 0A 0A 00 00 0A 00 00 00
/* Object 9, Instance = 0 */
83 00 00 18 0E 00 70 32 02 01
00 03 01 01 05 0A 0A 0A 90 05
F8 02 00 00 0F 0F 00 00 48 2D
07 0C 00 00 00 00
/* Object 15, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
00
/* Object 18, Instance = 0 */
00 00
/* Object 19, Instance = 0 */
00 00 00 00 00 00
/* Object 23, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00
/* Object 25, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00
/* Object 40, Instance = 0 */
00 00 00 00 00
/* Object 42, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
/* Object 46, Instance = 0 */
00 00 10 10 00 00 03 00 00 01
/* Object 47, Instance = 0 */
08 0A 28 0A 02 0A 00 8C 00 20
00 00 00
/* Object 55, Instance = 0 */
00 00 00 00 00 00
/* Object 56, Instance = 0 */
03 00 01 18 05 05 05 05 05 05
05 05 05 05 05 05 05 05 05 05
05 05 05 05 05 05 05 05 00 00
00 00 00 00 00 00 00 00 00 00
00 00
/* Object 57, Instance = 0 */
00 00 00
/* Object 61, Instance = 0 */
00 00 00 00 00
/* Object 61, Instance = 1 */
00 00 00 00 00
/* Object 62, Instance = 0 */
7F 03 00 16 00 00 00 00 00 00
04 08 10 18 05 00 0A 05 05 50
14 19 34 1A 64 00 00 04 40 00
00 00 00 00 30 32 02 00 01 00
05 00 00 00 00 00 00 00 00 00
00 00 0C 00
];
}
}
};

View file

@ -26,7 +26,7 @@
#include <linux/seq_file.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <linux/of_gpio.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
/* Early-suspend level */
@ -290,6 +290,8 @@ enum mxt_device_state { INIT, APPMODE, BOOTLOADER };
#define MXT_CFG_VERSION_LESS 1
#define MXT_CFG_VERSION_GREATER 2
#define MXT_COORDS_ARR_SIZE 4
#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
#define MXT_DEBUGFS_FILE "object"
@ -2326,14 +2328,228 @@ static void __devinit mxt_debugfs_init(struct mxt_data *data)
}
}
#ifdef CONFIG_OF
static int mxt_get_dt_coords(struct device *dev, char *name,
struct mxt_platform_data *pdata)
{
u32 coords[MXT_COORDS_ARR_SIZE];
struct property *prop;
struct device_node *np = dev->of_node;
int coords_size, rc;
prop = of_find_property(np, name, NULL);
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
coords_size = prop->length / sizeof(u32);
if (coords_size != MXT_COORDS_ARR_SIZE) {
dev_err(dev, "invalid %s\n", name);
return -EINVAL;
}
rc = of_property_read_u32_array(np, name, coords, coords_size);
if (rc && (rc != -EINVAL)) {
dev_err(dev, "Unable to read %s\n", name);
return rc;
}
if (strncmp(name, "atmel,panel-coords",
sizeof("atmel,panel-coords")) == 0) {
pdata->panel_minx = coords[0];
pdata->panel_miny = coords[1];
pdata->panel_maxx = coords[2];
pdata->panel_maxy = coords[3];
} else if (strncmp(name, "atmel,display-coords",
sizeof("atmel,display-coords")) == 0) {
pdata->disp_minx = coords[0];
pdata->disp_miny = coords[1];
pdata->disp_maxx = coords[2];
pdata->disp_maxy = coords[3];
} else {
dev_err(dev, "unsupported property %s\n", name);
return -EINVAL;
}
return 0;
}
static int mxt_parse_config(struct device *dev, struct device_node *np,
struct mxt_config_info *info)
{
struct property *prop;
u8 *temp_cfg;
prop = of_find_property(np, "atmel,config", &info->config_length);
if (!prop) {
dev_err(dev, "Looking up %s property in node %s failed",
"atmel,config", np->full_name);
return -ENODEV;
} else if (!info->config_length) {
dev_err(dev, "Invalid length of configuration data\n");
return -EINVAL;
}
temp_cfg = devm_kzalloc(dev,
info->config_length * sizeof(u8), GFP_KERNEL);
if (!temp_cfg) {
dev_err(dev, "Unable to allocate memory to store cfg\n");
return -ENOMEM;
}
memcpy(temp_cfg, prop->value, info->config_length);
info->config = temp_cfg;
return 0;
}
static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
{
int rc;
struct mxt_config_info *info;
struct device_node *temp, *np = dev->of_node;
struct property *prop;
u32 temp_val;
rc = mxt_get_dt_coords(dev, "atmel,panel-coords", pdata);
if (rc)
return rc;
rc = mxt_get_dt_coords(dev, "atmel,display-coords", pdata);
if (rc)
return rc;
/* regulator info */
pdata->i2c_pull_up = of_property_read_bool(np, "atmel,i2c-pull-up");
pdata->digital_pwr_regulator = of_property_read_bool(np,
"atmel,dig-reg-support");
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
0, &pdata->reset_gpio_flags);
pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio",
0, &pdata->irq_gpio_flags);
/* keycodes for keyarray object*/
prop = of_find_property(np, "atmel,key-codes", NULL);
if (prop) {
pdata->key_codes = devm_kzalloc(dev,
sizeof(int) * MXT_KEYARRAY_MAX_KEYS,
GFP_KERNEL);
if (!pdata->key_codes)
return -ENOMEM;
if ((prop->length/sizeof(u32)) == MXT_KEYARRAY_MAX_KEYS) {
rc = of_property_read_u32_array(np, "atmel,key-codes",
pdata->key_codes, MXT_KEYARRAY_MAX_KEYS);
if (rc) {
dev_err(dev, "Unable to read key codes\n");
return rc;
}
} else
return -EINVAL;
}
/* config array size */
pdata->config_array_size = 0;
temp = NULL;
while ((temp = of_get_next_child(np, temp)))
pdata->config_array_size++;
if (!pdata->config_array_size)
return 0;
info = devm_kzalloc(dev, pdata->config_array_size *
sizeof(struct mxt_config_info), GFP_KERNEL);
if (!info) {
dev_err(dev, "Unable to allocate memory\n");
return -ENOMEM;
}
pdata->config_array = info;
for_each_child_of_node(np, temp) {
rc = of_property_read_string(temp, "atmel,fw-name",
&info->fw_name);
if (rc && (rc != -EINVAL)) {
dev_err(dev, "Unable to read fw name\n");
return rc;
}
rc = of_property_read_u32(temp, "atmel,family-id", &temp_val);
if (rc) {
dev_err(dev, "Unable to read family id\n");
return rc;
} else
info->family_id = (u8) temp_val;
rc = of_property_read_u32(temp, "atmel,variant-id", &temp_val);
if (rc) {
dev_err(dev, "Unable to read variant id\n");
return rc;
} else
info->variant_id = (u8) temp_val;
rc = of_property_read_u32(temp, "atmel,version", &temp_val);
if (rc) {
dev_err(dev, "Unable to read controller version\n");
return rc;
} else
info->version = (u8) temp_val;
rc = of_property_read_u32(temp, "atmel,build", &temp_val);
if (rc) {
dev_err(dev, "Unable to read build id\n");
return rc;
} else
info->build = (u8) temp_val;
info->bootldr_id = of_property_read_u32(temp,
"atmel,bootldr-id", &temp_val);
if (rc) {
dev_err(dev, "Unable to read bootldr-id\n");
return rc;
} else
info->bootldr_id = (u8) temp_val;
rc = mxt_parse_config(dev, temp, info);
if (rc) {
dev_err(dev, "Unable to parse config data\n");
return rc;
}
info++;
}
return 0;
}
#else
static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
{
return -ENODEV;
}
#endif
static int __devinit mxt_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct mxt_platform_data *pdata = client->dev.platform_data;
struct mxt_platform_data *pdata;
struct mxt_data *data;
struct input_dev *input_dev;
int error, i;
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
sizeof(struct mxt_platform_data), GFP_KERNEL);
if (!pdata) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
error = mxt_parse_dt(&client->dev, pdata);
if (error)
return error;
} else
pdata = client->dev.platform_data;
if (!pdata)
return -EINVAL;
@ -2355,7 +2571,6 @@ static int __devinit mxt_probe(struct i2c_client *client,
data->client = client;
data->input_dev = input_dev;
data->pdata = pdata;
data->irq = client->irq;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
@ -2413,46 +2628,47 @@ static int __devinit mxt_probe(struct i2c_client *client,
if (gpio_is_valid(pdata->irq_gpio)) {
/* configure touchscreen irq gpio */
error = gpio_request(pdata->irq_gpio,
"mxt_irq_gpio");
error = gpio_request(pdata->irq_gpio, "mxt_irq_gpio");
if (error) {
pr_err("%s: unable to request gpio [%d]\n", __func__,
dev_err(&client->dev, "unable to request gpio [%d]\n",
pdata->irq_gpio);
goto err_power_on;
}
error = gpio_direction_input(pdata->irq_gpio);
if (error) {
pr_err("%s: unable to set_direction for gpio [%d]\n",
__func__, pdata->irq_gpio);
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
pdata->irq_gpio);
goto err_irq_gpio_req;
}
data->irq = client->irq = gpio_to_irq(pdata->irq_gpio);
} else {
dev_err(&client->dev, "irq gpio not provided\n");
goto err_power_on;
}
if (gpio_is_valid(pdata->reset_gpio)) {
/* configure touchscreen reset out gpio */
error = gpio_request(pdata->reset_gpio,
"mxt_reset_gpio");
error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
if (error) {
pr_err("%s: unable to request reset gpio %d\n",
__func__, pdata->reset_gpio);
dev_err(&client->dev, "unable to request gpio [%d]\n",
pdata->reset_gpio);
goto err_irq_gpio_req;
}
error = gpio_direction_output(
pdata->reset_gpio, 1);
error = gpio_direction_output(pdata->reset_gpio, 1);
if (error) {
pr_err("%s: unable to set direction for gpio %d\n",
__func__, pdata->reset_gpio);
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
pdata->reset_gpio);
goto err_reset_gpio_req;
}
}
mxt_reset_delay(data);
error = mxt_initialize(data);
if (error)
goto err_reset_gpio_req;
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
pdata->irqflags, client->dev.driver->name, data);
if (error) {
@ -2559,7 +2775,7 @@ static const struct i2c_device_id mxt_id[] = {
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
#ifdef CONFIG_OF
#ifdef OF_CONFIG
static struct of_device_id mxt_match_table[] = {
{ .compatible = "atmel,mxt-ts",},
{ },
@ -2572,6 +2788,7 @@ static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
.owner = THIS_MODULE,
.of_match_table = mxt_match_table,
#ifdef CONFIG_PM
.pm = &mxt_pm_ops,
#endif

View file

@ -69,7 +69,9 @@ struct mxt_platform_data {
bool i2c_pull_up;
bool digital_pwr_regulator;
int reset_gpio;
u32 reset_gpio_flags;
int irq_gpio;
u32 irq_gpio_flags;
int *key_codes;
u8(*read_chg) (void);