xref: /linux/drivers/hte/hte.c (revision 31ab09b4218879bc394c9faa6da983a82a694600)
1*31ab09b4SDipen Patel // SPDX-License-Identifier: GPL-2.0
2*31ab09b4SDipen Patel /*
3*31ab09b4SDipen Patel  * Copyright (c) 2021-2022 NVIDIA Corporation
4*31ab09b4SDipen Patel  *
5*31ab09b4SDipen Patel  * Author: Dipen Patel <dipenp@nvidia.com>
6*31ab09b4SDipen Patel  */
7*31ab09b4SDipen Patel 
8*31ab09b4SDipen Patel #include <linux/kernel.h>
9*31ab09b4SDipen Patel #include <linux/module.h>
10*31ab09b4SDipen Patel #include <linux/err.h>
11*31ab09b4SDipen Patel #include <linux/slab.h>
12*31ab09b4SDipen Patel #include <linux/of.h>
13*31ab09b4SDipen Patel #include <linux/of_device.h>
14*31ab09b4SDipen Patel #include <linux/mutex.h>
15*31ab09b4SDipen Patel #include <linux/uaccess.h>
16*31ab09b4SDipen Patel #include <linux/hte.h>
17*31ab09b4SDipen Patel #include <linux/delay.h>
18*31ab09b4SDipen Patel #include <linux/debugfs.h>
19*31ab09b4SDipen Patel 
20*31ab09b4SDipen Patel #define HTE_TS_NAME_LEN		10
21*31ab09b4SDipen Patel 
22*31ab09b4SDipen Patel /* Global list of the HTE devices */
23*31ab09b4SDipen Patel static DEFINE_SPINLOCK(hte_lock);
24*31ab09b4SDipen Patel static LIST_HEAD(hte_devices);
25*31ab09b4SDipen Patel 
26*31ab09b4SDipen Patel enum {
27*31ab09b4SDipen Patel 	HTE_TS_REGISTERED,
28*31ab09b4SDipen Patel 	HTE_TS_REQ,
29*31ab09b4SDipen Patel 	HTE_TS_DISABLE,
30*31ab09b4SDipen Patel 	HTE_TS_QUEUE_WK,
31*31ab09b4SDipen Patel };
32*31ab09b4SDipen Patel 
33*31ab09b4SDipen Patel /**
34*31ab09b4SDipen Patel  * struct hte_ts_info - Information related to requested timestamp.
35*31ab09b4SDipen Patel  *
36*31ab09b4SDipen Patel  * @xlated_id: Timestamp ID as understood between HTE subsys and HTE provider,
37*31ab09b4SDipen Patel  * See xlate callback API.
38*31ab09b4SDipen Patel  * @flags: Flags holding state information.
39*31ab09b4SDipen Patel  * @hte_cb_flags: Callback related flags.
40*31ab09b4SDipen Patel  * @seq: Timestamp sequence counter.
41*31ab09b4SDipen Patel  * @line_name: HTE allocated line name.
42*31ab09b4SDipen Patel  * @free_attr_name: If set, free the attr name.
43*31ab09b4SDipen Patel  * @cb: A nonsleeping callback function provided by clients.
44*31ab09b4SDipen Patel  * @tcb: A secondary sleeping callback function provided by clients.
45*31ab09b4SDipen Patel  * @dropped_ts: Dropped timestamps.
46*31ab09b4SDipen Patel  * @slock: Spin lock to synchronize between disable/enable,
47*31ab09b4SDipen Patel  * request/release APIs.
48*31ab09b4SDipen Patel  * @cb_work: callback workqueue, used when tcb is specified.
49*31ab09b4SDipen Patel  * @req_mlock: Lock during timestamp request/release APIs.
50*31ab09b4SDipen Patel  * @ts_dbg_root: Root for the debug fs.
51*31ab09b4SDipen Patel  * @gdev: HTE abstract device that this timestamp information belongs to.
52*31ab09b4SDipen Patel  * @cl_data: Client specific data.
53*31ab09b4SDipen Patel  */
54*31ab09b4SDipen Patel struct hte_ts_info {
55*31ab09b4SDipen Patel 	u32 xlated_id;
56*31ab09b4SDipen Patel 	unsigned long flags;
57*31ab09b4SDipen Patel 	unsigned long hte_cb_flags;
58*31ab09b4SDipen Patel 	u64 seq;
59*31ab09b4SDipen Patel 	char *line_name;
60*31ab09b4SDipen Patel 	bool free_attr_name;
61*31ab09b4SDipen Patel 	hte_ts_cb_t cb;
62*31ab09b4SDipen Patel 	hte_ts_sec_cb_t tcb;
63*31ab09b4SDipen Patel 	atomic_t dropped_ts;
64*31ab09b4SDipen Patel 	spinlock_t slock;
65*31ab09b4SDipen Patel 	struct work_struct cb_work;
66*31ab09b4SDipen Patel 	struct mutex req_mlock;
67*31ab09b4SDipen Patel 	struct dentry *ts_dbg_root;
68*31ab09b4SDipen Patel 	struct hte_device *gdev;
69*31ab09b4SDipen Patel 	void *cl_data;
70*31ab09b4SDipen Patel };
71*31ab09b4SDipen Patel 
72*31ab09b4SDipen Patel /**
73*31ab09b4SDipen Patel  * struct hte_device - HTE abstract device
74*31ab09b4SDipen Patel  * @nlines: Number of entities this device supports.
75*31ab09b4SDipen Patel  * @ts_req: Total number of entities requested.
76*31ab09b4SDipen Patel  * @sdev: Device used at various debug prints.
77*31ab09b4SDipen Patel  * @dbg_root: Root directory for debug fs.
78*31ab09b4SDipen Patel  * @list: List node to store hte_device for each provider.
79*31ab09b4SDipen Patel  * @chip: HTE chip providing this HTE device.
80*31ab09b4SDipen Patel  * @owner: helps prevent removal of modules when in use.
81*31ab09b4SDipen Patel  * @ei: Timestamp information.
82*31ab09b4SDipen Patel  */
83*31ab09b4SDipen Patel struct hte_device {
84*31ab09b4SDipen Patel 	u32 nlines;
85*31ab09b4SDipen Patel 	atomic_t ts_req;
86*31ab09b4SDipen Patel 	struct device *sdev;
87*31ab09b4SDipen Patel 	struct dentry *dbg_root;
88*31ab09b4SDipen Patel 	struct list_head list;
89*31ab09b4SDipen Patel 	struct hte_chip *chip;
90*31ab09b4SDipen Patel 	struct module *owner;
91*31ab09b4SDipen Patel 	struct hte_ts_info ei[];
92*31ab09b4SDipen Patel };
93*31ab09b4SDipen Patel 
94*31ab09b4SDipen Patel #ifdef CONFIG_DEBUG_FS
95*31ab09b4SDipen Patel 
96*31ab09b4SDipen Patel static struct dentry *hte_root;
97*31ab09b4SDipen Patel 
98*31ab09b4SDipen Patel static int __init hte_subsys_dbgfs_init(void)
99*31ab09b4SDipen Patel {
100*31ab09b4SDipen Patel 	/* creates /sys/kernel/debug/hte/ */
101*31ab09b4SDipen Patel 	hte_root = debugfs_create_dir("hte", NULL);
102*31ab09b4SDipen Patel 
103*31ab09b4SDipen Patel 	return 0;
104*31ab09b4SDipen Patel }
105*31ab09b4SDipen Patel subsys_initcall(hte_subsys_dbgfs_init);
106*31ab09b4SDipen Patel 
107*31ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev)
108*31ab09b4SDipen Patel {
109*31ab09b4SDipen Patel 	const struct hte_chip *chip = gdev->chip;
110*31ab09b4SDipen Patel 	const char *name = chip->name ? chip->name : dev_name(chip->dev);
111*31ab09b4SDipen Patel 
112*31ab09b4SDipen Patel 	gdev->dbg_root = debugfs_create_dir(name, hte_root);
113*31ab09b4SDipen Patel 
114*31ab09b4SDipen Patel 	debugfs_create_atomic_t("ts_requested", 0444, gdev->dbg_root,
115*31ab09b4SDipen Patel 				&gdev->ts_req);
116*31ab09b4SDipen Patel 	debugfs_create_u32("total_ts", 0444, gdev->dbg_root,
117*31ab09b4SDipen Patel 			   &gdev->nlines);
118*31ab09b4SDipen Patel }
119*31ab09b4SDipen Patel 
120*31ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
121*31ab09b4SDipen Patel {
122*31ab09b4SDipen Patel 	if (!ei->gdev->dbg_root || !name)
123*31ab09b4SDipen Patel 		return;
124*31ab09b4SDipen Patel 
125*31ab09b4SDipen Patel 	ei->ts_dbg_root = debugfs_create_dir(name, ei->gdev->dbg_root);
126*31ab09b4SDipen Patel 
127*31ab09b4SDipen Patel 	debugfs_create_atomic_t("dropped_timestamps", 0444, ei->ts_dbg_root,
128*31ab09b4SDipen Patel 				&ei->dropped_ts);
129*31ab09b4SDipen Patel }
130*31ab09b4SDipen Patel 
131*31ab09b4SDipen Patel #else
132*31ab09b4SDipen Patel 
133*31ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev)
134*31ab09b4SDipen Patel {
135*31ab09b4SDipen Patel }
136*31ab09b4SDipen Patel 
137*31ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
138*31ab09b4SDipen Patel {
139*31ab09b4SDipen Patel }
140*31ab09b4SDipen Patel 
141*31ab09b4SDipen Patel #endif
142*31ab09b4SDipen Patel 
143*31ab09b4SDipen Patel /**
144*31ab09b4SDipen Patel  * hte_ts_put() - Release and disable timestamp for the given desc.
145*31ab09b4SDipen Patel  *
146*31ab09b4SDipen Patel  * @desc: timestamp descriptor.
147*31ab09b4SDipen Patel  *
148*31ab09b4SDipen Patel  * Context: debugfs_remove_recursive() function call may use sleeping locks,
149*31ab09b4SDipen Patel  *	    not suitable from atomic context.
150*31ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
151*31ab09b4SDipen Patel  */
152*31ab09b4SDipen Patel int hte_ts_put(struct hte_ts_desc *desc)
153*31ab09b4SDipen Patel {
154*31ab09b4SDipen Patel 	int ret = 0;
155*31ab09b4SDipen Patel 	unsigned long flag;
156*31ab09b4SDipen Patel 	struct hte_device *gdev;
157*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
158*31ab09b4SDipen Patel 
159*31ab09b4SDipen Patel 	if (!desc)
160*31ab09b4SDipen Patel 		return -EINVAL;
161*31ab09b4SDipen Patel 
162*31ab09b4SDipen Patel 	ei = desc->hte_data;
163*31ab09b4SDipen Patel 
164*31ab09b4SDipen Patel 	if (!ei || !ei->gdev)
165*31ab09b4SDipen Patel 		return -EINVAL;
166*31ab09b4SDipen Patel 
167*31ab09b4SDipen Patel 	gdev = ei->gdev;
168*31ab09b4SDipen Patel 
169*31ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
170*31ab09b4SDipen Patel 
171*31ab09b4SDipen Patel 	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
172*31ab09b4SDipen Patel 	    !test_bit(HTE_TS_REGISTERED, &ei->flags))) {
173*31ab09b4SDipen Patel 		dev_info(gdev->sdev, "id:%d is not requested\n",
174*31ab09b4SDipen Patel 			 desc->attr.line_id);
175*31ab09b4SDipen Patel 		ret = -EINVAL;
176*31ab09b4SDipen Patel 		goto unlock;
177*31ab09b4SDipen Patel 	}
178*31ab09b4SDipen Patel 
179*31ab09b4SDipen Patel 	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
180*31ab09b4SDipen Patel 	    test_bit(HTE_TS_REGISTERED, &ei->flags))) {
181*31ab09b4SDipen Patel 		dev_info(gdev->sdev, "id:%d is registered but not requested\n",
182*31ab09b4SDipen Patel 			 desc->attr.line_id);
183*31ab09b4SDipen Patel 		ret = -EINVAL;
184*31ab09b4SDipen Patel 		goto unlock;
185*31ab09b4SDipen Patel 	}
186*31ab09b4SDipen Patel 
187*31ab09b4SDipen Patel 	if (test_bit(HTE_TS_REQ, &ei->flags) &&
188*31ab09b4SDipen Patel 	    !test_bit(HTE_TS_REGISTERED, &ei->flags)) {
189*31ab09b4SDipen Patel 		clear_bit(HTE_TS_REQ, &ei->flags);
190*31ab09b4SDipen Patel 		desc->hte_data = NULL;
191*31ab09b4SDipen Patel 		ret = 0;
192*31ab09b4SDipen Patel 		goto mod_put;
193*31ab09b4SDipen Patel 	}
194*31ab09b4SDipen Patel 
195*31ab09b4SDipen Patel 	ret = gdev->chip->ops->release(gdev->chip, desc, ei->xlated_id);
196*31ab09b4SDipen Patel 	if (ret) {
197*31ab09b4SDipen Patel 		dev_err(gdev->sdev, "id: %d free failed\n",
198*31ab09b4SDipen Patel 			desc->attr.line_id);
199*31ab09b4SDipen Patel 		goto unlock;
200*31ab09b4SDipen Patel 	}
201*31ab09b4SDipen Patel 
202*31ab09b4SDipen Patel 	kfree(ei->line_name);
203*31ab09b4SDipen Patel 	if (ei->free_attr_name)
204*31ab09b4SDipen Patel 		kfree_const(desc->attr.name);
205*31ab09b4SDipen Patel 
206*31ab09b4SDipen Patel 	debugfs_remove_recursive(ei->ts_dbg_root);
207*31ab09b4SDipen Patel 
208*31ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
209*31ab09b4SDipen Patel 
210*31ab09b4SDipen Patel 	if (test_bit(HTE_TS_QUEUE_WK, &ei->flags)) {
211*31ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
212*31ab09b4SDipen Patel 		flush_work(&ei->cb_work);
213*31ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
214*31ab09b4SDipen Patel 	}
215*31ab09b4SDipen Patel 
216*31ab09b4SDipen Patel 	atomic_dec(&gdev->ts_req);
217*31ab09b4SDipen Patel 	atomic_set(&ei->dropped_ts, 0);
218*31ab09b4SDipen Patel 
219*31ab09b4SDipen Patel 	ei->seq = 1;
220*31ab09b4SDipen Patel 	ei->flags = 0;
221*31ab09b4SDipen Patel 	desc->hte_data = NULL;
222*31ab09b4SDipen Patel 
223*31ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
224*31ab09b4SDipen Patel 
225*31ab09b4SDipen Patel 	ei->cb = NULL;
226*31ab09b4SDipen Patel 	ei->tcb = NULL;
227*31ab09b4SDipen Patel 	ei->cl_data = NULL;
228*31ab09b4SDipen Patel 
229*31ab09b4SDipen Patel mod_put:
230*31ab09b4SDipen Patel 	module_put(gdev->owner);
231*31ab09b4SDipen Patel unlock:
232*31ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
233*31ab09b4SDipen Patel 	dev_dbg(gdev->sdev, "release id: %d\n", desc->attr.line_id);
234*31ab09b4SDipen Patel 
235*31ab09b4SDipen Patel 	return ret;
236*31ab09b4SDipen Patel }
237*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_put);
238*31ab09b4SDipen Patel 
239*31ab09b4SDipen Patel static int hte_ts_dis_en_common(struct hte_ts_desc *desc, bool en)
240*31ab09b4SDipen Patel {
241*31ab09b4SDipen Patel 	u32 ts_id;
242*31ab09b4SDipen Patel 	struct hte_device *gdev;
243*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
244*31ab09b4SDipen Patel 	int ret;
245*31ab09b4SDipen Patel 	unsigned long flag;
246*31ab09b4SDipen Patel 
247*31ab09b4SDipen Patel 	if (!desc)
248*31ab09b4SDipen Patel 		return -EINVAL;
249*31ab09b4SDipen Patel 
250*31ab09b4SDipen Patel 	ei = desc->hte_data;
251*31ab09b4SDipen Patel 
252*31ab09b4SDipen Patel 	if (!ei || !ei->gdev)
253*31ab09b4SDipen Patel 		return -EINVAL;
254*31ab09b4SDipen Patel 
255*31ab09b4SDipen Patel 	gdev = ei->gdev;
256*31ab09b4SDipen Patel 	ts_id = desc->attr.line_id;
257*31ab09b4SDipen Patel 
258*31ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
259*31ab09b4SDipen Patel 
260*31ab09b4SDipen Patel 	if (!test_bit(HTE_TS_REGISTERED, &ei->flags)) {
261*31ab09b4SDipen Patel 		dev_dbg(gdev->sdev, "id:%d is not registered", ts_id);
262*31ab09b4SDipen Patel 		ret = -EUSERS;
263*31ab09b4SDipen Patel 		goto out;
264*31ab09b4SDipen Patel 	}
265*31ab09b4SDipen Patel 
266*31ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
267*31ab09b4SDipen Patel 
268*31ab09b4SDipen Patel 	if (en) {
269*31ab09b4SDipen Patel 		if (!test_bit(HTE_TS_DISABLE, &ei->flags)) {
270*31ab09b4SDipen Patel 			ret = 0;
271*31ab09b4SDipen Patel 			goto out_unlock;
272*31ab09b4SDipen Patel 		}
273*31ab09b4SDipen Patel 
274*31ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
275*31ab09b4SDipen Patel 		ret = gdev->chip->ops->enable(gdev->chip, ei->xlated_id);
276*31ab09b4SDipen Patel 		if (ret) {
277*31ab09b4SDipen Patel 			dev_warn(gdev->sdev, "id: %d enable failed\n",
278*31ab09b4SDipen Patel 				 ts_id);
279*31ab09b4SDipen Patel 			goto out;
280*31ab09b4SDipen Patel 		}
281*31ab09b4SDipen Patel 
282*31ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
283*31ab09b4SDipen Patel 		clear_bit(HTE_TS_DISABLE, &ei->flags);
284*31ab09b4SDipen Patel 	} else {
285*31ab09b4SDipen Patel 		if (test_bit(HTE_TS_DISABLE, &ei->flags)) {
286*31ab09b4SDipen Patel 			ret = 0;
287*31ab09b4SDipen Patel 			goto out_unlock;
288*31ab09b4SDipen Patel 		}
289*31ab09b4SDipen Patel 
290*31ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
291*31ab09b4SDipen Patel 		ret = gdev->chip->ops->disable(gdev->chip, ei->xlated_id);
292*31ab09b4SDipen Patel 		if (ret) {
293*31ab09b4SDipen Patel 			dev_warn(gdev->sdev, "id: %d disable failed\n",
294*31ab09b4SDipen Patel 				 ts_id);
295*31ab09b4SDipen Patel 			goto out;
296*31ab09b4SDipen Patel 		}
297*31ab09b4SDipen Patel 
298*31ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
299*31ab09b4SDipen Patel 		set_bit(HTE_TS_DISABLE, &ei->flags);
300*31ab09b4SDipen Patel 	}
301*31ab09b4SDipen Patel 
302*31ab09b4SDipen Patel out_unlock:
303*31ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
304*31ab09b4SDipen Patel out:
305*31ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
306*31ab09b4SDipen Patel 	return ret;
307*31ab09b4SDipen Patel }
308*31ab09b4SDipen Patel 
309*31ab09b4SDipen Patel /**
310*31ab09b4SDipen Patel  * hte_disable_ts() - Disable timestamp on given descriptor.
311*31ab09b4SDipen Patel  *
312*31ab09b4SDipen Patel  * The API does not release any resources associated with desc.
313*31ab09b4SDipen Patel  *
314*31ab09b4SDipen Patel  * @desc: ts descriptor, this is the same as returned by the request API.
315*31ab09b4SDipen Patel  *
316*31ab09b4SDipen Patel  * Context: Holds mutex lock, not suitable from atomic context.
317*31ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
318*31ab09b4SDipen Patel  */
319*31ab09b4SDipen Patel int hte_disable_ts(struct hte_ts_desc *desc)
320*31ab09b4SDipen Patel {
321*31ab09b4SDipen Patel 	return hte_ts_dis_en_common(desc, false);
322*31ab09b4SDipen Patel }
323*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_disable_ts);
324*31ab09b4SDipen Patel 
325*31ab09b4SDipen Patel /**
326*31ab09b4SDipen Patel  * hte_enable_ts() - Enable timestamp on given descriptor.
327*31ab09b4SDipen Patel  *
328*31ab09b4SDipen Patel  * @desc: ts descriptor, this is the same as returned by the request API.
329*31ab09b4SDipen Patel  *
330*31ab09b4SDipen Patel  * Context: Holds mutex lock, not suitable from atomic context.
331*31ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
332*31ab09b4SDipen Patel  */
333*31ab09b4SDipen Patel int hte_enable_ts(struct hte_ts_desc *desc)
334*31ab09b4SDipen Patel {
335*31ab09b4SDipen Patel 	return hte_ts_dis_en_common(desc, true);
336*31ab09b4SDipen Patel }
337*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_enable_ts);
338*31ab09b4SDipen Patel 
339*31ab09b4SDipen Patel static void hte_do_cb_work(struct work_struct *w)
340*31ab09b4SDipen Patel {
341*31ab09b4SDipen Patel 	unsigned long flag;
342*31ab09b4SDipen Patel 	struct hte_ts_info *ei = container_of(w, struct hte_ts_info, cb_work);
343*31ab09b4SDipen Patel 
344*31ab09b4SDipen Patel 	if (unlikely(!ei->tcb))
345*31ab09b4SDipen Patel 		return;
346*31ab09b4SDipen Patel 
347*31ab09b4SDipen Patel 	ei->tcb(ei->cl_data);
348*31ab09b4SDipen Patel 
349*31ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
350*31ab09b4SDipen Patel 	clear_bit(HTE_TS_QUEUE_WK, &ei->flags);
351*31ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
352*31ab09b4SDipen Patel }
353*31ab09b4SDipen Patel 
354*31ab09b4SDipen Patel static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb,
355*31ab09b4SDipen Patel 			hte_ts_sec_cb_t tcb, void *data)
356*31ab09b4SDipen Patel {
357*31ab09b4SDipen Patel 	int ret;
358*31ab09b4SDipen Patel 	struct hte_device *gdev;
359*31ab09b4SDipen Patel 	struct hte_ts_info *ei = desc->hte_data;
360*31ab09b4SDipen Patel 
361*31ab09b4SDipen Patel 	gdev = ei->gdev;
362*31ab09b4SDipen Patel 	/*
363*31ab09b4SDipen Patel 	 * There is a chance that multiple consumers requesting same entity,
364*31ab09b4SDipen Patel 	 * lock here.
365*31ab09b4SDipen Patel 	 */
366*31ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
367*31ab09b4SDipen Patel 
368*31ab09b4SDipen Patel 	if (test_bit(HTE_TS_REGISTERED, &ei->flags) ||
369*31ab09b4SDipen Patel 	    !test_bit(HTE_TS_REQ, &ei->flags)) {
370*31ab09b4SDipen Patel 		dev_dbg(gdev->chip->dev, "id:%u req failed\n",
371*31ab09b4SDipen Patel 			desc->attr.line_id);
372*31ab09b4SDipen Patel 		ret = -EUSERS;
373*31ab09b4SDipen Patel 		goto unlock;
374*31ab09b4SDipen Patel 	}
375*31ab09b4SDipen Patel 
376*31ab09b4SDipen Patel 	ei->cb = cb;
377*31ab09b4SDipen Patel 	ei->tcb = tcb;
378*31ab09b4SDipen Patel 	if (tcb)
379*31ab09b4SDipen Patel 		INIT_WORK(&ei->cb_work, hte_do_cb_work);
380*31ab09b4SDipen Patel 
381*31ab09b4SDipen Patel 	ret = gdev->chip->ops->request(gdev->chip, desc, ei->xlated_id);
382*31ab09b4SDipen Patel 	if (ret < 0) {
383*31ab09b4SDipen Patel 		dev_err(gdev->chip->dev, "ts request failed\n");
384*31ab09b4SDipen Patel 		goto unlock;
385*31ab09b4SDipen Patel 	}
386*31ab09b4SDipen Patel 
387*31ab09b4SDipen Patel 	ei->cl_data = data;
388*31ab09b4SDipen Patel 	ei->seq = 1;
389*31ab09b4SDipen Patel 
390*31ab09b4SDipen Patel 	atomic_inc(&gdev->ts_req);
391*31ab09b4SDipen Patel 
392*31ab09b4SDipen Patel 	ei->line_name = NULL;
393*31ab09b4SDipen Patel 	if (!desc->attr.name) {
394*31ab09b4SDipen Patel 		ei->line_name = kzalloc(HTE_TS_NAME_LEN, GFP_KERNEL);
395*31ab09b4SDipen Patel 		if (ei->line_name)
396*31ab09b4SDipen Patel 			scnprintf(ei->line_name, HTE_TS_NAME_LEN, "ts_%u",
397*31ab09b4SDipen Patel 				  desc->attr.line_id);
398*31ab09b4SDipen Patel 	}
399*31ab09b4SDipen Patel 
400*31ab09b4SDipen Patel 	hte_ts_dbgfs_init(desc->attr.name == NULL ?
401*31ab09b4SDipen Patel 			  ei->line_name : desc->attr.name, ei);
402*31ab09b4SDipen Patel 	set_bit(HTE_TS_REGISTERED, &ei->flags);
403*31ab09b4SDipen Patel 
404*31ab09b4SDipen Patel 	dev_dbg(gdev->chip->dev, "id: %u, xlated id:%u",
405*31ab09b4SDipen Patel 		desc->attr.line_id, ei->xlated_id);
406*31ab09b4SDipen Patel 
407*31ab09b4SDipen Patel 	ret = 0;
408*31ab09b4SDipen Patel 
409*31ab09b4SDipen Patel unlock:
410*31ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
411*31ab09b4SDipen Patel 
412*31ab09b4SDipen Patel 	return ret;
413*31ab09b4SDipen Patel }
414*31ab09b4SDipen Patel 
415*31ab09b4SDipen Patel static int hte_bind_ts_info_locked(struct hte_ts_info *ei,
416*31ab09b4SDipen Patel 				   struct hte_ts_desc *desc, u32 x_id)
417*31ab09b4SDipen Patel {
418*31ab09b4SDipen Patel 	int ret = 0;
419*31ab09b4SDipen Patel 
420*31ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
421*31ab09b4SDipen Patel 
422*31ab09b4SDipen Patel 	if (test_bit(HTE_TS_REQ, &ei->flags)) {
423*31ab09b4SDipen Patel 		dev_dbg(ei->gdev->chip->dev, "id:%u is already requested\n",
424*31ab09b4SDipen Patel 			desc->attr.line_id);
425*31ab09b4SDipen Patel 		ret = -EUSERS;
426*31ab09b4SDipen Patel 		goto out;
427*31ab09b4SDipen Patel 	}
428*31ab09b4SDipen Patel 
429*31ab09b4SDipen Patel 	set_bit(HTE_TS_REQ, &ei->flags);
430*31ab09b4SDipen Patel 	desc->hte_data = ei;
431*31ab09b4SDipen Patel 	ei->xlated_id = x_id;
432*31ab09b4SDipen Patel 
433*31ab09b4SDipen Patel out:
434*31ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
435*31ab09b4SDipen Patel 
436*31ab09b4SDipen Patel 	return ret;
437*31ab09b4SDipen Patel }
438*31ab09b4SDipen Patel 
439*31ab09b4SDipen Patel static struct hte_device *of_node_to_htedevice(struct device_node *np)
440*31ab09b4SDipen Patel {
441*31ab09b4SDipen Patel 	struct hte_device *gdev;
442*31ab09b4SDipen Patel 
443*31ab09b4SDipen Patel 	spin_lock(&hte_lock);
444*31ab09b4SDipen Patel 
445*31ab09b4SDipen Patel 	list_for_each_entry(gdev, &hte_devices, list)
446*31ab09b4SDipen Patel 		if (gdev->chip && gdev->chip->dev &&
447*31ab09b4SDipen Patel 		    gdev->chip->dev->of_node == np) {
448*31ab09b4SDipen Patel 			spin_unlock(&hte_lock);
449*31ab09b4SDipen Patel 			return gdev;
450*31ab09b4SDipen Patel 		}
451*31ab09b4SDipen Patel 
452*31ab09b4SDipen Patel 	spin_unlock(&hte_lock);
453*31ab09b4SDipen Patel 
454*31ab09b4SDipen Patel 	return ERR_PTR(-ENODEV);
455*31ab09b4SDipen Patel }
456*31ab09b4SDipen Patel 
457*31ab09b4SDipen Patel static struct hte_device *hte_find_dev_from_linedata(struct hte_ts_desc *desc)
458*31ab09b4SDipen Patel {
459*31ab09b4SDipen Patel 	struct hte_device *gdev;
460*31ab09b4SDipen Patel 
461*31ab09b4SDipen Patel 	spin_lock(&hte_lock);
462*31ab09b4SDipen Patel 
463*31ab09b4SDipen Patel 	list_for_each_entry(gdev, &hte_devices, list)
464*31ab09b4SDipen Patel 		if (gdev->chip && gdev->chip->match_from_linedata) {
465*31ab09b4SDipen Patel 			if (!gdev->chip->match_from_linedata(gdev->chip, desc))
466*31ab09b4SDipen Patel 				continue;
467*31ab09b4SDipen Patel 			spin_unlock(&hte_lock);
468*31ab09b4SDipen Patel 			return gdev;
469*31ab09b4SDipen Patel 		}
470*31ab09b4SDipen Patel 
471*31ab09b4SDipen Patel 	spin_unlock(&hte_lock);
472*31ab09b4SDipen Patel 
473*31ab09b4SDipen Patel 	return ERR_PTR(-ENODEV);
474*31ab09b4SDipen Patel }
475*31ab09b4SDipen Patel 
476*31ab09b4SDipen Patel /**
477*31ab09b4SDipen Patel  * of_hte_req_count - Return the number of entities to timestamp.
478*31ab09b4SDipen Patel  *
479*31ab09b4SDipen Patel  * The function returns the total count of the requested entities to timestamp
480*31ab09b4SDipen Patel  * by parsing device tree.
481*31ab09b4SDipen Patel  *
482*31ab09b4SDipen Patel  * @dev: The HTE consumer.
483*31ab09b4SDipen Patel  *
484*31ab09b4SDipen Patel  * Returns: Positive number on success, -ENOENT if no entries,
485*31ab09b4SDipen Patel  * -EINVAL for other errors.
486*31ab09b4SDipen Patel  */
487*31ab09b4SDipen Patel int of_hte_req_count(struct device *dev)
488*31ab09b4SDipen Patel {
489*31ab09b4SDipen Patel 	int count;
490*31ab09b4SDipen Patel 
491*31ab09b4SDipen Patel 	if (!dev || !dev->of_node)
492*31ab09b4SDipen Patel 		return -EINVAL;
493*31ab09b4SDipen Patel 
494*31ab09b4SDipen Patel 	count = of_count_phandle_with_args(dev->of_node, "timestamps",
495*31ab09b4SDipen Patel 					   "#timestamp-cells");
496*31ab09b4SDipen Patel 
497*31ab09b4SDipen Patel 	return count ? count : -ENOENT;
498*31ab09b4SDipen Patel }
499*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(of_hte_req_count);
500*31ab09b4SDipen Patel 
501*31ab09b4SDipen Patel static inline struct hte_device *hte_get_dev(struct hte_ts_desc *desc)
502*31ab09b4SDipen Patel {
503*31ab09b4SDipen Patel 	return hte_find_dev_from_linedata(desc);
504*31ab09b4SDipen Patel }
505*31ab09b4SDipen Patel 
506*31ab09b4SDipen Patel static struct hte_device *hte_of_get_dev(struct device *dev,
507*31ab09b4SDipen Patel 					 struct hte_ts_desc *desc,
508*31ab09b4SDipen Patel 					 int index,
509*31ab09b4SDipen Patel 					 struct of_phandle_args *args,
510*31ab09b4SDipen Patel 					 bool *free_name)
511*31ab09b4SDipen Patel {
512*31ab09b4SDipen Patel 	int ret;
513*31ab09b4SDipen Patel 	struct device_node *np;
514*31ab09b4SDipen Patel 	char *temp;
515*31ab09b4SDipen Patel 
516*31ab09b4SDipen Patel 	if (!dev->of_node)
517*31ab09b4SDipen Patel 		return ERR_PTR(-EINVAL);
518*31ab09b4SDipen Patel 
519*31ab09b4SDipen Patel 	np = dev->of_node;
520*31ab09b4SDipen Patel 
521*31ab09b4SDipen Patel 	if (!of_find_property(np, "timestamp-names", NULL)) {
522*31ab09b4SDipen Patel 		/* Let hte core construct it during request time */
523*31ab09b4SDipen Patel 		desc->attr.name = NULL;
524*31ab09b4SDipen Patel 	} else {
525*31ab09b4SDipen Patel 		ret = of_property_read_string_index(np, "timestamp-names",
526*31ab09b4SDipen Patel 						    index, &desc->attr.name);
527*31ab09b4SDipen Patel 		if (ret) {
528*31ab09b4SDipen Patel 			pr_err("can't parse \"timestamp-names\" property\n");
529*31ab09b4SDipen Patel 			return ERR_PTR(ret);
530*31ab09b4SDipen Patel 		}
531*31ab09b4SDipen Patel 		*free_name = false;
532*31ab09b4SDipen Patel 		if (desc->attr.name) {
533*31ab09b4SDipen Patel 			temp = skip_spaces(desc->attr.name);
534*31ab09b4SDipen Patel 			if (!*temp)
535*31ab09b4SDipen Patel 				desc->attr.name = NULL;
536*31ab09b4SDipen Patel 		}
537*31ab09b4SDipen Patel 	}
538*31ab09b4SDipen Patel 
539*31ab09b4SDipen Patel 	ret = of_parse_phandle_with_args(np, "timestamps", "#timestamp-cells",
540*31ab09b4SDipen Patel 					 index, args);
541*31ab09b4SDipen Patel 	if (ret) {
542*31ab09b4SDipen Patel 		pr_err("%s(): can't parse \"timestamps\" property\n",
543*31ab09b4SDipen Patel 		       __func__);
544*31ab09b4SDipen Patel 		return ERR_PTR(ret);
545*31ab09b4SDipen Patel 	}
546*31ab09b4SDipen Patel 
547*31ab09b4SDipen Patel 	of_node_put(args->np);
548*31ab09b4SDipen Patel 
549*31ab09b4SDipen Patel 	return of_node_to_htedevice(args->np);
550*31ab09b4SDipen Patel }
551*31ab09b4SDipen Patel 
552*31ab09b4SDipen Patel /**
553*31ab09b4SDipen Patel  * hte_ts_get() - The function to initialize and obtain HTE desc.
554*31ab09b4SDipen Patel  *
555*31ab09b4SDipen Patel  * The function initializes the consumer provided HTE descriptor. If consumer
556*31ab09b4SDipen Patel  * has device tree node, index is used to parse the line id and other details.
557*31ab09b4SDipen Patel  * The function needs to be called before using any request APIs.
558*31ab09b4SDipen Patel  *
559*31ab09b4SDipen Patel  * @dev: HTE consumer/client device, used in case of parsing device tree node.
560*31ab09b4SDipen Patel  * @desc: Pre-allocated timestamp descriptor.
561*31ab09b4SDipen Patel  * @index: The index will be used as an index to parse line_id from the
562*31ab09b4SDipen Patel  * device tree node if node is present.
563*31ab09b4SDipen Patel  *
564*31ab09b4SDipen Patel  * Context: Holds mutex lock.
565*31ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
566*31ab09b4SDipen Patel  */
567*31ab09b4SDipen Patel int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index)
568*31ab09b4SDipen Patel {
569*31ab09b4SDipen Patel 	struct hte_device *gdev;
570*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
571*31ab09b4SDipen Patel 	const struct fwnode_handle *fwnode;
572*31ab09b4SDipen Patel 	struct of_phandle_args args;
573*31ab09b4SDipen Patel 	u32 xlated_id;
574*31ab09b4SDipen Patel 	int ret;
575*31ab09b4SDipen Patel 	bool free_name;
576*31ab09b4SDipen Patel 
577*31ab09b4SDipen Patel 	if (!desc)
578*31ab09b4SDipen Patel 		return -EINVAL;
579*31ab09b4SDipen Patel 
580*31ab09b4SDipen Patel 	fwnode = dev ? dev_fwnode(dev) : NULL;
581*31ab09b4SDipen Patel 
582*31ab09b4SDipen Patel 	if (is_of_node(fwnode))
583*31ab09b4SDipen Patel 		gdev = hte_of_get_dev(dev, desc, index, &args, &free_name);
584*31ab09b4SDipen Patel 	else
585*31ab09b4SDipen Patel 		gdev = hte_get_dev(desc);
586*31ab09b4SDipen Patel 
587*31ab09b4SDipen Patel 	if (IS_ERR(gdev)) {
588*31ab09b4SDipen Patel 		pr_err("%s() no hte dev found\n", __func__);
589*31ab09b4SDipen Patel 		return PTR_ERR(gdev);
590*31ab09b4SDipen Patel 	}
591*31ab09b4SDipen Patel 
592*31ab09b4SDipen Patel 	if (!try_module_get(gdev->owner))
593*31ab09b4SDipen Patel 		return -ENODEV;
594*31ab09b4SDipen Patel 
595*31ab09b4SDipen Patel 	if (!gdev->chip) {
596*31ab09b4SDipen Patel 		pr_err("%s(): requested id does not have provider\n",
597*31ab09b4SDipen Patel 		       __func__);
598*31ab09b4SDipen Patel 		ret = -ENODEV;
599*31ab09b4SDipen Patel 		goto put;
600*31ab09b4SDipen Patel 	}
601*31ab09b4SDipen Patel 
602*31ab09b4SDipen Patel 	if (is_of_node(fwnode)) {
603*31ab09b4SDipen Patel 		if (!gdev->chip->xlate_of)
604*31ab09b4SDipen Patel 			ret = -EINVAL;
605*31ab09b4SDipen Patel 		else
606*31ab09b4SDipen Patel 			ret = gdev->chip->xlate_of(gdev->chip, &args,
607*31ab09b4SDipen Patel 						   desc, &xlated_id);
608*31ab09b4SDipen Patel 	} else {
609*31ab09b4SDipen Patel 		if (!gdev->chip->xlate_plat)
610*31ab09b4SDipen Patel 			ret = -EINVAL;
611*31ab09b4SDipen Patel 		else
612*31ab09b4SDipen Patel 			ret = gdev->chip->xlate_plat(gdev->chip, desc,
613*31ab09b4SDipen Patel 						     &xlated_id);
614*31ab09b4SDipen Patel 	}
615*31ab09b4SDipen Patel 
616*31ab09b4SDipen Patel 	if (ret < 0)
617*31ab09b4SDipen Patel 		goto put;
618*31ab09b4SDipen Patel 
619*31ab09b4SDipen Patel 	ei = &gdev->ei[xlated_id];
620*31ab09b4SDipen Patel 
621*31ab09b4SDipen Patel 	ret = hte_bind_ts_info_locked(ei, desc, xlated_id);
622*31ab09b4SDipen Patel 	if (ret)
623*31ab09b4SDipen Patel 		goto put;
624*31ab09b4SDipen Patel 
625*31ab09b4SDipen Patel 	ei->free_attr_name = free_name;
626*31ab09b4SDipen Patel 
627*31ab09b4SDipen Patel 	return 0;
628*31ab09b4SDipen Patel 
629*31ab09b4SDipen Patel put:
630*31ab09b4SDipen Patel 	module_put(gdev->owner);
631*31ab09b4SDipen Patel 	return ret;
632*31ab09b4SDipen Patel }
633*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_get);
634*31ab09b4SDipen Patel 
635*31ab09b4SDipen Patel static void __devm_hte_release_ts(void *res)
636*31ab09b4SDipen Patel {
637*31ab09b4SDipen Patel 	hte_ts_put(res);
638*31ab09b4SDipen Patel }
639*31ab09b4SDipen Patel 
640*31ab09b4SDipen Patel /**
641*31ab09b4SDipen Patel  * hte_request_ts_ns() - The API to request and enable hardware timestamp in
642*31ab09b4SDipen Patel  * nanoseconds.
643*31ab09b4SDipen Patel  *
644*31ab09b4SDipen Patel  * The entity is provider specific for example, GPIO lines, signals, buses
645*31ab09b4SDipen Patel  * etc...The API allocates necessary resources and enables the timestamp.
646*31ab09b4SDipen Patel  *
647*31ab09b4SDipen Patel  * @desc: Pre-allocated and initialized timestamp descriptor.
648*31ab09b4SDipen Patel  * @cb: Callback to push the timestamp data to consumer.
649*31ab09b4SDipen Patel  * @tcb: Optional callback. If its provided, subsystem initializes
650*31ab09b4SDipen Patel  * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
651*31ab09b4SDipen Patel  * @data: Client data, used during cb and tcb callbacks.
652*31ab09b4SDipen Patel  *
653*31ab09b4SDipen Patel  * Context: Holds mutex lock.
654*31ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
655*31ab09b4SDipen Patel  */
656*31ab09b4SDipen Patel int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb,
657*31ab09b4SDipen Patel 		      hte_ts_sec_cb_t tcb, void *data)
658*31ab09b4SDipen Patel {
659*31ab09b4SDipen Patel 	int ret;
660*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
661*31ab09b4SDipen Patel 
662*31ab09b4SDipen Patel 	if (!desc || !desc->hte_data || !cb)
663*31ab09b4SDipen Patel 		return -EINVAL;
664*31ab09b4SDipen Patel 
665*31ab09b4SDipen Patel 	ei = desc->hte_data;
666*31ab09b4SDipen Patel 	if (!ei || !ei->gdev)
667*31ab09b4SDipen Patel 		return -EINVAL;
668*31ab09b4SDipen Patel 
669*31ab09b4SDipen Patel 	ret = __hte_req_ts(desc, cb, tcb, data);
670*31ab09b4SDipen Patel 	if (ret < 0) {
671*31ab09b4SDipen Patel 		dev_err(ei->gdev->chip->dev,
672*31ab09b4SDipen Patel 			"failed to request id: %d\n", desc->attr.line_id);
673*31ab09b4SDipen Patel 		return ret;
674*31ab09b4SDipen Patel 	}
675*31ab09b4SDipen Patel 
676*31ab09b4SDipen Patel 	return 0;
677*31ab09b4SDipen Patel }
678*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_request_ts_ns);
679*31ab09b4SDipen Patel 
680*31ab09b4SDipen Patel /**
681*31ab09b4SDipen Patel  * devm_hte_request_ts_ns() - Resource managed API to request and enable
682*31ab09b4SDipen Patel  * hardware timestamp in nanoseconds.
683*31ab09b4SDipen Patel  *
684*31ab09b4SDipen Patel  * The entity is provider specific for example, GPIO lines, signals, buses
685*31ab09b4SDipen Patel  * etc...The API allocates necessary resources and enables the timestamp. It
686*31ab09b4SDipen Patel  * deallocates and disables automatically when the consumer exits.
687*31ab09b4SDipen Patel  *
688*31ab09b4SDipen Patel  * @dev: HTE consumer/client device.
689*31ab09b4SDipen Patel  * @desc: Pre-allocated and initialized timestamp descriptor.
690*31ab09b4SDipen Patel  * @cb: Callback to push the timestamp data to consumer.
691*31ab09b4SDipen Patel  * @tcb: Optional callback. If its provided, subsystem initializes
692*31ab09b4SDipen Patel  * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
693*31ab09b4SDipen Patel  * @data: Client data, used during cb and tcb callbacks.
694*31ab09b4SDipen Patel  *
695*31ab09b4SDipen Patel  * Context: Holds mutex lock.
696*31ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
697*31ab09b4SDipen Patel  */
698*31ab09b4SDipen Patel int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc,
699*31ab09b4SDipen Patel 			   hte_ts_cb_t cb, hte_ts_sec_cb_t tcb,
700*31ab09b4SDipen Patel 			   void *data)
701*31ab09b4SDipen Patel {
702*31ab09b4SDipen Patel 	int err;
703*31ab09b4SDipen Patel 
704*31ab09b4SDipen Patel 	if (!dev)
705*31ab09b4SDipen Patel 		return -EINVAL;
706*31ab09b4SDipen Patel 
707*31ab09b4SDipen Patel 	err = hte_request_ts_ns(desc, cb, tcb, data);
708*31ab09b4SDipen Patel 	if (err)
709*31ab09b4SDipen Patel 		return err;
710*31ab09b4SDipen Patel 
711*31ab09b4SDipen Patel 	err = devm_add_action_or_reset(dev, __devm_hte_release_ts, desc);
712*31ab09b4SDipen Patel 	if (err)
713*31ab09b4SDipen Patel 		return err;
714*31ab09b4SDipen Patel 
715*31ab09b4SDipen Patel 	return 0;
716*31ab09b4SDipen Patel }
717*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_request_ts_ns);
718*31ab09b4SDipen Patel 
719*31ab09b4SDipen Patel /**
720*31ab09b4SDipen Patel  * hte_init_line_attr() - Initialize line attributes.
721*31ab09b4SDipen Patel  *
722*31ab09b4SDipen Patel  * Zeroes out line attributes and initializes with provided arguments.
723*31ab09b4SDipen Patel  * The function needs to be called before calling any consumer facing
724*31ab09b4SDipen Patel  * functions.
725*31ab09b4SDipen Patel  *
726*31ab09b4SDipen Patel  * @desc: Pre-allocated timestamp descriptor.
727*31ab09b4SDipen Patel  * @line_id: line id.
728*31ab09b4SDipen Patel  * @edge_flags: edge flags related to line_id.
729*31ab09b4SDipen Patel  * @name: name of the line.
730*31ab09b4SDipen Patel  * @data: line data related to line_id.
731*31ab09b4SDipen Patel  *
732*31ab09b4SDipen Patel  * Context: Any.
733*31ab09b4SDipen Patel  * Returns: 0 on success or negative error code for the failure.
734*31ab09b4SDipen Patel  */
735*31ab09b4SDipen Patel int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id,
736*31ab09b4SDipen Patel 		       unsigned long edge_flags, const char *name, void *data)
737*31ab09b4SDipen Patel {
738*31ab09b4SDipen Patel 	if (!desc)
739*31ab09b4SDipen Patel 		return -EINVAL;
740*31ab09b4SDipen Patel 
741*31ab09b4SDipen Patel 	memset(&desc->attr, 0, sizeof(desc->attr));
742*31ab09b4SDipen Patel 
743*31ab09b4SDipen Patel 	desc->attr.edge_flags = edge_flags;
744*31ab09b4SDipen Patel 	desc->attr.line_id = line_id;
745*31ab09b4SDipen Patel 	desc->attr.line_data = data;
746*31ab09b4SDipen Patel 	if (name) {
747*31ab09b4SDipen Patel 		name =  kstrdup_const(name, GFP_KERNEL);
748*31ab09b4SDipen Patel 		if (!name)
749*31ab09b4SDipen Patel 			return -ENOMEM;
750*31ab09b4SDipen Patel 	}
751*31ab09b4SDipen Patel 
752*31ab09b4SDipen Patel 	desc->attr.name = name;
753*31ab09b4SDipen Patel 
754*31ab09b4SDipen Patel 	return 0;
755*31ab09b4SDipen Patel }
756*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_init_line_attr);
757*31ab09b4SDipen Patel 
758*31ab09b4SDipen Patel /**
759*31ab09b4SDipen Patel  * hte_get_clk_src_info() - Get the clock source information for a ts
760*31ab09b4SDipen Patel  * descriptor.
761*31ab09b4SDipen Patel  *
762*31ab09b4SDipen Patel  * @desc: ts descriptor, same as returned from request API.
763*31ab09b4SDipen Patel  * @ci: The API fills this structure with the clock information data.
764*31ab09b4SDipen Patel  *
765*31ab09b4SDipen Patel  * Context: Any context.
766*31ab09b4SDipen Patel  * Returns: 0 on success else negative error code on failure.
767*31ab09b4SDipen Patel  */
768*31ab09b4SDipen Patel int hte_get_clk_src_info(const struct hte_ts_desc *desc,
769*31ab09b4SDipen Patel 			 struct hte_clk_info *ci)
770*31ab09b4SDipen Patel {
771*31ab09b4SDipen Patel 	struct hte_chip *chip;
772*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
773*31ab09b4SDipen Patel 
774*31ab09b4SDipen Patel 	if (!desc || !desc->hte_data || !ci) {
775*31ab09b4SDipen Patel 		pr_debug("%s:%d\n", __func__, __LINE__);
776*31ab09b4SDipen Patel 		return -EINVAL;
777*31ab09b4SDipen Patel 	}
778*31ab09b4SDipen Patel 
779*31ab09b4SDipen Patel 	ei = desc->hte_data;
780*31ab09b4SDipen Patel 	if (!ei->gdev || !ei->gdev->chip)
781*31ab09b4SDipen Patel 		return -EINVAL;
782*31ab09b4SDipen Patel 
783*31ab09b4SDipen Patel 	chip = ei->gdev->chip;
784*31ab09b4SDipen Patel 	if (!chip->ops->get_clk_src_info)
785*31ab09b4SDipen Patel 		return -EOPNOTSUPP;
786*31ab09b4SDipen Patel 
787*31ab09b4SDipen Patel 	return chip->ops->get_clk_src_info(chip, ci);
788*31ab09b4SDipen Patel }
789*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_get_clk_src_info);
790*31ab09b4SDipen Patel 
791*31ab09b4SDipen Patel /**
792*31ab09b4SDipen Patel  * hte_push_ts_ns() - Push timestamp data in nanoseconds.
793*31ab09b4SDipen Patel  *
794*31ab09b4SDipen Patel  * It is used by the provider to push timestamp data.
795*31ab09b4SDipen Patel  *
796*31ab09b4SDipen Patel  * @chip: The HTE chip, used during the registration.
797*31ab09b4SDipen Patel  * @xlated_id: entity id understood by both subsystem and provider, this is
798*31ab09b4SDipen Patel  * obtained from xlate callback during request API.
799*31ab09b4SDipen Patel  * @data: timestamp data.
800*31ab09b4SDipen Patel  *
801*31ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
802*31ab09b4SDipen Patel  */
803*31ab09b4SDipen Patel int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id,
804*31ab09b4SDipen Patel 		   struct hte_ts_data *data)
805*31ab09b4SDipen Patel {
806*31ab09b4SDipen Patel 	enum hte_return ret;
807*31ab09b4SDipen Patel 	int st = 0;
808*31ab09b4SDipen Patel 	struct hte_ts_info *ei;
809*31ab09b4SDipen Patel 	unsigned long flag;
810*31ab09b4SDipen Patel 
811*31ab09b4SDipen Patel 	if (!chip || !data || !chip->gdev)
812*31ab09b4SDipen Patel 		return -EINVAL;
813*31ab09b4SDipen Patel 
814*31ab09b4SDipen Patel 	if (xlated_id > chip->nlines)
815*31ab09b4SDipen Patel 		return -EINVAL;
816*31ab09b4SDipen Patel 
817*31ab09b4SDipen Patel 	ei = &chip->gdev->ei[xlated_id];
818*31ab09b4SDipen Patel 
819*31ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
820*31ab09b4SDipen Patel 
821*31ab09b4SDipen Patel 	/* timestamp sequence counter */
822*31ab09b4SDipen Patel 	data->seq = ei->seq++;
823*31ab09b4SDipen Patel 
824*31ab09b4SDipen Patel 	if (!test_bit(HTE_TS_REGISTERED, &ei->flags) ||
825*31ab09b4SDipen Patel 	    test_bit(HTE_TS_DISABLE, &ei->flags)) {
826*31ab09b4SDipen Patel 		dev_dbg(chip->dev, "Unknown timestamp push\n");
827*31ab09b4SDipen Patel 		atomic_inc(&ei->dropped_ts);
828*31ab09b4SDipen Patel 		st = -EINVAL;
829*31ab09b4SDipen Patel 		goto unlock;
830*31ab09b4SDipen Patel 	}
831*31ab09b4SDipen Patel 
832*31ab09b4SDipen Patel 	ret = ei->cb(data, ei->cl_data);
833*31ab09b4SDipen Patel 	if (ret == HTE_RUN_SECOND_CB && ei->tcb) {
834*31ab09b4SDipen Patel 		queue_work(system_unbound_wq, &ei->cb_work);
835*31ab09b4SDipen Patel 		set_bit(HTE_TS_QUEUE_WK, &ei->flags);
836*31ab09b4SDipen Patel 	}
837*31ab09b4SDipen Patel 
838*31ab09b4SDipen Patel unlock:
839*31ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
840*31ab09b4SDipen Patel 
841*31ab09b4SDipen Patel 	return st;
842*31ab09b4SDipen Patel }
843*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_push_ts_ns);
844*31ab09b4SDipen Patel 
845*31ab09b4SDipen Patel static int hte_register_chip(struct hte_chip *chip)
846*31ab09b4SDipen Patel {
847*31ab09b4SDipen Patel 	struct hte_device *gdev;
848*31ab09b4SDipen Patel 	u32 i;
849*31ab09b4SDipen Patel 
850*31ab09b4SDipen Patel 	if (!chip || !chip->dev || !chip->dev->of_node)
851*31ab09b4SDipen Patel 		return -EINVAL;
852*31ab09b4SDipen Patel 
853*31ab09b4SDipen Patel 	if (!chip->ops || !chip->ops->request || !chip->ops->release) {
854*31ab09b4SDipen Patel 		dev_err(chip->dev, "Driver needs to provide ops\n");
855*31ab09b4SDipen Patel 		return -EINVAL;
856*31ab09b4SDipen Patel 	}
857*31ab09b4SDipen Patel 
858*31ab09b4SDipen Patel 	gdev = kzalloc(struct_size(gdev, ei, chip->nlines), GFP_KERNEL);
859*31ab09b4SDipen Patel 	if (!gdev)
860*31ab09b4SDipen Patel 		return -ENOMEM;
861*31ab09b4SDipen Patel 
862*31ab09b4SDipen Patel 	gdev->chip = chip;
863*31ab09b4SDipen Patel 	chip->gdev = gdev;
864*31ab09b4SDipen Patel 	gdev->nlines = chip->nlines;
865*31ab09b4SDipen Patel 	gdev->sdev = chip->dev;
866*31ab09b4SDipen Patel 
867*31ab09b4SDipen Patel 	for (i = 0; i < chip->nlines; i++) {
868*31ab09b4SDipen Patel 		gdev->ei[i].gdev = gdev;
869*31ab09b4SDipen Patel 		mutex_init(&gdev->ei[i].req_mlock);
870*31ab09b4SDipen Patel 		spin_lock_init(&gdev->ei[i].slock);
871*31ab09b4SDipen Patel 	}
872*31ab09b4SDipen Patel 
873*31ab09b4SDipen Patel 	if (chip->dev->driver)
874*31ab09b4SDipen Patel 		gdev->owner = chip->dev->driver->owner;
875*31ab09b4SDipen Patel 	else
876*31ab09b4SDipen Patel 		gdev->owner = THIS_MODULE;
877*31ab09b4SDipen Patel 
878*31ab09b4SDipen Patel 	of_node_get(chip->dev->of_node);
879*31ab09b4SDipen Patel 
880*31ab09b4SDipen Patel 	INIT_LIST_HEAD(&gdev->list);
881*31ab09b4SDipen Patel 
882*31ab09b4SDipen Patel 	spin_lock(&hte_lock);
883*31ab09b4SDipen Patel 	list_add_tail(&gdev->list, &hte_devices);
884*31ab09b4SDipen Patel 	spin_unlock(&hte_lock);
885*31ab09b4SDipen Patel 
886*31ab09b4SDipen Patel 	hte_chip_dbgfs_init(gdev);
887*31ab09b4SDipen Patel 
888*31ab09b4SDipen Patel 	dev_dbg(chip->dev, "Added hte chip\n");
889*31ab09b4SDipen Patel 
890*31ab09b4SDipen Patel 	return 0;
891*31ab09b4SDipen Patel }
892*31ab09b4SDipen Patel 
893*31ab09b4SDipen Patel static int hte_unregister_chip(struct hte_chip *chip)
894*31ab09b4SDipen Patel {
895*31ab09b4SDipen Patel 	struct hte_device *gdev;
896*31ab09b4SDipen Patel 
897*31ab09b4SDipen Patel 	if (!chip)
898*31ab09b4SDipen Patel 		return -EINVAL;
899*31ab09b4SDipen Patel 
900*31ab09b4SDipen Patel 	gdev = chip->gdev;
901*31ab09b4SDipen Patel 
902*31ab09b4SDipen Patel 	spin_lock(&hte_lock);
903*31ab09b4SDipen Patel 	list_del(&gdev->list);
904*31ab09b4SDipen Patel 	spin_unlock(&hte_lock);
905*31ab09b4SDipen Patel 
906*31ab09b4SDipen Patel 	gdev->chip = NULL;
907*31ab09b4SDipen Patel 
908*31ab09b4SDipen Patel 	of_node_put(chip->dev->of_node);
909*31ab09b4SDipen Patel 	debugfs_remove_recursive(gdev->dbg_root);
910*31ab09b4SDipen Patel 	kfree(gdev);
911*31ab09b4SDipen Patel 
912*31ab09b4SDipen Patel 	dev_dbg(chip->dev, "Removed hte chip\n");
913*31ab09b4SDipen Patel 
914*31ab09b4SDipen Patel 	return 0;
915*31ab09b4SDipen Patel }
916*31ab09b4SDipen Patel 
917*31ab09b4SDipen Patel static void _hte_devm_unregister_chip(void *chip)
918*31ab09b4SDipen Patel {
919*31ab09b4SDipen Patel 	hte_unregister_chip(chip);
920*31ab09b4SDipen Patel }
921*31ab09b4SDipen Patel 
922*31ab09b4SDipen Patel /**
923*31ab09b4SDipen Patel  * devm_hte_register_chip() - Resource managed API to register HTE chip.
924*31ab09b4SDipen Patel  *
925*31ab09b4SDipen Patel  * It is used by the provider to register itself with the HTE subsystem.
926*31ab09b4SDipen Patel  * The unregistration is done automatically when the provider exits.
927*31ab09b4SDipen Patel  *
928*31ab09b4SDipen Patel  * @chip: the HTE chip to add to subsystem.
929*31ab09b4SDipen Patel  *
930*31ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
931*31ab09b4SDipen Patel  */
932*31ab09b4SDipen Patel int devm_hte_register_chip(struct hte_chip *chip)
933*31ab09b4SDipen Patel {
934*31ab09b4SDipen Patel 	int err;
935*31ab09b4SDipen Patel 
936*31ab09b4SDipen Patel 	err = hte_register_chip(chip);
937*31ab09b4SDipen Patel 	if (err)
938*31ab09b4SDipen Patel 		return err;
939*31ab09b4SDipen Patel 
940*31ab09b4SDipen Patel 	err = devm_add_action_or_reset(chip->dev, _hte_devm_unregister_chip,
941*31ab09b4SDipen Patel 				       chip);
942*31ab09b4SDipen Patel 	if (err)
943*31ab09b4SDipen Patel 		return err;
944*31ab09b4SDipen Patel 
945*31ab09b4SDipen Patel 	return 0;
946*31ab09b4SDipen Patel }
947*31ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_register_chip);
948