linux/drivers/slimbus/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2011-2017, The Linux Foundation
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/errno.h>
   8#include <linux/slab.h>
   9#include <linux/init.h>
  10#include <linux/idr.h>
  11#include <linux/of.h>
  12#include <linux/of_device.h>
  13#include <linux/pm_runtime.h>
  14#include <linux/slimbus.h>
  15#include "slimbus.h"
  16
  17static DEFINE_IDA(ctrl_ida);
  18
  19static const struct slim_device_id *slim_match(const struct slim_device_id *id,
  20                                               const struct slim_device *sbdev)
  21{
  22        while (id->manf_id != 0 || id->prod_code != 0) {
  23                if (id->manf_id == sbdev->e_addr.manf_id &&
  24                    id->prod_code == sbdev->e_addr.prod_code &&
  25                    id->dev_index == sbdev->e_addr.dev_index &&
  26                    id->instance == sbdev->e_addr.instance)
  27                        return id;
  28                id++;
  29        }
  30        return NULL;
  31}
  32
  33static int slim_device_match(struct device *dev, struct device_driver *drv)
  34{
  35        struct slim_device *sbdev = to_slim_device(dev);
  36        struct slim_driver *sbdrv = to_slim_driver(drv);
  37
  38        /* Attempt an OF style match first */
  39        if (of_driver_match_device(dev, drv))
  40                return 1;
  41
  42        return !!slim_match(sbdrv->id_table, sbdev);
  43}
  44
  45static void slim_device_update_status(struct slim_device *sbdev,
  46                                      enum slim_device_status status)
  47{
  48        struct slim_driver *sbdrv;
  49
  50        if (sbdev->status == status)
  51                return;
  52
  53        sbdev->status = status;
  54        if (!sbdev->dev.driver)
  55                return;
  56
  57        sbdrv = to_slim_driver(sbdev->dev.driver);
  58        if (sbdrv->device_status)
  59                sbdrv->device_status(sbdev, sbdev->status);
  60}
  61
  62static int slim_device_probe(struct device *dev)
  63{
  64        struct slim_device      *sbdev = to_slim_device(dev);
  65        struct slim_driver      *sbdrv = to_slim_driver(dev->driver);
  66        int ret;
  67
  68        ret = sbdrv->probe(sbdev);
  69        if (ret)
  70                return ret;
  71
  72        /* try getting the logical address after probe */
  73        ret = slim_get_logical_addr(sbdev);
  74        if (!ret) {
  75                slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
  76        } else {
  77                dev_err(&sbdev->dev, "Failed to get logical address\n");
  78                ret = -EPROBE_DEFER;
  79        }
  80
  81        return ret;
  82}
  83
  84static void slim_device_remove(struct device *dev)
  85{
  86        struct slim_device *sbdev = to_slim_device(dev);
  87        struct slim_driver *sbdrv;
  88
  89        if (dev->driver) {
  90                sbdrv = to_slim_driver(dev->driver);
  91                if (sbdrv->remove)
  92                        sbdrv->remove(sbdev);
  93        }
  94}
  95
  96static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
  97{
  98        struct slim_device *sbdev = to_slim_device(dev);
  99
 100        return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
 101}
 102
 103struct bus_type slimbus_bus = {
 104        .name           = "slimbus",
 105        .match          = slim_device_match,
 106        .probe          = slim_device_probe,
 107        .remove         = slim_device_remove,
 108        .uevent         = slim_device_uevent,
 109};
 110EXPORT_SYMBOL_GPL(slimbus_bus);
 111
 112/*
 113 * __slim_driver_register() - Client driver registration with SLIMbus
 114 *
 115 * @drv:Client driver to be associated with client-device.
 116 * @owner: owning module/driver
 117 *
 118 * This API will register the client driver with the SLIMbus
 119 * It is called from the driver's module-init function.
 120 */
 121int __slim_driver_register(struct slim_driver *drv, struct module *owner)
 122{
 123        /* ID table and probe are mandatory */
 124        if (!(drv->driver.of_match_table || drv->id_table) || !drv->probe)
 125                return -EINVAL;
 126
 127        drv->driver.bus = &slimbus_bus;
 128        drv->driver.owner = owner;
 129
 130        return driver_register(&drv->driver);
 131}
 132EXPORT_SYMBOL_GPL(__slim_driver_register);
 133
 134/*
 135 * slim_driver_unregister() - Undo effect of slim_driver_register
 136 *
 137 * @drv: Client driver to be unregistered
 138 */
 139void slim_driver_unregister(struct slim_driver *drv)
 140{
 141        driver_unregister(&drv->driver);
 142}
 143EXPORT_SYMBOL_GPL(slim_driver_unregister);
 144
 145static void slim_dev_release(struct device *dev)
 146{
 147        struct slim_device *sbdev = to_slim_device(dev);
 148
 149        kfree(sbdev);
 150}
 151
 152static int slim_add_device(struct slim_controller *ctrl,
 153                           struct slim_device *sbdev,
 154                           struct device_node *node)
 155{
 156        sbdev->dev.bus = &slimbus_bus;
 157        sbdev->dev.parent = ctrl->dev;
 158        sbdev->dev.release = slim_dev_release;
 159        sbdev->dev.driver = NULL;
 160        sbdev->ctrl = ctrl;
 161        INIT_LIST_HEAD(&sbdev->stream_list);
 162        spin_lock_init(&sbdev->stream_list_lock);
 163        sbdev->dev.of_node = of_node_get(node);
 164        sbdev->dev.fwnode = of_fwnode_handle(node);
 165
 166        dev_set_name(&sbdev->dev, "%x:%x:%x:%x",
 167                                  sbdev->e_addr.manf_id,
 168                                  sbdev->e_addr.prod_code,
 169                                  sbdev->e_addr.dev_index,
 170                                  sbdev->e_addr.instance);
 171
 172        return device_register(&sbdev->dev);
 173}
 174
 175static struct slim_device *slim_alloc_device(struct slim_controller *ctrl,
 176                                             struct slim_eaddr *eaddr,
 177                                             struct device_node *node)
 178{
 179        struct slim_device *sbdev;
 180        int ret;
 181
 182        sbdev = kzalloc(sizeof(*sbdev), GFP_KERNEL);
 183        if (!sbdev)
 184                return NULL;
 185
 186        sbdev->e_addr = *eaddr;
 187        ret = slim_add_device(ctrl, sbdev, node);
 188        if (ret) {
 189                put_device(&sbdev->dev);
 190                return NULL;
 191        }
 192
 193        return sbdev;
 194}
 195
 196static void of_register_slim_devices(struct slim_controller *ctrl)
 197{
 198        struct device *dev = ctrl->dev;
 199        struct device_node *node;
 200
 201        if (!ctrl->dev->of_node)
 202                return;
 203
 204        for_each_child_of_node(ctrl->dev->of_node, node) {
 205                struct slim_device *sbdev;
 206                struct slim_eaddr e_addr;
 207                const char *compat = NULL;
 208                int reg[2], ret;
 209                int manf_id, prod_code;
 210
 211                compat = of_get_property(node, "compatible", NULL);
 212                if (!compat)
 213                        continue;
 214
 215                ret = sscanf(compat, "slim%x,%x", &manf_id, &prod_code);
 216                if (ret != 2) {
 217                        dev_err(dev, "Manf ID & Product code not found %s\n",
 218                                compat);
 219                        continue;
 220                }
 221
 222                ret = of_property_read_u32_array(node, "reg", reg, 2);
 223                if (ret) {
 224                        dev_err(dev, "Device and Instance id not found:%d\n",
 225                                ret);
 226                        continue;
 227                }
 228
 229                e_addr.dev_index = reg[0];
 230                e_addr.instance = reg[1];
 231                e_addr.manf_id = manf_id;
 232                e_addr.prod_code = prod_code;
 233
 234                sbdev = slim_alloc_device(ctrl, &e_addr, node);
 235                if (!sbdev)
 236                        continue;
 237        }
 238}
 239
 240/*
 241 * slim_register_controller() - Controller bring-up and registration.
 242 *
 243 * @ctrl: Controller to be registered.
 244 *
 245 * A controller is registered with the framework using this API.
 246 * If devices on a controller were registered before controller,
 247 * this will make sure that they get probed when controller is up
 248 */
 249int slim_register_controller(struct slim_controller *ctrl)
 250{
 251        int id;
 252
 253        id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
 254        if (id < 0)
 255                return id;
 256
 257        ctrl->id = id;
 258
 259        if (!ctrl->min_cg)
 260                ctrl->min_cg = SLIM_MIN_CLK_GEAR;
 261        if (!ctrl->max_cg)
 262                ctrl->max_cg = SLIM_MAX_CLK_GEAR;
 263
 264        ida_init(&ctrl->laddr_ida);
 265        idr_init(&ctrl->tid_idr);
 266        mutex_init(&ctrl->lock);
 267        mutex_init(&ctrl->sched.m_reconf);
 268        init_completion(&ctrl->sched.pause_comp);
 269        spin_lock_init(&ctrl->txn_lock);
 270
 271        dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n",
 272                ctrl->name, ctrl->dev);
 273
 274        of_register_slim_devices(ctrl);
 275
 276        return 0;
 277}
 278EXPORT_SYMBOL_GPL(slim_register_controller);
 279
 280/* slim_remove_device: Remove the effect of slim_add_device() */
 281static void slim_remove_device(struct slim_device *sbdev)
 282{
 283        of_node_put(sbdev->dev.of_node);
 284        device_unregister(&sbdev->dev);
 285}
 286
 287static int slim_ctrl_remove_device(struct device *dev, void *null)
 288{
 289        slim_remove_device(to_slim_device(dev));
 290        return 0;
 291}
 292
 293/**
 294 * slim_unregister_controller() - Controller tear-down.
 295 *
 296 * @ctrl: Controller to tear-down.
 297 */
 298int slim_unregister_controller(struct slim_controller *ctrl)
 299{
 300        /* Remove all clients */
 301        device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device);
 302        ida_simple_remove(&ctrl_ida, ctrl->id);
 303
 304        return 0;
 305}
 306EXPORT_SYMBOL_GPL(slim_unregister_controller);
 307
 308/**
 309 * slim_report_absent() - Controller calls this function when a device
 310 *      reports absent, OR when the device cannot be communicated with
 311 *
 312 * @sbdev: Device that cannot be reached, or sent report absent
 313 */
 314void slim_report_absent(struct slim_device *sbdev)
 315{
 316        struct slim_controller *ctrl = sbdev->ctrl;
 317
 318        if (!ctrl)
 319                return;
 320
 321        /* invalidate logical addresses */
 322        mutex_lock(&ctrl->lock);
 323        sbdev->is_laddr_valid = false;
 324        mutex_unlock(&ctrl->lock);
 325        if (!ctrl->get_laddr)
 326                ida_simple_remove(&ctrl->laddr_ida, sbdev->laddr);
 327        slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_DOWN);
 328}
 329EXPORT_SYMBOL_GPL(slim_report_absent);
 330
 331static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b)
 332{
 333        return (a->manf_id == b->manf_id &&
 334                a->prod_code == b->prod_code &&
 335                a->dev_index == b->dev_index &&
 336                a->instance == b->instance);
 337}
 338
 339static int slim_match_dev(struct device *dev, void *data)
 340{
 341        struct slim_eaddr *e_addr = data;
 342        struct slim_device *sbdev = to_slim_device(dev);
 343
 344        return slim_eaddr_equal(&sbdev->e_addr, e_addr);
 345}
 346
 347static struct slim_device *find_slim_device(struct slim_controller *ctrl,
 348                                            struct slim_eaddr *eaddr)
 349{
 350        struct slim_device *sbdev;
 351        struct device *dev;
 352
 353        dev = device_find_child(ctrl->dev, eaddr, slim_match_dev);
 354        if (dev) {
 355                sbdev = to_slim_device(dev);
 356                return sbdev;
 357        }
 358
 359        return NULL;
 360}
 361
 362/**
 363 * slim_get_device() - get handle to a device.
 364 *
 365 * @ctrl: Controller on which this device will be added/queried
 366 * @e_addr: Enumeration address of the device to be queried
 367 *
 368 * Return: pointer to a device if it has already reported. Creates a new
 369 * device and returns pointer to it if the device has not yet enumerated.
 370 */
 371struct slim_device *slim_get_device(struct slim_controller *ctrl,
 372                                    struct slim_eaddr *e_addr)
 373{
 374        struct slim_device *sbdev;
 375
 376        sbdev = find_slim_device(ctrl, e_addr);
 377        if (!sbdev) {
 378                sbdev = slim_alloc_device(ctrl, e_addr, NULL);
 379                if (!sbdev)
 380                        return ERR_PTR(-ENOMEM);
 381        }
 382
 383        return sbdev;
 384}
 385EXPORT_SYMBOL_GPL(slim_get_device);
 386
 387static int of_slim_match_dev(struct device *dev, void *data)
 388{
 389        struct device_node *np = data;
 390        struct slim_device *sbdev = to_slim_device(dev);
 391
 392        return (sbdev->dev.of_node == np);
 393}
 394
 395static struct slim_device *of_find_slim_device(struct slim_controller *ctrl,
 396                                               struct device_node *np)
 397{
 398        struct slim_device *sbdev;
 399        struct device *dev;
 400
 401        dev = device_find_child(ctrl->dev, np, of_slim_match_dev);
 402        if (dev) {
 403                sbdev = to_slim_device(dev);
 404                return sbdev;
 405        }
 406
 407        return NULL;
 408}
 409
 410/**
 411 * of_slim_get_device() - get handle to a device using dt node.
 412 *
 413 * @ctrl: Controller on which this device will be added/queried
 414 * @np: node pointer to device
 415 *
 416 * Return: pointer to a device if it has already reported. Creates a new
 417 * device and returns pointer to it if the device has not yet enumerated.
 418 */
 419struct slim_device *of_slim_get_device(struct slim_controller *ctrl,
 420                                       struct device_node *np)
 421{
 422        return of_find_slim_device(ctrl, np);
 423}
 424EXPORT_SYMBOL_GPL(of_slim_get_device);
 425
 426static int slim_device_alloc_laddr(struct slim_device *sbdev,
 427                                   bool report_present)
 428{
 429        struct slim_controller *ctrl = sbdev->ctrl;
 430        u8 laddr;
 431        int ret;
 432
 433        mutex_lock(&ctrl->lock);
 434        if (ctrl->get_laddr) {
 435                ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr);
 436                if (ret < 0)
 437                        goto err;
 438        } else if (report_present) {
 439                ret = ida_simple_get(&ctrl->laddr_ida,
 440                                     0, SLIM_LA_MANAGER - 1, GFP_KERNEL);
 441                if (ret < 0)
 442                        goto err;
 443
 444                laddr = ret;
 445        } else {
 446                ret = -EINVAL;
 447                goto err;
 448        }
 449
 450        if (ctrl->set_laddr) {
 451                ret = ctrl->set_laddr(ctrl, &sbdev->e_addr, laddr);
 452                if (ret) {
 453                        ret = -EINVAL;
 454                        goto err;
 455                }
 456        }
 457
 458        sbdev->laddr = laddr;
 459        sbdev->is_laddr_valid = true;
 460        mutex_unlock(&ctrl->lock);
 461
 462        slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
 463
 464        dev_dbg(ctrl->dev, "setting slimbus l-addr:%x, ea:%x,%x,%x,%x\n",
 465                laddr, sbdev->e_addr.manf_id, sbdev->e_addr.prod_code,
 466                sbdev->e_addr.dev_index, sbdev->e_addr.instance);
 467
 468        return 0;
 469
 470err:
 471        mutex_unlock(&ctrl->lock);
 472        return ret;
 473
 474}
 475
 476/**
 477 * slim_device_report_present() - Report enumerated device.
 478 *
 479 * @ctrl: Controller with which device is enumerated.
 480 * @e_addr: Enumeration address of the device.
 481 * @laddr: Return logical address (if valid flag is false)
 482 *
 483 * Called by controller in response to REPORT_PRESENT. Framework will assign
 484 * a logical address to this enumeration address.
 485 * Function returns -EXFULL to indicate that all logical addresses are already
 486 * taken.
 487 */
 488int slim_device_report_present(struct slim_controller *ctrl,
 489                               struct slim_eaddr *e_addr, u8 *laddr)
 490{
 491        struct slim_device *sbdev;
 492        int ret;
 493
 494        ret = pm_runtime_get_sync(ctrl->dev);
 495
 496        if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
 497                dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n",
 498                                    ctrl->sched.clk_state, ret);
 499                goto slimbus_not_active;
 500        }
 501
 502        sbdev = slim_get_device(ctrl, e_addr);
 503        if (IS_ERR(sbdev))
 504                return -ENODEV;
 505
 506        if (sbdev->is_laddr_valid) {
 507                *laddr = sbdev->laddr;
 508                return 0;
 509        }
 510
 511        ret = slim_device_alloc_laddr(sbdev, true);
 512
 513slimbus_not_active:
 514        pm_runtime_mark_last_busy(ctrl->dev);
 515        pm_runtime_put_autosuspend(ctrl->dev);
 516        return ret;
 517}
 518EXPORT_SYMBOL_GPL(slim_device_report_present);
 519
 520/**
 521 * slim_get_logical_addr() - get/allocate logical address of a SLIMbus device.
 522 *
 523 * @sbdev: client handle requesting the address.
 524 *
 525 * Return: zero if a logical address is valid or a new logical address
 526 * has been assigned. error code in case of error.
 527 */
 528int slim_get_logical_addr(struct slim_device *sbdev)
 529{
 530        if (!sbdev->is_laddr_valid)
 531                return slim_device_alloc_laddr(sbdev, false);
 532
 533        return 0;
 534}
 535EXPORT_SYMBOL_GPL(slim_get_logical_addr);
 536
 537static void __exit slimbus_exit(void)
 538{
 539        bus_unregister(&slimbus_bus);
 540}
 541module_exit(slimbus_exit);
 542
 543static int __init slimbus_init(void)
 544{
 545        return bus_register(&slimbus_bus);
 546}
 547postcore_initcall(slimbus_init);
 548
 549MODULE_LICENSE("GPL v2");
 550MODULE_DESCRIPTION("SLIMbus core");
 551