blob: c4648b69f58994e6ac7b43d7976b8f05371fb3cc [file] [log] [blame]
/* add cypress new driver ttda-02.03.01.476713 */
/* add the log dynamic control */
/*fixed memory related issues*/
/*
* cyttsp4_devtree.c
* Cypress TrueTouch(TM) Standard Product V4 Device Tree Support Driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2013 Cypress Semiconductor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2, and only version 2, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/slab.h>
/* cyttsp */
#include <linux/cyttsp4_bus.h>
#include <linux/cyttsp4_core.h>
#include <linux/cyttsp4_btn.h>
#include <linux/cyttsp4_mt.h>
#include <linux/cyttsp4_proximity.h>
#include <linux/cyttsp4_platform.h>
#include "cyttsp4_regs.h"
#include "cyttsp4_devtree.h"
#include <linux/of_gpio.h>
#include "cyttsp4_device_access.h"
#define ENABLE_VIRTUAL_KEYS
#define MAX_NAME_LENGTH 64
#ifdef CONFIG_INPUT_HW_ATE
#define MAX_VIRTUALKEYS_NUM 500
char buf_virtualkeys[MAX_VIRTUALKEYS_NUM];
ssize_t buf_vkey_size = 0;
#endif
enum cyttsp4_device_type {
DEVICE_MT,
DEVICE_BTN,
DEVICE_PROXIMITY,
#if 1 //hauwei 0701
DEVICE_LOADER,
#endif //huawei 0701
DEVICE_TYPE_MAX,
};
struct cyttsp4_device_pdata_func {
void *(*create_and_get_pdata) (struct device_node *);
void (*free_pdata) (void *);
};
#ifdef ENABLE_VIRTUAL_KEYS
static struct kobject *board_properties_kobj;
struct cyttsp4_virtual_keys {
struct kobj_attribute kobj_attr;
u16 *data;
int size;
};
#endif
struct cyttsp4_extended_mt_platform_data {
struct cyttsp4_mt_platform_data pdata;
#ifdef ENABLE_VIRTUAL_KEYS
struct cyttsp4_virtual_keys vkeys;
#endif
};
static inline int get_inp_dev_name(struct device_node *dev_node,
const char **inp_dev_name)
{
return of_property_read_string(dev_node, "cy,inp_dev_name",
inp_dev_name);
}
static u16 *create_and_get_u16_array(struct device_node *dev_node,
const char *name, int *size)
{
const __be32 *values;
u16 *val_array;
int len;
int sz;
int rc;
int i;
values = of_get_property(dev_node, name, &len);
if (values == NULL)
return NULL;
sz = len / sizeof(u32);
tp_log_debug("%s: %s size:%d\n", __func__, name, sz);
val_array = kzalloc(sz * sizeof(u16), GFP_KERNEL);
if (val_array == NULL) {
rc = -ENOMEM;
goto fail;
}
for (i = 0; i < sz; i++)
val_array[i] = (u16) be32_to_cpup(values++);
*size = sz;
return val_array;
fail:
return ERR_PTR(rc);
}
/*
The caller should free abs and frmwrk pointer safely
The function to do it is: free_touch_framework
*/
static struct touch_framework *create_and_get_touch_framework(struct device_node
*dev_node)
{
struct touch_framework *frmwrk;
u16 *abs;
int size;
int rc;
abs = create_and_get_u16_array(dev_node, "cy,abs", &size);
if (IS_ERR_OR_NULL(abs))
return (void *)abs;
/* Check for valid abs size */
if (size % CY_NUM_ABS_SET) {
rc = -EINVAL;
goto fail_free_abs;
}
frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL);
if (frmwrk == NULL) {
rc = -ENOMEM;
goto fail_free_abs;
}
frmwrk->abs = abs;
frmwrk->size = size;
return frmwrk;
fail_free_abs:
kfree(abs);
return ERR_PTR(rc);
}
static void free_touch_framework(struct touch_framework *frmwrk)
{
/*If call in failure case when frmwrk is free but abs is not it might crash,
use check even its called in failure case */
if (frmwrk)
kfree(frmwrk->abs);
kfree(frmwrk);
}
static struct touch_wakeup_keys *create_and_get_wakeup_keys(struct device_node
*dev_node)
{
struct touch_wakeup_keys *wakeup_keys = NULL;
u16 *keys = NULL;
int size = 0;
int rc = 0;
keys =
create_and_get_u16_array(dev_node, "cy,easy_wakeup_gesture_keys",
&size);
if (IS_ERR_OR_NULL(keys))
return (void *)keys;
/* Check for valid abs size */
if (size > 8) {
rc = -EINVAL;
goto fail_free_keys;
}
wakeup_keys = kzalloc(sizeof(*wakeup_keys), GFP_KERNEL);
if (wakeup_keys == NULL) {
rc = -ENOMEM;
goto fail_free_keys;
}
wakeup_keys->keys = keys;
wakeup_keys->size = size;
return wakeup_keys;
fail_free_keys:
kfree(keys);
return ERR_PTR(rc);
}
static void free_wakeup_keys(struct touch_wakeup_keys *wakeup_keys)
{
/*If call in failure case when frmwrk is free but abs is not it might crash,
use check even its called in failure case */
if (wakeup_keys)
kfree(wakeup_keys->keys);
kfree(wakeup_keys);
}
#ifdef ENABLE_VIRTUAL_KEYS
#define VIRTUAL_KEY_ELEMENT_SIZE 5
static ssize_t virtual_keys_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct cyttsp4_virtual_keys *vkeys = container_of(attr,
struct
cyttsp4_virtual_keys,
kobj_attr);
u16 *data = vkeys->data;
int size = vkeys->size;
int index;
int i;
index = 0;
for (i = 0; i < size; i += VIRTUAL_KEY_ELEMENT_SIZE)
index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
"0x01:%d:%d:%d:%d:%d\n",
data[i], data[i + 1], data[i + 2],
data[i + 3], data[i + 4]);
#ifdef CONFIG_INPUT_HW_ATE
if (index < MAX_VIRTUALKEYS_NUM) {
memcpy(buf_virtualkeys, buf, index);
buf_vkey_size = index;
tp_log_debug("%s: virtual_keys_show : buf_vkey_size = %d\n",
__func__, index);
} else {
tp_log_debug("%s: virtual_keys_show : index = %d\n", __func__,
index);
}
#endif
return index;
}
static int setup_virtual_keys(struct device_node *dev_node,
const char *inp_dev_name,
struct cyttsp4_virtual_keys *vkeys)
{
char *name;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(dev_node, "cy,virtual_keys", &size);
if (data == NULL) {
/*if virtual keys are not supported return error */
return -ENOMEM;
} else if (IS_ERR(data)) {
rc = PTR_ERR(data);
goto fail;
}
/* Check for valid virtual keys size */
if (size % VIRTUAL_KEY_ELEMENT_SIZE) {
rc = -EINVAL;
goto fail_free_data;
}
name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (name == NULL) {
rc = -ENOMEM;
goto fail_free_data;
}
snprintf(name, MAX_NAME_LENGTH, "virtualkeys.%s", inp_dev_name);
vkeys->data = data;
vkeys->size = size;
/* TODO: Instantiate in board file and export it */
if (board_properties_kobj == NULL)
board_properties_kobj =
kobject_create_and_add("board_properties", NULL);
if (board_properties_kobj == NULL) {
tp_log_err("%s: Cannot get board_properties kobject!\n",
__func__);
rc = -EINVAL;
goto fail_free_name;
}
/* Initialize dynamic SysFs attribute */
sysfs_attr_init(&vkeys->kobj_attr.attr);
vkeys->kobj_attr.attr.name = name;
vkeys->kobj_attr.attr.mode = S_IRUGO;
vkeys->kobj_attr.show = virtual_keys_show;
rc = sysfs_create_file(board_properties_kobj, &vkeys->kobj_attr.attr);
if (rc)
goto fail_del_kobj;
return 0;
fail_del_kobj:
kobject_del(board_properties_kobj);
fail_free_name:
kfree(name);
vkeys->kobj_attr.attr.name = NULL;
fail_free_data:
kfree(data);
vkeys->data = NULL;
vkeys->size = 0;
fail:
return rc;
}
static void free_virtual_keys(struct cyttsp4_virtual_keys *vkeys)
{
if (board_properties_kobj)
sysfs_remove_file(board_properties_kobj,
&vkeys->kobj_attr.attr);
kfree(vkeys->data);
vkeys->data = NULL;
vkeys->size = 0;
kfree(vkeys->kobj_attr.attr.name);
vkeys->kobj_attr.attr.name = NULL;
}
#endif
static void *create_and_get_mt_pdata(struct device_node *dev_node)
{
struct cyttsp4_extended_mt_platform_data *ext_pdata;
struct cyttsp4_mt_platform_data *pdata;
u32 value;
int rc;
ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL);
if (ext_pdata == NULL) {
rc = -ENOMEM;
goto fail;
}
pdata = &ext_pdata->pdata;
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
/* Optional fields */
rc = of_property_read_u32(dev_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_x", &value);
if (!rc)
pdata->vkeys_x = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_y", &value);
if (!rc)
pdata->vkeys_y = value;
pdata->wakeup_keys = create_and_get_wakeup_keys(dev_node);
if (IS_ERR_OR_NULL(pdata->wakeup_keys)) {
tp_log_err("%s: Wakeup gesture is not configured!\n", __func__);
pdata->wakeup_keys = NULL;
} else {
tp_log_debug
("%s: Wakeup gesture is configured for %d guestures\n",
__func__, pdata->wakeup_keys->size);
}
/* Required fields */
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
#ifdef ENABLE_VIRTUAL_KEYS
rc = setup_virtual_keys(dev_node, pdata->inp_dev_name,
&ext_pdata->vkeys);
if (rc) {
tp_log_err
("%s: Cannot setup virtual keys, only TP will work now!\n",
__func__);
//If the virtual keys are not supported the TP should work fine;
}
#endif
return pdata;
fail_free_pdata:
#ifdef ENABLE_VIRTUAL_KEYS
free_touch_framework(pdata->frmwrk);
#endif
free_wakeup_keys(pdata->wakeup_keys);
kfree(ext_pdata);
fail:
return ERR_PTR(rc);
}
static void free_mt_pdata(void *pdata)
{
struct cyttsp4_mt_platform_data *mt_pdata =
(struct cyttsp4_mt_platform_data *)pdata;
struct cyttsp4_extended_mt_platform_data *ext_mt_pdata =
container_of(mt_pdata,
struct cyttsp4_extended_mt_platform_data, pdata);
if (mt_pdata) {
free_touch_framework(mt_pdata->frmwrk);
free_wakeup_keys(mt_pdata->wakeup_keys);
}
free_touch_framework(mt_pdata->frmwrk);
#ifdef ENABLE_VIRTUAL_KEYS
free_virtual_keys(&ext_mt_pdata->vkeys);
#endif
kfree(ext_mt_pdata);
}
static void *create_and_get_btn_pdata(struct device_node *dev_node)
{
struct cyttsp4_btn_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_btn_pdata(void *pdata)
{
struct cyttsp4_btn_platform_data *btn_pdata =
(struct cyttsp4_btn_platform_data *)pdata;
kfree(btn_pdata);
}
static void *create_and_get_proximity_pdata(struct device_node *dev_node)
{
struct cyttsp4_proximity_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
/*now memory is allocated for frmwrk */
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_proximity_pdata(void *pdata)
{
struct cyttsp4_proximity_platform_data *proximity_pdata =
(struct cyttsp4_proximity_platform_data *)pdata;
if (proximity_pdata)
free_touch_framework(proximity_pdata->frmwrk);
kfree(proximity_pdata);
}
#if 1 //huawei 0701
static inline int get_firmware_name(struct device_node *dev_node,
const char **firmware_name)
{
return of_property_read_string(dev_node, "cy,firmware_name",
firmware_name);
}
static inline int get_tp_location(struct device_node *dev_node,
tp_location * tp_location)
{
int rc;
char const *get_tp_location;
rc = of_property_read_string(dev_node, "cy,tp_location",
&get_tp_location);
if (rc) {
tp_log_err("%s: read string error, rc=%d\n", __func__, rc);
goto fail_get_string;
}
if (!strncmp("COF", get_tp_location, MAX_NAME_LENGTH)) {
*tp_location = TP_COF;
} else if (!strncmp("COB", get_tp_location, MAX_NAME_LENGTH)) {
*tp_location = TP_COB;
} else {
*tp_location = TP_UNKNOW;
tp_log_err("%s: tp_location is unknown, get_tp_location=%s\n",
__func__, get_tp_location);
goto fail_get_string;
}
fail_get_string:
return rc;
}
static inline int get_product_family(struct device_node *dev_node,
const char **tp_product_family)
{
return of_property_read_string(dev_node, "cy,product_family",
tp_product_family);
}
static void *create_and_get_loader_pdata(struct device_node *dev_node)
{
struct cyttsp4_loader_platform_data *pdata;
int rc;
u32 value;
#if 0
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL) {
//if (&_cyttsp4_loader_platform_data == NULL) {
rc = -ENOMEM;
goto fail;
}
#else
pdata = &_cyttsp4_loader_platform_data;
#endif
rc = get_firmware_name(dev_node, &pdata->firmware_name);
if (rc)
goto fail_free_pdata;
rc = get_tp_location(dev_node, &pdata->tp_location);
if (rc)
goto fail_free_pdata;
/*add for force recalibration */
rc = of_property_read_u32(dev_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = get_product_family(dev_node, &pdata->tp_product_family);
if (rc)
goto fail_free_pdata;
return pdata;
fail_free_pdata:
//kfree(pdata);
//fail:
return ERR_PTR(rc);
}
static void free_loader_pdata(void *pdata)
{
//now the loader's pdata is _cyttsp4_loader_platform_data
#if 0
struct cyttsp4_loader_platform_data *loader_pdata =
(struct cyttsp4_loader_platform_data *)pdata;
kfree(loader_pdata);
#endif
}
#endif //huawei 0701
static struct cyttsp4_device_pdata_func device_pdata_funcs[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = {
.create_and_get_pdata = create_and_get_mt_pdata,
.free_pdata = free_mt_pdata,
},
[DEVICE_BTN] = {
.create_and_get_pdata = create_and_get_btn_pdata,
.free_pdata = free_btn_pdata,
},
[DEVICE_PROXIMITY] = {
.create_and_get_pdata =
create_and_get_proximity_pdata,
.free_pdata = free_proximity_pdata,
},
#if 1 //huawei 0701
[DEVICE_LOADER] = {
.create_and_get_pdata = create_and_get_loader_pdata,
.free_pdata = free_loader_pdata,
},
#endif //huawei 0701
};
static const char *device_names[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = "cy,mt",
[DEVICE_BTN] = "cy,btn",
[DEVICE_PROXIMITY] = "cy,proximity",
#if 1 //huawei 0701
[DEVICE_LOADER] = "cy,loader",
#endif //huawei 0701
};
static int get_device_type(struct device_node *dev_node,
enum cyttsp4_device_type *type)
{
const char *name;
enum cyttsp4_device_type t;
int rc;
rc = of_property_read_string(dev_node, "name", &name);
if (rc)
return rc;
for (t = 0; t < DEVICE_TYPE_MAX; t++)
if (!strncmp(name, device_names[t], MAX_NAME_LENGTH)) {
*type = t;
return 0;
}
return -EINVAL;
}
static inline void *create_and_get_device_pdata(struct device_node *dev_node,
enum cyttsp4_device_type type)
{
return device_pdata_funcs[type].create_and_get_pdata(dev_node);
}
static inline void free_device_pdata(void *pdata, enum cyttsp4_device_type type)
{
device_pdata_funcs[type].free_pdata(pdata);
}
static int register_device(struct device_node *dev_node, const char *core_id)
{
struct cyttsp4_device_info info = { 0 };
enum cyttsp4_device_type type;
struct cyttsp4_loader_platform_data *pdata;
int rc;
info.core_id = core_id;
rc = of_property_read_string(dev_node, "cy,name", &info.name);
if (rc) {
tp_log_err("%s: OF error rc=%d at line %d for cy,name\n",
__func__, rc, __LINE__);
goto fail;
} else
tp_log_debug("%s: OF cy,name: %s\n", __func__, info.name);
rc = get_device_type(dev_node, &type);
if (rc) {
tp_log_err("%s: Get device type failed: %s\n", __func__,
info.name);
goto fail;
}
info.platform_data = create_and_get_device_pdata(dev_node, type);
if (DEVICE_LOADER == type) {
pdata =
(struct cyttsp4_loader_platform_data *)info.platform_data;
}
if (IS_ERR(info.platform_data)) {
tp_log_err("%s: Invalid platform data for: %s\n", __func__,
info.name);
rc = PTR_ERR(info.platform_data);
goto fail;
}
rc = cyttsp4_register_device(&info);
if (rc) {
tp_log_err("%s: register device error for: %s\n", __func__,
info.name);
goto fail_free;
}
return 0;
fail_free:
free_device_pdata(info.platform_data, type);
fail:
return rc;
}
static struct touch_settings *create_and_get_touch_setting(struct device_node
*core_node,
const char *name)
{
struct touch_settings *setting;
char *tag_name;
u32 tag_value;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(core_node, name, &size);
if (IS_ERR_OR_NULL(data))
return (void *)data;
tp_log_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size);
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
if (setting == NULL) {
rc = -ENOMEM;
goto fail_free_data;
}
setting->data = (u8 *) data;
setting->size = size;
tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (tag_name == NULL) {
rc = -ENOMEM;
goto fail_free_setting;
}
snprintf(tag_name, MAX_NAME_LENGTH, "%s-tag", name);
rc = of_property_read_u32(core_node, tag_name, &tag_value);
if (!rc)
setting->tag = tag_value;
kfree(tag_name);
return setting;
fail_free_setting:
kfree(setting);
fail_free_data:
kfree(data);
return ERR_PTR(rc);
}
static void free_touch_setting(struct touch_settings *setting)
{
if (setting) {
kfree(setting->data);
kfree(setting);
}
}
static char *touch_setting_names[CY_IC_GRPNUM_NUM] = {
NULL, /* CY_IC_GRPNUM_RESERVED */
"cy,cmd_regs", /* CY_IC_GRPNUM_CMD_REGS */
"cy,tch_rep", /* CY_IC_GRPNUM_TCH_REP */
"cy,data_rec", /* CY_IC_GRPNUM_DATA_REC */
"cy,test_rec", /* CY_IC_GRPNUM_TEST_REC */
"cy,pcfg_rec", /* CY_IC_GRPNUM_PCFG_REC */
"cy,tch_parm_val", /* CY_IC_GRPNUM_TCH_PARM_VAL */
"cy,tch_parm_size", /* CY_IC_GRPNUM_TCH_PARM_SIZE */
NULL, /* CY_IC_GRPNUM_RESERVED1 */
NULL, /* CY_IC_GRPNUM_RESERVED2 */
"cy,opcfg_rec", /* CY_IC_GRPNUM_OPCFG_REC */
"cy,ddata_rec", /* CY_IC_GRPNUM_DDATA_REC */
"cy,mdata_rec", /* CY_IC_GRPNUM_MDATA_REC */
"cy,test_regs", /* CY_IC_GRPNUM_TEST_REGS */
"cy,btn_keys", /* CY_IC_GRPNUM_BTN_KEYS */
NULL, /* CY_IC_GRPNUM_TTHE_REGS */
};
static cypress4_tp_cap_info tp_cap_data = {
.min_mut_cap = -2950,
.max_mut_cap = -1500,
.min_self_cap = -600,
.max_self_cap = 1300,
.tx_lines = 16,
.rx_lines = 28,
.self_cap_num = 28,
.data_ok = true,
.ignore_list_mut_cap = NULL,
.ignore_list_size_mut_cap = 0,
.ignore_list_size_self_cap = 0,
.data_start_byte = 0,
.tp_ic_version = CY_TMD445,
};
cypress4_tp_cap_info tp_get_cap_data_f(void)
{
return tp_cap_data;
}
static int atoi(const char *psz_buf)
{
int i = 0, val = 0, sym = 1;
while (psz_buf[i] != '\0') {
if (' ' != psz_buf[i]) {
if ('-' == psz_buf[i]) {
sym = -1;
} else if ('+' == psz_buf[i]) {
sym = 1;
} else if ((psz_buf[i] >= '0') && (psz_buf[i] <= '9')) {
val = val * 10 + (psz_buf[i] - '0');
} else {
tp_log_err("%s: unexpect symbol %c\n", __func__,
psz_buf[i]);
return sym * val;
}
}
i++;
}
return sym * val;
}
static void get_tp_cap_pdata(struct device_node *core_node)
{
const char *min_mut_cap_str;
const char *max_mut_cap_str;
const char *min_self_cap_str;
const char *max_self_cap_str;
char const *get_tp_ic_version;
u32 value;
int rc = 0;
int size = 0;
u16 *data = NULL;
/* min_mut_cap */
rc = of_property_read_string(core_node, "cy,min_mut_cap",
&min_mut_cap_str);
if (!rc) {
tp_log_info("%s: OF cy,min_mut_cap: %s\n", __func__,
min_mut_cap_str);
tp_cap_data.min_mut_cap = atoi(min_mut_cap_str);
} else {
goto tp_cap_get_fail;
}
/* max_mut_cap */
//memset(tmp_str, 0, CYP_CAP_NUM_MAX);
rc = of_property_read_string(core_node, "cy,max_mut_cap",
&max_mut_cap_str);
if (!rc) {
tp_log_info("%s: OF cy,max_mut_cap: %s\n", __func__,
max_mut_cap_str);
tp_cap_data.max_mut_cap = atoi(max_mut_cap_str);
} else {
goto tp_cap_get_fail;
}
/* min_self_cap */
//memset(tmp_str, 0, CYP_CAP_NUM_MAX);
rc = of_property_read_string(core_node, "cy,min_self_cap",
&min_self_cap_str);
if (!rc) {
tp_log_info("%s: OF cy,min_self_cap: %s\n", __func__,
min_self_cap_str);
tp_cap_data.min_self_cap = atoi(min_self_cap_str);
} else {
goto tp_cap_get_fail;
}
/* max_self_cap */
//memset(tmp_str, 0, CYP_CAP_NUM_MAX);
rc = of_property_read_string(core_node, "cy,max_self_cap",
&max_self_cap_str);
if (!rc) {
tp_log_info("%s: OF cy,max_self_cap: %s\n", __func__,
max_self_cap_str);
tp_cap_data.max_self_cap = atoi(max_self_cap_str);
} else {
goto tp_cap_get_fail;
}
data =
create_and_get_u16_array(core_node, "cy,ignore_list_mut_cap",
&size);
if (!IS_ERR_OR_NULL(data)) {
tp_cap_data.ignore_list_size_mut_cap = size;
tp_cap_data.ignore_list_mut_cap = data;
} else {
tp_cap_data.ignore_list_size_mut_cap = 0;
tp_cap_data.ignore_list_mut_cap = NULL;
}
data =
create_and_get_u16_array(core_node, "cy,ignore_list_self_cap",
&size);
if (!IS_ERR_OR_NULL(data)) {
tp_cap_data.ignore_list_size_self_cap = size;
tp_cap_data.ignore_list_self_cap = data;
} else {
tp_cap_data.ignore_list_size_self_cap = 0;
tp_cap_data.ignore_list_self_cap = NULL;
}
rc = of_property_read_u32(core_node, "cy,tx_lines", &value);
if (!rc) {
tp_log_info("%s: OF cy,tx_lines: %d\n", __func__, value);
tp_cap_data.tx_lines = value;
} else {
goto tp_cap_get_fail;
}
rc = of_property_read_u32(core_node, "cy,data_start_byte", &value);
if (!rc) {
tp_log_info("%s: OF cy,data_start_byte: %d\n", __func__, value);
tp_cap_data.data_start_byte = value;
} else {
goto tp_cap_get_fail;
}
rc = of_property_read_u32(core_node, "cy,rx_lines", &value);
if (!rc) {
tp_log_info("%s: OF cy,rx_lines: %d\n", __func__, value);
tp_cap_data.rx_lines = value;
} else {
goto tp_cap_get_fail;
}
rc = of_property_read_u32(core_node, "cy,self_cap_num", &value);
if (!rc) {
tp_log_info("%s: OF cy,self_cap_num: %d\n", __func__, value);
tp_cap_data.self_cap_num = value;
} else {
goto tp_cap_get_fail;
}
/*tp_ic_version */
rc = of_property_read_string(core_node, "cy,tp_ic_version",
&get_tp_ic_version);
if (rc) {
tp_log_err("%s: read tp ic version error, rc=%d\n", __func__,
rc);
goto tp_cap_get_fail;
}
if (!strncmp("TMD463", get_tp_ic_version, MAX_NAME_LENGTH)) {
tp_cap_data.tp_ic_version = CY_TMD463;
} else if (!strncmp("TMD445", get_tp_ic_version, MAX_NAME_LENGTH)) {
tp_cap_data.tp_ic_version = CY_TMD445;
} else {
tp_cap_data.tp_ic_version = CY_TMDUNKNOW;
tp_log_err("%s: tp ic version is unknown\n", __func__);
goto tp_cap_get_fail;
}
return;
tp_cap_get_fail:
tp_log_err("%s: get capacitance info fail!!!\n", __func__);
tp_cap_data.data_ok = false;
return;
}
static struct cyttsp4_core_platform_data *create_and_get_core_pdata(struct
device_node
*core_node)
{
struct cyttsp4_core_platform_data *pdata;
u32 value;
int rc = -EINVAL;
int i;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL) {
rc = -ENOMEM;
goto fail;
}
value = of_get_named_gpio(core_node, "cy,irq_gpio", 0);
if (!gpio_is_valid(value)) {
goto fail_free;
}
pdata->irq_gpio = value;
value = of_get_named_gpio(core_node, "cy,rst_gpio", 0);
if (gpio_is_valid(value)) {
pdata->rst_gpio = value;
}
tp_log_info("%s: irq-gpio=%d,rst-gpio=%d\n", __func__, pdata->irq_gpio,
pdata->rst_gpio);
#if 0
/* Required fields */
rc = of_property_read_u32(core_node, "cy,irq_gpio", &value);
if (rc)
goto fail_free;
pdata->irq_gpio = value;
/* Optional fields */
/* rst_gpio is optional since a platform may use
* power cycling instead of using the XRES pin
*/
rc = of_property_read_u32(core_node, "cy,rst_gpio", &value);
if (!rc)
pdata->rst_gpio = value;
#endif
rc = of_property_read_u32(core_node, "cy,level_irq_udelay", &value);
if (!rc)
pdata->level_irq_udelay = value;
rc = of_property_read_u32(core_node, "cy,max_xfer_len", &value);
if (!rc)
pdata->max_xfer_len = value;
rc = of_property_read_u32(core_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(core_node,
"cy,easy_wakeup_supported_gestures", &value);
if (!rc)
pdata->easy_wakeup_supported_gestures = value;
/*add for glove function */
rc = of_property_read_u32(core_node, "cy,use_configure_sensitivity",
&value);
if (!rc)
pdata->use_configure_sensitivity = value;
rc = of_property_read_u32(core_node, "cy,easy_wakeup_gesture", &value);
if (!rc)
pdata->easy_wakeup_gesture = (u8) value;
/* read tp capacitance infomation */
get_tp_cap_pdata(core_node);
for (i = 0; (unsigned int)i < ARRAY_SIZE(touch_setting_names); i++) {
if (touch_setting_names[i] == NULL)
continue;
pdata->sett[i] = create_and_get_touch_setting(core_node,
touch_setting_names
[i]);
if (IS_ERR(pdata->sett[i])) {
rc = PTR_ERR(pdata->sett[i]);
goto fail_free_sett;
} else if (pdata->sett[i] == NULL)
tp_log_debug("%s: No data for setting '%s'\n", __func__,
touch_setting_names[i]);
}
tp_log_debug("%s: irq_gpio:%d rst_gpio:%d level_irq_udelay:%d\n"
"max_xfer_len:%d flags:%d easy_wakeup_gesture:%d\n",
__func__, pdata->irq_gpio, pdata->rst_gpio,
pdata->level_irq_udelay, pdata->max_xfer_len, pdata->flags,
pdata->easy_wakeup_gesture);
pdata->xres = cyttsp4_xres;
pdata->init = cyttsp4_init;
pdata->power = cyttsp4_power;
#ifdef CYTTSP4_DETECT_HW
pdata->detect = cyttsp4_detect;
#endif
pdata->irq_stat = cyttsp4_irq_stat;
pdata->loader_pdata = &_cyttsp4_loader_platform_data;
return pdata;
fail_free_sett:
for (i--; i >= 0; i--)
free_touch_setting(pdata->sett[i]);
fail_free:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_core_pdata(struct cyttsp4_core_platform_data *pdata)
{
int i;
for (i = 0; i < CY_TOUCH_SETTINGS_MAX; i++)
free_touch_setting(pdata->sett[i]);
kfree(tp_cap_data.ignore_list_mut_cap);
kfree(tp_cap_data.ignore_list_self_cap);
kfree(pdata);
}
static int register_core_device(struct device_node *core_node,
const char *adap_id, const char **core_id)
{
struct cyttsp4_core_info info = { 0 };
int rc;
rc = of_property_read_string(core_node, "cy,name", &info.name);
if (rc) {
tp_log_err("%s: OF error rc=%d at line %d for cy,name\n",
__func__, rc, __LINE__);
goto fail;
} else
tp_log_debug("%s: OF cy,name: %s\n", __func__, info.name);
rc = of_property_read_string(core_node, "cy,id", &info.id);
if (rc) {
tp_log_err("%s: OF error rc=%d at line %d for cy,id\n",
__func__, rc, __LINE__);
goto fail;
} else
tp_log_debug("%s: OF cy,id: %s\n", __func__, info.id);
info.platform_data = create_and_get_core_pdata(core_node);
if (IS_ERR(info.platform_data)) {
rc = PTR_ERR(info.platform_data);
goto fail;
}
info.adap_id = adap_id;
rc = cyttsp4_register_core_device(&info);
if (rc)
goto fail_free;
*core_id = info.id;
return 0;
fail_free:
free_core_pdata(info.platform_data);
fail:
return rc;
}
int cyttsp4_devtree_register_devices(struct device *adap_dev)
{
struct device_node *core_node, *dev_node;
const char *adap_id;
int count = 0;
int rc;
if (!adap_dev->of_node)
return 0;
rc = of_property_read_string(adap_dev->of_node, "cy,adapter_id",
&adap_id);
if (rc)
return rc;
/* There should be only one core node */
for_each_child_of_node(adap_dev->of_node, core_node) {
const char *core_id = NULL;
const char *name;
rc = of_property_read_string(core_node, "name", &name);
if (!rc)
tp_log_debug("%s: name:%s\n", __func__, name);
rc = register_core_device(core_node, adap_id, &core_id);
if (rc)
break;
/* Increment reference count */
of_node_get(core_node);
for_each_child_of_node(core_node, dev_node) {
count++;
rc = register_device(dev_node, core_id);
if (rc)
break;
/* Increment reference count */
of_node_get(dev_node);
}
}
tp_log_debug("%s: %d child node(s) found\n", __func__, count);
return rc;
}
EXPORT_SYMBOL_GPL(cyttsp4_devtree_register_devices);
static int __init cyttsp4_devtree_init(void)
{
return 0;
}
module_init(cyttsp4_devtree_init);
static void __exit cyttsp4_devtree_exit(void)
{
}
module_exit(cyttsp4_devtree_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cypress Semiconductor");