/* * pt_devtree.c * Parade TrueTouch(TM) Standard Product Device Tree Support Module. * For use with Parade touchscreen controllers. * Supported parts include: * TMA5XX * TMA448 * TMA445A * TT21XXX * TT31XXX * TT4XXXX * TT7XXX * TC3XXX * * Copyright (C) 2015-2020 Parade Technologies * * 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. * * Contact Parade Technologies at www.paradetech.com */ #include #include #include #include #include "pt_platform.h" #include "pt_regs.h" #define MAX_NAME_LENGTH 64 static bool is_create_and_get_pdata; enum pt_device_type { DEVICE_MT, DEVICE_BTN, DEVICE_PROXIMITY, DEVICE_TYPE_MAX, }; struct pt_device_pdata_func { void * (*create_and_get_pdata)(struct device_node *dn); void (*free_pdata)(void *ptr); }; struct pt_pdata_ptr { void **pdata; }; #ifdef ENABLE_VIRTUAL_KEYS static struct kobject *board_properties_kobj; struct pt_virtual_keys { struct kobj_attribute kobj_attr; u16 *data; int size; }; #endif struct pt_extended_mt_platform_data { struct pt_mt_platform_data pdata; #ifdef ENABLE_VIRTUAL_KEYS struct pt_virtual_keys vkeys; #endif }; /******************************************************************************* * FUNCTION: get_inp_dev_name * * SUMMARY: Get the name of input device from dts. * * RETURN: * 0 = success * !0 = failure * * PARAMETERS: * *dev_node - pointer to device_node structure * **inp_dev_name - double pointer to the name of input device ******************************************************************************/ static inline int get_inp_dev_name(struct device_node *dev_node, const char **inp_dev_name) { return of_property_read_string(dev_node, "parade,inp_dev_name", inp_dev_name); } /******************************************************************************* * FUNCTION: create_and_get_u16_array * * SUMMARY: Create and get u16 array from dts. * * RETURN: * success: the pointer of the created array * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure * *name - name of device node * size - number of u16 array elements ******************************************************************************/ static s16 *create_and_get_u16_array(struct device_node *dev_node, const char *name, int *size) { const __be32 *values; s16 *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); pr_debug("%s: %s size:%d\n", __func__, name, sz); val_array = kcalloc(sz, sizeof(s16), GFP_KERNEL); if (!val_array) { rc = -ENOMEM; goto fail; } for (i = 0; i < sz; i++) val_array[i] = (s16)be32_to_cpup(values++); *size = sz; return val_array; fail: return ERR_PTR(rc); } /******************************************************************************* * FUNCTION: create_and_get_touch_framework * * SUMMARY: Create and get touch framework structure from dts. * * RETURN: * success: the pointer of the touch framework data * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure ******************************************************************************/ static struct touch_framework *create_and_get_touch_framework( struct device_node *dev_node) { struct touch_framework *frmwrk; s16 *abs; int size; int rc; abs = create_and_get_u16_array(dev_node, "parade,abs", &size); if (IS_ERR_OR_NULL(abs)) return (void *)abs; /* Check for valid abs size */ if (size % PT_NUM_ABS_SET) { rc = -EINVAL; goto fail_free_abs; } frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL); if (!frmwrk) { rc = -ENOMEM; goto fail_free_abs; } frmwrk->abs = abs; frmwrk->size = size; return frmwrk; fail_free_abs: kfree(abs); return ERR_PTR(rc); } /******************************************************************************* * FUNCTION: free_touch_framework * * SUMMARY: Free all the pointer of touch framework structure. * * PARAMETERS: * *frmwrk - pointer to touch framework structure ******************************************************************************/ static void free_touch_framework(struct touch_framework *frmwrk) { kfree(frmwrk->abs); kfree(frmwrk); } #ifdef ENABLE_VIRTUAL_KEYS #define VIRTUAL_KEY_ELEMENT_SIZE 5 /******************************************************************************* * FUNCTION: virtual_keys_show * * SUMMARY: Show method for the board_properties sysfs node that will show the * information for all virtual keys * * RETURN: size of data written to sysfs node * * PARAMETERS: * *kobj - pointer to kobject structure * *attr - pointer to kobject attributes * *buf - pointer to print output buffer ******************************************************************************/ static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct pt_virtual_keys *vkeys = container_of(attr, struct pt_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, PT_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]); return index; } /******************************************************************************* * FUNCTION: setup_virtual_keys * * SUMMARY: Create virtual key data array from dts and set up dynamic sysfs for * board_properties node. * * RETURN: * 0 = success * !0 = failure * * PARAMETERS: * *dev_node - pointer to device_node structure * **inp_dev_name - double pointer to the name of input device * *vkeys - pointer to virtual key structure ******************************************************************************/ static int setup_virtual_keys(struct device_node *dev_node, const char *inp_dev_name, struct pt_virtual_keys *vkeys) { char *name; u16 *data; int size; int rc; data = create_and_get_u16_array(dev_node, "parade,virtual_keys", &size); if (data == NULL) return 0; 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) { 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) { pr_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 = 0444; 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; fail: return rc; } /******************************************************************************* * FUNCTION: free_virtual_keys * * SUMMARY: Remove board_properties node and free all pointers. * * PARAMETERS: * *vkeys - pointer to virtual key structure ******************************************************************************/ static void free_virtual_keys(struct pt_virtual_keys *vkeys) { if (board_properties_kobj) sysfs_remove_file(board_properties_kobj, &vkeys->kobj_attr.attr); kobject_del(board_properties_kobj); board_properties_kobj = NULL; kfree(vkeys->data); kfree(vkeys->kobj_attr.attr.name); } #endif /******************************************************************************* * FUNCTION: create_and_get_mt_pdata * * SUMMARY: Create and get touch platform data from dts.Touch framework and * virtual keys are set up in this function. * * RETURN: * success: the pointer of the platform data * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure ******************************************************************************/ static void *create_and_get_mt_pdata(struct device_node *dev_node) { struct pt_extended_mt_platform_data *ext_pdata; struct pt_mt_platform_data *pdata; u32 value; int rc; ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL); if (!ext_pdata) { 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, "parade,flags", &value); if (!rc) pdata->flags = value; rc = of_property_read_u32(dev_node, "parade,vkeys_x", &value); if (!rc) pdata->vkeys_x = value; rc = of_property_read_u32(dev_node, "parade,vkeys_y", &value); if (!rc) pdata->vkeys_y = value; /* 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) { pr_err("%s: Cannot setup virtual keys!\n", __func__); goto fail_free_pdata; } #endif return pdata; fail_free_pdata: kfree(ext_pdata); fail: return ERR_PTR(rc); } /******************************************************************************* * FUNCTION: free_mt_pdata * * SUMMARY: Free all pointers that include touch framework, virtual keys and * touch data. * * PARAMETERS: * *vkeys - pointer to virtual key structure ******************************************************************************/ static void free_mt_pdata(void *pdata) { struct pt_mt_platform_data *mt_pdata = (struct pt_mt_platform_data *)pdata; struct pt_extended_mt_platform_data *ext_mt_pdata = container_of(mt_pdata, struct pt_extended_mt_platform_data, pdata); free_touch_framework(mt_pdata->frmwrk); #ifdef ENABLE_VIRTUAL_KEYS free_virtual_keys(&ext_mt_pdata->vkeys); #endif kfree(ext_mt_pdata); } /******************************************************************************* * FUNCTION: create_and_get_btn_pdata * * SUMMARY: Create and get button platform data from dts. * * RETURN: * success: the pointer of the platform data * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure ******************************************************************************/ static void *create_and_get_btn_pdata(struct device_node *dev_node) { struct pt_btn_platform_data *pdata; int rc; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { 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); } /******************************************************************************* * FUNCTION: free_btn_pdata * * SUMMARY: Free all pointers for button platform data. * * PARAMETERS: * *vkeys - pointer to virtual key structure ******************************************************************************/ static void free_btn_pdata(void *pdata) { struct pt_btn_platform_data *btn_pdata = (struct pt_btn_platform_data *)pdata; kfree(btn_pdata); } /******************************************************************************* * FUNCTION: create_and_get_proximity_pdata * * SUMMARY: Create and get proximity platform data from dts. * * RETURN: * success: the pointer of the proximity platform data * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure ******************************************************************************/ static void *create_and_get_proximity_pdata(struct device_node *dev_node) { struct pt_proximity_platform_data *pdata; int rc; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { 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; } return pdata; fail_free_pdata: kfree(pdata); fail: return ERR_PTR(rc); } /******************************************************************************* * FUNCTION: free_proximity_pdata * * SUMMARY: Free all pointers for proximity platform data. * * PARAMETERS: * *vkeys - pointer to virtual key structure ******************************************************************************/ static void free_proximity_pdata(void *pdata) { struct pt_proximity_platform_data *proximity_pdata = (struct pt_proximity_platform_data *)pdata; free_touch_framework(proximity_pdata->frmwrk); kfree(proximity_pdata); } static struct pt_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, }, }; static struct pt_pdata_ptr pdata_ptr[DEVICE_TYPE_MAX]; static const char *device_names[DEVICE_TYPE_MAX] = { [DEVICE_MT] = "parade,mt", [DEVICE_BTN] = "parade,btn", [DEVICE_PROXIMITY] = "parade,proximity", }; /******************************************************************************* * FUNCTION: set_pdata_ptr * * SUMMARY: Set platform data pointer for touch, button, proximity module. * * PARAMETERS: * *pdata - pointer to platform data structure ******************************************************************************/ static void set_pdata_ptr(struct pt_platform_data *pdata) { pdata_ptr[DEVICE_MT].pdata = (void **)&pdata->mt_pdata; pdata_ptr[DEVICE_BTN].pdata = (void **)&pdata->btn_pdata; pdata_ptr[DEVICE_PROXIMITY].pdata = (void **)&pdata->prox_pdata; } /******************************************************************************* * FUNCTION: get_device_type * * SUMMARY: Determine the device type[mt,btn,proximity] from dts. * * RETURN: * 0 = success * !0 = failure * * PARAMETERS: * *dev_node - pointer to device_node structure * *type - pointer to store the device type ******************************************************************************/ static int get_device_type(struct device_node *dev_node, enum pt_device_type *type) { const char *name; enum pt_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; } /******************************************************************************* * FUNCTION: create_and_get_device_pdata * * SUMMARY: Create platform data for mt, btn, proximity module. * * RETURN: * success: the pointer of the platform data * fail : error code with type of error pointer * * PARAMETERS: * *dev_node - pointer to device_node structure * type - determine the device type ******************************************************************************/ static inline void *create_and_get_device_pdata(struct device_node *dev_node, enum pt_device_type type) { return device_pdata_funcs[type].create_and_get_pdata(dev_node); } /******************************************************************************* * FUNCTION: free_device_pdata * * SUMMARY: Free platform data for mt, btn, proximity module. * * PARAMETERS: * type - determine the device type ******************************************************************************/ static inline void free_device_pdata(enum pt_device_type type) { device_pdata_funcs[type].free_pdata(*pdata_ptr[type].pdata); } /******************************************************************************* * FUNCTION: create_and_get_touch_setting * * SUMMARY: Create and get touch settings from dts. * * RETURN: * success: the pointer of touch settings * fail : error code with type of error pointer * * PARAMETERS: * *core_node - pointer to device_node structure * name - name of touch setting ******************************************************************************/ 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; pr_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size); setting = kzalloc(sizeof(*setting), GFP_KERNEL); if (!setting) { rc = -ENOMEM; goto fail_free_data; } setting->data = (u8 *)data; setting->size = size; tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL); if (!tag_name) { 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); } /******************************************************************************* * FUNCTION: free_touch_setting * * SUMMARY: Free touch setting data. * * PARAMETERS: * setting - pointer to touch setting ******************************************************************************/ static void free_touch_setting(struct touch_settings *setting) { if (setting) { kfree(setting->data); kfree(setting); } } static char *touch_setting_names[PT_IC_GRPNUM_NUM] = { NULL, /* PT_IC_GRPNUM_RESERVED */ "parade,cmd_regs", /* PT_IC_GRPNUM_CMD_REGS */ "parade,tch_rep", /* PT_IC_GRPNUM_TCH_REP */ "parade,data_rec", /* PT_IC_GRPNUM_DATA_REC */ "parade,test_rec", /* PT_IC_GRPNUM_TEST_REC */ "parade,pcfg_rec", /* PT_IC_GRPNUM_PCFG_REC */ "parade,tch_parm_val", /* PT_IC_GRPNUM_TCH_PARM_VAL */ "parade,tch_parm_size", /* PT_IC_GRPNUM_TCH_PARM_SIZE */ NULL, /* PT_IC_GRPNUM_RESERVED1 */ NULL, /* PT_IC_GRPNUM_RESERVED2 */ "parade,opcfg_rec", /* PT_IC_GRPNUM_OPCFG_REC */ "parade,ddata_rec", /* PT_IC_GRPNUM_DDATA_REC */ "parade,mdata_rec", /* PT_IC_GRPNUM_MDATA_REC */ "parade,test_regs", /* PT_IC_GRPNUM_TEST_REGS */ "parade,btn_keys", /* PT_IC_GRPNUM_BTN_KEYS */ NULL, /* PT_IC_GRPNUM_TTHE_REGS */ }; /******************************************************************************* * FUNCTION: pt_check_dsi_panel_dt * * SUMMARY: Get the DSI active panel information from dtsi * * RETURN: * 0 = success * !0 = fail * * PARAMETERS: * np - pointer to device_node structure * active_panel - name of active DSI panel ******************************************************************************/ static int pt_check_dsi_panel_dt(struct device_node *np, struct drm_panel **active_panel) { int i; int count; struct device_node *node; struct drm_panel *panel; count = of_count_phandle_with_args(np, "panel", NULL); pr_info("%s: Active panel count: %d\n", __func__, count); if (count <= 0) return 0; for (i = 0; i < count; i++) { node = of_parse_phandle(np, "panel", i); if (node != NULL) pr_info("%s: Node handle successfully parsed !\n", __func__); panel = of_drm_find_panel(node); of_node_put(node); if (!IS_ERR(panel)) { pr_info("%s: Active panel selected !\n", __func__); *active_panel = panel; return 0; } } pr_err("%s: Active panel NOT selected !\n", __func__); return PTR_ERR(panel); } /******************************************************************************* * FUNCTION: create_and_get_core_pdata * * SUMMARY: Create and get core module platform data from dts. * * RETURN: * success: the pointer of core platform data * fail : error code with type of error pointer * * PARAMETERS: * *core_node - pointer to device_node structure ******************************************************************************/ static struct pt_core_platform_data *create_and_get_core_pdata( struct device_node *core_node) { struct pt_core_platform_data *pdata; u32 value; int rc; int i; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { rc = -ENOMEM; goto fail; } /* Required fields */ value = of_get_named_gpio_flags(core_node, "parade,irq_gpio", 0, &pdata->irq_gpio_flags); pdata->irq_gpio = value; rc = of_property_read_u32(core_node, "parade,hid_desc_register", &value); if (rc) goto fail_free; pdata->hid_desc_register = value; /* Optional fields */ /* rst_gpio is optional since a platform may use * power cycling instead of using the XRES pin */ value = of_get_named_gpio_flags(core_node, "parade,rst_gpio", 0, &pdata->rst_gpio_flags); pdata->rst_gpio = value; rc = of_property_read_u32(core_node, "parade,ddi_rst_gpio", &value); if (!rc) pdata->ddi_rst_gpio = value; rc = of_property_read_u32(core_node, "parade,vddi_gpio", &value); if (!rc) pdata->vddi_gpio = value; rc = of_property_read_u32(core_node, "parade,vcc_gpio", &value); if (!rc) pdata->vcc_gpio = value; rc = of_property_read_u32(core_node, "parade,avdd_gpio", &value); if (!rc) pdata->avdd_gpio = value; rc = of_property_read_u32(core_node, "parade,avee_gpio", &value); if (!rc) pdata->avee_gpio = value; rc = of_property_read_u32(core_node, "parade,level_irq_udelay", &value); if (!rc) pdata->level_irq_udelay = value; rc = of_property_read_u32(core_node, "parade,vendor_id", &value); if (!rc) pdata->vendor_id = value; rc = of_property_read_u32(core_node, "parade,product_id", &value); if (!rc) pdata->product_id = value; rc = of_property_read_u32(core_node, "parade,flags", &value); if (!rc) pdata->flags = value; rc = of_property_read_u32(core_node, "parade,easy_wakeup_gesture", &value); if (!rc) pdata->easy_wakeup_gesture = (u8)value; rc = of_property_read_u32(core_node, "parade,config_dut_generation", &value); if (!rc) pdata->config_dut_generation = (u8)value; else { pr_err("%s: dut_generation is not configured, set default: DUT_PIP2_CAPABLE!\n", __func__); pdata->config_dut_generation = CONFIG_DUT_PIP2_CAPABLE; } rc = of_property_read_u32(core_node, "parade,watchdog_force_stop", &value); if (!rc) { if (value) pdata->watchdog_force_stop = true; else pdata->watchdog_force_stop = false; } else { pr_err("%s: watchdog_force_stop is not configured, set default: false!\n", __func__); pdata->watchdog_force_stop = false; } rc = of_property_read_u32(core_node, "parade,panel_id_support", &value); if (!rc) { pdata->panel_id_support = (u8)value; } else { pr_err("%s: panel_id_support is not configured, set default: PT_PANEL_ID_DISABLE\n", __func__); pdata->panel_id_support = PT_PANEL_ID_DISABLE; } 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) pr_debug("%s: No data for setting '%s'\n", __func__, touch_setting_names[i]); } pr_debug("%s: irq_gpio:%d rst_gpio:%d\n" "hid_desc_reg:%d level_irq_udelay:%d vendor_id:%d prod_id:%d\n" "flags:%d easy_wakeup_gesture:%d\n", __func__, pdata->irq_gpio, pdata->rst_gpio, pdata->hid_desc_register, pdata->level_irq_udelay, pdata->vendor_id, pdata->product_id, pdata->flags, pdata->easy_wakeup_gesture); pdata->xres = pt_xres; pdata->init = pt_init; pdata->power = pt_power; pdata->detect = pt_detect; pdata->irq_stat = pt_irq_stat; pdata->setup_power = pt_setup_power; pdata->setup_irq = pt_setup_irq; 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); } /******************************************************************************* * FUNCTION: free_core_pdata * * SUMMARY: Free the core module platform data and touch settings data. * * RETURN: * success: the pointer of core platform data * fail : error code with type of error pointer * * PARAMETERS: * *core_node - pointer to device_node structure ******************************************************************************/ static void free_core_pdata(void *pdata) { struct pt_core_platform_data *core_pdata = pdata; unsigned int i; for (i = 0; i < ARRAY_SIZE(touch_setting_names); i++) free_touch_setting(core_pdata->sett[i]); kfree(core_pdata); } /******************************************************************************* * FUNCTION: pt_devtree_create_and_get_pdata * * SUMMARY: Parse dts and set up platform data for core module, multi-touch(mt) * module, button(btn) module, proximity module.And Assign platform data * pointer for loader module. * * RETURN: * 0 = success * !0 = failure * * PARAMETERS: * *adap_dev - pointer to device structure ******************************************************************************/ int pt_devtree_create_and_get_pdata(struct device *adap_dev) { struct pt_platform_data *pdata; struct device_node *core_node, *dev_node, *dev_node_fail; struct drm_panel *active_panel = NULL; enum pt_device_type type; int count = 0; int rc = 0; pr_info("%s: Start of fetch dtsi..\n", __func__); if (is_create_and_get_pdata == true) return 0; if (!adap_dev->of_node) return 0; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; adap_dev->platform_data = pdata; set_pdata_ptr(pdata); /* There should be only one core node */ for_each_child_of_node(adap_dev->of_node, core_node) { const char *name; rc = of_property_read_string(core_node, "name", &name); if (!rc) pr_debug("%s: name:%s\n", __func__, name); rc = pt_check_dsi_panel_dt(core_node, &active_panel); if (rc) { pr_err("%s: Panel not selected, rc=%d\n", __func__, rc); if (rc == -EPROBE_DEFER) { pr_err("%s: Probe defer selected, rc=%d\n", __func__, rc); kfree(pdata); return rc; } } pdata->core_pdata = create_and_get_core_pdata(core_node); if (IS_ERR(pdata->core_pdata)) { pr_err("%s: Error in fetch dtsi..\n", __func__); rc = PTR_ERR(pdata->core_pdata); break; } pr_info("%s: End of fetch dtsi..\n", __func__); pdata->core_pdata->active_panel = active_panel; pr_info("%s: Successful insert of active panel in core data\n", __func__); /* Increment reference count */ of_node_get(core_node); for_each_child_of_node(core_node, dev_node) { count++; rc = get_device_type(dev_node, &type); if (rc) break; *pdata_ptr[type].pdata = create_and_get_device_pdata(dev_node, type); if (IS_ERR(*pdata_ptr[type].pdata)) rc = PTR_ERR(*pdata_ptr[type].pdata); if (rc) break; /* Increment reference count */ of_node_get(dev_node); } if (rc) { free_core_pdata(pdata->core_pdata); of_node_put(core_node); for_each_child_of_node(core_node, dev_node_fail) { if (dev_node == dev_node_fail) break; rc = get_device_type(dev_node, &type); if (rc) break; free_device_pdata(type); of_node_put(dev_node); } break; } pdata->loader_pdata = &_pt_loader_platform_data; } is_create_and_get_pdata = true; pr_debug("%s: %d child node(s) found\n", __func__, count); return rc; } EXPORT_SYMBOL_GPL(pt_devtree_create_and_get_pdata); /******************************************************************************* * FUNCTION: pt_devtree_clean_pdata * * SUMMARY: Free all platform data for core module, multi-touch(mt) module, * button(btn) module, proximity module. * * RETURN: * 0 = success * !0 = failure * * PARAMETERS: * *adap_dev - pointer to device structure ******************************************************************************/ int pt_devtree_clean_pdata(struct device *adap_dev) { struct pt_platform_data *pdata; struct device_node *core_node, *dev_node; enum pt_device_type type; int rc = 0; if (is_create_and_get_pdata == false) return 0; if (!adap_dev->of_node) return 0; pdata = dev_get_platdata(adap_dev); set_pdata_ptr(pdata); free_core_pdata(pdata->core_pdata); for_each_child_of_node(adap_dev->of_node, core_node) { of_node_put(core_node); for_each_child_of_node(core_node, dev_node) { rc = get_device_type(dev_node, &type); if (rc) break; free_device_pdata(type); of_node_put(dev_node); } } is_create_and_get_pdata = false; return rc; } EXPORT_SYMBOL_GPL(pt_devtree_clean_pdata); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product DeviceTree Driver"); MODULE_AUTHOR("Parade Technologies ");