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> 124b14e62aSSagar Dharia #include <linux/pm_runtime.h> 133648e78eSSagar Dharia #include <linux/slimbus.h> 1446a2bb5aSSagar Dharia #include "slimbus.h" 1546a2bb5aSSagar Dharia 1646a2bb5aSSagar Dharia static DEFINE_IDA(ctrl_ida); 173648e78eSSagar Dharia 183648e78eSSagar Dharia static const struct slim_device_id *slim_match(const struct slim_device_id *id, 193648e78eSSagar Dharia const struct slim_device *sbdev) 203648e78eSSagar Dharia { 213648e78eSSagar Dharia while (id->manf_id != 0 || id->prod_code != 0) { 223648e78eSSagar Dharia if (id->manf_id == sbdev->e_addr.manf_id && 233648e78eSSagar Dharia id->prod_code == sbdev->e_addr.prod_code) 243648e78eSSagar Dharia return id; 253648e78eSSagar Dharia id++; 263648e78eSSagar Dharia } 273648e78eSSagar Dharia return NULL; 283648e78eSSagar Dharia } 293648e78eSSagar Dharia 303648e78eSSagar Dharia static int slim_device_match(struct device *dev, struct device_driver *drv) 313648e78eSSagar Dharia { 323648e78eSSagar Dharia struct slim_device *sbdev = to_slim_device(dev); 333648e78eSSagar Dharia struct slim_driver *sbdrv = to_slim_driver(drv); 343648e78eSSagar Dharia 353648e78eSSagar Dharia return !!slim_match(sbdrv->id_table, sbdev); 363648e78eSSagar Dharia } 373648e78eSSagar Dharia 383648e78eSSagar Dharia static int slim_device_probe(struct device *dev) 393648e78eSSagar Dharia { 403648e78eSSagar Dharia struct slim_device *sbdev = to_slim_device(dev); 413648e78eSSagar Dharia struct slim_driver *sbdrv = to_slim_driver(dev->driver); 423648e78eSSagar Dharia 433648e78eSSagar Dharia return sbdrv->probe(sbdev); 443648e78eSSagar Dharia } 453648e78eSSagar Dharia 463648e78eSSagar Dharia static int slim_device_remove(struct device *dev) 473648e78eSSagar Dharia { 483648e78eSSagar Dharia struct slim_device *sbdev = to_slim_device(dev); 493648e78eSSagar Dharia struct slim_driver *sbdrv; 503648e78eSSagar Dharia 513648e78eSSagar Dharia if (dev->driver) { 523648e78eSSagar Dharia sbdrv = to_slim_driver(dev->driver); 533648e78eSSagar Dharia if (sbdrv->remove) 543648e78eSSagar Dharia sbdrv->remove(sbdev); 553648e78eSSagar Dharia } 563648e78eSSagar Dharia 573648e78eSSagar Dharia return 0; 583648e78eSSagar Dharia } 593648e78eSSagar Dharia 603648e78eSSagar Dharia struct bus_type slimbus_bus = { 613648e78eSSagar Dharia .name = "slimbus", 623648e78eSSagar Dharia .match = slim_device_match, 633648e78eSSagar Dharia .probe = slim_device_probe, 643648e78eSSagar Dharia .remove = slim_device_remove, 653648e78eSSagar Dharia }; 663648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slimbus_bus); 673648e78eSSagar Dharia 683648e78eSSagar Dharia /* 693648e78eSSagar Dharia * __slim_driver_register() - Client driver registration with SLIMbus 703648e78eSSagar Dharia * 713648e78eSSagar Dharia * @drv:Client driver to be associated with client-device. 723648e78eSSagar Dharia * @owner: owning module/driver 733648e78eSSagar Dharia * 743648e78eSSagar Dharia * This API will register the client driver with the SLIMbus 753648e78eSSagar Dharia * It is called from the driver's module-init function. 763648e78eSSagar Dharia */ 773648e78eSSagar Dharia int __slim_driver_register(struct slim_driver *drv, struct module *owner) 783648e78eSSagar Dharia { 793648e78eSSagar Dharia /* ID table and probe are mandatory */ 803648e78eSSagar Dharia if (!drv->id_table || !drv->probe) 813648e78eSSagar Dharia return -EINVAL; 823648e78eSSagar Dharia 833648e78eSSagar Dharia drv->driver.bus = &slimbus_bus; 843648e78eSSagar Dharia drv->driver.owner = owner; 853648e78eSSagar Dharia 863648e78eSSagar Dharia return driver_register(&drv->driver); 873648e78eSSagar Dharia } 883648e78eSSagar Dharia EXPORT_SYMBOL_GPL(__slim_driver_register); 893648e78eSSagar Dharia 903648e78eSSagar Dharia /* 913648e78eSSagar Dharia * slim_driver_unregister() - Undo effect of slim_driver_register 923648e78eSSagar Dharia * 933648e78eSSagar Dharia * @drv: Client driver to be unregistered 943648e78eSSagar Dharia */ 953648e78eSSagar Dharia void slim_driver_unregister(struct slim_driver *drv) 963648e78eSSagar Dharia { 973648e78eSSagar Dharia driver_unregister(&drv->driver); 983648e78eSSagar Dharia } 993648e78eSSagar Dharia EXPORT_SYMBOL_GPL(slim_driver_unregister); 1003648e78eSSagar Dharia 10146a2bb5aSSagar Dharia static void slim_dev_release(struct device *dev) 10246a2bb5aSSagar Dharia { 10346a2bb5aSSagar Dharia struct slim_device *sbdev = to_slim_device(dev); 10446a2bb5aSSagar Dharia 10546a2bb5aSSagar Dharia kfree(sbdev); 10646a2bb5aSSagar Dharia } 10746a2bb5aSSagar Dharia 10846a2bb5aSSagar Dharia static int slim_add_device(struct slim_controller *ctrl, 10946a2bb5aSSagar Dharia struct slim_device *sbdev, 11046a2bb5aSSagar Dharia struct device_node *node) 11146a2bb5aSSagar Dharia { 11246a2bb5aSSagar Dharia sbdev->dev.bus = &slimbus_bus; 11346a2bb5aSSagar Dharia sbdev->dev.parent = ctrl->dev; 11446a2bb5aSSagar Dharia sbdev->dev.release = slim_dev_release; 11546a2bb5aSSagar Dharia sbdev->dev.driver = NULL; 11646a2bb5aSSagar Dharia sbdev->ctrl = ctrl; 117*abb9c9b8SSrinivas Kandagatla INIT_LIST_HEAD(&sbdev->stream_list); 118*abb9c9b8SSrinivas Kandagatla spin_lock_init(&sbdev->stream_list_lock); 11946a2bb5aSSagar Dharia 1207588a511SSrinivas Kandagatla if (node) 1217588a511SSrinivas Kandagatla sbdev->dev.of_node = of_node_get(node); 1227588a511SSrinivas Kandagatla 12346a2bb5aSSagar Dharia dev_set_name(&sbdev->dev, "%x:%x:%x:%x", 12446a2bb5aSSagar Dharia sbdev->e_addr.manf_id, 12546a2bb5aSSagar Dharia sbdev->e_addr.prod_code, 12646a2bb5aSSagar Dharia sbdev->e_addr.dev_index, 12746a2bb5aSSagar Dharia sbdev->e_addr.instance); 12846a2bb5aSSagar Dharia 12946a2bb5aSSagar Dharia return device_register(&sbdev->dev); 13046a2bb5aSSagar Dharia } 13146a2bb5aSSagar Dharia 13246a2bb5aSSagar Dharia static struct slim_device *slim_alloc_device(struct slim_controller *ctrl, 13346a2bb5aSSagar Dharia struct slim_eaddr *eaddr, 13446a2bb5aSSagar Dharia struct device_node *node) 13546a2bb5aSSagar Dharia { 13646a2bb5aSSagar Dharia struct slim_device *sbdev; 13746a2bb5aSSagar Dharia int ret; 13846a2bb5aSSagar Dharia 13946a2bb5aSSagar Dharia sbdev = kzalloc(sizeof(*sbdev), GFP_KERNEL); 14046a2bb5aSSagar Dharia if (!sbdev) 14146a2bb5aSSagar Dharia return NULL; 14246a2bb5aSSagar Dharia 14346a2bb5aSSagar Dharia sbdev->e_addr = *eaddr; 14446a2bb5aSSagar Dharia ret = slim_add_device(ctrl, sbdev, node); 14546a2bb5aSSagar Dharia if (ret) { 146bd329f02SArvind Yadav put_device(&sbdev->dev); 14746a2bb5aSSagar Dharia return NULL; 14846a2bb5aSSagar Dharia } 14946a2bb5aSSagar Dharia 15046a2bb5aSSagar Dharia return sbdev; 15146a2bb5aSSagar Dharia } 15246a2bb5aSSagar Dharia 1537588a511SSrinivas Kandagatla static void of_register_slim_devices(struct slim_controller *ctrl) 1547588a511SSrinivas Kandagatla { 1557588a511SSrinivas Kandagatla struct device *dev = ctrl->dev; 1567588a511SSrinivas Kandagatla struct device_node *node; 1577588a511SSrinivas Kandagatla 1587588a511SSrinivas Kandagatla if (!ctrl->dev->of_node) 1597588a511SSrinivas Kandagatla return; 1607588a511SSrinivas Kandagatla 1617588a511SSrinivas Kandagatla for_each_child_of_node(ctrl->dev->of_node, node) { 1627588a511SSrinivas Kandagatla struct slim_device *sbdev; 1637588a511SSrinivas Kandagatla struct slim_eaddr e_addr; 1647588a511SSrinivas Kandagatla const char *compat = NULL; 1657588a511SSrinivas Kandagatla int reg[2], ret; 1667588a511SSrinivas Kandagatla int manf_id, prod_code; 1677588a511SSrinivas Kandagatla 1687588a511SSrinivas Kandagatla compat = of_get_property(node, "compatible", NULL); 1697588a511SSrinivas Kandagatla if (!compat) 1707588a511SSrinivas Kandagatla continue; 1717588a511SSrinivas Kandagatla 1727588a511SSrinivas Kandagatla ret = sscanf(compat, "slim%x,%x", &manf_id, &prod_code); 1737588a511SSrinivas Kandagatla if (ret != 2) { 1747588a511SSrinivas Kandagatla dev_err(dev, "Manf ID & Product code not found %s\n", 1757588a511SSrinivas Kandagatla compat); 1767588a511SSrinivas Kandagatla continue; 1777588a511SSrinivas Kandagatla } 1787588a511SSrinivas Kandagatla 1797588a511SSrinivas Kandagatla ret = of_property_read_u32_array(node, "reg", reg, 2); 1807588a511SSrinivas Kandagatla if (ret) { 1817588a511SSrinivas Kandagatla dev_err(dev, "Device and Instance id not found:%d\n", 1827588a511SSrinivas Kandagatla ret); 1837588a511SSrinivas Kandagatla continue; 1847588a511SSrinivas Kandagatla } 1857588a511SSrinivas Kandagatla 1867588a511SSrinivas Kandagatla e_addr.dev_index = reg[0]; 1877588a511SSrinivas Kandagatla e_addr.instance = reg[1]; 1887588a511SSrinivas Kandagatla e_addr.manf_id = manf_id; 1897588a511SSrinivas Kandagatla e_addr.prod_code = prod_code; 1907588a511SSrinivas Kandagatla 1917588a511SSrinivas Kandagatla sbdev = slim_alloc_device(ctrl, &e_addr, node); 1927588a511SSrinivas Kandagatla if (!sbdev) 1937588a511SSrinivas Kandagatla continue; 1947588a511SSrinivas Kandagatla } 1957588a511SSrinivas Kandagatla } 1967588a511SSrinivas Kandagatla 19746a2bb5aSSagar Dharia /* 19846a2bb5aSSagar Dharia * slim_register_controller() - Controller bring-up and registration. 19946a2bb5aSSagar Dharia * 20046a2bb5aSSagar Dharia * @ctrl: Controller to be registered. 20146a2bb5aSSagar Dharia * 20246a2bb5aSSagar Dharia * A controller is registered with the framework using this API. 20346a2bb5aSSagar Dharia * If devices on a controller were registered before controller, 20446a2bb5aSSagar Dharia * this will make sure that they get probed when controller is up 20546a2bb5aSSagar Dharia */ 20646a2bb5aSSagar Dharia int slim_register_controller(struct slim_controller *ctrl) 20746a2bb5aSSagar Dharia { 20846a2bb5aSSagar Dharia int id; 20946a2bb5aSSagar Dharia 21046a2bb5aSSagar Dharia id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL); 21146a2bb5aSSagar Dharia if (id < 0) 21246a2bb5aSSagar Dharia return id; 21346a2bb5aSSagar Dharia 21446a2bb5aSSagar Dharia ctrl->id = id; 21546a2bb5aSSagar Dharia 21646a2bb5aSSagar Dharia if (!ctrl->min_cg) 21746a2bb5aSSagar Dharia ctrl->min_cg = SLIM_MIN_CLK_GEAR; 21846a2bb5aSSagar Dharia if (!ctrl->max_cg) 21946a2bb5aSSagar Dharia ctrl->max_cg = SLIM_MAX_CLK_GEAR; 22046a2bb5aSSagar Dharia 22146a2bb5aSSagar Dharia ida_init(&ctrl->laddr_ida); 22246a2bb5aSSagar Dharia idr_init(&ctrl->tid_idr); 22346a2bb5aSSagar Dharia mutex_init(&ctrl->lock); 2244b14e62aSSagar Dharia mutex_init(&ctrl->sched.m_reconf); 2254b14e62aSSagar Dharia init_completion(&ctrl->sched.pause_comp); 22646a2bb5aSSagar Dharia 22746a2bb5aSSagar Dharia dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n", 22846a2bb5aSSagar Dharia ctrl->name, ctrl->dev); 22946a2bb5aSSagar Dharia 2307588a511SSrinivas Kandagatla of_register_slim_devices(ctrl); 2317588a511SSrinivas Kandagatla 23246a2bb5aSSagar Dharia return 0; 23346a2bb5aSSagar Dharia } 23446a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_register_controller); 23546a2bb5aSSagar Dharia 23646a2bb5aSSagar Dharia /* slim_remove_device: Remove the effect of slim_add_device() */ 23746a2bb5aSSagar Dharia static void slim_remove_device(struct slim_device *sbdev) 23846a2bb5aSSagar Dharia { 23946a2bb5aSSagar Dharia device_unregister(&sbdev->dev); 24046a2bb5aSSagar Dharia } 24146a2bb5aSSagar Dharia 24246a2bb5aSSagar Dharia static int slim_ctrl_remove_device(struct device *dev, void *null) 24346a2bb5aSSagar Dharia { 24446a2bb5aSSagar Dharia slim_remove_device(to_slim_device(dev)); 24546a2bb5aSSagar Dharia return 0; 24646a2bb5aSSagar Dharia } 24746a2bb5aSSagar Dharia 24846a2bb5aSSagar Dharia /** 24946a2bb5aSSagar Dharia * slim_unregister_controller() - Controller tear-down. 25046a2bb5aSSagar Dharia * 25146a2bb5aSSagar Dharia * @ctrl: Controller to tear-down. 25246a2bb5aSSagar Dharia */ 25346a2bb5aSSagar Dharia int slim_unregister_controller(struct slim_controller *ctrl) 25446a2bb5aSSagar Dharia { 25546a2bb5aSSagar Dharia /* Remove all clients */ 25646a2bb5aSSagar Dharia device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device); 2574b14e62aSSagar Dharia /* Enter Clock Pause */ 2584b14e62aSSagar Dharia slim_ctrl_clk_pause(ctrl, false, 0); 25946a2bb5aSSagar Dharia ida_simple_remove(&ctrl_ida, ctrl->id); 26046a2bb5aSSagar Dharia 26146a2bb5aSSagar Dharia return 0; 26246a2bb5aSSagar Dharia } 26346a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_unregister_controller); 26446a2bb5aSSagar Dharia 26546a2bb5aSSagar Dharia static void slim_device_update_status(struct slim_device *sbdev, 26646a2bb5aSSagar Dharia enum slim_device_status status) 26746a2bb5aSSagar Dharia { 26846a2bb5aSSagar Dharia struct slim_driver *sbdrv; 26946a2bb5aSSagar Dharia 27046a2bb5aSSagar Dharia if (sbdev->status == status) 27146a2bb5aSSagar Dharia return; 27246a2bb5aSSagar Dharia 27346a2bb5aSSagar Dharia sbdev->status = status; 27446a2bb5aSSagar Dharia if (!sbdev->dev.driver) 27546a2bb5aSSagar Dharia return; 27646a2bb5aSSagar Dharia 27746a2bb5aSSagar Dharia sbdrv = to_slim_driver(sbdev->dev.driver); 27846a2bb5aSSagar Dharia if (sbdrv->device_status) 27946a2bb5aSSagar Dharia sbdrv->device_status(sbdev, sbdev->status); 28046a2bb5aSSagar Dharia } 28146a2bb5aSSagar Dharia 28246a2bb5aSSagar Dharia /** 28346a2bb5aSSagar Dharia * slim_report_absent() - Controller calls this function when a device 28446a2bb5aSSagar Dharia * reports absent, OR when the device cannot be communicated with 28546a2bb5aSSagar Dharia * 28646a2bb5aSSagar Dharia * @sbdev: Device that cannot be reached, or sent report absent 28746a2bb5aSSagar Dharia */ 28846a2bb5aSSagar Dharia void slim_report_absent(struct slim_device *sbdev) 28946a2bb5aSSagar Dharia { 29046a2bb5aSSagar Dharia struct slim_controller *ctrl = sbdev->ctrl; 29146a2bb5aSSagar Dharia 29246a2bb5aSSagar Dharia if (!ctrl) 29346a2bb5aSSagar Dharia return; 29446a2bb5aSSagar Dharia 29546a2bb5aSSagar Dharia /* invalidate logical addresses */ 29646a2bb5aSSagar Dharia mutex_lock(&ctrl->lock); 29746a2bb5aSSagar Dharia sbdev->is_laddr_valid = false; 29846a2bb5aSSagar Dharia mutex_unlock(&ctrl->lock); 29946a2bb5aSSagar Dharia 30046a2bb5aSSagar Dharia ida_simple_remove(&ctrl->laddr_ida, sbdev->laddr); 30146a2bb5aSSagar Dharia slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_DOWN); 30246a2bb5aSSagar Dharia } 30346a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_report_absent); 30446a2bb5aSSagar Dharia 30546a2bb5aSSagar Dharia static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b) 30646a2bb5aSSagar Dharia { 30746a2bb5aSSagar Dharia return (a->manf_id == b->manf_id && 30846a2bb5aSSagar Dharia a->prod_code == b->prod_code && 30946a2bb5aSSagar Dharia a->dev_index == b->dev_index && 31046a2bb5aSSagar Dharia a->instance == b->instance); 31146a2bb5aSSagar Dharia } 31246a2bb5aSSagar Dharia 31346a2bb5aSSagar Dharia static int slim_match_dev(struct device *dev, void *data) 31446a2bb5aSSagar Dharia { 31546a2bb5aSSagar Dharia struct slim_eaddr *e_addr = data; 31646a2bb5aSSagar Dharia struct slim_device *sbdev = to_slim_device(dev); 31746a2bb5aSSagar Dharia 31846a2bb5aSSagar Dharia return slim_eaddr_equal(&sbdev->e_addr, e_addr); 31946a2bb5aSSagar Dharia } 32046a2bb5aSSagar Dharia 32146a2bb5aSSagar Dharia static struct slim_device *find_slim_device(struct slim_controller *ctrl, 32246a2bb5aSSagar Dharia struct slim_eaddr *eaddr) 32346a2bb5aSSagar Dharia { 32446a2bb5aSSagar Dharia struct slim_device *sbdev; 32546a2bb5aSSagar Dharia struct device *dev; 32646a2bb5aSSagar Dharia 32746a2bb5aSSagar Dharia dev = device_find_child(ctrl->dev, eaddr, slim_match_dev); 32846a2bb5aSSagar Dharia if (dev) { 32946a2bb5aSSagar Dharia sbdev = to_slim_device(dev); 33046a2bb5aSSagar Dharia return sbdev; 33146a2bb5aSSagar Dharia } 33246a2bb5aSSagar Dharia 33346a2bb5aSSagar Dharia return NULL; 33446a2bb5aSSagar Dharia } 33546a2bb5aSSagar Dharia 33646a2bb5aSSagar Dharia /** 33746a2bb5aSSagar Dharia * slim_get_device() - get handle to a device. 33846a2bb5aSSagar Dharia * 33946a2bb5aSSagar Dharia * @ctrl: Controller on which this device will be added/queried 34046a2bb5aSSagar Dharia * @e_addr: Enumeration address of the device to be queried 34146a2bb5aSSagar Dharia * 34246a2bb5aSSagar Dharia * Return: pointer to a device if it has already reported. Creates a new 34346a2bb5aSSagar Dharia * device and returns pointer to it if the device has not yet enumerated. 34446a2bb5aSSagar Dharia */ 34546a2bb5aSSagar Dharia struct slim_device *slim_get_device(struct slim_controller *ctrl, 34646a2bb5aSSagar Dharia struct slim_eaddr *e_addr) 34746a2bb5aSSagar Dharia { 34846a2bb5aSSagar Dharia struct slim_device *sbdev; 34946a2bb5aSSagar Dharia 35046a2bb5aSSagar Dharia sbdev = find_slim_device(ctrl, e_addr); 35146a2bb5aSSagar Dharia if (!sbdev) { 35246a2bb5aSSagar Dharia sbdev = slim_alloc_device(ctrl, e_addr, NULL); 35346a2bb5aSSagar Dharia if (!sbdev) 35446a2bb5aSSagar Dharia return ERR_PTR(-ENOMEM); 35546a2bb5aSSagar Dharia } 35646a2bb5aSSagar Dharia 35746a2bb5aSSagar Dharia return sbdev; 35846a2bb5aSSagar Dharia } 35946a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_device); 36046a2bb5aSSagar Dharia 361e0772de8SSrinivas Kandagatla static int of_slim_match_dev(struct device *dev, void *data) 362e0772de8SSrinivas Kandagatla { 363e0772de8SSrinivas Kandagatla struct device_node *np = data; 364e0772de8SSrinivas Kandagatla struct slim_device *sbdev = to_slim_device(dev); 365e0772de8SSrinivas Kandagatla 366e0772de8SSrinivas Kandagatla return (sbdev->dev.of_node == np); 367e0772de8SSrinivas Kandagatla } 368e0772de8SSrinivas Kandagatla 369e0772de8SSrinivas Kandagatla static struct slim_device *of_find_slim_device(struct slim_controller *ctrl, 370e0772de8SSrinivas Kandagatla struct device_node *np) 371e0772de8SSrinivas Kandagatla { 372e0772de8SSrinivas Kandagatla struct slim_device *sbdev; 373e0772de8SSrinivas Kandagatla struct device *dev; 374e0772de8SSrinivas Kandagatla 375e0772de8SSrinivas Kandagatla dev = device_find_child(ctrl->dev, np, of_slim_match_dev); 376e0772de8SSrinivas Kandagatla if (dev) { 377e0772de8SSrinivas Kandagatla sbdev = to_slim_device(dev); 378e0772de8SSrinivas Kandagatla return sbdev; 379e0772de8SSrinivas Kandagatla } 380e0772de8SSrinivas Kandagatla 381e0772de8SSrinivas Kandagatla return NULL; 382e0772de8SSrinivas Kandagatla } 383e0772de8SSrinivas Kandagatla 384e0772de8SSrinivas Kandagatla /** 385e0772de8SSrinivas Kandagatla * of_slim_get_device() - get handle to a device using dt node. 386e0772de8SSrinivas Kandagatla * 387e0772de8SSrinivas Kandagatla * @ctrl: Controller on which this device will be added/queried 388e0772de8SSrinivas Kandagatla * @np: node pointer to device 389e0772de8SSrinivas Kandagatla * 390e0772de8SSrinivas Kandagatla * Return: pointer to a device if it has already reported. Creates a new 391e0772de8SSrinivas Kandagatla * device and returns pointer to it if the device has not yet enumerated. 392e0772de8SSrinivas Kandagatla */ 393e0772de8SSrinivas Kandagatla struct slim_device *of_slim_get_device(struct slim_controller *ctrl, 394e0772de8SSrinivas Kandagatla struct device_node *np) 395e0772de8SSrinivas Kandagatla { 396e0772de8SSrinivas Kandagatla return of_find_slim_device(ctrl, np); 397e0772de8SSrinivas Kandagatla } 398e0772de8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_slim_get_device); 399e0772de8SSrinivas Kandagatla 40046a2bb5aSSagar Dharia static int slim_device_alloc_laddr(struct slim_device *sbdev, 40146a2bb5aSSagar Dharia bool report_present) 40246a2bb5aSSagar Dharia { 40346a2bb5aSSagar Dharia struct slim_controller *ctrl = sbdev->ctrl; 40446a2bb5aSSagar Dharia u8 laddr; 40546a2bb5aSSagar Dharia int ret; 40646a2bb5aSSagar Dharia 40746a2bb5aSSagar Dharia mutex_lock(&ctrl->lock); 40846a2bb5aSSagar Dharia if (ctrl->get_laddr) { 40946a2bb5aSSagar Dharia ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr); 41046a2bb5aSSagar Dharia if (ret < 0) 41146a2bb5aSSagar Dharia goto err; 41246a2bb5aSSagar Dharia } else if (report_present) { 41346a2bb5aSSagar Dharia ret = ida_simple_get(&ctrl->laddr_ida, 41446a2bb5aSSagar Dharia 0, SLIM_LA_MANAGER - 1, GFP_KERNEL); 41546a2bb5aSSagar Dharia if (ret < 0) 41646a2bb5aSSagar Dharia goto err; 41746a2bb5aSSagar Dharia 41846a2bb5aSSagar Dharia laddr = ret; 41946a2bb5aSSagar Dharia } else { 42046a2bb5aSSagar Dharia ret = -EINVAL; 42146a2bb5aSSagar Dharia goto err; 42246a2bb5aSSagar Dharia } 42346a2bb5aSSagar Dharia 42446a2bb5aSSagar Dharia if (ctrl->set_laddr) { 42546a2bb5aSSagar Dharia ret = ctrl->set_laddr(ctrl, &sbdev->e_addr, laddr); 42646a2bb5aSSagar Dharia if (ret) { 42746a2bb5aSSagar Dharia ret = -EINVAL; 42846a2bb5aSSagar Dharia goto err; 42946a2bb5aSSagar Dharia } 43046a2bb5aSSagar Dharia } 43146a2bb5aSSagar Dharia 43246a2bb5aSSagar Dharia sbdev->laddr = laddr; 43346a2bb5aSSagar Dharia sbdev->is_laddr_valid = true; 43446a2bb5aSSagar Dharia 43546a2bb5aSSagar Dharia slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP); 43646a2bb5aSSagar Dharia 43746a2bb5aSSagar Dharia dev_dbg(ctrl->dev, "setting slimbus l-addr:%x, ea:%x,%x,%x,%x\n", 43846a2bb5aSSagar Dharia laddr, sbdev->e_addr.manf_id, sbdev->e_addr.prod_code, 43946a2bb5aSSagar Dharia sbdev->e_addr.dev_index, sbdev->e_addr.instance); 44046a2bb5aSSagar Dharia 44146a2bb5aSSagar Dharia err: 44246a2bb5aSSagar Dharia mutex_unlock(&ctrl->lock); 44346a2bb5aSSagar Dharia return ret; 44446a2bb5aSSagar Dharia 44546a2bb5aSSagar Dharia } 44646a2bb5aSSagar Dharia 44746a2bb5aSSagar Dharia /** 44846a2bb5aSSagar Dharia * slim_device_report_present() - Report enumerated device. 44946a2bb5aSSagar Dharia * 45046a2bb5aSSagar Dharia * @ctrl: Controller with which device is enumerated. 45146a2bb5aSSagar Dharia * @e_addr: Enumeration address of the device. 45246a2bb5aSSagar Dharia * @laddr: Return logical address (if valid flag is false) 45346a2bb5aSSagar Dharia * 45446a2bb5aSSagar Dharia * Called by controller in response to REPORT_PRESENT. Framework will assign 45546a2bb5aSSagar Dharia * a logical address to this enumeration address. 45646a2bb5aSSagar Dharia * Function returns -EXFULL to indicate that all logical addresses are already 45746a2bb5aSSagar Dharia * taken. 45846a2bb5aSSagar Dharia */ 45946a2bb5aSSagar Dharia int slim_device_report_present(struct slim_controller *ctrl, 46046a2bb5aSSagar Dharia struct slim_eaddr *e_addr, u8 *laddr) 46146a2bb5aSSagar Dharia { 46246a2bb5aSSagar Dharia struct slim_device *sbdev; 46346a2bb5aSSagar Dharia int ret; 46446a2bb5aSSagar Dharia 4654b14e62aSSagar Dharia ret = pm_runtime_get_sync(ctrl->dev); 4664b14e62aSSagar Dharia 4674b14e62aSSagar Dharia if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) { 4684b14e62aSSagar Dharia dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n", 4694b14e62aSSagar Dharia ctrl->sched.clk_state, ret); 4704b14e62aSSagar Dharia goto slimbus_not_active; 4714b14e62aSSagar Dharia } 4724b14e62aSSagar Dharia 47346a2bb5aSSagar Dharia sbdev = slim_get_device(ctrl, e_addr); 47446a2bb5aSSagar Dharia if (IS_ERR(sbdev)) 47546a2bb5aSSagar Dharia return -ENODEV; 47646a2bb5aSSagar Dharia 47746a2bb5aSSagar Dharia if (sbdev->is_laddr_valid) { 47846a2bb5aSSagar Dharia *laddr = sbdev->laddr; 47946a2bb5aSSagar Dharia return 0; 48046a2bb5aSSagar Dharia } 48146a2bb5aSSagar Dharia 48246a2bb5aSSagar Dharia ret = slim_device_alloc_laddr(sbdev, true); 48346a2bb5aSSagar Dharia 4844b14e62aSSagar Dharia slimbus_not_active: 4854b14e62aSSagar Dharia pm_runtime_mark_last_busy(ctrl->dev); 4864b14e62aSSagar Dharia pm_runtime_put_autosuspend(ctrl->dev); 48746a2bb5aSSagar Dharia return ret; 48846a2bb5aSSagar Dharia } 48946a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_device_report_present); 49046a2bb5aSSagar Dharia 49146a2bb5aSSagar Dharia /** 49246a2bb5aSSagar Dharia * slim_get_logical_addr() - get/allocate logical address of a SLIMbus device. 49346a2bb5aSSagar Dharia * 49446a2bb5aSSagar Dharia * @sbdev: client handle requesting the address. 49546a2bb5aSSagar Dharia * 49646a2bb5aSSagar Dharia * Return: zero if a logical address is valid or a new logical address 49746a2bb5aSSagar Dharia * has been assigned. error code in case of error. 49846a2bb5aSSagar Dharia */ 49946a2bb5aSSagar Dharia int slim_get_logical_addr(struct slim_device *sbdev) 50046a2bb5aSSagar Dharia { 50146a2bb5aSSagar Dharia if (!sbdev->is_laddr_valid) 50246a2bb5aSSagar Dharia return slim_device_alloc_laddr(sbdev, false); 50346a2bb5aSSagar Dharia 50446a2bb5aSSagar Dharia return 0; 50546a2bb5aSSagar Dharia } 50646a2bb5aSSagar Dharia EXPORT_SYMBOL_GPL(slim_get_logical_addr); 50746a2bb5aSSagar Dharia 5083648e78eSSagar Dharia static void __exit slimbus_exit(void) 5093648e78eSSagar Dharia { 5103648e78eSSagar Dharia bus_unregister(&slimbus_bus); 5113648e78eSSagar Dharia } 5123648e78eSSagar Dharia module_exit(slimbus_exit); 5133648e78eSSagar Dharia 5143648e78eSSagar Dharia static int __init slimbus_init(void) 5153648e78eSSagar Dharia { 5163648e78eSSagar Dharia return bus_register(&slimbus_bus); 5173648e78eSSagar Dharia } 5183648e78eSSagar Dharia postcore_initcall(slimbus_init); 5193648e78eSSagar Dharia 5203648e78eSSagar Dharia MODULE_LICENSE("GPL v2"); 5213648e78eSSagar Dharia MODULE_DESCRIPTION("SLIMbus core"); 522