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