1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * cyttsp5_devtree.c
3*4882a593Smuzhiyun * Parade TrueTouch(TM) Standard Product V5 Device Tree Support Module.
4*4882a593Smuzhiyun * For use with Parade touchscreen controllers.
5*4882a593Smuzhiyun * Supported parts include:
6*4882a593Smuzhiyun * CYTMA5XX
7*4882a593Smuzhiyun * CYTMA448
8*4882a593Smuzhiyun * CYTMA445A
9*4882a593Smuzhiyun * CYTT21XXX
10*4882a593Smuzhiyun * CYTT31XXX
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Copyright (C) 2015 Parade Technologies
13*4882a593Smuzhiyun * Copyright (C) 2013-2015 Cypress Semiconductor
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
16*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License
17*4882a593Smuzhiyun * version 2, and only version 2, as published by the
18*4882a593Smuzhiyun * Free Software Foundation.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
21*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
22*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23*4882a593Smuzhiyun * GNU General Public License for more details.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include <linux/device.h>
30*4882a593Smuzhiyun #include <linux/err.h>
31*4882a593Smuzhiyun #include <linux/of_device.h>
32*4882a593Smuzhiyun #include <linux/slab.h>
33*4882a593Smuzhiyun #include <linux/of_gpio.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* cyttsp */
36*4882a593Smuzhiyun #include "cyttsp5_regs.h"
37*4882a593Smuzhiyun #include "cyttsp5_platform.h"
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun //#define ENABLE_VIRTUAL_KEYS
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define MAX_NAME_LENGTH 64
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun enum cyttsp5_device_type {
44*4882a593Smuzhiyun DEVICE_MT,
45*4882a593Smuzhiyun DEVICE_BTN,
46*4882a593Smuzhiyun DEVICE_PROXIMITY,
47*4882a593Smuzhiyun DEVICE_TYPE_MAX,
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun struct cyttsp5_device_pdata_func {
52*4882a593Smuzhiyun void * (*create_and_get_pdata)(struct device_node *);
53*4882a593Smuzhiyun void (*free_pdata)(void *);
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun struct cyttsp5_pdata_ptr {
57*4882a593Smuzhiyun void **pdata;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #ifdef ENABLE_VIRTUAL_KEYS
61*4882a593Smuzhiyun static struct kobject *board_properties_kobj;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun struct cyttsp5_virtual_keys {
64*4882a593Smuzhiyun struct kobj_attribute kobj_attr;
65*4882a593Smuzhiyun u16 *data;
66*4882a593Smuzhiyun int size;
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun struct cyttsp5_extended_mt_platform_data {
71*4882a593Smuzhiyun struct cyttsp5_mt_platform_data pdata;
72*4882a593Smuzhiyun #ifdef ENABLE_VIRTUAL_KEYS
73*4882a593Smuzhiyun struct cyttsp5_virtual_keys vkeys;
74*4882a593Smuzhiyun #endif
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun
get_inp_dev_name(struct device_node * dev_node,const char ** inp_dev_name)77*4882a593Smuzhiyun static inline int get_inp_dev_name(struct device_node *dev_node,
78*4882a593Smuzhiyun const char **inp_dev_name)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun return of_property_read_string(dev_node, "cy,inp_dev_name",
81*4882a593Smuzhiyun inp_dev_name);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
create_and_get_u16_array(struct device_node * dev_node,const char * name,int * size)84*4882a593Smuzhiyun static s16 *create_and_get_u16_array(struct device_node *dev_node,
85*4882a593Smuzhiyun const char *name, int *size)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun const __be32 *values;
88*4882a593Smuzhiyun s16 *val_array;
89*4882a593Smuzhiyun int len;
90*4882a593Smuzhiyun int sz;
91*4882a593Smuzhiyun int rc;
92*4882a593Smuzhiyun int i;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun values = of_get_property(dev_node, name, &len);
95*4882a593Smuzhiyun if (values == NULL)
96*4882a593Smuzhiyun return NULL;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun sz = len / sizeof(u32);
99*4882a593Smuzhiyun pr_debug("%s: %s size:%d\n", __func__, name, sz);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun val_array = kcalloc(sz, sizeof(s16), GFP_KERNEL);
102*4882a593Smuzhiyun if (!val_array) {
103*4882a593Smuzhiyun rc = -ENOMEM;
104*4882a593Smuzhiyun goto fail;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun //printk("create_and_get_u16_array\n");
107*4882a593Smuzhiyun for (i = 0; i < sz; i++){
108*4882a593Smuzhiyun val_array[i] = (s16)be32_to_cpup(values++);
109*4882a593Smuzhiyun //printk("%d ", val_array[i]);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun //printk("\ncreate_and_get_u16_array\n");
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun *size = sz;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return val_array;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun fail:
119*4882a593Smuzhiyun return ERR_PTR(rc);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
create_and_get_touch_framework(struct device_node * dev_node)122*4882a593Smuzhiyun static struct touch_framework *create_and_get_touch_framework(
123*4882a593Smuzhiyun struct device_node *dev_node)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct touch_framework *frmwrk;
126*4882a593Smuzhiyun s16 *abs;
127*4882a593Smuzhiyun int size;
128*4882a593Smuzhiyun int rc;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun abs = create_and_get_u16_array(dev_node, "cy,abs", &size);
131*4882a593Smuzhiyun if (IS_ERR_OR_NULL(abs))
132*4882a593Smuzhiyun return (void *)abs;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Check for valid abs size */
135*4882a593Smuzhiyun if (size % CY_NUM_ABS_SET) {
136*4882a593Smuzhiyun rc = -EINVAL;
137*4882a593Smuzhiyun goto fail_free_abs;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL);
141*4882a593Smuzhiyun if (!frmwrk) {
142*4882a593Smuzhiyun rc = -ENOMEM;
143*4882a593Smuzhiyun goto fail_free_abs;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun frmwrk->abs = abs;
147*4882a593Smuzhiyun frmwrk->size = size;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return frmwrk;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun fail_free_abs:
152*4882a593Smuzhiyun kfree(abs);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun return ERR_PTR(rc);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
free_touch_framework(struct touch_framework * frmwrk)157*4882a593Smuzhiyun static void free_touch_framework(struct touch_framework *frmwrk)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun kfree(frmwrk->abs);
160*4882a593Smuzhiyun kfree(frmwrk);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun #ifdef ENABLE_VIRTUAL_KEYS
164*4882a593Smuzhiyun #define VIRTUAL_KEY_ELEMENT_SIZE 5
virtual_keys_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)165*4882a593Smuzhiyun static ssize_t virtual_keys_show(struct kobject *kobj,
166*4882a593Smuzhiyun struct kobj_attribute *attr, char *buf)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun struct cyttsp5_virtual_keys *vkeys = container_of(attr,
169*4882a593Smuzhiyun struct cyttsp5_virtual_keys, kobj_attr);
170*4882a593Smuzhiyun u16 *data = vkeys->data;
171*4882a593Smuzhiyun int size = vkeys->size;
172*4882a593Smuzhiyun int index;
173*4882a593Smuzhiyun int i;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun index = 0;
176*4882a593Smuzhiyun for (i = 0; i < size; i += VIRTUAL_KEY_ELEMENT_SIZE)
177*4882a593Smuzhiyun index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
178*4882a593Smuzhiyun "0x01:%d:%d:%d:%d:%d\n",
179*4882a593Smuzhiyun data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return index;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
setup_virtual_keys(struct device_node * dev_node,const char * inp_dev_name,struct cyttsp5_virtual_keys * vkeys)184*4882a593Smuzhiyun static int setup_virtual_keys(struct device_node *dev_node,
185*4882a593Smuzhiyun const char *inp_dev_name, struct cyttsp5_virtual_keys *vkeys)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun char *name;
188*4882a593Smuzhiyun u16 *data;
189*4882a593Smuzhiyun int size;
190*4882a593Smuzhiyun int rc;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun data = create_and_get_u16_array(dev_node, "cy,virtual_keys", &size);
193*4882a593Smuzhiyun if (data == NULL)
194*4882a593Smuzhiyun return 0;
195*4882a593Smuzhiyun else if (IS_ERR(data)) {
196*4882a593Smuzhiyun rc = PTR_ERR(data);
197*4882a593Smuzhiyun goto fail;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* Check for valid virtual keys size */
201*4882a593Smuzhiyun if (size % VIRTUAL_KEY_ELEMENT_SIZE) {
202*4882a593Smuzhiyun rc = -EINVAL;
203*4882a593Smuzhiyun goto fail_free_data;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
207*4882a593Smuzhiyun if (!name) {
208*4882a593Smuzhiyun rc = -ENOMEM;
209*4882a593Smuzhiyun goto fail_free_data;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun snprintf(name, MAX_NAME_LENGTH, "virtualkeys.%s", inp_dev_name);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun vkeys->data = data;
215*4882a593Smuzhiyun vkeys->size = size;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* TODO: Instantiate in board file and export it */
218*4882a593Smuzhiyun if (board_properties_kobj == NULL)
219*4882a593Smuzhiyun board_properties_kobj =
220*4882a593Smuzhiyun kobject_create_and_add("board_properties", NULL);
221*4882a593Smuzhiyun if (board_properties_kobj == NULL) {
222*4882a593Smuzhiyun pr_err("%s: Cannot get board_properties kobject!\n", __func__);
223*4882a593Smuzhiyun rc = -EINVAL;
224*4882a593Smuzhiyun goto fail_free_name;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /* Initialize dynamic SysFs attribute */
228*4882a593Smuzhiyun sysfs_attr_init(&vkeys->kobj_attr.attr);
229*4882a593Smuzhiyun vkeys->kobj_attr.attr.name = name;
230*4882a593Smuzhiyun vkeys->kobj_attr.attr.mode = S_IRUGO;
231*4882a593Smuzhiyun vkeys->kobj_attr.show = virtual_keys_show;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun rc = sysfs_create_file(board_properties_kobj, &vkeys->kobj_attr.attr);
234*4882a593Smuzhiyun if (rc)
235*4882a593Smuzhiyun goto fail_del_kobj;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return 0;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun fail_del_kobj:
240*4882a593Smuzhiyun kobject_del(board_properties_kobj);
241*4882a593Smuzhiyun fail_free_name:
242*4882a593Smuzhiyun kfree(name);
243*4882a593Smuzhiyun vkeys->kobj_attr.attr.name = NULL;
244*4882a593Smuzhiyun fail_free_data:
245*4882a593Smuzhiyun kfree(data);
246*4882a593Smuzhiyun vkeys->data = NULL;
247*4882a593Smuzhiyun fail:
248*4882a593Smuzhiyun return rc;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
free_virtual_keys(struct cyttsp5_virtual_keys * vkeys)251*4882a593Smuzhiyun static void free_virtual_keys(struct cyttsp5_virtual_keys *vkeys)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun if (board_properties_kobj)
254*4882a593Smuzhiyun sysfs_remove_file(board_properties_kobj,
255*4882a593Smuzhiyun &vkeys->kobj_attr.attr);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun kobject_del(board_properties_kobj);
259*4882a593Smuzhiyun board_properties_kobj = NULL;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun kfree(vkeys->data);
262*4882a593Smuzhiyun kfree(vkeys->kobj_attr.attr.name);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun #endif
265*4882a593Smuzhiyun
create_and_get_mt_pdata(struct device_node * dev_node)266*4882a593Smuzhiyun static void *create_and_get_mt_pdata(struct device_node *dev_node)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct cyttsp5_extended_mt_platform_data *ext_pdata;
269*4882a593Smuzhiyun struct cyttsp5_mt_platform_data *pdata;
270*4882a593Smuzhiyun u32 value;
271*4882a593Smuzhiyun int rc;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL);
274*4882a593Smuzhiyun if (!ext_pdata) {
275*4882a593Smuzhiyun rc = -ENOMEM;
276*4882a593Smuzhiyun goto fail;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun pdata = &ext_pdata->pdata;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
282*4882a593Smuzhiyun if (rc)
283*4882a593Smuzhiyun goto fail_free_pdata;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Optional fields */
286*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,flags", &value);
287*4882a593Smuzhiyun if (!rc)
288*4882a593Smuzhiyun pdata->flags = value;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,vkeys_x", &value);
291*4882a593Smuzhiyun if (!rc)
292*4882a593Smuzhiyun pdata->vkeys_x = value;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,vkeys_y", &value);
295*4882a593Smuzhiyun if (!rc)
296*4882a593Smuzhiyun pdata->vkeys_y = value;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,revert_x", &value);
299*4882a593Smuzhiyun if (!rc)
300*4882a593Smuzhiyun pdata->swap_x = value;
301*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,revert_y", &value);
302*4882a593Smuzhiyun if (!rc)
303*4882a593Smuzhiyun pdata->swap_y = value;
304*4882a593Smuzhiyun rc = of_property_read_u32(dev_node, "cy,xy_exchange", &value);
305*4882a593Smuzhiyun if (!rc)
306*4882a593Smuzhiyun pdata->xy_exchange = value;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* Required fields */
310*4882a593Smuzhiyun pdata->frmwrk = create_and_get_touch_framework(dev_node);
311*4882a593Smuzhiyun if (pdata->frmwrk == NULL) {
312*4882a593Smuzhiyun rc = -EINVAL;
313*4882a593Smuzhiyun goto fail_free_pdata;
314*4882a593Smuzhiyun } else if (IS_ERR(pdata->frmwrk)) {
315*4882a593Smuzhiyun rc = PTR_ERR(pdata->frmwrk);
316*4882a593Smuzhiyun goto fail_free_pdata;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun #ifdef ENABLE_VIRTUAL_KEYS
319*4882a593Smuzhiyun rc = setup_virtual_keys(dev_node, pdata->inp_dev_name,
320*4882a593Smuzhiyun &ext_pdata->vkeys);
321*4882a593Smuzhiyun if (rc) {
322*4882a593Smuzhiyun pr_err("%s: Cannot setup virtual keys!\n", __func__);
323*4882a593Smuzhiyun goto fail_free_pdata;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun #endif
326*4882a593Smuzhiyun return pdata;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun fail_free_pdata:
329*4882a593Smuzhiyun kfree(ext_pdata);
330*4882a593Smuzhiyun fail:
331*4882a593Smuzhiyun return ERR_PTR(rc);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
free_mt_pdata(void * pdata)334*4882a593Smuzhiyun static void free_mt_pdata(void *pdata)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun struct cyttsp5_mt_platform_data *mt_pdata =
337*4882a593Smuzhiyun (struct cyttsp5_mt_platform_data *)pdata;
338*4882a593Smuzhiyun struct cyttsp5_extended_mt_platform_data *ext_mt_pdata =
339*4882a593Smuzhiyun container_of(mt_pdata,
340*4882a593Smuzhiyun struct cyttsp5_extended_mt_platform_data, pdata);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun free_touch_framework(mt_pdata->frmwrk);
343*4882a593Smuzhiyun #ifdef ENABLE_VIRTUAL_KEYS
344*4882a593Smuzhiyun free_virtual_keys(&ext_mt_pdata->vkeys);
345*4882a593Smuzhiyun #endif
346*4882a593Smuzhiyun kfree(ext_mt_pdata);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
create_and_get_btn_pdata(struct device_node * dev_node)349*4882a593Smuzhiyun static void *create_and_get_btn_pdata(struct device_node *dev_node)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct cyttsp5_btn_platform_data *pdata;
352*4882a593Smuzhiyun int rc;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
355*4882a593Smuzhiyun if (!pdata) {
356*4882a593Smuzhiyun rc = -ENOMEM;
357*4882a593Smuzhiyun goto fail;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
361*4882a593Smuzhiyun if (rc)
362*4882a593Smuzhiyun goto fail_free_pdata;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return pdata;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun fail_free_pdata:
367*4882a593Smuzhiyun kfree(pdata);
368*4882a593Smuzhiyun fail:
369*4882a593Smuzhiyun return ERR_PTR(rc);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
free_btn_pdata(void * pdata)372*4882a593Smuzhiyun static void free_btn_pdata(void *pdata)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun struct cyttsp5_btn_platform_data *btn_pdata =
375*4882a593Smuzhiyun (struct cyttsp5_btn_platform_data *)pdata;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun kfree(btn_pdata);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
create_and_get_proximity_pdata(struct device_node * dev_node)380*4882a593Smuzhiyun static void *create_and_get_proximity_pdata(struct device_node *dev_node)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun struct cyttsp5_proximity_platform_data *pdata;
383*4882a593Smuzhiyun int rc;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
386*4882a593Smuzhiyun if (!pdata) {
387*4882a593Smuzhiyun rc = -ENOMEM;
388*4882a593Smuzhiyun goto fail;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
392*4882a593Smuzhiyun if (rc)
393*4882a593Smuzhiyun goto fail_free_pdata;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun pdata->frmwrk = create_and_get_touch_framework(dev_node);
396*4882a593Smuzhiyun if (pdata->frmwrk == NULL) {
397*4882a593Smuzhiyun rc = -EINVAL;
398*4882a593Smuzhiyun goto fail_free_pdata;
399*4882a593Smuzhiyun } else if (IS_ERR(pdata->frmwrk)) {
400*4882a593Smuzhiyun rc = PTR_ERR(pdata->frmwrk);
401*4882a593Smuzhiyun goto fail_free_pdata;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun return pdata;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun fail_free_pdata:
407*4882a593Smuzhiyun kfree(pdata);
408*4882a593Smuzhiyun fail:
409*4882a593Smuzhiyun return ERR_PTR(rc);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
free_proximity_pdata(void * pdata)412*4882a593Smuzhiyun static void free_proximity_pdata(void *pdata)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun struct cyttsp5_proximity_platform_data *proximity_pdata =
415*4882a593Smuzhiyun (struct cyttsp5_proximity_platform_data *)pdata;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun free_touch_framework(proximity_pdata->frmwrk);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun kfree(proximity_pdata);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun static struct cyttsp5_device_pdata_func device_pdata_funcs[DEVICE_TYPE_MAX] = {
423*4882a593Smuzhiyun [DEVICE_MT] = {
424*4882a593Smuzhiyun .create_and_get_pdata = create_and_get_mt_pdata,
425*4882a593Smuzhiyun .free_pdata = free_mt_pdata,
426*4882a593Smuzhiyun },
427*4882a593Smuzhiyun [DEVICE_BTN] = {
428*4882a593Smuzhiyun .create_and_get_pdata = create_and_get_btn_pdata,
429*4882a593Smuzhiyun .free_pdata = free_btn_pdata,
430*4882a593Smuzhiyun },
431*4882a593Smuzhiyun [DEVICE_PROXIMITY] = {
432*4882a593Smuzhiyun .create_and_get_pdata = create_and_get_proximity_pdata,
433*4882a593Smuzhiyun .free_pdata = free_proximity_pdata,
434*4882a593Smuzhiyun },
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun static struct cyttsp5_pdata_ptr pdata_ptr[DEVICE_TYPE_MAX];
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun static const char *device_names[DEVICE_TYPE_MAX] = {
440*4882a593Smuzhiyun [DEVICE_MT] = "cy,mt",
441*4882a593Smuzhiyun [DEVICE_BTN] = "cy,btn",
442*4882a593Smuzhiyun [DEVICE_PROXIMITY] = "cy,proximity",
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun
set_pdata_ptr(struct cyttsp5_platform_data * pdata)445*4882a593Smuzhiyun static void set_pdata_ptr(struct cyttsp5_platform_data *pdata)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun pdata_ptr[DEVICE_MT].pdata = (void **)&pdata->mt_pdata;
448*4882a593Smuzhiyun pdata_ptr[DEVICE_BTN].pdata = (void **)&pdata->btn_pdata;
449*4882a593Smuzhiyun pdata_ptr[DEVICE_PROXIMITY].pdata = (void **)&pdata->prox_pdata;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
get_device_type(struct device_node * dev_node,enum cyttsp5_device_type * type)452*4882a593Smuzhiyun static int get_device_type(struct device_node *dev_node,
453*4882a593Smuzhiyun enum cyttsp5_device_type *type)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun const char *name;
456*4882a593Smuzhiyun enum cyttsp5_device_type t;
457*4882a593Smuzhiyun int rc;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun rc = of_property_read_string(dev_node, "name", &name);
460*4882a593Smuzhiyun if (rc)
461*4882a593Smuzhiyun return rc;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun for (t = 0; t < DEVICE_TYPE_MAX; t++)
464*4882a593Smuzhiyun if (!strncmp(name, device_names[t], MAX_NAME_LENGTH)) {
465*4882a593Smuzhiyun *type = t;
466*4882a593Smuzhiyun return 0;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun return -EINVAL;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
create_and_get_device_pdata(struct device_node * dev_node,enum cyttsp5_device_type type)472*4882a593Smuzhiyun static inline void *create_and_get_device_pdata(struct device_node *dev_node,
473*4882a593Smuzhiyun enum cyttsp5_device_type type)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun return device_pdata_funcs[type].create_and_get_pdata(dev_node);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
free_device_pdata(enum cyttsp5_device_type type)478*4882a593Smuzhiyun static inline void free_device_pdata(enum cyttsp5_device_type type)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun device_pdata_funcs[type].free_pdata(*pdata_ptr[type].pdata);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
create_and_get_touch_setting(struct device_node * core_node,const char * name)483*4882a593Smuzhiyun static struct touch_settings *create_and_get_touch_setting(
484*4882a593Smuzhiyun struct device_node *core_node, const char *name)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun struct touch_settings *setting;
487*4882a593Smuzhiyun char *tag_name;
488*4882a593Smuzhiyun u32 tag_value;
489*4882a593Smuzhiyun u16 *data;
490*4882a593Smuzhiyun int size;
491*4882a593Smuzhiyun int rc;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun data = create_and_get_u16_array(core_node, name, &size);
494*4882a593Smuzhiyun if (IS_ERR_OR_NULL(data))
495*4882a593Smuzhiyun return (void *)data;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun pr_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun setting = kzalloc(sizeof(*setting), GFP_KERNEL);
500*4882a593Smuzhiyun if (!setting) {
501*4882a593Smuzhiyun rc = -ENOMEM;
502*4882a593Smuzhiyun goto fail_free_data;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun setting->data = (u8 *)data;
506*4882a593Smuzhiyun setting->size = size;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
509*4882a593Smuzhiyun if (!tag_name) {
510*4882a593Smuzhiyun rc = -ENOMEM;
511*4882a593Smuzhiyun goto fail_free_setting;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun snprintf(tag_name, MAX_NAME_LENGTH, "%s-tag", name);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun rc = of_property_read_u32(core_node, tag_name, &tag_value);
517*4882a593Smuzhiyun if (!rc)
518*4882a593Smuzhiyun setting->tag = tag_value;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun kfree(tag_name);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun return setting;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun fail_free_setting:
525*4882a593Smuzhiyun kfree(setting);
526*4882a593Smuzhiyun fail_free_data:
527*4882a593Smuzhiyun kfree(data);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return ERR_PTR(rc);
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
free_touch_setting(struct touch_settings * setting)532*4882a593Smuzhiyun static void free_touch_setting(struct touch_settings *setting)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun if (setting) {
535*4882a593Smuzhiyun kfree(setting->data);
536*4882a593Smuzhiyun kfree(setting);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun static char *touch_setting_names[CY_IC_GRPNUM_NUM] = {
541*4882a593Smuzhiyun NULL, /* CY_IC_GRPNUM_RESERVED */
542*4882a593Smuzhiyun "cy,cmd_regs", /* CY_IC_GRPNUM_CMD_REGS */
543*4882a593Smuzhiyun "cy,tch_rep", /* CY_IC_GRPNUM_TCH_REP */
544*4882a593Smuzhiyun "cy,data_rec", /* CY_IC_GRPNUM_DATA_REC */
545*4882a593Smuzhiyun "cy,test_rec", /* CY_IC_GRPNUM_TEST_REC */
546*4882a593Smuzhiyun "cy,pcfg_rec", /* CY_IC_GRPNUM_PCFG_REC */
547*4882a593Smuzhiyun "cy,tch_parm_val", /* CY_IC_GRPNUM_TCH_PARM_VAL */
548*4882a593Smuzhiyun "cy,tch_parm_size", /* CY_IC_GRPNUM_TCH_PARM_SIZE */
549*4882a593Smuzhiyun NULL, /* CY_IC_GRPNUM_RESERVED1 */
550*4882a593Smuzhiyun NULL, /* CY_IC_GRPNUM_RESERVED2 */
551*4882a593Smuzhiyun "cy,opcfg_rec", /* CY_IC_GRPNUM_OPCFG_REC */
552*4882a593Smuzhiyun "cy,ddata_rec", /* CY_IC_GRPNUM_DDATA_REC */
553*4882a593Smuzhiyun "cy,mdata_rec", /* CY_IC_GRPNUM_MDATA_REC */
554*4882a593Smuzhiyun "cy,test_regs", /* CY_IC_GRPNUM_TEST_REGS */
555*4882a593Smuzhiyun "cy,btn_keys", /* CY_IC_GRPNUM_BTN_KEYS */
556*4882a593Smuzhiyun NULL, /* CY_IC_GRPNUM_TTHE_REGS */
557*4882a593Smuzhiyun };
558*4882a593Smuzhiyun
create_and_get_core_pdata(struct device_node * core_node)559*4882a593Smuzhiyun static struct cyttsp5_core_platform_data *create_and_get_core_pdata(
560*4882a593Smuzhiyun struct device_node *core_node)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun struct cyttsp5_core_platform_data *pdata;
563*4882a593Smuzhiyun u32 value;
564*4882a593Smuzhiyun int rc;
565*4882a593Smuzhiyun int i;
566*4882a593Smuzhiyun int reset_gpio = -1, irq_gpio = -1, pwr_1v8_io = -1, pwr_2v8_io;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
569*4882a593Smuzhiyun if (!pdata) {
570*4882a593Smuzhiyun rc = -ENOMEM;
571*4882a593Smuzhiyun goto fail;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /* Required fields */
575*4882a593Smuzhiyun irq_gpio = of_get_named_gpio(core_node, "cy,irq_gpio", 0);
576*4882a593Smuzhiyun if (gpio_is_valid(irq_gpio)) {
577*4882a593Smuzhiyun pdata->irq_gpio = irq_gpio;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun /* Optional fields */
580*4882a593Smuzhiyun /* rst_gpio is optional since a platform may use
581*4882a593Smuzhiyun * power cycling instead of using the XRES pin
582*4882a593Smuzhiyun */
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun reset_gpio = of_get_named_gpio(core_node, "cy,rst_gpio", 0);
585*4882a593Smuzhiyun if (gpio_is_valid(reset_gpio)) {
586*4882a593Smuzhiyun pdata->rst_gpio = reset_gpio;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun pwr_1v8_io = of_get_named_gpio(core_node, "cy,1v8_gpio", 0);
589*4882a593Smuzhiyun if (gpio_is_valid(pwr_1v8_io)) {
590*4882a593Smuzhiyun rc = gpio_request(pwr_1v8_io, NULL);
591*4882a593Smuzhiyun if (rc < 0) {
592*4882a593Smuzhiyun printk("pwr_1v8_io request failed,rc=%d\n", rc);
593*4882a593Smuzhiyun } else {
594*4882a593Smuzhiyun gpio_direction_output(pwr_1v8_io, 1);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun pwr_2v8_io = of_get_named_gpio(core_node, "cy,2v8_gpio", 0);
599*4882a593Smuzhiyun if (gpio_is_valid(pwr_2v8_io)) {
600*4882a593Smuzhiyun rc = gpio_request(pwr_2v8_io, NULL);
601*4882a593Smuzhiyun if (rc < 0) {
602*4882a593Smuzhiyun printk("pwr_2v8_io request failed,rc=%d\n", rc);
603*4882a593Smuzhiyun } else {
604*4882a593Smuzhiyun gpio_direction_output(pwr_2v8_io, 1);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,hid_desc_register", &value);
609*4882a593Smuzhiyun if (rc)
610*4882a593Smuzhiyun goto fail_free;
611*4882a593Smuzhiyun pdata->hid_desc_register = value;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,level_irq_udelay", &value);
614*4882a593Smuzhiyun if (!rc)
615*4882a593Smuzhiyun pdata->level_irq_udelay = value;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,vendor_id", &value);
618*4882a593Smuzhiyun if (!rc)
619*4882a593Smuzhiyun pdata->vendor_id = value;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,product_id", &value);
622*4882a593Smuzhiyun if (!rc)
623*4882a593Smuzhiyun pdata->product_id = value;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,flags", &value);
626*4882a593Smuzhiyun if (!rc)
627*4882a593Smuzhiyun pdata->flags = value;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun rc = of_property_read_u32(core_node, "cy,easy_wakeup_gesture", &value);
630*4882a593Smuzhiyun if (!rc)
631*4882a593Smuzhiyun pdata->easy_wakeup_gesture = (u8)value;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun for (i = 0; (unsigned int)i < ARRAY_SIZE(touch_setting_names); i++) {
634*4882a593Smuzhiyun if (touch_setting_names[i] == NULL)
635*4882a593Smuzhiyun continue;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun pdata->sett[i] = create_and_get_touch_setting(core_node,
638*4882a593Smuzhiyun touch_setting_names[i]);
639*4882a593Smuzhiyun if (IS_ERR(pdata->sett[i])) {
640*4882a593Smuzhiyun rc = PTR_ERR(pdata->sett[i]);
641*4882a593Smuzhiyun goto fail_free_sett;
642*4882a593Smuzhiyun } else if (pdata->sett[i] == NULL)
643*4882a593Smuzhiyun pr_debug("%s: No data for setting '%s'\n", __func__,
644*4882a593Smuzhiyun touch_setting_names[i]);
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun pr_debug("%s: irq_gpio:%d rst_gpio:%d\n"
648*4882a593Smuzhiyun "hid_desc_register:%d level_irq_udelay:%d vendor_id:%d product_id:%d\n"
649*4882a593Smuzhiyun "flags:%d easy_wakeup_gesture:%d\n", __func__,
650*4882a593Smuzhiyun pdata->irq_gpio, pdata->rst_gpio,
651*4882a593Smuzhiyun pdata->hid_desc_register,
652*4882a593Smuzhiyun pdata->level_irq_udelay, pdata->vendor_id, pdata->product_id,
653*4882a593Smuzhiyun pdata->flags, pdata->easy_wakeup_gesture);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun pdata->xres = cyttsp5_xres;
656*4882a593Smuzhiyun pdata->init = cyttsp5_init;
657*4882a593Smuzhiyun pdata->power = cyttsp5_power;
658*4882a593Smuzhiyun pdata->detect = cyttsp5_detect;
659*4882a593Smuzhiyun pdata->irq_stat = cyttsp5_irq_stat;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun return pdata;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun fail_free_sett:
664*4882a593Smuzhiyun for (i--; i >= 0; i--)
665*4882a593Smuzhiyun free_touch_setting(pdata->sett[i]);
666*4882a593Smuzhiyun fail_free:
667*4882a593Smuzhiyun kfree(pdata);
668*4882a593Smuzhiyun fail:
669*4882a593Smuzhiyun return ERR_PTR(rc);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
free_core_pdata(void * pdata)672*4882a593Smuzhiyun static void free_core_pdata(void *pdata)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun struct cyttsp5_core_platform_data *core_pdata = pdata;
675*4882a593Smuzhiyun unsigned int i;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(touch_setting_names); i++)
678*4882a593Smuzhiyun free_touch_setting(core_pdata->sett[i]);
679*4882a593Smuzhiyun kfree(core_pdata);
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun
cyttsp5_devtree_create_and_get_pdata(struct device * adap_dev)682*4882a593Smuzhiyun int cyttsp5_devtree_create_and_get_pdata(struct device *adap_dev)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun struct cyttsp5_platform_data *pdata;
685*4882a593Smuzhiyun struct device_node *core_node, *dev_node, *dev_node_fail;
686*4882a593Smuzhiyun enum cyttsp5_device_type type;
687*4882a593Smuzhiyun int count = 0;
688*4882a593Smuzhiyun int rc = 0;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun if (!adap_dev->of_node)
691*4882a593Smuzhiyun return 0;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
694*4882a593Smuzhiyun if (!pdata)
695*4882a593Smuzhiyun return -ENOMEM;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun adap_dev->platform_data = pdata;
698*4882a593Smuzhiyun set_pdata_ptr(pdata);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /* There should be only one core node */
701*4882a593Smuzhiyun for_each_child_of_node(adap_dev->of_node, core_node) {
702*4882a593Smuzhiyun const char *name;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun rc = of_property_read_string(core_node, "name", &name);
705*4882a593Smuzhiyun if (!rc)
706*4882a593Smuzhiyun pr_debug("%s: name:%s\n", __func__, name);
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun pdata->core_pdata = create_and_get_core_pdata(core_node);
709*4882a593Smuzhiyun if (IS_ERR(pdata->core_pdata)) {
710*4882a593Smuzhiyun rc = PTR_ERR(pdata->core_pdata);
711*4882a593Smuzhiyun break;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /* Increment reference count */
715*4882a593Smuzhiyun of_node_get(core_node);
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun for_each_child_of_node(core_node, dev_node) {
718*4882a593Smuzhiyun count++;
719*4882a593Smuzhiyun rc = get_device_type(dev_node, &type);
720*4882a593Smuzhiyun if (rc)
721*4882a593Smuzhiyun break;
722*4882a593Smuzhiyun *pdata_ptr[type].pdata
723*4882a593Smuzhiyun = create_and_get_device_pdata(dev_node, type);
724*4882a593Smuzhiyun if (IS_ERR(*pdata_ptr[type].pdata))
725*4882a593Smuzhiyun rc = PTR_ERR(*pdata_ptr[type].pdata);
726*4882a593Smuzhiyun if (rc)
727*4882a593Smuzhiyun break;
728*4882a593Smuzhiyun /* Increment reference count */
729*4882a593Smuzhiyun of_node_get(dev_node);
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun if (rc) {
733*4882a593Smuzhiyun free_core_pdata(pdata->core_pdata);
734*4882a593Smuzhiyun of_node_put(core_node);
735*4882a593Smuzhiyun for_each_child_of_node(core_node, dev_node_fail) {
736*4882a593Smuzhiyun if (dev_node == dev_node_fail)
737*4882a593Smuzhiyun break;
738*4882a593Smuzhiyun rc = get_device_type(dev_node, &type);
739*4882a593Smuzhiyun if (rc)
740*4882a593Smuzhiyun break;
741*4882a593Smuzhiyun free_device_pdata(type);
742*4882a593Smuzhiyun of_node_put(dev_node);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun break;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun pdata->loader_pdata = &_cyttsp5_loader_platform_data;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun pr_info("%s: %d child node(s) found\n", __func__, count);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun return rc;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cyttsp5_devtree_create_and_get_pdata);
754*4882a593Smuzhiyun
cyttsp5_devtree_clean_pdata(struct device * adap_dev)755*4882a593Smuzhiyun int cyttsp5_devtree_clean_pdata(struct device *adap_dev)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun struct cyttsp5_platform_data *pdata;
758*4882a593Smuzhiyun struct device_node *core_node, *dev_node;
759*4882a593Smuzhiyun enum cyttsp5_device_type type;
760*4882a593Smuzhiyun int rc = 0;
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun if (!adap_dev->of_node)
763*4882a593Smuzhiyun return 0;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun pdata = dev_get_platdata(adap_dev);
766*4882a593Smuzhiyun set_pdata_ptr(pdata);
767*4882a593Smuzhiyun for_each_child_of_node(adap_dev->of_node, core_node) {
768*4882a593Smuzhiyun free_core_pdata(pdata->core_pdata);
769*4882a593Smuzhiyun of_node_put(core_node);
770*4882a593Smuzhiyun for_each_child_of_node(core_node, dev_node) {
771*4882a593Smuzhiyun rc = get_device_type(dev_node, &type);
772*4882a593Smuzhiyun if (rc)
773*4882a593Smuzhiyun break;
774*4882a593Smuzhiyun free_device_pdata(type);
775*4882a593Smuzhiyun of_node_put(dev_node);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun return rc;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cyttsp5_devtree_clean_pdata);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun MODULE_LICENSE("GPL");
784*4882a593Smuzhiyun MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product DeviceTree Driver");
785*4882a593Smuzhiyun MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
786