xref: /linux/drivers/slimbus/core.c (revision c3bdd5e65185f46150b3bac103b3854040487857)
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 
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 
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 
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 
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 
843648e78eSSagar Dharia static int 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 	return 0;
963648e78eSSagar Dharia }
973648e78eSSagar Dharia 
989e663f48SSrinivas Kandagatla static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
999e663f48SSrinivas Kandagatla {
1009e663f48SSrinivas Kandagatla 	struct slim_device *sbdev = to_slim_device(dev);
1019e663f48SSrinivas Kandagatla 	int ret;
1029e663f48SSrinivas Kandagatla 
1039e663f48SSrinivas Kandagatla 	ret = of_device_uevent_modalias(dev, env);
1049e663f48SSrinivas Kandagatla 	if (ret != -ENODEV)
1059e663f48SSrinivas Kandagatla 		return ret;
1069e663f48SSrinivas Kandagatla 
1079e663f48SSrinivas Kandagatla 	return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
1089e663f48SSrinivas Kandagatla }
1099e663f48SSrinivas Kandagatla 
1103648e78eSSagar Dharia struct bus_type slimbus_bus = {
1113648e78eSSagar Dharia 	.name		= "slimbus",
1123648e78eSSagar Dharia 	.match		= slim_device_match,
1133648e78eSSagar Dharia 	.probe		= slim_device_probe,
1143648e78eSSagar Dharia 	.remove		= slim_device_remove,
1159e663f48SSrinivas Kandagatla 	.uevent		= slim_device_uevent,
1163648e78eSSagar Dharia };
1173648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slimbus_bus);
1183648e78eSSagar Dharia 
1193648e78eSSagar Dharia /*
1203648e78eSSagar Dharia  * __slim_driver_register() - Client driver registration with SLIMbus
1213648e78eSSagar Dharia  *
1223648e78eSSagar Dharia  * @drv:Client driver to be associated with client-device.
1233648e78eSSagar Dharia  * @owner: owning module/driver
1243648e78eSSagar Dharia  *
1253648e78eSSagar Dharia  * This API will register the client driver with the SLIMbus
1263648e78eSSagar Dharia  * It is called from the driver's module-init function.
1273648e78eSSagar Dharia  */
1283648e78eSSagar Dharia int __slim_driver_register(struct slim_driver *drv, struct module *owner)
1293648e78eSSagar Dharia {
1303648e78eSSagar Dharia 	/* ID table and probe are mandatory */
13114a649d3SSrinivas Kandagatla 	if (!(drv->driver.of_match_table || drv->id_table) || !drv->probe)
1323648e78eSSagar Dharia 		return -EINVAL;
1333648e78eSSagar Dharia 
1343648e78eSSagar Dharia 	drv->driver.bus = &slimbus_bus;
1353648e78eSSagar Dharia 	drv->driver.owner = owner;
1363648e78eSSagar Dharia 
1373648e78eSSagar Dharia 	return driver_register(&drv->driver);
1383648e78eSSagar Dharia }
1393648e78eSSagar Dharia EXPORT_SYMBOL_GPL(__slim_driver_register);
1403648e78eSSagar Dharia 
1413648e78eSSagar Dharia /*
1423648e78eSSagar Dharia  * slim_driver_unregister() - Undo effect of slim_driver_register
1433648e78eSSagar Dharia  *
1443648e78eSSagar Dharia  * @drv: Client driver to be unregistered
1453648e78eSSagar Dharia  */
1463648e78eSSagar Dharia void slim_driver_unregister(struct slim_driver *drv)
1473648e78eSSagar Dharia {
1483648e78eSSagar Dharia 	driver_unregister(&drv->driver);
1493648e78eSSagar Dharia }
1503648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slim_driver_unregister);
1513648e78eSSagar Dharia 
15246a2bb5aSSagar Dharia static void slim_dev_release(struct device *dev)
15346a2bb5aSSagar Dharia {
15446a2bb5aSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
15546a2bb5aSSagar Dharia 
15646a2bb5aSSagar Dharia 	kfree(sbdev);
15746a2bb5aSSagar Dharia }
15846a2bb5aSSagar Dharia 
15946a2bb5aSSagar Dharia static int slim_add_device(struct slim_controller *ctrl,
16046a2bb5aSSagar Dharia 			   struct slim_device *sbdev,
16146a2bb5aSSagar Dharia 			   struct device_node *node)
16246a2bb5aSSagar Dharia {
16346a2bb5aSSagar Dharia 	sbdev->dev.bus = &slimbus_bus;
16446a2bb5aSSagar Dharia 	sbdev->dev.parent = ctrl->dev;
16546a2bb5aSSagar Dharia 	sbdev->dev.release = slim_dev_release;
16646a2bb5aSSagar Dharia 	sbdev->dev.driver = NULL;
16746a2bb5aSSagar Dharia 	sbdev->ctrl = ctrl;
168abb9c9b8SSrinivas Kandagatla 	INIT_LIST_HEAD(&sbdev->stream_list);
169abb9c9b8SSrinivas Kandagatla 	spin_lock_init(&sbdev->stream_list_lock);
17046a2bb5aSSagar Dharia 
1717588a511SSrinivas Kandagatla 	if (node)
1727588a511SSrinivas Kandagatla 		sbdev->dev.of_node = of_node_get(node);
1737588a511SSrinivas Kandagatla 
17446a2bb5aSSagar Dharia 	dev_set_name(&sbdev->dev, "%x:%x:%x:%x",
17546a2bb5aSSagar Dharia 				  sbdev->e_addr.manf_id,
17646a2bb5aSSagar Dharia 				  sbdev->e_addr.prod_code,
17746a2bb5aSSagar Dharia 				  sbdev->e_addr.dev_index,
17846a2bb5aSSagar Dharia 				  sbdev->e_addr.instance);
17946a2bb5aSSagar Dharia 
18046a2bb5aSSagar Dharia 	return device_register(&sbdev->dev);
18146a2bb5aSSagar Dharia }
18246a2bb5aSSagar Dharia 
18346a2bb5aSSagar Dharia static struct slim_device *slim_alloc_device(struct slim_controller *ctrl,
18446a2bb5aSSagar Dharia 					     struct slim_eaddr *eaddr,
18546a2bb5aSSagar Dharia 					     struct device_node *node)
18646a2bb5aSSagar Dharia {
18746a2bb5aSSagar Dharia 	struct slim_device *sbdev;
18846a2bb5aSSagar Dharia 	int ret;
18946a2bb5aSSagar Dharia 
19046a2bb5aSSagar Dharia 	sbdev = kzalloc(sizeof(*sbdev), GFP_KERNEL);
19146a2bb5aSSagar Dharia 	if (!sbdev)
19246a2bb5aSSagar Dharia 		return NULL;
19346a2bb5aSSagar Dharia 
19446a2bb5aSSagar Dharia 	sbdev->e_addr = *eaddr;
19546a2bb5aSSagar Dharia 	ret = slim_add_device(ctrl, sbdev, node);
19646a2bb5aSSagar Dharia 	if (ret) {
197bd329f02SArvind Yadav 		put_device(&sbdev->dev);
19846a2bb5aSSagar Dharia 		return NULL;
19946a2bb5aSSagar Dharia 	}
20046a2bb5aSSagar Dharia 
20146a2bb5aSSagar Dharia 	return sbdev;
20246a2bb5aSSagar Dharia }
20346a2bb5aSSagar Dharia 
2047588a511SSrinivas Kandagatla static void of_register_slim_devices(struct slim_controller *ctrl)
2057588a511SSrinivas Kandagatla {
2067588a511SSrinivas Kandagatla 	struct device *dev = ctrl->dev;
2077588a511SSrinivas Kandagatla 	struct device_node *node;
2087588a511SSrinivas Kandagatla 
2097588a511SSrinivas Kandagatla 	if (!ctrl->dev->of_node)
2107588a511SSrinivas Kandagatla 		return;
2117588a511SSrinivas Kandagatla 
2127588a511SSrinivas Kandagatla 	for_each_child_of_node(ctrl->dev->of_node, node) {
2137588a511SSrinivas Kandagatla 		struct slim_device *sbdev;
2147588a511SSrinivas Kandagatla 		struct slim_eaddr e_addr;
2157588a511SSrinivas Kandagatla 		const char *compat = NULL;
2167588a511SSrinivas Kandagatla 		int reg[2], ret;
2177588a511SSrinivas Kandagatla 		int manf_id, prod_code;
2187588a511SSrinivas Kandagatla 
2197588a511SSrinivas Kandagatla 		compat = of_get_property(node, "compatible", NULL);
2207588a511SSrinivas Kandagatla 		if (!compat)
2217588a511SSrinivas Kandagatla 			continue;
2227588a511SSrinivas Kandagatla 
2237588a511SSrinivas Kandagatla 		ret = sscanf(compat, "slim%x,%x", &manf_id, &prod_code);
2247588a511SSrinivas Kandagatla 		if (ret != 2) {
2257588a511SSrinivas Kandagatla 			dev_err(dev, "Manf ID & Product code not found %s\n",
2267588a511SSrinivas Kandagatla 				compat);
2277588a511SSrinivas Kandagatla 			continue;
2287588a511SSrinivas Kandagatla 		}
2297588a511SSrinivas Kandagatla 
2307588a511SSrinivas Kandagatla 		ret = of_property_read_u32_array(node, "reg", reg, 2);
2317588a511SSrinivas Kandagatla 		if (ret) {
2327588a511SSrinivas Kandagatla 			dev_err(dev, "Device and Instance id not found:%d\n",
2337588a511SSrinivas Kandagatla 				ret);
2347588a511SSrinivas Kandagatla 			continue;
2357588a511SSrinivas Kandagatla 		}
2367588a511SSrinivas Kandagatla 
2377588a511SSrinivas Kandagatla 		e_addr.dev_index = reg[0];
2387588a511SSrinivas Kandagatla 		e_addr.instance = reg[1];
2397588a511SSrinivas Kandagatla 		e_addr.manf_id = manf_id;
2407588a511SSrinivas Kandagatla 		e_addr.prod_code = prod_code;
2417588a511SSrinivas Kandagatla 
2427588a511SSrinivas Kandagatla 		sbdev = slim_alloc_device(ctrl, &e_addr, node);
2437588a511SSrinivas Kandagatla 		if (!sbdev)
2447588a511SSrinivas Kandagatla 			continue;
2457588a511SSrinivas Kandagatla 	}
2467588a511SSrinivas Kandagatla }
2477588a511SSrinivas Kandagatla 
24846a2bb5aSSagar Dharia /*
24946a2bb5aSSagar Dharia  * slim_register_controller() - Controller bring-up and registration.
25046a2bb5aSSagar Dharia  *
25146a2bb5aSSagar Dharia  * @ctrl: Controller to be registered.
25246a2bb5aSSagar Dharia  *
25346a2bb5aSSagar Dharia  * A controller is registered with the framework using this API.
25446a2bb5aSSagar Dharia  * If devices on a controller were registered before controller,
25546a2bb5aSSagar Dharia  * this will make sure that they get probed when controller is up
25646a2bb5aSSagar Dharia  */
25746a2bb5aSSagar Dharia int slim_register_controller(struct slim_controller *ctrl)
25846a2bb5aSSagar Dharia {
25946a2bb5aSSagar Dharia 	int id;
26046a2bb5aSSagar Dharia 
26146a2bb5aSSagar Dharia 	id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
26246a2bb5aSSagar Dharia 	if (id < 0)
26346a2bb5aSSagar Dharia 		return id;
26446a2bb5aSSagar Dharia 
26546a2bb5aSSagar Dharia 	ctrl->id = id;
26646a2bb5aSSagar Dharia 
26746a2bb5aSSagar Dharia 	if (!ctrl->min_cg)
26846a2bb5aSSagar Dharia 		ctrl->min_cg = SLIM_MIN_CLK_GEAR;
26946a2bb5aSSagar Dharia 	if (!ctrl->max_cg)
27046a2bb5aSSagar Dharia 		ctrl->max_cg = SLIM_MAX_CLK_GEAR;
27146a2bb5aSSagar Dharia 
27246a2bb5aSSagar Dharia 	ida_init(&ctrl->laddr_ida);
27346a2bb5aSSagar Dharia 	idr_init(&ctrl->tid_idr);
27446a2bb5aSSagar Dharia 	mutex_init(&ctrl->lock);
2754b14e62aSSagar Dharia 	mutex_init(&ctrl->sched.m_reconf);
2764b14e62aSSagar Dharia 	init_completion(&ctrl->sched.pause_comp);
277*8147760dSSrinivas Kandagatla 	spin_lock_init(&ctrl->txn_lock);
27846a2bb5aSSagar Dharia 
27946a2bb5aSSagar Dharia 	dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n",
28046a2bb5aSSagar Dharia 		ctrl->name, ctrl->dev);
28146a2bb5aSSagar Dharia 
2827588a511SSrinivas Kandagatla 	of_register_slim_devices(ctrl);
2837588a511SSrinivas Kandagatla 
28446a2bb5aSSagar Dharia 	return 0;
28546a2bb5aSSagar Dharia }
28646a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_register_controller);
28746a2bb5aSSagar Dharia 
28846a2bb5aSSagar Dharia /* slim_remove_device: Remove the effect of slim_add_device() */
28946a2bb5aSSagar Dharia static void slim_remove_device(struct slim_device *sbdev)
29046a2bb5aSSagar Dharia {
29146a2bb5aSSagar Dharia 	device_unregister(&sbdev->dev);
29246a2bb5aSSagar Dharia }
29346a2bb5aSSagar Dharia 
29446a2bb5aSSagar Dharia static int slim_ctrl_remove_device(struct device *dev, void *null)
29546a2bb5aSSagar Dharia {
29646a2bb5aSSagar Dharia 	slim_remove_device(to_slim_device(dev));
29746a2bb5aSSagar Dharia 	return 0;
29846a2bb5aSSagar Dharia }
29946a2bb5aSSagar Dharia 
30046a2bb5aSSagar Dharia /**
30146a2bb5aSSagar Dharia  * slim_unregister_controller() - Controller tear-down.
30246a2bb5aSSagar Dharia  *
30346a2bb5aSSagar Dharia  * @ctrl: Controller to tear-down.
30446a2bb5aSSagar Dharia  */
30546a2bb5aSSagar Dharia int slim_unregister_controller(struct slim_controller *ctrl)
30646a2bb5aSSagar Dharia {
30746a2bb5aSSagar Dharia 	/* Remove all clients */
30846a2bb5aSSagar Dharia 	device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device);
3094b14e62aSSagar Dharia 	/* Enter Clock Pause */
3104b14e62aSSagar Dharia 	slim_ctrl_clk_pause(ctrl, false, 0);
31146a2bb5aSSagar Dharia 	ida_simple_remove(&ctrl_ida, ctrl->id);
31246a2bb5aSSagar Dharia 
31346a2bb5aSSagar Dharia 	return 0;
31446a2bb5aSSagar Dharia }
31546a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_unregister_controller);
31646a2bb5aSSagar Dharia 
31746a2bb5aSSagar Dharia /**
31846a2bb5aSSagar Dharia  * slim_report_absent() - Controller calls this function when a device
31946a2bb5aSSagar Dharia  *	reports absent, OR when the device cannot be communicated with
32046a2bb5aSSagar Dharia  *
32146a2bb5aSSagar Dharia  * @sbdev: Device that cannot be reached, or sent report absent
32246a2bb5aSSagar Dharia  */
32346a2bb5aSSagar Dharia void slim_report_absent(struct slim_device *sbdev)
32446a2bb5aSSagar Dharia {
32546a2bb5aSSagar Dharia 	struct slim_controller *ctrl = sbdev->ctrl;
32646a2bb5aSSagar Dharia 
32746a2bb5aSSagar Dharia 	if (!ctrl)
32846a2bb5aSSagar Dharia 		return;
32946a2bb5aSSagar Dharia 
33046a2bb5aSSagar Dharia 	/* invalidate logical addresses */
33146a2bb5aSSagar Dharia 	mutex_lock(&ctrl->lock);
33246a2bb5aSSagar Dharia 	sbdev->is_laddr_valid = false;
33346a2bb5aSSagar Dharia 	mutex_unlock(&ctrl->lock);
33446a2bb5aSSagar Dharia 
33546a2bb5aSSagar Dharia 	ida_simple_remove(&ctrl->laddr_ida, sbdev->laddr);
33646a2bb5aSSagar Dharia 	slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_DOWN);
33746a2bb5aSSagar Dharia }
33846a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_report_absent);
33946a2bb5aSSagar Dharia 
34046a2bb5aSSagar Dharia static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b)
34146a2bb5aSSagar Dharia {
34246a2bb5aSSagar Dharia 	return (a->manf_id == b->manf_id &&
34346a2bb5aSSagar Dharia 		a->prod_code == b->prod_code &&
34446a2bb5aSSagar Dharia 		a->dev_index == b->dev_index &&
34546a2bb5aSSagar Dharia 		a->instance == b->instance);
34646a2bb5aSSagar Dharia }
34746a2bb5aSSagar Dharia 
34846a2bb5aSSagar Dharia static int slim_match_dev(struct device *dev, void *data)
34946a2bb5aSSagar Dharia {
35046a2bb5aSSagar Dharia 	struct slim_eaddr *e_addr = data;
35146a2bb5aSSagar Dharia 	struct slim_device *sbdev = to_slim_device(dev);
35246a2bb5aSSagar Dharia 
35346a2bb5aSSagar Dharia 	return slim_eaddr_equal(&sbdev->e_addr, e_addr);
35446a2bb5aSSagar Dharia }
35546a2bb5aSSagar Dharia 
35646a2bb5aSSagar Dharia static struct slim_device *find_slim_device(struct slim_controller *ctrl,
35746a2bb5aSSagar Dharia 					    struct slim_eaddr *eaddr)
35846a2bb5aSSagar Dharia {
35946a2bb5aSSagar Dharia 	struct slim_device *sbdev;
36046a2bb5aSSagar Dharia 	struct device *dev;
36146a2bb5aSSagar Dharia 
36246a2bb5aSSagar Dharia 	dev = device_find_child(ctrl->dev, eaddr, slim_match_dev);
36346a2bb5aSSagar Dharia 	if (dev) {
36446a2bb5aSSagar Dharia 		sbdev = to_slim_device(dev);
36546a2bb5aSSagar Dharia 		return sbdev;
36646a2bb5aSSagar Dharia 	}
36746a2bb5aSSagar Dharia 
36846a2bb5aSSagar Dharia 	return NULL;
36946a2bb5aSSagar Dharia }
37046a2bb5aSSagar Dharia 
37146a2bb5aSSagar Dharia /**
37246a2bb5aSSagar Dharia  * slim_get_device() - get handle to a device.
37346a2bb5aSSagar Dharia  *
37446a2bb5aSSagar Dharia  * @ctrl: Controller on which this device will be added/queried
37546a2bb5aSSagar Dharia  * @e_addr: Enumeration address of the device to be queried
37646a2bb5aSSagar Dharia  *
37746a2bb5aSSagar Dharia  * Return: pointer to a device if it has already reported. Creates a new
37846a2bb5aSSagar Dharia  * device and returns pointer to it if the device has not yet enumerated.
37946a2bb5aSSagar Dharia  */
38046a2bb5aSSagar Dharia struct slim_device *slim_get_device(struct slim_controller *ctrl,
38146a2bb5aSSagar Dharia 				    struct slim_eaddr *e_addr)
38246a2bb5aSSagar Dharia {
38346a2bb5aSSagar Dharia 	struct slim_device *sbdev;
38446a2bb5aSSagar Dharia 
38546a2bb5aSSagar Dharia 	sbdev = find_slim_device(ctrl, e_addr);
38646a2bb5aSSagar Dharia 	if (!sbdev) {
38746a2bb5aSSagar Dharia 		sbdev = slim_alloc_device(ctrl, e_addr, NULL);
38846a2bb5aSSagar Dharia 		if (!sbdev)
38946a2bb5aSSagar Dharia 			return ERR_PTR(-ENOMEM);
39046a2bb5aSSagar Dharia 	}
39146a2bb5aSSagar Dharia 
39246a2bb5aSSagar Dharia 	return sbdev;
39346a2bb5aSSagar Dharia }
39446a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_device);
39546a2bb5aSSagar Dharia 
396e0772de8SSrinivas Kandagatla static int of_slim_match_dev(struct device *dev, void *data)
397e0772de8SSrinivas Kandagatla {
398e0772de8SSrinivas Kandagatla 	struct device_node *np = data;
399e0772de8SSrinivas Kandagatla 	struct slim_device *sbdev = to_slim_device(dev);
400e0772de8SSrinivas Kandagatla 
401e0772de8SSrinivas Kandagatla 	return (sbdev->dev.of_node == np);
402e0772de8SSrinivas Kandagatla }
403e0772de8SSrinivas Kandagatla 
404e0772de8SSrinivas Kandagatla static struct slim_device *of_find_slim_device(struct slim_controller *ctrl,
405e0772de8SSrinivas Kandagatla 					       struct device_node *np)
406e0772de8SSrinivas Kandagatla {
407e0772de8SSrinivas Kandagatla 	struct slim_device *sbdev;
408e0772de8SSrinivas Kandagatla 	struct device *dev;
409e0772de8SSrinivas Kandagatla 
410e0772de8SSrinivas Kandagatla 	dev = device_find_child(ctrl->dev, np, of_slim_match_dev);
411e0772de8SSrinivas Kandagatla 	if (dev) {
412e0772de8SSrinivas Kandagatla 		sbdev = to_slim_device(dev);
413e0772de8SSrinivas Kandagatla 		return sbdev;
414e0772de8SSrinivas Kandagatla 	}
415e0772de8SSrinivas Kandagatla 
416e0772de8SSrinivas Kandagatla 	return NULL;
417e0772de8SSrinivas Kandagatla }
418e0772de8SSrinivas Kandagatla 
419e0772de8SSrinivas Kandagatla /**
420e0772de8SSrinivas Kandagatla  * of_slim_get_device() - get handle to a device using dt node.
421e0772de8SSrinivas Kandagatla  *
422e0772de8SSrinivas Kandagatla  * @ctrl: Controller on which this device will be added/queried
423e0772de8SSrinivas Kandagatla  * @np: node pointer to device
424e0772de8SSrinivas Kandagatla  *
425e0772de8SSrinivas Kandagatla  * Return: pointer to a device if it has already reported. Creates a new
426e0772de8SSrinivas Kandagatla  * device and returns pointer to it if the device has not yet enumerated.
427e0772de8SSrinivas Kandagatla  */
428e0772de8SSrinivas Kandagatla struct slim_device *of_slim_get_device(struct slim_controller *ctrl,
429e0772de8SSrinivas Kandagatla 				       struct device_node *np)
430e0772de8SSrinivas Kandagatla {
431e0772de8SSrinivas Kandagatla 	return of_find_slim_device(ctrl, np);
432e0772de8SSrinivas Kandagatla }
433e0772de8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_slim_get_device);
434e0772de8SSrinivas Kandagatla 
43546a2bb5aSSagar Dharia static int slim_device_alloc_laddr(struct slim_device *sbdev,
43646a2bb5aSSagar Dharia 				   bool report_present)
43746a2bb5aSSagar Dharia {
43846a2bb5aSSagar Dharia 	struct slim_controller *ctrl = sbdev->ctrl;
43946a2bb5aSSagar Dharia 	u8 laddr;
44046a2bb5aSSagar Dharia 	int ret;
44146a2bb5aSSagar Dharia 
44246a2bb5aSSagar Dharia 	mutex_lock(&ctrl->lock);
44346a2bb5aSSagar Dharia 	if (ctrl->get_laddr) {
44446a2bb5aSSagar Dharia 		ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr);
44546a2bb5aSSagar Dharia 		if (ret < 0)
44646a2bb5aSSagar Dharia 			goto err;
44746a2bb5aSSagar Dharia 	} else if (report_present) {
44846a2bb5aSSagar Dharia 		ret = ida_simple_get(&ctrl->laddr_ida,
44946a2bb5aSSagar Dharia 				     0, SLIM_LA_MANAGER - 1, GFP_KERNEL);
45046a2bb5aSSagar Dharia 		if (ret < 0)
45146a2bb5aSSagar Dharia 			goto err;
45246a2bb5aSSagar Dharia 
45346a2bb5aSSagar Dharia 		laddr = ret;
45446a2bb5aSSagar Dharia 	} else {
45546a2bb5aSSagar Dharia 		ret = -EINVAL;
45646a2bb5aSSagar Dharia 		goto err;
45746a2bb5aSSagar Dharia 	}
45846a2bb5aSSagar Dharia 
45946a2bb5aSSagar Dharia 	if (ctrl->set_laddr) {
46046a2bb5aSSagar Dharia 		ret = ctrl->set_laddr(ctrl, &sbdev->e_addr, laddr);
46146a2bb5aSSagar Dharia 		if (ret) {
46246a2bb5aSSagar Dharia 			ret = -EINVAL;
46346a2bb5aSSagar Dharia 			goto err;
46446a2bb5aSSagar Dharia 		}
46546a2bb5aSSagar Dharia 	}
46646a2bb5aSSagar Dharia 
46746a2bb5aSSagar Dharia 	sbdev->laddr = laddr;
46846a2bb5aSSagar Dharia 	sbdev->is_laddr_valid = true;
469cfb32101SSrinivas Kandagatla 	mutex_unlock(&ctrl->lock);
47046a2bb5aSSagar Dharia 
47146a2bb5aSSagar Dharia 	slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
47246a2bb5aSSagar Dharia 
47346a2bb5aSSagar Dharia 	dev_dbg(ctrl->dev, "setting slimbus l-addr:%x, ea:%x,%x,%x,%x\n",
47446a2bb5aSSagar Dharia 		laddr, sbdev->e_addr.manf_id, sbdev->e_addr.prod_code,
47546a2bb5aSSagar Dharia 		sbdev->e_addr.dev_index, sbdev->e_addr.instance);
47646a2bb5aSSagar Dharia 
477cfb32101SSrinivas Kandagatla 	return 0;
478cfb32101SSrinivas Kandagatla 
47946a2bb5aSSagar Dharia err:
48046a2bb5aSSagar Dharia 	mutex_unlock(&ctrl->lock);
48146a2bb5aSSagar Dharia 	return ret;
48246a2bb5aSSagar Dharia 
48346a2bb5aSSagar Dharia }
48446a2bb5aSSagar Dharia 
48546a2bb5aSSagar Dharia /**
48646a2bb5aSSagar Dharia  * slim_device_report_present() - Report enumerated device.
48746a2bb5aSSagar Dharia  *
48846a2bb5aSSagar Dharia  * @ctrl: Controller with which device is enumerated.
48946a2bb5aSSagar Dharia  * @e_addr: Enumeration address of the device.
49046a2bb5aSSagar Dharia  * @laddr: Return logical address (if valid flag is false)
49146a2bb5aSSagar Dharia  *
49246a2bb5aSSagar Dharia  * Called by controller in response to REPORT_PRESENT. Framework will assign
49346a2bb5aSSagar Dharia  * a logical address to this enumeration address.
49446a2bb5aSSagar Dharia  * Function returns -EXFULL to indicate that all logical addresses are already
49546a2bb5aSSagar Dharia  * taken.
49646a2bb5aSSagar Dharia  */
49746a2bb5aSSagar Dharia int slim_device_report_present(struct slim_controller *ctrl,
49846a2bb5aSSagar Dharia 			       struct slim_eaddr *e_addr, u8 *laddr)
49946a2bb5aSSagar Dharia {
50046a2bb5aSSagar Dharia 	struct slim_device *sbdev;
50146a2bb5aSSagar Dharia 	int ret;
50246a2bb5aSSagar Dharia 
5034b14e62aSSagar Dharia 	ret = pm_runtime_get_sync(ctrl->dev);
5044b14e62aSSagar Dharia 
5054b14e62aSSagar Dharia 	if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
5064b14e62aSSagar Dharia 		dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n",
5074b14e62aSSagar Dharia 				    ctrl->sched.clk_state, ret);
5084b14e62aSSagar Dharia 		goto slimbus_not_active;
5094b14e62aSSagar Dharia 	}
5104b14e62aSSagar Dharia 
51146a2bb5aSSagar Dharia 	sbdev = slim_get_device(ctrl, e_addr);
51246a2bb5aSSagar Dharia 	if (IS_ERR(sbdev))
51346a2bb5aSSagar Dharia 		return -ENODEV;
51446a2bb5aSSagar Dharia 
51546a2bb5aSSagar Dharia 	if (sbdev->is_laddr_valid) {
51646a2bb5aSSagar Dharia 		*laddr = sbdev->laddr;
51746a2bb5aSSagar Dharia 		return 0;
51846a2bb5aSSagar Dharia 	}
51946a2bb5aSSagar Dharia 
52046a2bb5aSSagar Dharia 	ret = slim_device_alloc_laddr(sbdev, true);
52146a2bb5aSSagar Dharia 
5224b14e62aSSagar Dharia slimbus_not_active:
5234b14e62aSSagar Dharia 	pm_runtime_mark_last_busy(ctrl->dev);
5244b14e62aSSagar Dharia 	pm_runtime_put_autosuspend(ctrl->dev);
52546a2bb5aSSagar Dharia 	return ret;
52646a2bb5aSSagar Dharia }
52746a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_device_report_present);
52846a2bb5aSSagar Dharia 
52946a2bb5aSSagar Dharia /**
53046a2bb5aSSagar Dharia  * slim_get_logical_addr() - get/allocate logical address of a SLIMbus device.
53146a2bb5aSSagar Dharia  *
53246a2bb5aSSagar Dharia  * @sbdev: client handle requesting the address.
53346a2bb5aSSagar Dharia  *
53446a2bb5aSSagar Dharia  * Return: zero if a logical address is valid or a new logical address
53546a2bb5aSSagar Dharia  * has been assigned. error code in case of error.
53646a2bb5aSSagar Dharia  */
53746a2bb5aSSagar Dharia int slim_get_logical_addr(struct slim_device *sbdev)
53846a2bb5aSSagar Dharia {
53946a2bb5aSSagar Dharia 	if (!sbdev->is_laddr_valid)
54046a2bb5aSSagar Dharia 		return slim_device_alloc_laddr(sbdev, false);
54146a2bb5aSSagar Dharia 
54246a2bb5aSSagar Dharia 	return 0;
54346a2bb5aSSagar Dharia }
54446a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_logical_addr);
54546a2bb5aSSagar Dharia 
5463648e78eSSagar Dharia static void __exit slimbus_exit(void)
5473648e78eSSagar Dharia {
5483648e78eSSagar Dharia 	bus_unregister(&slimbus_bus);
5493648e78eSSagar Dharia }
5503648e78eSSagar Dharia module_exit(slimbus_exit);
5513648e78eSSagar Dharia 
5523648e78eSSagar Dharia static int __init slimbus_init(void)
5533648e78eSSagar Dharia {
5543648e78eSSagar Dharia 	return bus_register(&slimbus_bus);
5553648e78eSSagar Dharia }
5563648e78eSSagar Dharia postcore_initcall(slimbus_init);
5573648e78eSSagar Dharia 
5583648e78eSSagar Dharia MODULE_LICENSE("GPL v2");
5593648e78eSSagar Dharia MODULE_DESCRIPTION("SLIMbus core");
560