xref: /openbmc/linux/drivers/slimbus/core.c (revision 0ef9d78b)
13648e78eSSagar Dharia // SPDX-License-Identifier: GPL-2.0
23648e78eSSagar Dharia /*
33648e78eSSagar Dharia  * Copyright (c) 2011-2017, The Linux Foundation
43648e78eSSagar Dharia  */
53648e78eSSagar Dharia 
63648e78eSSagar Dharia #include <linux/kernel.h>
73648e78eSSagar Dharia #include <linux/errno.h>
83648e78eSSagar Dharia #include <linux/slab.h>
93648e78eSSagar Dharia #include <linux/init.h>
1046a2bb5aSSagar Dharia #include <linux/idr.h>
117588a511SSrinivas Kandagatla #include <linux/of.h>
129e663f48SSrinivas Kandagatla #include <linux/of_device.h>
134b14e62aSSagar Dharia #include <linux/pm_runtime.h>
143648e78eSSagar Dharia #include <linux/slimbus.h>
1546a2bb5aSSagar Dharia #include "slimbus.h"
1646a2bb5aSSagar Dharia 
1746a2bb5aSSagar Dharia static DEFINE_IDA(ctrl_ida);
183648e78eSSagar Dharia 
slim_match(const struct slim_device_id * id,const struct slim_device * sbdev)193648e78eSSagar Dharia static const struct slim_device_id *slim_match(const struct slim_device_id *id,
203648e78eSSagar Dharia 					       const struct slim_device *sbdev)
213648e78eSSagar Dharia {
223648e78eSSagar Dharia 	while (id->manf_id != 0 || id->prod_code != 0) {
233648e78eSSagar Dharia 		if (id->manf_id == sbdev->e_addr.manf_id &&
248631f940SSrinivas Kandagatla 		    id->prod_code == sbdev->e_addr.prod_code &&
258631f940SSrinivas Kandagatla 		    id->dev_index == sbdev->e_addr.dev_index &&
268631f940SSrinivas Kandagatla 		    id->instance == sbdev->e_addr.instance)
273648e78eSSagar Dharia 			return id;
283648e78eSSagar Dharia 		id++;
293648e78eSSagar Dharia 	}
303648e78eSSagar Dharia 	return NULL;
313648e78eSSagar Dharia }
323648e78eSSagar Dharia 
slim_device_match(struct device * dev,struct device_driver * drv)333648e78eSSagar Dharia static int slim_device_match(struct device *dev, struct device_driver *drv)
343648e78eSSagar Dharia {
353648e78eSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
363648e78eSSagar Dharia 	struct slim_driver *sbdrv = to_slim_driver(drv);
373648e78eSSagar Dharia 
3814a649d3SSrinivas Kandagatla 	/* Attempt an OF style match first */
3914a649d3SSrinivas Kandagatla 	if (of_driver_match_device(dev, drv))
4014a649d3SSrinivas Kandagatla 		return 1;
4114a649d3SSrinivas Kandagatla 
423648e78eSSagar Dharia 	return !!slim_match(sbdrv->id_table, sbdev);
433648e78eSSagar Dharia }
443648e78eSSagar Dharia 
slim_device_update_status(struct slim_device * sbdev,enum slim_device_status status)45380c6246SSrinivas Kandagatla static void slim_device_update_status(struct slim_device *sbdev,
46380c6246SSrinivas Kandagatla 				      enum slim_device_status status)
47380c6246SSrinivas Kandagatla {
48380c6246SSrinivas Kandagatla 	struct slim_driver *sbdrv;
49380c6246SSrinivas Kandagatla 
50380c6246SSrinivas Kandagatla 	if (sbdev->status == status)
51380c6246SSrinivas Kandagatla 		return;
52380c6246SSrinivas Kandagatla 
53380c6246SSrinivas Kandagatla 	sbdev->status = status;
54380c6246SSrinivas Kandagatla 	if (!sbdev->dev.driver)
55380c6246SSrinivas Kandagatla 		return;
56380c6246SSrinivas Kandagatla 
57380c6246SSrinivas Kandagatla 	sbdrv = to_slim_driver(sbdev->dev.driver);
58380c6246SSrinivas Kandagatla 	if (sbdrv->device_status)
59380c6246SSrinivas Kandagatla 		sbdrv->device_status(sbdev, sbdev->status);
60380c6246SSrinivas Kandagatla }
61380c6246SSrinivas Kandagatla 
slim_device_probe(struct device * dev)623648e78eSSagar Dharia static int slim_device_probe(struct device *dev)
633648e78eSSagar Dharia {
643648e78eSSagar Dharia 	struct slim_device	*sbdev = to_slim_device(dev);
653648e78eSSagar Dharia 	struct slim_driver	*sbdrv = to_slim_driver(dev->driver);
668f3d5fcdSSrinivas Kandagatla 	int ret;
673648e78eSSagar Dharia 
688f3d5fcdSSrinivas Kandagatla 	ret = sbdrv->probe(sbdev);
698f3d5fcdSSrinivas Kandagatla 	if (ret)
708f3d5fcdSSrinivas Kandagatla 		return ret;
718f3d5fcdSSrinivas Kandagatla 
728f3d5fcdSSrinivas Kandagatla 	/* try getting the logical address after probe */
738f3d5fcdSSrinivas Kandagatla 	ret = slim_get_logical_addr(sbdev);
748f3d5fcdSSrinivas Kandagatla 	if (!ret) {
75380c6246SSrinivas Kandagatla 		slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
768f3d5fcdSSrinivas Kandagatla 	} else {
778f3d5fcdSSrinivas Kandagatla 		dev_err(&sbdev->dev, "Failed to get logical address\n");
788f3d5fcdSSrinivas Kandagatla 		ret = -EPROBE_DEFER;
798f3d5fcdSSrinivas Kandagatla 	}
808f3d5fcdSSrinivas Kandagatla 
818f3d5fcdSSrinivas Kandagatla 	return ret;
823648e78eSSagar Dharia }
833648e78eSSagar Dharia 
slim_device_remove(struct device * dev)84fc7a6209SUwe Kleine-König static void slim_device_remove(struct device *dev)
853648e78eSSagar Dharia {
863648e78eSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
873648e78eSSagar Dharia 	struct slim_driver *sbdrv;
883648e78eSSagar Dharia 
893648e78eSSagar Dharia 	if (dev->driver) {
903648e78eSSagar Dharia 		sbdrv = to_slim_driver(dev->driver);
913648e78eSSagar Dharia 		if (sbdrv->remove)
923648e78eSSagar Dharia 			sbdrv->remove(sbdev);
933648e78eSSagar Dharia 	}
943648e78eSSagar Dharia }
953648e78eSSagar Dharia 
slim_device_uevent(const struct device * dev,struct kobj_uevent_env * env)962a81ada3SGreg Kroah-Hartman static int slim_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
979e663f48SSrinivas Kandagatla {
982a81ada3SGreg Kroah-Hartman 	const struct slim_device *sbdev = to_slim_device(dev);
999e663f48SSrinivas Kandagatla 
1009e663f48SSrinivas Kandagatla 	return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
1019e663f48SSrinivas Kandagatla }
1029e663f48SSrinivas Kandagatla 
1033648e78eSSagar Dharia struct bus_type slimbus_bus = {
1043648e78eSSagar Dharia 	.name		= "slimbus",
1053648e78eSSagar Dharia 	.match		= slim_device_match,
1063648e78eSSagar Dharia 	.probe		= slim_device_probe,
1073648e78eSSagar Dharia 	.remove		= slim_device_remove,
1089e663f48SSrinivas Kandagatla 	.uevent		= slim_device_uevent,
1093648e78eSSagar Dharia };
1103648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slimbus_bus);
1113648e78eSSagar Dharia 
1123648e78eSSagar Dharia /*
1133648e78eSSagar Dharia  * __slim_driver_register() - Client driver registration with SLIMbus
1143648e78eSSagar Dharia  *
1153648e78eSSagar Dharia  * @drv:Client driver to be associated with client-device.
1163648e78eSSagar Dharia  * @owner: owning module/driver
1173648e78eSSagar Dharia  *
1183648e78eSSagar Dharia  * This API will register the client driver with the SLIMbus
1193648e78eSSagar Dharia  * It is called from the driver's module-init function.
1203648e78eSSagar Dharia  */
__slim_driver_register(struct slim_driver * drv,struct module * owner)1213648e78eSSagar Dharia int __slim_driver_register(struct slim_driver *drv, struct module *owner)
1223648e78eSSagar Dharia {
1233648e78eSSagar Dharia 	/* ID table and probe are mandatory */
12414a649d3SSrinivas Kandagatla 	if (!(drv->driver.of_match_table || drv->id_table) || !drv->probe)
1253648e78eSSagar Dharia 		return -EINVAL;
1263648e78eSSagar Dharia 
1273648e78eSSagar Dharia 	drv->driver.bus = &slimbus_bus;
1283648e78eSSagar Dharia 	drv->driver.owner = owner;
1293648e78eSSagar Dharia 
1303648e78eSSagar Dharia 	return driver_register(&drv->driver);
1313648e78eSSagar Dharia }
1323648e78eSSagar Dharia EXPORT_SYMBOL_GPL(__slim_driver_register);
1333648e78eSSagar Dharia 
1343648e78eSSagar Dharia /*
1353648e78eSSagar Dharia  * slim_driver_unregister() - Undo effect of slim_driver_register
1363648e78eSSagar Dharia  *
1373648e78eSSagar Dharia  * @drv: Client driver to be unregistered
1383648e78eSSagar Dharia  */
slim_driver_unregister(struct slim_driver * drv)1393648e78eSSagar Dharia void slim_driver_unregister(struct slim_driver *drv)
1403648e78eSSagar Dharia {
1413648e78eSSagar Dharia 	driver_unregister(&drv->driver);
1423648e78eSSagar Dharia }
1433648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slim_driver_unregister);
1443648e78eSSagar Dharia 
slim_dev_release(struct device * dev)14546a2bb5aSSagar Dharia static void slim_dev_release(struct device *dev)
14646a2bb5aSSagar Dharia {
14746a2bb5aSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
14846a2bb5aSSagar Dharia 
14946a2bb5aSSagar Dharia 	kfree(sbdev);
15046a2bb5aSSagar Dharia }
15146a2bb5aSSagar Dharia 
slim_add_device(struct slim_controller * ctrl,struct slim_device * sbdev,struct device_node * node)15246a2bb5aSSagar Dharia static int slim_add_device(struct slim_controller *ctrl,
15346a2bb5aSSagar Dharia 			   struct slim_device *sbdev,
15446a2bb5aSSagar Dharia 			   struct device_node *node)
15546a2bb5aSSagar Dharia {
15646a2bb5aSSagar Dharia 	sbdev->dev.bus = &slimbus_bus;
15746a2bb5aSSagar Dharia 	sbdev->dev.parent = ctrl->dev;
15846a2bb5aSSagar Dharia 	sbdev->dev.release = slim_dev_release;
15946a2bb5aSSagar Dharia 	sbdev->dev.driver = NULL;
16046a2bb5aSSagar Dharia 	sbdev->ctrl = ctrl;
161abb9c9b8SSrinivas Kandagatla 	INIT_LIST_HEAD(&sbdev->stream_list);
162abb9c9b8SSrinivas Kandagatla 	spin_lock_init(&sbdev->stream_list_lock);
1637588a511SSrinivas Kandagatla 	sbdev->dev.of_node = of_node_get(node);
164dbf4d133SSaravana Kannan 	sbdev->dev.fwnode = of_fwnode_handle(node);
1657588a511SSrinivas Kandagatla 
16646a2bb5aSSagar Dharia 	dev_set_name(&sbdev->dev, "%x:%x:%x:%x",
16746a2bb5aSSagar Dharia 				  sbdev->e_addr.manf_id,
16846a2bb5aSSagar Dharia 				  sbdev->e_addr.prod_code,
16946a2bb5aSSagar Dharia 				  sbdev->e_addr.dev_index,
17046a2bb5aSSagar Dharia 				  sbdev->e_addr.instance);
17146a2bb5aSSagar Dharia 
17246a2bb5aSSagar Dharia 	return device_register(&sbdev->dev);
17346a2bb5aSSagar Dharia }
17446a2bb5aSSagar Dharia 
slim_alloc_device(struct slim_controller * ctrl,struct slim_eaddr * eaddr,struct device_node * node)17546a2bb5aSSagar Dharia static struct slim_device *slim_alloc_device(struct slim_controller *ctrl,
17646a2bb5aSSagar Dharia 					     struct slim_eaddr *eaddr,
17746a2bb5aSSagar Dharia 					     struct device_node *node)
17846a2bb5aSSagar Dharia {
17946a2bb5aSSagar Dharia 	struct slim_device *sbdev;
18046a2bb5aSSagar Dharia 	int ret;
18146a2bb5aSSagar Dharia 
18246a2bb5aSSagar Dharia 	sbdev = kzalloc(sizeof(*sbdev), GFP_KERNEL);
18346a2bb5aSSagar Dharia 	if (!sbdev)
18446a2bb5aSSagar Dharia 		return NULL;
18546a2bb5aSSagar Dharia 
18646a2bb5aSSagar Dharia 	sbdev->e_addr = *eaddr;
18746a2bb5aSSagar Dharia 	ret = slim_add_device(ctrl, sbdev, node);
18846a2bb5aSSagar Dharia 	if (ret) {
189bd329f02SArvind Yadav 		put_device(&sbdev->dev);
19046a2bb5aSSagar Dharia 		return NULL;
19146a2bb5aSSagar Dharia 	}
19246a2bb5aSSagar Dharia 
19346a2bb5aSSagar Dharia 	return sbdev;
19446a2bb5aSSagar Dharia }
19546a2bb5aSSagar Dharia 
of_register_slim_devices(struct slim_controller * ctrl)1967588a511SSrinivas Kandagatla static void of_register_slim_devices(struct slim_controller *ctrl)
1977588a511SSrinivas Kandagatla {
1987588a511SSrinivas Kandagatla 	struct device *dev = ctrl->dev;
1997588a511SSrinivas Kandagatla 	struct device_node *node;
2007588a511SSrinivas Kandagatla 
2017588a511SSrinivas Kandagatla 	if (!ctrl->dev->of_node)
2027588a511SSrinivas Kandagatla 		return;
2037588a511SSrinivas Kandagatla 
2047588a511SSrinivas Kandagatla 	for_each_child_of_node(ctrl->dev->of_node, node) {
2057588a511SSrinivas Kandagatla 		struct slim_device *sbdev;
2067588a511SSrinivas Kandagatla 		struct slim_eaddr e_addr;
2077588a511SSrinivas Kandagatla 		const char *compat = NULL;
2087588a511SSrinivas Kandagatla 		int reg[2], ret;
2097588a511SSrinivas Kandagatla 		int manf_id, prod_code;
2107588a511SSrinivas Kandagatla 
2117588a511SSrinivas Kandagatla 		compat = of_get_property(node, "compatible", NULL);
2127588a511SSrinivas Kandagatla 		if (!compat)
2137588a511SSrinivas Kandagatla 			continue;
2147588a511SSrinivas Kandagatla 
2157588a511SSrinivas Kandagatla 		ret = sscanf(compat, "slim%x,%x", &manf_id, &prod_code);
2167588a511SSrinivas Kandagatla 		if (ret != 2) {
2177588a511SSrinivas Kandagatla 			dev_err(dev, "Manf ID & Product code not found %s\n",
2187588a511SSrinivas Kandagatla 				compat);
2197588a511SSrinivas Kandagatla 			continue;
2207588a511SSrinivas Kandagatla 		}
2217588a511SSrinivas Kandagatla 
2227588a511SSrinivas Kandagatla 		ret = of_property_read_u32_array(node, "reg", reg, 2);
2237588a511SSrinivas Kandagatla 		if (ret) {
2247588a511SSrinivas Kandagatla 			dev_err(dev, "Device and Instance id not found:%d\n",
2257588a511SSrinivas Kandagatla 				ret);
2267588a511SSrinivas Kandagatla 			continue;
2277588a511SSrinivas Kandagatla 		}
2287588a511SSrinivas Kandagatla 
2297588a511SSrinivas Kandagatla 		e_addr.dev_index = reg[0];
2307588a511SSrinivas Kandagatla 		e_addr.instance = reg[1];
2317588a511SSrinivas Kandagatla 		e_addr.manf_id = manf_id;
2327588a511SSrinivas Kandagatla 		e_addr.prod_code = prod_code;
2337588a511SSrinivas Kandagatla 
2347588a511SSrinivas Kandagatla 		sbdev = slim_alloc_device(ctrl, &e_addr, node);
2357588a511SSrinivas Kandagatla 		if (!sbdev)
2367588a511SSrinivas Kandagatla 			continue;
2377588a511SSrinivas Kandagatla 	}
2387588a511SSrinivas Kandagatla }
2397588a511SSrinivas Kandagatla 
24046a2bb5aSSagar Dharia /*
24146a2bb5aSSagar Dharia  * slim_register_controller() - Controller bring-up and registration.
24246a2bb5aSSagar Dharia  *
24346a2bb5aSSagar Dharia  * @ctrl: Controller to be registered.
24446a2bb5aSSagar Dharia  *
24546a2bb5aSSagar Dharia  * A controller is registered with the framework using this API.
24646a2bb5aSSagar Dharia  * If devices on a controller were registered before controller,
24746a2bb5aSSagar Dharia  * this will make sure that they get probed when controller is up
24846a2bb5aSSagar Dharia  */
slim_register_controller(struct slim_controller * ctrl)24946a2bb5aSSagar Dharia int slim_register_controller(struct slim_controller *ctrl)
25046a2bb5aSSagar Dharia {
25146a2bb5aSSagar Dharia 	int id;
25246a2bb5aSSagar Dharia 
253ad804659Skeliu 	id = ida_alloc(&ctrl_ida, GFP_KERNEL);
25446a2bb5aSSagar Dharia 	if (id < 0)
25546a2bb5aSSagar Dharia 		return id;
25646a2bb5aSSagar Dharia 
25746a2bb5aSSagar Dharia 	ctrl->id = id;
25846a2bb5aSSagar Dharia 
25946a2bb5aSSagar Dharia 	if (!ctrl->min_cg)
26046a2bb5aSSagar Dharia 		ctrl->min_cg = SLIM_MIN_CLK_GEAR;
26146a2bb5aSSagar Dharia 	if (!ctrl->max_cg)
26246a2bb5aSSagar Dharia 		ctrl->max_cg = SLIM_MAX_CLK_GEAR;
26346a2bb5aSSagar Dharia 
26446a2bb5aSSagar Dharia 	ida_init(&ctrl->laddr_ida);
26546a2bb5aSSagar Dharia 	idr_init(&ctrl->tid_idr);
26646a2bb5aSSagar Dharia 	mutex_init(&ctrl->lock);
2674b14e62aSSagar Dharia 	mutex_init(&ctrl->sched.m_reconf);
2684b14e62aSSagar Dharia 	init_completion(&ctrl->sched.pause_comp);
2698147760dSSrinivas Kandagatla 	spin_lock_init(&ctrl->txn_lock);
27046a2bb5aSSagar Dharia 
27146a2bb5aSSagar Dharia 	dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n",
27246a2bb5aSSagar Dharia 		ctrl->name, ctrl->dev);
27346a2bb5aSSagar Dharia 
2747588a511SSrinivas Kandagatla 	of_register_slim_devices(ctrl);
2757588a511SSrinivas Kandagatla 
27646a2bb5aSSagar Dharia 	return 0;
27746a2bb5aSSagar Dharia }
27846a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_register_controller);
27946a2bb5aSSagar Dharia 
28046a2bb5aSSagar Dharia /* slim_remove_device: Remove the effect of slim_add_device() */
slim_remove_device(struct slim_device * sbdev)28146a2bb5aSSagar Dharia static void slim_remove_device(struct slim_device *sbdev)
28246a2bb5aSSagar Dharia {
28301360857SSaravana Kannan 	of_node_put(sbdev->dev.of_node);
28446a2bb5aSSagar Dharia 	device_unregister(&sbdev->dev);
28546a2bb5aSSagar Dharia }
28646a2bb5aSSagar Dharia 
slim_ctrl_remove_device(struct device * dev,void * null)28746a2bb5aSSagar Dharia static int slim_ctrl_remove_device(struct device *dev, void *null)
28846a2bb5aSSagar Dharia {
28946a2bb5aSSagar Dharia 	slim_remove_device(to_slim_device(dev));
29046a2bb5aSSagar Dharia 	return 0;
29146a2bb5aSSagar Dharia }
29246a2bb5aSSagar Dharia 
29346a2bb5aSSagar Dharia /**
29446a2bb5aSSagar Dharia  * slim_unregister_controller() - Controller tear-down.
29546a2bb5aSSagar Dharia  *
29646a2bb5aSSagar Dharia  * @ctrl: Controller to tear-down.
29746a2bb5aSSagar Dharia  */
slim_unregister_controller(struct slim_controller * ctrl)29846a2bb5aSSagar Dharia int slim_unregister_controller(struct slim_controller *ctrl)
29946a2bb5aSSagar Dharia {
30046a2bb5aSSagar Dharia 	/* Remove all clients */
30146a2bb5aSSagar Dharia 	device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device);
302ad804659Skeliu 	ida_free(&ctrl_ida, ctrl->id);
30346a2bb5aSSagar Dharia 
30446a2bb5aSSagar Dharia 	return 0;
30546a2bb5aSSagar Dharia }
30646a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_unregister_controller);
30746a2bb5aSSagar Dharia 
30846a2bb5aSSagar Dharia /**
30946a2bb5aSSagar Dharia  * slim_report_absent() - Controller calls this function when a device
31046a2bb5aSSagar Dharia  *	reports absent, OR when the device cannot be communicated with
31146a2bb5aSSagar Dharia  *
31246a2bb5aSSagar Dharia  * @sbdev: Device that cannot be reached, or sent report absent
31346a2bb5aSSagar Dharia  */
slim_report_absent(struct slim_device * sbdev)31446a2bb5aSSagar Dharia void slim_report_absent(struct slim_device *sbdev)
31546a2bb5aSSagar Dharia {
31646a2bb5aSSagar Dharia 	struct slim_controller *ctrl = sbdev->ctrl;
31746a2bb5aSSagar Dharia 
31846a2bb5aSSagar Dharia 	if (!ctrl)
31946a2bb5aSSagar Dharia 		return;
32046a2bb5aSSagar Dharia 
32146a2bb5aSSagar Dharia 	/* invalidate logical addresses */
32246a2bb5aSSagar Dharia 	mutex_lock(&ctrl->lock);
32346a2bb5aSSagar Dharia 	sbdev->is_laddr_valid = false;
32446a2bb5aSSagar Dharia 	mutex_unlock(&ctrl->lock);
325f97769fdSSrinivas Kandagatla 	if (!ctrl->get_laddr)
326ad804659Skeliu 		ida_free(&ctrl->laddr_ida, sbdev->laddr);
32746a2bb5aSSagar Dharia 	slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_DOWN);
32846a2bb5aSSagar Dharia }
32946a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_report_absent);
33046a2bb5aSSagar Dharia 
slim_eaddr_equal(struct slim_eaddr * a,struct slim_eaddr * b)33146a2bb5aSSagar Dharia static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b)
33246a2bb5aSSagar Dharia {
33346a2bb5aSSagar Dharia 	return (a->manf_id == b->manf_id &&
33446a2bb5aSSagar Dharia 		a->prod_code == b->prod_code &&
33546a2bb5aSSagar Dharia 		a->dev_index == b->dev_index &&
33646a2bb5aSSagar Dharia 		a->instance == b->instance);
33746a2bb5aSSagar Dharia }
33846a2bb5aSSagar Dharia 
slim_match_dev(struct device * dev,void * data)33946a2bb5aSSagar Dharia static int slim_match_dev(struct device *dev, void *data)
34046a2bb5aSSagar Dharia {
34146a2bb5aSSagar Dharia 	struct slim_eaddr *e_addr = data;
34246a2bb5aSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
34346a2bb5aSSagar Dharia 
34446a2bb5aSSagar Dharia 	return slim_eaddr_equal(&sbdev->e_addr, e_addr);
34546a2bb5aSSagar Dharia }
34646a2bb5aSSagar Dharia 
find_slim_device(struct slim_controller * ctrl,struct slim_eaddr * eaddr)34746a2bb5aSSagar Dharia static struct slim_device *find_slim_device(struct slim_controller *ctrl,
34846a2bb5aSSagar Dharia 					    struct slim_eaddr *eaddr)
34946a2bb5aSSagar Dharia {
35046a2bb5aSSagar Dharia 	struct slim_device *sbdev;
35146a2bb5aSSagar Dharia 	struct device *dev;
35246a2bb5aSSagar Dharia 
35346a2bb5aSSagar Dharia 	dev = device_find_child(ctrl->dev, eaddr, slim_match_dev);
35446a2bb5aSSagar Dharia 	if (dev) {
35546a2bb5aSSagar Dharia 		sbdev = to_slim_device(dev);
35646a2bb5aSSagar Dharia 		return sbdev;
35746a2bb5aSSagar Dharia 	}
35846a2bb5aSSagar Dharia 
35946a2bb5aSSagar Dharia 	return NULL;
36046a2bb5aSSagar Dharia }
36146a2bb5aSSagar Dharia 
36246a2bb5aSSagar Dharia /**
36346a2bb5aSSagar Dharia  * slim_get_device() - get handle to a device.
36446a2bb5aSSagar Dharia  *
36546a2bb5aSSagar Dharia  * @ctrl: Controller on which this device will be added/queried
36646a2bb5aSSagar Dharia  * @e_addr: Enumeration address of the device to be queried
36746a2bb5aSSagar Dharia  *
36846a2bb5aSSagar Dharia  * Return: pointer to a device if it has already reported. Creates a new
36946a2bb5aSSagar Dharia  * device and returns pointer to it if the device has not yet enumerated.
37046a2bb5aSSagar Dharia  */
slim_get_device(struct slim_controller * ctrl,struct slim_eaddr * e_addr)37146a2bb5aSSagar Dharia struct slim_device *slim_get_device(struct slim_controller *ctrl,
37246a2bb5aSSagar Dharia 				    struct slim_eaddr *e_addr)
37346a2bb5aSSagar Dharia {
37446a2bb5aSSagar Dharia 	struct slim_device *sbdev;
37546a2bb5aSSagar Dharia 
37646a2bb5aSSagar Dharia 	sbdev = find_slim_device(ctrl, e_addr);
37746a2bb5aSSagar Dharia 	if (!sbdev) {
37846a2bb5aSSagar Dharia 		sbdev = slim_alloc_device(ctrl, e_addr, NULL);
37946a2bb5aSSagar Dharia 		if (!sbdev)
38046a2bb5aSSagar Dharia 			return ERR_PTR(-ENOMEM);
38146a2bb5aSSagar Dharia 	}
38246a2bb5aSSagar Dharia 
38346a2bb5aSSagar Dharia 	return sbdev;
38446a2bb5aSSagar Dharia }
38546a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_device);
38646a2bb5aSSagar Dharia 
of_slim_match_dev(struct device * dev,void * data)387e0772de8SSrinivas Kandagatla static int of_slim_match_dev(struct device *dev, void *data)
388e0772de8SSrinivas Kandagatla {
389e0772de8SSrinivas Kandagatla 	struct device_node *np = data;
390e0772de8SSrinivas Kandagatla 	struct slim_device *sbdev = to_slim_device(dev);
391e0772de8SSrinivas Kandagatla 
392e0772de8SSrinivas Kandagatla 	return (sbdev->dev.of_node == np);
393e0772de8SSrinivas Kandagatla }
394e0772de8SSrinivas Kandagatla 
of_find_slim_device(struct slim_controller * ctrl,struct device_node * np)395e0772de8SSrinivas Kandagatla static struct slim_device *of_find_slim_device(struct slim_controller *ctrl,
396e0772de8SSrinivas Kandagatla 					       struct device_node *np)
397e0772de8SSrinivas Kandagatla {
398e0772de8SSrinivas Kandagatla 	struct slim_device *sbdev;
399e0772de8SSrinivas Kandagatla 	struct device *dev;
400e0772de8SSrinivas Kandagatla 
401e0772de8SSrinivas Kandagatla 	dev = device_find_child(ctrl->dev, np, of_slim_match_dev);
402e0772de8SSrinivas Kandagatla 	if (dev) {
403e0772de8SSrinivas Kandagatla 		sbdev = to_slim_device(dev);
404e0772de8SSrinivas Kandagatla 		return sbdev;
405e0772de8SSrinivas Kandagatla 	}
406e0772de8SSrinivas Kandagatla 
407e0772de8SSrinivas Kandagatla 	return NULL;
408e0772de8SSrinivas Kandagatla }
409e0772de8SSrinivas Kandagatla 
410e0772de8SSrinivas Kandagatla /**
411e0772de8SSrinivas Kandagatla  * of_slim_get_device() - get handle to a device using dt node.
412e0772de8SSrinivas Kandagatla  *
413e0772de8SSrinivas Kandagatla  * @ctrl: Controller on which this device will be added/queried
414e0772de8SSrinivas Kandagatla  * @np: node pointer to device
415e0772de8SSrinivas Kandagatla  *
416e0772de8SSrinivas Kandagatla  * Return: pointer to a device if it has already reported. Creates a new
417e0772de8SSrinivas Kandagatla  * device and returns pointer to it if the device has not yet enumerated.
418e0772de8SSrinivas Kandagatla  */
of_slim_get_device(struct slim_controller * ctrl,struct device_node * np)419e0772de8SSrinivas Kandagatla struct slim_device *of_slim_get_device(struct slim_controller *ctrl,
420e0772de8SSrinivas Kandagatla 				       struct device_node *np)
421e0772de8SSrinivas Kandagatla {
422e0772de8SSrinivas Kandagatla 	return of_find_slim_device(ctrl, np);
423e0772de8SSrinivas Kandagatla }
424e0772de8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_slim_get_device);
425e0772de8SSrinivas Kandagatla 
slim_device_alloc_laddr(struct slim_device * sbdev,bool report_present)42646a2bb5aSSagar Dharia static int slim_device_alloc_laddr(struct slim_device *sbdev,
42746a2bb5aSSagar Dharia 				   bool report_present)
42846a2bb5aSSagar Dharia {
42946a2bb5aSSagar Dharia 	struct slim_controller *ctrl = sbdev->ctrl;
43046a2bb5aSSagar Dharia 	u8 laddr;
43146a2bb5aSSagar Dharia 	int ret;
43246a2bb5aSSagar Dharia 
43346a2bb5aSSagar Dharia 	mutex_lock(&ctrl->lock);
43446a2bb5aSSagar Dharia 	if (ctrl->get_laddr) {
43546a2bb5aSSagar Dharia 		ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr);
43646a2bb5aSSagar Dharia 		if (ret < 0)
43746a2bb5aSSagar Dharia 			goto err;
43846a2bb5aSSagar Dharia 	} else if (report_present) {
4390ef9d78bSChristophe JAILLET 		ret = ida_alloc_max(&ctrl->laddr_ida,
4400ef9d78bSChristophe JAILLET 				    SLIM_LA_MANAGER - 1, GFP_KERNEL);
44146a2bb5aSSagar Dharia 		if (ret < 0)
44246a2bb5aSSagar Dharia 			goto err;
44346a2bb5aSSagar Dharia 
44446a2bb5aSSagar Dharia 		laddr = ret;
44546a2bb5aSSagar Dharia 	} else {
44646a2bb5aSSagar Dharia 		ret = -EINVAL;
44746a2bb5aSSagar Dharia 		goto err;
44846a2bb5aSSagar Dharia 	}
44946a2bb5aSSagar Dharia 
45046a2bb5aSSagar Dharia 	if (ctrl->set_laddr) {
45146a2bb5aSSagar Dharia 		ret = ctrl->set_laddr(ctrl, &sbdev->e_addr, laddr);
45246a2bb5aSSagar Dharia 		if (ret) {
45346a2bb5aSSagar Dharia 			ret = -EINVAL;
45446a2bb5aSSagar Dharia 			goto err;
45546a2bb5aSSagar Dharia 		}
45646a2bb5aSSagar Dharia 	}
45746a2bb5aSSagar Dharia 
45846a2bb5aSSagar Dharia 	sbdev->laddr = laddr;
45946a2bb5aSSagar Dharia 	sbdev->is_laddr_valid = true;
460cfb32101SSrinivas Kandagatla 	mutex_unlock(&ctrl->lock);
46146a2bb5aSSagar Dharia 
46246a2bb5aSSagar Dharia 	slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
46346a2bb5aSSagar Dharia 
46446a2bb5aSSagar Dharia 	dev_dbg(ctrl->dev, "setting slimbus l-addr:%x, ea:%x,%x,%x,%x\n",
46546a2bb5aSSagar Dharia 		laddr, sbdev->e_addr.manf_id, sbdev->e_addr.prod_code,
46646a2bb5aSSagar Dharia 		sbdev->e_addr.dev_index, sbdev->e_addr.instance);
46746a2bb5aSSagar Dharia 
468cfb32101SSrinivas Kandagatla 	return 0;
469cfb32101SSrinivas Kandagatla 
47046a2bb5aSSagar Dharia err:
47146a2bb5aSSagar Dharia 	mutex_unlock(&ctrl->lock);
47246a2bb5aSSagar Dharia 	return ret;
47346a2bb5aSSagar Dharia 
47446a2bb5aSSagar Dharia }
47546a2bb5aSSagar Dharia 
47646a2bb5aSSagar Dharia /**
47746a2bb5aSSagar Dharia  * slim_device_report_present() - Report enumerated device.
47846a2bb5aSSagar Dharia  *
47946a2bb5aSSagar Dharia  * @ctrl: Controller with which device is enumerated.
48046a2bb5aSSagar Dharia  * @e_addr: Enumeration address of the device.
48146a2bb5aSSagar Dharia  * @laddr: Return logical address (if valid flag is false)
48246a2bb5aSSagar Dharia  *
48346a2bb5aSSagar Dharia  * Called by controller in response to REPORT_PRESENT. Framework will assign
48446a2bb5aSSagar Dharia  * a logical address to this enumeration address.
48546a2bb5aSSagar Dharia  * Function returns -EXFULL to indicate that all logical addresses are already
48646a2bb5aSSagar Dharia  * taken.
48746a2bb5aSSagar Dharia  */
slim_device_report_present(struct slim_controller * ctrl,struct slim_eaddr * e_addr,u8 * laddr)48846a2bb5aSSagar Dharia int slim_device_report_present(struct slim_controller *ctrl,
48946a2bb5aSSagar Dharia 			       struct slim_eaddr *e_addr, u8 *laddr)
49046a2bb5aSSagar Dharia {
49146a2bb5aSSagar Dharia 	struct slim_device *sbdev;
49246a2bb5aSSagar Dharia 	int ret;
49346a2bb5aSSagar Dharia 
4944b14e62aSSagar Dharia 	ret = pm_runtime_get_sync(ctrl->dev);
4954b14e62aSSagar Dharia 
4964b14e62aSSagar Dharia 	if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
4974b14e62aSSagar Dharia 		dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n",
4984b14e62aSSagar Dharia 				    ctrl->sched.clk_state, ret);
4994b14e62aSSagar Dharia 		goto slimbus_not_active;
5004b14e62aSSagar Dharia 	}
5014b14e62aSSagar Dharia 
50246a2bb5aSSagar Dharia 	sbdev = slim_get_device(ctrl, e_addr);
50346a2bb5aSSagar Dharia 	if (IS_ERR(sbdev))
50446a2bb5aSSagar Dharia 		return -ENODEV;
50546a2bb5aSSagar Dharia 
50646a2bb5aSSagar Dharia 	if (sbdev->is_laddr_valid) {
50746a2bb5aSSagar Dharia 		*laddr = sbdev->laddr;
50846a2bb5aSSagar Dharia 		return 0;
50946a2bb5aSSagar Dharia 	}
51046a2bb5aSSagar Dharia 
51146a2bb5aSSagar Dharia 	ret = slim_device_alloc_laddr(sbdev, true);
51246a2bb5aSSagar Dharia 
5134b14e62aSSagar Dharia slimbus_not_active:
5144b14e62aSSagar Dharia 	pm_runtime_mark_last_busy(ctrl->dev);
5154b14e62aSSagar Dharia 	pm_runtime_put_autosuspend(ctrl->dev);
51646a2bb5aSSagar Dharia 	return ret;
51746a2bb5aSSagar Dharia }
51846a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_device_report_present);
51946a2bb5aSSagar Dharia 
52046a2bb5aSSagar Dharia /**
52146a2bb5aSSagar Dharia  * slim_get_logical_addr() - get/allocate logical address of a SLIMbus device.
52246a2bb5aSSagar Dharia  *
52346a2bb5aSSagar Dharia  * @sbdev: client handle requesting the address.
52446a2bb5aSSagar Dharia  *
52546a2bb5aSSagar Dharia  * Return: zero if a logical address is valid or a new logical address
52646a2bb5aSSagar Dharia  * has been assigned. error code in case of error.
52746a2bb5aSSagar Dharia  */
slim_get_logical_addr(struct slim_device * sbdev)52846a2bb5aSSagar Dharia int slim_get_logical_addr(struct slim_device *sbdev)
52946a2bb5aSSagar Dharia {
53046a2bb5aSSagar Dharia 	if (!sbdev->is_laddr_valid)
53146a2bb5aSSagar Dharia 		return slim_device_alloc_laddr(sbdev, false);
53246a2bb5aSSagar Dharia 
53346a2bb5aSSagar Dharia 	return 0;
53446a2bb5aSSagar Dharia }
53546a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_logical_addr);
53646a2bb5aSSagar Dharia 
slimbus_exit(void)5373648e78eSSagar Dharia static void __exit slimbus_exit(void)
5383648e78eSSagar Dharia {
5393648e78eSSagar Dharia 	bus_unregister(&slimbus_bus);
5403648e78eSSagar Dharia }
5413648e78eSSagar Dharia module_exit(slimbus_exit);
5423648e78eSSagar Dharia 
slimbus_init(void)5433648e78eSSagar Dharia static int __init slimbus_init(void)
5443648e78eSSagar Dharia {
5453648e78eSSagar Dharia 	return bus_register(&slimbus_bus);
5463648e78eSSagar Dharia }
5473648e78eSSagar Dharia postcore_initcall(slimbus_init);
5483648e78eSSagar Dharia 
5493648e78eSSagar Dharia MODULE_LICENSE("GPL v2");
5503648e78eSSagar Dharia MODULE_DESCRIPTION("SLIMbus core");
551