xref: /linux/drivers/hte/hte.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
131ab09b4SDipen Patel // SPDX-License-Identifier: GPL-2.0
231ab09b4SDipen Patel /*
331ab09b4SDipen Patel  * Copyright (c) 2021-2022 NVIDIA Corporation
431ab09b4SDipen Patel  *
531ab09b4SDipen Patel  * Author: Dipen Patel <dipenp@nvidia.com>
631ab09b4SDipen Patel  */
731ab09b4SDipen Patel 
831ab09b4SDipen Patel #include <linux/kernel.h>
931ab09b4SDipen Patel #include <linux/module.h>
1031ab09b4SDipen Patel #include <linux/err.h>
1131ab09b4SDipen Patel #include <linux/slab.h>
1231ab09b4SDipen Patel #include <linux/of.h>
1331ab09b4SDipen Patel #include <linux/mutex.h>
1431ab09b4SDipen Patel #include <linux/uaccess.h>
1531ab09b4SDipen Patel #include <linux/hte.h>
1631ab09b4SDipen Patel #include <linux/delay.h>
1731ab09b4SDipen Patel #include <linux/debugfs.h>
1832bc7297SRob Herring #include <linux/device.h>
1931ab09b4SDipen Patel 
2031ab09b4SDipen Patel /* Global list of the HTE devices */
2131ab09b4SDipen Patel static DEFINE_SPINLOCK(hte_lock);
2231ab09b4SDipen Patel static LIST_HEAD(hte_devices);
2331ab09b4SDipen Patel 
2431ab09b4SDipen Patel enum {
2531ab09b4SDipen Patel 	HTE_TS_REGISTERED,
2631ab09b4SDipen Patel 	HTE_TS_REQ,
2731ab09b4SDipen Patel 	HTE_TS_DISABLE,
2831ab09b4SDipen Patel 	HTE_TS_QUEUE_WK,
2931ab09b4SDipen Patel };
3031ab09b4SDipen Patel 
3131ab09b4SDipen Patel /**
3231ab09b4SDipen Patel  * struct hte_ts_info - Information related to requested timestamp.
3331ab09b4SDipen Patel  *
3431ab09b4SDipen Patel  * @xlated_id: Timestamp ID as understood between HTE subsys and HTE provider,
3531ab09b4SDipen Patel  * See xlate callback API.
3631ab09b4SDipen Patel  * @flags: Flags holding state information.
3731ab09b4SDipen Patel  * @hte_cb_flags: Callback related flags.
3831ab09b4SDipen Patel  * @seq: Timestamp sequence counter.
3931ab09b4SDipen Patel  * @line_name: HTE allocated line name.
4031ab09b4SDipen Patel  * @free_attr_name: If set, free the attr name.
4131ab09b4SDipen Patel  * @cb: A nonsleeping callback function provided by clients.
4231ab09b4SDipen Patel  * @tcb: A secondary sleeping callback function provided by clients.
4331ab09b4SDipen Patel  * @dropped_ts: Dropped timestamps.
4431ab09b4SDipen Patel  * @slock: Spin lock to synchronize between disable/enable,
4531ab09b4SDipen Patel  * request/release APIs.
4631ab09b4SDipen Patel  * @cb_work: callback workqueue, used when tcb is specified.
4731ab09b4SDipen Patel  * @req_mlock: Lock during timestamp request/release APIs.
4831ab09b4SDipen Patel  * @ts_dbg_root: Root for the debug fs.
4931ab09b4SDipen Patel  * @gdev: HTE abstract device that this timestamp information belongs to.
5031ab09b4SDipen Patel  * @cl_data: Client specific data.
5131ab09b4SDipen Patel  */
5231ab09b4SDipen Patel struct hte_ts_info {
5331ab09b4SDipen Patel 	u32 xlated_id;
5431ab09b4SDipen Patel 	unsigned long flags;
5531ab09b4SDipen Patel 	unsigned long hte_cb_flags;
5631ab09b4SDipen Patel 	u64 seq;
5731ab09b4SDipen Patel 	char *line_name;
5831ab09b4SDipen Patel 	bool free_attr_name;
5931ab09b4SDipen Patel 	hte_ts_cb_t cb;
6031ab09b4SDipen Patel 	hte_ts_sec_cb_t tcb;
6131ab09b4SDipen Patel 	atomic_t dropped_ts;
6231ab09b4SDipen Patel 	spinlock_t slock;
6331ab09b4SDipen Patel 	struct work_struct cb_work;
6431ab09b4SDipen Patel 	struct mutex req_mlock;
6531ab09b4SDipen Patel 	struct dentry *ts_dbg_root;
6631ab09b4SDipen Patel 	struct hte_device *gdev;
6731ab09b4SDipen Patel 	void *cl_data;
6831ab09b4SDipen Patel };
6931ab09b4SDipen Patel 
7031ab09b4SDipen Patel /**
7131ab09b4SDipen Patel  * struct hte_device - HTE abstract device
7231ab09b4SDipen Patel  * @nlines: Number of entities this device supports.
7331ab09b4SDipen Patel  * @ts_req: Total number of entities requested.
7431ab09b4SDipen Patel  * @sdev: Device used at various debug prints.
7531ab09b4SDipen Patel  * @dbg_root: Root directory for debug fs.
7631ab09b4SDipen Patel  * @list: List node to store hte_device for each provider.
7731ab09b4SDipen Patel  * @chip: HTE chip providing this HTE device.
7831ab09b4SDipen Patel  * @owner: helps prevent removal of modules when in use.
7931ab09b4SDipen Patel  * @ei: Timestamp information.
8031ab09b4SDipen Patel  */
8131ab09b4SDipen Patel struct hte_device {
8231ab09b4SDipen Patel 	u32 nlines;
8331ab09b4SDipen Patel 	atomic_t ts_req;
8431ab09b4SDipen Patel 	struct device *sdev;
8531ab09b4SDipen Patel 	struct dentry *dbg_root;
8631ab09b4SDipen Patel 	struct list_head list;
8731ab09b4SDipen Patel 	struct hte_chip *chip;
8831ab09b4SDipen Patel 	struct module *owner;
89d4843668SKees Cook 	struct hte_ts_info ei[] __counted_by(nlines);
9031ab09b4SDipen Patel };
9131ab09b4SDipen Patel 
9231ab09b4SDipen Patel #ifdef CONFIG_DEBUG_FS
9331ab09b4SDipen Patel 
9431ab09b4SDipen Patel static struct dentry *hte_root;
9531ab09b4SDipen Patel 
hte_subsys_dbgfs_init(void)9631ab09b4SDipen Patel static int __init hte_subsys_dbgfs_init(void)
9731ab09b4SDipen Patel {
9831ab09b4SDipen Patel 	/* creates /sys/kernel/debug/hte/ */
9931ab09b4SDipen Patel 	hte_root = debugfs_create_dir("hte", NULL);
10031ab09b4SDipen Patel 
10131ab09b4SDipen Patel 	return 0;
10231ab09b4SDipen Patel }
10331ab09b4SDipen Patel subsys_initcall(hte_subsys_dbgfs_init);
10431ab09b4SDipen Patel 
hte_chip_dbgfs_init(struct hte_device * gdev)10531ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev)
10631ab09b4SDipen Patel {
10731ab09b4SDipen Patel 	const struct hte_chip *chip = gdev->chip;
10831ab09b4SDipen Patel 	const char *name = chip->name ? chip->name : dev_name(chip->dev);
10931ab09b4SDipen Patel 
11031ab09b4SDipen Patel 	gdev->dbg_root = debugfs_create_dir(name, hte_root);
11131ab09b4SDipen Patel 
11231ab09b4SDipen Patel 	debugfs_create_atomic_t("ts_requested", 0444, gdev->dbg_root,
11331ab09b4SDipen Patel 				&gdev->ts_req);
11431ab09b4SDipen Patel 	debugfs_create_u32("total_ts", 0444, gdev->dbg_root,
11531ab09b4SDipen Patel 			   &gdev->nlines);
11631ab09b4SDipen Patel }
11731ab09b4SDipen Patel 
hte_ts_dbgfs_init(const char * name,struct hte_ts_info * ei)11831ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
11931ab09b4SDipen Patel {
12031ab09b4SDipen Patel 	if (!ei->gdev->dbg_root || !name)
12131ab09b4SDipen Patel 		return;
12231ab09b4SDipen Patel 
12331ab09b4SDipen Patel 	ei->ts_dbg_root = debugfs_create_dir(name, ei->gdev->dbg_root);
12431ab09b4SDipen Patel 
12531ab09b4SDipen Patel 	debugfs_create_atomic_t("dropped_timestamps", 0444, ei->ts_dbg_root,
12631ab09b4SDipen Patel 				&ei->dropped_ts);
12731ab09b4SDipen Patel }
12831ab09b4SDipen Patel 
12931ab09b4SDipen Patel #else
13031ab09b4SDipen Patel 
hte_chip_dbgfs_init(struct hte_device * gdev)13131ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev)
13231ab09b4SDipen Patel {
13331ab09b4SDipen Patel }
13431ab09b4SDipen Patel 
hte_ts_dbgfs_init(const char * name,struct hte_ts_info * ei)13531ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
13631ab09b4SDipen Patel {
13731ab09b4SDipen Patel }
13831ab09b4SDipen Patel 
13931ab09b4SDipen Patel #endif
14031ab09b4SDipen Patel 
14131ab09b4SDipen Patel /**
14231ab09b4SDipen Patel  * hte_ts_put() - Release and disable timestamp for the given desc.
14331ab09b4SDipen Patel  *
14431ab09b4SDipen Patel  * @desc: timestamp descriptor.
14531ab09b4SDipen Patel  *
14631ab09b4SDipen Patel  * Context: debugfs_remove_recursive() function call may use sleeping locks,
14731ab09b4SDipen Patel  *	    not suitable from atomic context.
14831ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
14931ab09b4SDipen Patel  */
hte_ts_put(struct hte_ts_desc * desc)15031ab09b4SDipen Patel int hte_ts_put(struct hte_ts_desc *desc)
15131ab09b4SDipen Patel {
15231ab09b4SDipen Patel 	int ret = 0;
15331ab09b4SDipen Patel 	unsigned long flag;
15431ab09b4SDipen Patel 	struct hte_device *gdev;
15531ab09b4SDipen Patel 	struct hte_ts_info *ei;
15631ab09b4SDipen Patel 
15731ab09b4SDipen Patel 	if (!desc)
15831ab09b4SDipen Patel 		return -EINVAL;
15931ab09b4SDipen Patel 
16031ab09b4SDipen Patel 	ei = desc->hte_data;
16131ab09b4SDipen Patel 
16231ab09b4SDipen Patel 	if (!ei || !ei->gdev)
16331ab09b4SDipen Patel 		return -EINVAL;
16431ab09b4SDipen Patel 
16531ab09b4SDipen Patel 	gdev = ei->gdev;
16631ab09b4SDipen Patel 
16731ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
16831ab09b4SDipen Patel 
16931ab09b4SDipen Patel 	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
17031ab09b4SDipen Patel 	    !test_bit(HTE_TS_REGISTERED, &ei->flags))) {
17131ab09b4SDipen Patel 		dev_info(gdev->sdev, "id:%d is not requested\n",
17231ab09b4SDipen Patel 			 desc->attr.line_id);
17331ab09b4SDipen Patel 		ret = -EINVAL;
17431ab09b4SDipen Patel 		goto unlock;
17531ab09b4SDipen Patel 	}
17631ab09b4SDipen Patel 
17731ab09b4SDipen Patel 	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
17831ab09b4SDipen Patel 	    test_bit(HTE_TS_REGISTERED, &ei->flags))) {
17931ab09b4SDipen Patel 		dev_info(gdev->sdev, "id:%d is registered but not requested\n",
18031ab09b4SDipen Patel 			 desc->attr.line_id);
18131ab09b4SDipen Patel 		ret = -EINVAL;
18231ab09b4SDipen Patel 		goto unlock;
18331ab09b4SDipen Patel 	}
18431ab09b4SDipen Patel 
18531ab09b4SDipen Patel 	if (test_bit(HTE_TS_REQ, &ei->flags) &&
18631ab09b4SDipen Patel 	    !test_bit(HTE_TS_REGISTERED, &ei->flags)) {
18731ab09b4SDipen Patel 		clear_bit(HTE_TS_REQ, &ei->flags);
18831ab09b4SDipen Patel 		desc->hte_data = NULL;
18931ab09b4SDipen Patel 		ret = 0;
19031ab09b4SDipen Patel 		goto mod_put;
19131ab09b4SDipen Patel 	}
19231ab09b4SDipen Patel 
19331ab09b4SDipen Patel 	ret = gdev->chip->ops->release(gdev->chip, desc, ei->xlated_id);
19431ab09b4SDipen Patel 	if (ret) {
19531ab09b4SDipen Patel 		dev_err(gdev->sdev, "id: %d free failed\n",
19631ab09b4SDipen Patel 			desc->attr.line_id);
19731ab09b4SDipen Patel 		goto unlock;
19831ab09b4SDipen Patel 	}
19931ab09b4SDipen Patel 
20031ab09b4SDipen Patel 	kfree(ei->line_name);
20131ab09b4SDipen Patel 	if (ei->free_attr_name)
20231ab09b4SDipen Patel 		kfree_const(desc->attr.name);
20331ab09b4SDipen Patel 
20431ab09b4SDipen Patel 	debugfs_remove_recursive(ei->ts_dbg_root);
20531ab09b4SDipen Patel 
20631ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
20731ab09b4SDipen Patel 
20831ab09b4SDipen Patel 	if (test_bit(HTE_TS_QUEUE_WK, &ei->flags)) {
20931ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
21031ab09b4SDipen Patel 		flush_work(&ei->cb_work);
21131ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
21231ab09b4SDipen Patel 	}
21331ab09b4SDipen Patel 
21431ab09b4SDipen Patel 	atomic_dec(&gdev->ts_req);
21531ab09b4SDipen Patel 	atomic_set(&ei->dropped_ts, 0);
21631ab09b4SDipen Patel 
21731ab09b4SDipen Patel 	ei->seq = 1;
21831ab09b4SDipen Patel 	ei->flags = 0;
21931ab09b4SDipen Patel 	desc->hte_data = NULL;
22031ab09b4SDipen Patel 
22131ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
22231ab09b4SDipen Patel 
22331ab09b4SDipen Patel 	ei->cb = NULL;
22431ab09b4SDipen Patel 	ei->tcb = NULL;
22531ab09b4SDipen Patel 	ei->cl_data = NULL;
22631ab09b4SDipen Patel 
22731ab09b4SDipen Patel mod_put:
22831ab09b4SDipen Patel 	module_put(gdev->owner);
22931ab09b4SDipen Patel unlock:
23031ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
23131ab09b4SDipen Patel 	dev_dbg(gdev->sdev, "release id: %d\n", desc->attr.line_id);
23231ab09b4SDipen Patel 
23331ab09b4SDipen Patel 	return ret;
23431ab09b4SDipen Patel }
23531ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_put);
23631ab09b4SDipen Patel 
hte_ts_dis_en_common(struct hte_ts_desc * desc,bool en)23731ab09b4SDipen Patel static int hte_ts_dis_en_common(struct hte_ts_desc *desc, bool en)
23831ab09b4SDipen Patel {
23931ab09b4SDipen Patel 	u32 ts_id;
24031ab09b4SDipen Patel 	struct hte_device *gdev;
24131ab09b4SDipen Patel 	struct hte_ts_info *ei;
24231ab09b4SDipen Patel 	int ret;
24331ab09b4SDipen Patel 	unsigned long flag;
24431ab09b4SDipen Patel 
24531ab09b4SDipen Patel 	if (!desc)
24631ab09b4SDipen Patel 		return -EINVAL;
24731ab09b4SDipen Patel 
24831ab09b4SDipen Patel 	ei = desc->hte_data;
24931ab09b4SDipen Patel 
25031ab09b4SDipen Patel 	if (!ei || !ei->gdev)
25131ab09b4SDipen Patel 		return -EINVAL;
25231ab09b4SDipen Patel 
25331ab09b4SDipen Patel 	gdev = ei->gdev;
25431ab09b4SDipen Patel 	ts_id = desc->attr.line_id;
25531ab09b4SDipen Patel 
25631ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
25731ab09b4SDipen Patel 
25831ab09b4SDipen Patel 	if (!test_bit(HTE_TS_REGISTERED, &ei->flags)) {
25931ab09b4SDipen Patel 		dev_dbg(gdev->sdev, "id:%d is not registered", ts_id);
26031ab09b4SDipen Patel 		ret = -EUSERS;
26131ab09b4SDipen Patel 		goto out;
26231ab09b4SDipen Patel 	}
26331ab09b4SDipen Patel 
26431ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
26531ab09b4SDipen Patel 
26631ab09b4SDipen Patel 	if (en) {
26731ab09b4SDipen Patel 		if (!test_bit(HTE_TS_DISABLE, &ei->flags)) {
26831ab09b4SDipen Patel 			ret = 0;
26931ab09b4SDipen Patel 			goto out_unlock;
27031ab09b4SDipen Patel 		}
27131ab09b4SDipen Patel 
27231ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
27331ab09b4SDipen Patel 		ret = gdev->chip->ops->enable(gdev->chip, ei->xlated_id);
27431ab09b4SDipen Patel 		if (ret) {
27531ab09b4SDipen Patel 			dev_warn(gdev->sdev, "id: %d enable failed\n",
27631ab09b4SDipen Patel 				 ts_id);
27731ab09b4SDipen Patel 			goto out;
27831ab09b4SDipen Patel 		}
27931ab09b4SDipen Patel 
28031ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
28131ab09b4SDipen Patel 		clear_bit(HTE_TS_DISABLE, &ei->flags);
28231ab09b4SDipen Patel 	} else {
28331ab09b4SDipen Patel 		if (test_bit(HTE_TS_DISABLE, &ei->flags)) {
28431ab09b4SDipen Patel 			ret = 0;
28531ab09b4SDipen Patel 			goto out_unlock;
28631ab09b4SDipen Patel 		}
28731ab09b4SDipen Patel 
28831ab09b4SDipen Patel 		spin_unlock_irqrestore(&ei->slock, flag);
28931ab09b4SDipen Patel 		ret = gdev->chip->ops->disable(gdev->chip, ei->xlated_id);
29031ab09b4SDipen Patel 		if (ret) {
29131ab09b4SDipen Patel 			dev_warn(gdev->sdev, "id: %d disable failed\n",
29231ab09b4SDipen Patel 				 ts_id);
29331ab09b4SDipen Patel 			goto out;
29431ab09b4SDipen Patel 		}
29531ab09b4SDipen Patel 
29631ab09b4SDipen Patel 		spin_lock_irqsave(&ei->slock, flag);
29731ab09b4SDipen Patel 		set_bit(HTE_TS_DISABLE, &ei->flags);
29831ab09b4SDipen Patel 	}
29931ab09b4SDipen Patel 
30031ab09b4SDipen Patel out_unlock:
30131ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
30231ab09b4SDipen Patel out:
30331ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
30431ab09b4SDipen Patel 	return ret;
30531ab09b4SDipen Patel }
30631ab09b4SDipen Patel 
30731ab09b4SDipen Patel /**
30831ab09b4SDipen Patel  * hte_disable_ts() - Disable timestamp on given descriptor.
30931ab09b4SDipen Patel  *
31031ab09b4SDipen Patel  * The API does not release any resources associated with desc.
31131ab09b4SDipen Patel  *
31231ab09b4SDipen Patel  * @desc: ts descriptor, this is the same as returned by the request API.
31331ab09b4SDipen Patel  *
31431ab09b4SDipen Patel  * Context: Holds mutex lock, not suitable from atomic context.
31531ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
31631ab09b4SDipen Patel  */
hte_disable_ts(struct hte_ts_desc * desc)31731ab09b4SDipen Patel int hte_disable_ts(struct hte_ts_desc *desc)
31831ab09b4SDipen Patel {
31931ab09b4SDipen Patel 	return hte_ts_dis_en_common(desc, false);
32031ab09b4SDipen Patel }
32131ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_disable_ts);
32231ab09b4SDipen Patel 
32331ab09b4SDipen Patel /**
32431ab09b4SDipen Patel  * hte_enable_ts() - Enable timestamp on given descriptor.
32531ab09b4SDipen Patel  *
32631ab09b4SDipen Patel  * @desc: ts descriptor, this is the same as returned by the request API.
32731ab09b4SDipen Patel  *
32831ab09b4SDipen Patel  * Context: Holds mutex lock, not suitable from atomic context.
32931ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
33031ab09b4SDipen Patel  */
hte_enable_ts(struct hte_ts_desc * desc)33131ab09b4SDipen Patel int hte_enable_ts(struct hte_ts_desc *desc)
33231ab09b4SDipen Patel {
33331ab09b4SDipen Patel 	return hte_ts_dis_en_common(desc, true);
33431ab09b4SDipen Patel }
33531ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_enable_ts);
33631ab09b4SDipen Patel 
hte_do_cb_work(struct work_struct * w)33731ab09b4SDipen Patel static void hte_do_cb_work(struct work_struct *w)
33831ab09b4SDipen Patel {
33931ab09b4SDipen Patel 	unsigned long flag;
34031ab09b4SDipen Patel 	struct hte_ts_info *ei = container_of(w, struct hte_ts_info, cb_work);
34131ab09b4SDipen Patel 
34231ab09b4SDipen Patel 	if (unlikely(!ei->tcb))
34331ab09b4SDipen Patel 		return;
34431ab09b4SDipen Patel 
34531ab09b4SDipen Patel 	ei->tcb(ei->cl_data);
34631ab09b4SDipen Patel 
34731ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
34831ab09b4SDipen Patel 	clear_bit(HTE_TS_QUEUE_WK, &ei->flags);
34931ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
35031ab09b4SDipen Patel }
35131ab09b4SDipen Patel 
__hte_req_ts(struct hte_ts_desc * desc,hte_ts_cb_t cb,hte_ts_sec_cb_t tcb,void * data)35231ab09b4SDipen Patel static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb,
35331ab09b4SDipen Patel 			hte_ts_sec_cb_t tcb, void *data)
35431ab09b4SDipen Patel {
35531ab09b4SDipen Patel 	int ret;
35631ab09b4SDipen Patel 	struct hte_device *gdev;
35731ab09b4SDipen Patel 	struct hte_ts_info *ei = desc->hte_data;
35831ab09b4SDipen Patel 
35931ab09b4SDipen Patel 	gdev = ei->gdev;
36031ab09b4SDipen Patel 	/*
36131ab09b4SDipen Patel 	 * There is a chance that multiple consumers requesting same entity,
36231ab09b4SDipen Patel 	 * lock here.
36331ab09b4SDipen Patel 	 */
36431ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
36531ab09b4SDipen Patel 
36631ab09b4SDipen Patel 	if (test_bit(HTE_TS_REGISTERED, &ei->flags) ||
36731ab09b4SDipen Patel 	    !test_bit(HTE_TS_REQ, &ei->flags)) {
36831ab09b4SDipen Patel 		dev_dbg(gdev->chip->dev, "id:%u req failed\n",
36931ab09b4SDipen Patel 			desc->attr.line_id);
37031ab09b4SDipen Patel 		ret = -EUSERS;
37131ab09b4SDipen Patel 		goto unlock;
37231ab09b4SDipen Patel 	}
37331ab09b4SDipen Patel 
37431ab09b4SDipen Patel 	ei->cb = cb;
37531ab09b4SDipen Patel 	ei->tcb = tcb;
37631ab09b4SDipen Patel 	if (tcb)
37731ab09b4SDipen Patel 		INIT_WORK(&ei->cb_work, hte_do_cb_work);
37831ab09b4SDipen Patel 
37931ab09b4SDipen Patel 	ret = gdev->chip->ops->request(gdev->chip, desc, ei->xlated_id);
38031ab09b4SDipen Patel 	if (ret < 0) {
38131ab09b4SDipen Patel 		dev_err(gdev->chip->dev, "ts request failed\n");
38231ab09b4SDipen Patel 		goto unlock;
38331ab09b4SDipen Patel 	}
38431ab09b4SDipen Patel 
38531ab09b4SDipen Patel 	ei->cl_data = data;
38631ab09b4SDipen Patel 	ei->seq = 1;
38731ab09b4SDipen Patel 
38831ab09b4SDipen Patel 	atomic_inc(&gdev->ts_req);
38931ab09b4SDipen Patel 
390*fc62d5e2SAndy Shevchenko 	if (desc->attr.name)
39131ab09b4SDipen Patel 		ei->line_name = NULL;
392*fc62d5e2SAndy Shevchenko 	else
393*fc62d5e2SAndy Shevchenko 		ei->line_name = kasprintf(GFP_KERNEL, "ts_%u", desc->attr.line_id);
39431ab09b4SDipen Patel 
39531ab09b4SDipen Patel 	hte_ts_dbgfs_init(desc->attr.name == NULL ?
39631ab09b4SDipen Patel 			  ei->line_name : desc->attr.name, ei);
39731ab09b4SDipen Patel 	set_bit(HTE_TS_REGISTERED, &ei->flags);
39831ab09b4SDipen Patel 
39931ab09b4SDipen Patel 	dev_dbg(gdev->chip->dev, "id: %u, xlated id:%u",
40031ab09b4SDipen Patel 		desc->attr.line_id, ei->xlated_id);
40131ab09b4SDipen Patel 
40231ab09b4SDipen Patel 	ret = 0;
40331ab09b4SDipen Patel 
40431ab09b4SDipen Patel unlock:
40531ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
40631ab09b4SDipen Patel 
40731ab09b4SDipen Patel 	return ret;
40831ab09b4SDipen Patel }
40931ab09b4SDipen Patel 
hte_bind_ts_info_locked(struct hte_ts_info * ei,struct hte_ts_desc * desc,u32 x_id)41031ab09b4SDipen Patel static int hte_bind_ts_info_locked(struct hte_ts_info *ei,
41131ab09b4SDipen Patel 				   struct hte_ts_desc *desc, u32 x_id)
41231ab09b4SDipen Patel {
41331ab09b4SDipen Patel 	int ret = 0;
41431ab09b4SDipen Patel 
41531ab09b4SDipen Patel 	mutex_lock(&ei->req_mlock);
41631ab09b4SDipen Patel 
41731ab09b4SDipen Patel 	if (test_bit(HTE_TS_REQ, &ei->flags)) {
41831ab09b4SDipen Patel 		dev_dbg(ei->gdev->chip->dev, "id:%u is already requested\n",
41931ab09b4SDipen Patel 			desc->attr.line_id);
42031ab09b4SDipen Patel 		ret = -EUSERS;
42131ab09b4SDipen Patel 		goto out;
42231ab09b4SDipen Patel 	}
42331ab09b4SDipen Patel 
42431ab09b4SDipen Patel 	set_bit(HTE_TS_REQ, &ei->flags);
42531ab09b4SDipen Patel 	desc->hte_data = ei;
42631ab09b4SDipen Patel 	ei->xlated_id = x_id;
42731ab09b4SDipen Patel 
42831ab09b4SDipen Patel out:
42931ab09b4SDipen Patel 	mutex_unlock(&ei->req_mlock);
43031ab09b4SDipen Patel 
43131ab09b4SDipen Patel 	return ret;
43231ab09b4SDipen Patel }
43331ab09b4SDipen Patel 
of_node_to_htedevice(struct device_node * np)43431ab09b4SDipen Patel static struct hte_device *of_node_to_htedevice(struct device_node *np)
43531ab09b4SDipen Patel {
43631ab09b4SDipen Patel 	struct hte_device *gdev;
43731ab09b4SDipen Patel 
43831ab09b4SDipen Patel 	spin_lock(&hte_lock);
43931ab09b4SDipen Patel 
44031ab09b4SDipen Patel 	list_for_each_entry(gdev, &hte_devices, list)
44131ab09b4SDipen Patel 		if (gdev->chip && gdev->chip->dev &&
4429e0c2d40Sye xingchen 		    device_match_of_node(gdev->chip->dev, np)) {
44331ab09b4SDipen Patel 			spin_unlock(&hte_lock);
44431ab09b4SDipen Patel 			return gdev;
44531ab09b4SDipen Patel 		}
44631ab09b4SDipen Patel 
44731ab09b4SDipen Patel 	spin_unlock(&hte_lock);
44831ab09b4SDipen Patel 
44931ab09b4SDipen Patel 	return ERR_PTR(-ENODEV);
45031ab09b4SDipen Patel }
45131ab09b4SDipen Patel 
hte_find_dev_from_linedata(struct hte_ts_desc * desc)45231ab09b4SDipen Patel static struct hte_device *hte_find_dev_from_linedata(struct hte_ts_desc *desc)
45331ab09b4SDipen Patel {
45431ab09b4SDipen Patel 	struct hte_device *gdev;
45531ab09b4SDipen Patel 
45631ab09b4SDipen Patel 	spin_lock(&hte_lock);
45731ab09b4SDipen Patel 
45831ab09b4SDipen Patel 	list_for_each_entry(gdev, &hte_devices, list)
45931ab09b4SDipen Patel 		if (gdev->chip && gdev->chip->match_from_linedata) {
46031ab09b4SDipen Patel 			if (!gdev->chip->match_from_linedata(gdev->chip, desc))
46131ab09b4SDipen Patel 				continue;
46231ab09b4SDipen Patel 			spin_unlock(&hte_lock);
46331ab09b4SDipen Patel 			return gdev;
46431ab09b4SDipen Patel 		}
46531ab09b4SDipen Patel 
46631ab09b4SDipen Patel 	spin_unlock(&hte_lock);
46731ab09b4SDipen Patel 
46831ab09b4SDipen Patel 	return ERR_PTR(-ENODEV);
46931ab09b4SDipen Patel }
47031ab09b4SDipen Patel 
47131ab09b4SDipen Patel /**
47231ab09b4SDipen Patel  * of_hte_req_count - Return the number of entities to timestamp.
47331ab09b4SDipen Patel  *
47431ab09b4SDipen Patel  * The function returns the total count of the requested entities to timestamp
47531ab09b4SDipen Patel  * by parsing device tree.
47631ab09b4SDipen Patel  *
47731ab09b4SDipen Patel  * @dev: The HTE consumer.
47831ab09b4SDipen Patel  *
47931ab09b4SDipen Patel  * Returns: Positive number on success, -ENOENT if no entries,
48031ab09b4SDipen Patel  * -EINVAL for other errors.
48131ab09b4SDipen Patel  */
of_hte_req_count(struct device * dev)48231ab09b4SDipen Patel int of_hte_req_count(struct device *dev)
48331ab09b4SDipen Patel {
48431ab09b4SDipen Patel 	int count;
48531ab09b4SDipen Patel 
48631ab09b4SDipen Patel 	if (!dev || !dev->of_node)
48731ab09b4SDipen Patel 		return -EINVAL;
48831ab09b4SDipen Patel 
48931ab09b4SDipen Patel 	count = of_count_phandle_with_args(dev->of_node, "timestamps",
49031ab09b4SDipen Patel 					   "#timestamp-cells");
49131ab09b4SDipen Patel 
49231ab09b4SDipen Patel 	return count ? count : -ENOENT;
49331ab09b4SDipen Patel }
49431ab09b4SDipen Patel EXPORT_SYMBOL_GPL(of_hte_req_count);
49531ab09b4SDipen Patel 
hte_get_dev(struct hte_ts_desc * desc)49631ab09b4SDipen Patel static inline struct hte_device *hte_get_dev(struct hte_ts_desc *desc)
49731ab09b4SDipen Patel {
49831ab09b4SDipen Patel 	return hte_find_dev_from_linedata(desc);
49931ab09b4SDipen Patel }
50031ab09b4SDipen Patel 
hte_of_get_dev(struct device * dev,struct hte_ts_desc * desc,int index,struct of_phandle_args * args,bool * free_name)50131ab09b4SDipen Patel static struct hte_device *hte_of_get_dev(struct device *dev,
50231ab09b4SDipen Patel 					 struct hte_ts_desc *desc,
50331ab09b4SDipen Patel 					 int index,
50431ab09b4SDipen Patel 					 struct of_phandle_args *args,
50531ab09b4SDipen Patel 					 bool *free_name)
50631ab09b4SDipen Patel {
50731ab09b4SDipen Patel 	int ret;
50831ab09b4SDipen Patel 	struct device_node *np;
50931ab09b4SDipen Patel 	char *temp;
51031ab09b4SDipen Patel 
51131ab09b4SDipen Patel 	if (!dev->of_node)
51231ab09b4SDipen Patel 		return ERR_PTR(-EINVAL);
51331ab09b4SDipen Patel 
51431ab09b4SDipen Patel 	np = dev->of_node;
51531ab09b4SDipen Patel 
516902dea62SRob Herring 	if (!of_property_present(np, "timestamp-names")) {
51731ab09b4SDipen Patel 		/* Let hte core construct it during request time */
51831ab09b4SDipen Patel 		desc->attr.name = NULL;
51931ab09b4SDipen Patel 	} else {
52031ab09b4SDipen Patel 		ret = of_property_read_string_index(np, "timestamp-names",
52131ab09b4SDipen Patel 						    index, &desc->attr.name);
52231ab09b4SDipen Patel 		if (ret) {
52331ab09b4SDipen Patel 			pr_err("can't parse \"timestamp-names\" property\n");
52431ab09b4SDipen Patel 			return ERR_PTR(ret);
52531ab09b4SDipen Patel 		}
52631ab09b4SDipen Patel 		*free_name = false;
52731ab09b4SDipen Patel 		if (desc->attr.name) {
52831ab09b4SDipen Patel 			temp = skip_spaces(desc->attr.name);
52931ab09b4SDipen Patel 			if (!*temp)
53031ab09b4SDipen Patel 				desc->attr.name = NULL;
53131ab09b4SDipen Patel 		}
53231ab09b4SDipen Patel 	}
53331ab09b4SDipen Patel 
53431ab09b4SDipen Patel 	ret = of_parse_phandle_with_args(np, "timestamps", "#timestamp-cells",
53531ab09b4SDipen Patel 					 index, args);
53631ab09b4SDipen Patel 	if (ret) {
53731ab09b4SDipen Patel 		pr_err("%s(): can't parse \"timestamps\" property\n",
53831ab09b4SDipen Patel 		       __func__);
53931ab09b4SDipen Patel 		return ERR_PTR(ret);
54031ab09b4SDipen Patel 	}
54131ab09b4SDipen Patel 
54231ab09b4SDipen Patel 	of_node_put(args->np);
54331ab09b4SDipen Patel 
54431ab09b4SDipen Patel 	return of_node_to_htedevice(args->np);
54531ab09b4SDipen Patel }
54631ab09b4SDipen Patel 
54731ab09b4SDipen Patel /**
54831ab09b4SDipen Patel  * hte_ts_get() - The function to initialize and obtain HTE desc.
54931ab09b4SDipen Patel  *
55031ab09b4SDipen Patel  * The function initializes the consumer provided HTE descriptor. If consumer
55131ab09b4SDipen Patel  * has device tree node, index is used to parse the line id and other details.
55231ab09b4SDipen Patel  * The function needs to be called before using any request APIs.
55331ab09b4SDipen Patel  *
55431ab09b4SDipen Patel  * @dev: HTE consumer/client device, used in case of parsing device tree node.
55531ab09b4SDipen Patel  * @desc: Pre-allocated timestamp descriptor.
55631ab09b4SDipen Patel  * @index: The index will be used as an index to parse line_id from the
55731ab09b4SDipen Patel  * device tree node if node is present.
55831ab09b4SDipen Patel  *
55931ab09b4SDipen Patel  * Context: Holds mutex lock.
56031ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
56131ab09b4SDipen Patel  */
hte_ts_get(struct device * dev,struct hte_ts_desc * desc,int index)56231ab09b4SDipen Patel int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index)
56331ab09b4SDipen Patel {
56431ab09b4SDipen Patel 	struct hte_device *gdev;
56531ab09b4SDipen Patel 	struct hte_ts_info *ei;
56631ab09b4SDipen Patel 	const struct fwnode_handle *fwnode;
56731ab09b4SDipen Patel 	struct of_phandle_args args;
56831ab09b4SDipen Patel 	u32 xlated_id;
56931ab09b4SDipen Patel 	int ret;
570348b10b0SDan Carpenter 	bool free_name = false;
57131ab09b4SDipen Patel 
57231ab09b4SDipen Patel 	if (!desc)
57331ab09b4SDipen Patel 		return -EINVAL;
57431ab09b4SDipen Patel 
57531ab09b4SDipen Patel 	fwnode = dev ? dev_fwnode(dev) : NULL;
57631ab09b4SDipen Patel 
57731ab09b4SDipen Patel 	if (is_of_node(fwnode))
57831ab09b4SDipen Patel 		gdev = hte_of_get_dev(dev, desc, index, &args, &free_name);
57931ab09b4SDipen Patel 	else
58031ab09b4SDipen Patel 		gdev = hte_get_dev(desc);
58131ab09b4SDipen Patel 
58231ab09b4SDipen Patel 	if (IS_ERR(gdev)) {
58331ab09b4SDipen Patel 		pr_err("%s() no hte dev found\n", __func__);
58431ab09b4SDipen Patel 		return PTR_ERR(gdev);
58531ab09b4SDipen Patel 	}
58631ab09b4SDipen Patel 
58731ab09b4SDipen Patel 	if (!try_module_get(gdev->owner))
58831ab09b4SDipen Patel 		return -ENODEV;
58931ab09b4SDipen Patel 
59031ab09b4SDipen Patel 	if (!gdev->chip) {
59131ab09b4SDipen Patel 		pr_err("%s(): requested id does not have provider\n",
59231ab09b4SDipen Patel 		       __func__);
59331ab09b4SDipen Patel 		ret = -ENODEV;
59431ab09b4SDipen Patel 		goto put;
59531ab09b4SDipen Patel 	}
59631ab09b4SDipen Patel 
59731ab09b4SDipen Patel 	if (is_of_node(fwnode)) {
59831ab09b4SDipen Patel 		if (!gdev->chip->xlate_of)
59931ab09b4SDipen Patel 			ret = -EINVAL;
60031ab09b4SDipen Patel 		else
60131ab09b4SDipen Patel 			ret = gdev->chip->xlate_of(gdev->chip, &args,
60231ab09b4SDipen Patel 						   desc, &xlated_id);
60331ab09b4SDipen Patel 	} else {
60431ab09b4SDipen Patel 		if (!gdev->chip->xlate_plat)
60531ab09b4SDipen Patel 			ret = -EINVAL;
60631ab09b4SDipen Patel 		else
60731ab09b4SDipen Patel 			ret = gdev->chip->xlate_plat(gdev->chip, desc,
60831ab09b4SDipen Patel 						     &xlated_id);
60931ab09b4SDipen Patel 	}
61031ab09b4SDipen Patel 
61131ab09b4SDipen Patel 	if (ret < 0)
61231ab09b4SDipen Patel 		goto put;
61331ab09b4SDipen Patel 
61431ab09b4SDipen Patel 	ei = &gdev->ei[xlated_id];
61531ab09b4SDipen Patel 
61631ab09b4SDipen Patel 	ret = hte_bind_ts_info_locked(ei, desc, xlated_id);
61731ab09b4SDipen Patel 	if (ret)
61831ab09b4SDipen Patel 		goto put;
61931ab09b4SDipen Patel 
62031ab09b4SDipen Patel 	ei->free_attr_name = free_name;
62131ab09b4SDipen Patel 
62231ab09b4SDipen Patel 	return 0;
62331ab09b4SDipen Patel 
62431ab09b4SDipen Patel put:
62531ab09b4SDipen Patel 	module_put(gdev->owner);
62631ab09b4SDipen Patel 	return ret;
62731ab09b4SDipen Patel }
62831ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_get);
62931ab09b4SDipen Patel 
__devm_hte_release_ts(void * res)63031ab09b4SDipen Patel static void __devm_hte_release_ts(void *res)
63131ab09b4SDipen Patel {
63231ab09b4SDipen Patel 	hte_ts_put(res);
63331ab09b4SDipen Patel }
63431ab09b4SDipen Patel 
63531ab09b4SDipen Patel /**
63631ab09b4SDipen Patel  * hte_request_ts_ns() - The API to request and enable hardware timestamp in
63731ab09b4SDipen Patel  * nanoseconds.
63831ab09b4SDipen Patel  *
63931ab09b4SDipen Patel  * The entity is provider specific for example, GPIO lines, signals, buses
64031ab09b4SDipen Patel  * etc...The API allocates necessary resources and enables the timestamp.
64131ab09b4SDipen Patel  *
64231ab09b4SDipen Patel  * @desc: Pre-allocated and initialized timestamp descriptor.
64331ab09b4SDipen Patel  * @cb: Callback to push the timestamp data to consumer.
64431ab09b4SDipen Patel  * @tcb: Optional callback. If its provided, subsystem initializes
64531ab09b4SDipen Patel  * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
64631ab09b4SDipen Patel  * @data: Client data, used during cb and tcb callbacks.
64731ab09b4SDipen Patel  *
64831ab09b4SDipen Patel  * Context: Holds mutex lock.
64931ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
65031ab09b4SDipen Patel  */
hte_request_ts_ns(struct hte_ts_desc * desc,hte_ts_cb_t cb,hte_ts_sec_cb_t tcb,void * data)65131ab09b4SDipen Patel int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb,
65231ab09b4SDipen Patel 		      hte_ts_sec_cb_t tcb, void *data)
65331ab09b4SDipen Patel {
65431ab09b4SDipen Patel 	int ret;
65531ab09b4SDipen Patel 	struct hte_ts_info *ei;
65631ab09b4SDipen Patel 
65731ab09b4SDipen Patel 	if (!desc || !desc->hte_data || !cb)
65831ab09b4SDipen Patel 		return -EINVAL;
65931ab09b4SDipen Patel 
66031ab09b4SDipen Patel 	ei = desc->hte_data;
66131ab09b4SDipen Patel 	if (!ei || !ei->gdev)
66231ab09b4SDipen Patel 		return -EINVAL;
66331ab09b4SDipen Patel 
66431ab09b4SDipen Patel 	ret = __hte_req_ts(desc, cb, tcb, data);
66531ab09b4SDipen Patel 	if (ret < 0) {
66631ab09b4SDipen Patel 		dev_err(ei->gdev->chip->dev,
66731ab09b4SDipen Patel 			"failed to request id: %d\n", desc->attr.line_id);
66831ab09b4SDipen Patel 		return ret;
66931ab09b4SDipen Patel 	}
67031ab09b4SDipen Patel 
67131ab09b4SDipen Patel 	return 0;
67231ab09b4SDipen Patel }
67331ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_request_ts_ns);
67431ab09b4SDipen Patel 
67531ab09b4SDipen Patel /**
67631ab09b4SDipen Patel  * devm_hte_request_ts_ns() - Resource managed API to request and enable
67731ab09b4SDipen Patel  * hardware timestamp in nanoseconds.
67831ab09b4SDipen Patel  *
67931ab09b4SDipen Patel  * The entity is provider specific for example, GPIO lines, signals, buses
68031ab09b4SDipen Patel  * etc...The API allocates necessary resources and enables the timestamp. It
68131ab09b4SDipen Patel  * deallocates and disables automatically when the consumer exits.
68231ab09b4SDipen Patel  *
68331ab09b4SDipen Patel  * @dev: HTE consumer/client device.
68431ab09b4SDipen Patel  * @desc: Pre-allocated and initialized timestamp descriptor.
68531ab09b4SDipen Patel  * @cb: Callback to push the timestamp data to consumer.
68631ab09b4SDipen Patel  * @tcb: Optional callback. If its provided, subsystem initializes
68731ab09b4SDipen Patel  * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
68831ab09b4SDipen Patel  * @data: Client data, used during cb and tcb callbacks.
68931ab09b4SDipen Patel  *
69031ab09b4SDipen Patel  * Context: Holds mutex lock.
69131ab09b4SDipen Patel  * Returns: Returns 0 on success or negative error code on failure.
69231ab09b4SDipen Patel  */
devm_hte_request_ts_ns(struct device * dev,struct hte_ts_desc * desc,hte_ts_cb_t cb,hte_ts_sec_cb_t tcb,void * data)69331ab09b4SDipen Patel int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc,
69431ab09b4SDipen Patel 			   hte_ts_cb_t cb, hte_ts_sec_cb_t tcb,
69531ab09b4SDipen Patel 			   void *data)
69631ab09b4SDipen Patel {
69731ab09b4SDipen Patel 	int err;
69831ab09b4SDipen Patel 
69931ab09b4SDipen Patel 	if (!dev)
70031ab09b4SDipen Patel 		return -EINVAL;
70131ab09b4SDipen Patel 
70231ab09b4SDipen Patel 	err = hte_request_ts_ns(desc, cb, tcb, data);
70331ab09b4SDipen Patel 	if (err)
70431ab09b4SDipen Patel 		return err;
70531ab09b4SDipen Patel 
70631ab09b4SDipen Patel 	err = devm_add_action_or_reset(dev, __devm_hte_release_ts, desc);
70731ab09b4SDipen Patel 	if (err)
70831ab09b4SDipen Patel 		return err;
70931ab09b4SDipen Patel 
71031ab09b4SDipen Patel 	return 0;
71131ab09b4SDipen Patel }
71231ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_request_ts_ns);
71331ab09b4SDipen Patel 
71431ab09b4SDipen Patel /**
71531ab09b4SDipen Patel  * hte_init_line_attr() - Initialize line attributes.
71631ab09b4SDipen Patel  *
71731ab09b4SDipen Patel  * Zeroes out line attributes and initializes with provided arguments.
71831ab09b4SDipen Patel  * The function needs to be called before calling any consumer facing
71931ab09b4SDipen Patel  * functions.
72031ab09b4SDipen Patel  *
72131ab09b4SDipen Patel  * @desc: Pre-allocated timestamp descriptor.
72231ab09b4SDipen Patel  * @line_id: line id.
72331ab09b4SDipen Patel  * @edge_flags: edge flags related to line_id.
72431ab09b4SDipen Patel  * @name: name of the line.
72531ab09b4SDipen Patel  * @data: line data related to line_id.
72631ab09b4SDipen Patel  *
72731ab09b4SDipen Patel  * Context: Any.
72831ab09b4SDipen Patel  * Returns: 0 on success or negative error code for the failure.
72931ab09b4SDipen Patel  */
hte_init_line_attr(struct hte_ts_desc * desc,u32 line_id,unsigned long edge_flags,const char * name,void * data)73031ab09b4SDipen Patel int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id,
73131ab09b4SDipen Patel 		       unsigned long edge_flags, const char *name, void *data)
73231ab09b4SDipen Patel {
73331ab09b4SDipen Patel 	if (!desc)
73431ab09b4SDipen Patel 		return -EINVAL;
73531ab09b4SDipen Patel 
73631ab09b4SDipen Patel 	memset(&desc->attr, 0, sizeof(desc->attr));
73731ab09b4SDipen Patel 
73831ab09b4SDipen Patel 	desc->attr.edge_flags = edge_flags;
73931ab09b4SDipen Patel 	desc->attr.line_id = line_id;
74031ab09b4SDipen Patel 	desc->attr.line_data = data;
74131ab09b4SDipen Patel 	if (name) {
74231ab09b4SDipen Patel 		name =  kstrdup_const(name, GFP_KERNEL);
74331ab09b4SDipen Patel 		if (!name)
74431ab09b4SDipen Patel 			return -ENOMEM;
74531ab09b4SDipen Patel 	}
74631ab09b4SDipen Patel 
74731ab09b4SDipen Patel 	desc->attr.name = name;
74831ab09b4SDipen Patel 
74931ab09b4SDipen Patel 	return 0;
75031ab09b4SDipen Patel }
75131ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_init_line_attr);
75231ab09b4SDipen Patel 
75331ab09b4SDipen Patel /**
75431ab09b4SDipen Patel  * hte_get_clk_src_info() - Get the clock source information for a ts
75531ab09b4SDipen Patel  * descriptor.
75631ab09b4SDipen Patel  *
75731ab09b4SDipen Patel  * @desc: ts descriptor, same as returned from request API.
75831ab09b4SDipen Patel  * @ci: The API fills this structure with the clock information data.
75931ab09b4SDipen Patel  *
76031ab09b4SDipen Patel  * Context: Any context.
76131ab09b4SDipen Patel  * Returns: 0 on success else negative error code on failure.
76231ab09b4SDipen Patel  */
hte_get_clk_src_info(const struct hte_ts_desc * desc,struct hte_clk_info * ci)76331ab09b4SDipen Patel int hte_get_clk_src_info(const struct hte_ts_desc *desc,
76431ab09b4SDipen Patel 			 struct hte_clk_info *ci)
76531ab09b4SDipen Patel {
76631ab09b4SDipen Patel 	struct hte_chip *chip;
76731ab09b4SDipen Patel 	struct hte_ts_info *ei;
76831ab09b4SDipen Patel 
76931ab09b4SDipen Patel 	if (!desc || !desc->hte_data || !ci) {
77031ab09b4SDipen Patel 		pr_debug("%s:%d\n", __func__, __LINE__);
77131ab09b4SDipen Patel 		return -EINVAL;
77231ab09b4SDipen Patel 	}
77331ab09b4SDipen Patel 
77431ab09b4SDipen Patel 	ei = desc->hte_data;
77531ab09b4SDipen Patel 	if (!ei->gdev || !ei->gdev->chip)
77631ab09b4SDipen Patel 		return -EINVAL;
77731ab09b4SDipen Patel 
77831ab09b4SDipen Patel 	chip = ei->gdev->chip;
77931ab09b4SDipen Patel 	if (!chip->ops->get_clk_src_info)
78031ab09b4SDipen Patel 		return -EOPNOTSUPP;
78131ab09b4SDipen Patel 
78231ab09b4SDipen Patel 	return chip->ops->get_clk_src_info(chip, ci);
78331ab09b4SDipen Patel }
78431ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_get_clk_src_info);
78531ab09b4SDipen Patel 
78631ab09b4SDipen Patel /**
78731ab09b4SDipen Patel  * hte_push_ts_ns() - Push timestamp data in nanoseconds.
78831ab09b4SDipen Patel  *
78931ab09b4SDipen Patel  * It is used by the provider to push timestamp data.
79031ab09b4SDipen Patel  *
79131ab09b4SDipen Patel  * @chip: The HTE chip, used during the registration.
79231ab09b4SDipen Patel  * @xlated_id: entity id understood by both subsystem and provider, this is
79331ab09b4SDipen Patel  * obtained from xlate callback during request API.
79431ab09b4SDipen Patel  * @data: timestamp data.
79531ab09b4SDipen Patel  *
79631ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
79731ab09b4SDipen Patel  */
hte_push_ts_ns(const struct hte_chip * chip,u32 xlated_id,struct hte_ts_data * data)79831ab09b4SDipen Patel int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id,
79931ab09b4SDipen Patel 		   struct hte_ts_data *data)
80031ab09b4SDipen Patel {
80131ab09b4SDipen Patel 	enum hte_return ret;
80231ab09b4SDipen Patel 	int st = 0;
80331ab09b4SDipen Patel 	struct hte_ts_info *ei;
80431ab09b4SDipen Patel 	unsigned long flag;
80531ab09b4SDipen Patel 
80631ab09b4SDipen Patel 	if (!chip || !data || !chip->gdev)
80731ab09b4SDipen Patel 		return -EINVAL;
80831ab09b4SDipen Patel 
809e30b64a3SDan Carpenter 	if (xlated_id >= chip->nlines)
81031ab09b4SDipen Patel 		return -EINVAL;
81131ab09b4SDipen Patel 
81231ab09b4SDipen Patel 	ei = &chip->gdev->ei[xlated_id];
81331ab09b4SDipen Patel 
81431ab09b4SDipen Patel 	spin_lock_irqsave(&ei->slock, flag);
81531ab09b4SDipen Patel 
81631ab09b4SDipen Patel 	/* timestamp sequence counter */
81731ab09b4SDipen Patel 	data->seq = ei->seq++;
81831ab09b4SDipen Patel 
81931ab09b4SDipen Patel 	if (!test_bit(HTE_TS_REGISTERED, &ei->flags) ||
82031ab09b4SDipen Patel 	    test_bit(HTE_TS_DISABLE, &ei->flags)) {
82131ab09b4SDipen Patel 		dev_dbg(chip->dev, "Unknown timestamp push\n");
82231ab09b4SDipen Patel 		atomic_inc(&ei->dropped_ts);
82331ab09b4SDipen Patel 		st = -EINVAL;
82431ab09b4SDipen Patel 		goto unlock;
82531ab09b4SDipen Patel 	}
82631ab09b4SDipen Patel 
82731ab09b4SDipen Patel 	ret = ei->cb(data, ei->cl_data);
82831ab09b4SDipen Patel 	if (ret == HTE_RUN_SECOND_CB && ei->tcb) {
82931ab09b4SDipen Patel 		queue_work(system_unbound_wq, &ei->cb_work);
83031ab09b4SDipen Patel 		set_bit(HTE_TS_QUEUE_WK, &ei->flags);
83131ab09b4SDipen Patel 	}
83231ab09b4SDipen Patel 
83331ab09b4SDipen Patel unlock:
83431ab09b4SDipen Patel 	spin_unlock_irqrestore(&ei->slock, flag);
83531ab09b4SDipen Patel 
83631ab09b4SDipen Patel 	return st;
83731ab09b4SDipen Patel }
83831ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_push_ts_ns);
83931ab09b4SDipen Patel 
hte_register_chip(struct hte_chip * chip)84031ab09b4SDipen Patel static int hte_register_chip(struct hte_chip *chip)
84131ab09b4SDipen Patel {
84231ab09b4SDipen Patel 	struct hte_device *gdev;
84331ab09b4SDipen Patel 	u32 i;
84431ab09b4SDipen Patel 
84531ab09b4SDipen Patel 	if (!chip || !chip->dev || !chip->dev->of_node)
84631ab09b4SDipen Patel 		return -EINVAL;
84731ab09b4SDipen Patel 
84831ab09b4SDipen Patel 	if (!chip->ops || !chip->ops->request || !chip->ops->release) {
84931ab09b4SDipen Patel 		dev_err(chip->dev, "Driver needs to provide ops\n");
85031ab09b4SDipen Patel 		return -EINVAL;
85131ab09b4SDipen Patel 	}
85231ab09b4SDipen Patel 
85331ab09b4SDipen Patel 	gdev = kzalloc(struct_size(gdev, ei, chip->nlines), GFP_KERNEL);
85431ab09b4SDipen Patel 	if (!gdev)
85531ab09b4SDipen Patel 		return -ENOMEM;
85631ab09b4SDipen Patel 
85731ab09b4SDipen Patel 	gdev->chip = chip;
85831ab09b4SDipen Patel 	chip->gdev = gdev;
85931ab09b4SDipen Patel 	gdev->nlines = chip->nlines;
86031ab09b4SDipen Patel 	gdev->sdev = chip->dev;
86131ab09b4SDipen Patel 
86231ab09b4SDipen Patel 	for (i = 0; i < chip->nlines; i++) {
86331ab09b4SDipen Patel 		gdev->ei[i].gdev = gdev;
86431ab09b4SDipen Patel 		mutex_init(&gdev->ei[i].req_mlock);
86531ab09b4SDipen Patel 		spin_lock_init(&gdev->ei[i].slock);
86631ab09b4SDipen Patel 	}
86731ab09b4SDipen Patel 
86831ab09b4SDipen Patel 	if (chip->dev->driver)
86931ab09b4SDipen Patel 		gdev->owner = chip->dev->driver->owner;
87031ab09b4SDipen Patel 	else
87131ab09b4SDipen Patel 		gdev->owner = THIS_MODULE;
87231ab09b4SDipen Patel 
87331ab09b4SDipen Patel 	of_node_get(chip->dev->of_node);
87431ab09b4SDipen Patel 
87531ab09b4SDipen Patel 	INIT_LIST_HEAD(&gdev->list);
87631ab09b4SDipen Patel 
87731ab09b4SDipen Patel 	spin_lock(&hte_lock);
87831ab09b4SDipen Patel 	list_add_tail(&gdev->list, &hte_devices);
87931ab09b4SDipen Patel 	spin_unlock(&hte_lock);
88031ab09b4SDipen Patel 
88131ab09b4SDipen Patel 	hte_chip_dbgfs_init(gdev);
88231ab09b4SDipen Patel 
88331ab09b4SDipen Patel 	dev_dbg(chip->dev, "Added hte chip\n");
88431ab09b4SDipen Patel 
88531ab09b4SDipen Patel 	return 0;
88631ab09b4SDipen Patel }
88731ab09b4SDipen Patel 
hte_unregister_chip(struct hte_chip * chip)88831ab09b4SDipen Patel static int hte_unregister_chip(struct hte_chip *chip)
88931ab09b4SDipen Patel {
89031ab09b4SDipen Patel 	struct hte_device *gdev;
89131ab09b4SDipen Patel 
89231ab09b4SDipen Patel 	if (!chip)
89331ab09b4SDipen Patel 		return -EINVAL;
89431ab09b4SDipen Patel 
89531ab09b4SDipen Patel 	gdev = chip->gdev;
89631ab09b4SDipen Patel 
89731ab09b4SDipen Patel 	spin_lock(&hte_lock);
89831ab09b4SDipen Patel 	list_del(&gdev->list);
89931ab09b4SDipen Patel 	spin_unlock(&hte_lock);
90031ab09b4SDipen Patel 
90131ab09b4SDipen Patel 	gdev->chip = NULL;
90231ab09b4SDipen Patel 
90331ab09b4SDipen Patel 	of_node_put(chip->dev->of_node);
90431ab09b4SDipen Patel 	debugfs_remove_recursive(gdev->dbg_root);
90531ab09b4SDipen Patel 	kfree(gdev);
90631ab09b4SDipen Patel 
90731ab09b4SDipen Patel 	dev_dbg(chip->dev, "Removed hte chip\n");
90831ab09b4SDipen Patel 
90931ab09b4SDipen Patel 	return 0;
91031ab09b4SDipen Patel }
91131ab09b4SDipen Patel 
_hte_devm_unregister_chip(void * chip)91231ab09b4SDipen Patel static void _hte_devm_unregister_chip(void *chip)
91331ab09b4SDipen Patel {
91431ab09b4SDipen Patel 	hte_unregister_chip(chip);
91531ab09b4SDipen Patel }
91631ab09b4SDipen Patel 
91731ab09b4SDipen Patel /**
91831ab09b4SDipen Patel  * devm_hte_register_chip() - Resource managed API to register HTE chip.
91931ab09b4SDipen Patel  *
92031ab09b4SDipen Patel  * It is used by the provider to register itself with the HTE subsystem.
92131ab09b4SDipen Patel  * The unregistration is done automatically when the provider exits.
92231ab09b4SDipen Patel  *
92331ab09b4SDipen Patel  * @chip: the HTE chip to add to subsystem.
92431ab09b4SDipen Patel  *
92531ab09b4SDipen Patel  * Returns: 0 on success or a negative error code on failure.
92631ab09b4SDipen Patel  */
devm_hte_register_chip(struct hte_chip * chip)92731ab09b4SDipen Patel int devm_hte_register_chip(struct hte_chip *chip)
92831ab09b4SDipen Patel {
92931ab09b4SDipen Patel 	int err;
93031ab09b4SDipen Patel 
93131ab09b4SDipen Patel 	err = hte_register_chip(chip);
93231ab09b4SDipen Patel 	if (err)
93331ab09b4SDipen Patel 		return err;
93431ab09b4SDipen Patel 
93531ab09b4SDipen Patel 	err = devm_add_action_or_reset(chip->dev, _hte_devm_unregister_chip,
93631ab09b4SDipen Patel 				       chip);
93731ab09b4SDipen Patel 	if (err)
93831ab09b4SDipen Patel 		return err;
93931ab09b4SDipen Patel 
94031ab09b4SDipen Patel 	return 0;
94131ab09b4SDipen Patel }
94231ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_register_chip);
943