xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/cyttsp5/cyttsp5_devtree.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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