mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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:
parent
e55483ad0e
commit
915eaefb52
3 changed files with 366 additions and 19 deletions
|
@ -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
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue