linux/drivers/hsi/hsi_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * HSI core.
   4 *
   5 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
   6 *
   7 * Contact: Carlos Chinea <carlos.chinea@nokia.com>
   8 */
   9#include <linux/hsi/hsi.h>
  10#include <linux/compiler.h>
  11#include <linux/list.h>
  12#include <linux/kobject.h>
  13#include <linux/slab.h>
  14#include <linux/string.h>
  15#include <linux/notifier.h>
  16#include <linux/of.h>
  17#include <linux/of_device.h>
  18#include "hsi_core.h"
  19
  20static ssize_t modalias_show(struct device *dev,
  21                        struct device_attribute *a __maybe_unused, char *buf)
  22{
  23        return sprintf(buf, "hsi:%s\n", dev_name(dev));
  24}
  25static DEVICE_ATTR_RO(modalias);
  26
  27static struct attribute *hsi_bus_dev_attrs[] = {
  28        &dev_attr_modalias.attr,
  29        NULL,
  30};
  31ATTRIBUTE_GROUPS(hsi_bus_dev);
  32
  33static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
  34{
  35        add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev));
  36
  37        return 0;
  38}
  39
  40static int hsi_bus_match(struct device *dev, struct device_driver *driver)
  41{
  42        if (of_driver_match_device(dev, driver))
  43                return true;
  44
  45        if (strcmp(dev_name(dev), driver->name) == 0)
  46                return true;
  47
  48        return false;
  49}
  50
  51static struct bus_type hsi_bus_type = {
  52        .name           = "hsi",
  53        .dev_groups     = hsi_bus_dev_groups,
  54        .match          = hsi_bus_match,
  55        .uevent         = hsi_bus_uevent,
  56};
  57
  58static void hsi_client_release(struct device *dev)
  59{
  60        struct hsi_client *cl = to_hsi_client(dev);
  61
  62        kfree(cl->tx_cfg.channels);
  63        kfree(cl->rx_cfg.channels);
  64        kfree(cl);
  65}
  66
  67struct hsi_client *hsi_new_client(struct hsi_port *port,
  68                                                struct hsi_board_info *info)
  69{
  70        struct hsi_client *cl;
  71        size_t size;
  72
  73        cl = kzalloc(sizeof(*cl), GFP_KERNEL);
  74        if (!cl)
  75                goto err;
  76
  77        cl->tx_cfg = info->tx_cfg;
  78        if (cl->tx_cfg.channels) {
  79                size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels);
  80                cl->tx_cfg.channels = kmemdup(info->tx_cfg.channels, size,
  81                                              GFP_KERNEL);
  82                if (!cl->tx_cfg.channels)
  83                        goto err_tx;
  84        }
  85
  86        cl->rx_cfg = info->rx_cfg;
  87        if (cl->rx_cfg.channels) {
  88                size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels);
  89                cl->rx_cfg.channels = kmemdup(info->rx_cfg.channels, size,
  90                                              GFP_KERNEL);
  91                if (!cl->rx_cfg.channels)
  92                        goto err_rx;
  93        }
  94
  95        cl->device.bus = &hsi_bus_type;
  96        cl->device.parent = &port->device;
  97        cl->device.release = hsi_client_release;
  98        dev_set_name(&cl->device, "%s", info->name);
  99        cl->device.platform_data = info->platform_data;
 100        if (info->archdata)
 101                cl->device.archdata = *info->archdata;
 102        if (device_register(&cl->device) < 0) {
 103                pr_err("hsi: failed to register client: %s\n", info->name);
 104                put_device(&cl->device);
 105        }
 106
 107        return cl;
 108err_rx:
 109        kfree(cl->tx_cfg.channels);
 110err_tx:
 111        kfree(cl);
 112err:
 113        return NULL;
 114}
 115EXPORT_SYMBOL_GPL(hsi_new_client);
 116
 117static void hsi_scan_board_info(struct hsi_controller *hsi)
 118{
 119        struct hsi_cl_info *cl_info;
 120        struct hsi_port *p;
 121
 122        list_for_each_entry(cl_info, &hsi_board_list, list)
 123                if (cl_info->info.hsi_id == hsi->id) {
 124                        p = hsi_find_port_num(hsi, cl_info->info.port);
 125                        if (!p)
 126                                continue;
 127                        hsi_new_client(p, &cl_info->info);
 128                }
 129}
 130
 131#ifdef CONFIG_OF
 132static struct hsi_board_info hsi_char_dev_info = {
 133        .name = "hsi_char",
 134};
 135
 136static int hsi_of_property_parse_mode(struct device_node *client, char *name,
 137                                      unsigned int *result)
 138{
 139        const char *mode;
 140        int err;
 141
 142        err = of_property_read_string(client, name, &mode);
 143        if (err < 0)
 144                return err;
 145
 146        if (strcmp(mode, "stream") == 0)
 147                *result = HSI_MODE_STREAM;
 148        else if (strcmp(mode, "frame") == 0)
 149                *result = HSI_MODE_FRAME;
 150        else
 151                return -EINVAL;
 152
 153        return 0;
 154}
 155
 156static int hsi_of_property_parse_flow(struct device_node *client, char *name,
 157                                      unsigned int *result)
 158{
 159        const char *flow;
 160        int err;
 161
 162        err = of_property_read_string(client, name, &flow);
 163        if (err < 0)
 164                return err;
 165
 166        if (strcmp(flow, "synchronized") == 0)
 167                *result = HSI_FLOW_SYNC;
 168        else if (strcmp(flow, "pipeline") == 0)
 169                *result = HSI_FLOW_PIPE;
 170        else
 171                return -EINVAL;
 172
 173        return 0;
 174}
 175
 176static int hsi_of_property_parse_arb_mode(struct device_node *client,
 177                                          char *name, unsigned int *result)
 178{
 179        const char *arb_mode;
 180        int err;
 181
 182        err = of_property_read_string(client, name, &arb_mode);
 183        if (err < 0)
 184                return err;
 185
 186        if (strcmp(arb_mode, "round-robin") == 0)
 187                *result = HSI_ARB_RR;
 188        else if (strcmp(arb_mode, "priority") == 0)
 189                *result = HSI_ARB_PRIO;
 190        else
 191                return -EINVAL;
 192
 193        return 0;
 194}
 195
 196static void hsi_add_client_from_dt(struct hsi_port *port,
 197                                                struct device_node *client)
 198{
 199        struct hsi_client *cl;
 200        struct hsi_channel channel;
 201        struct property *prop;
 202        char name[32];
 203        int length, cells, err, i, max_chan, mode;
 204
 205        cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 206        if (!cl)
 207                return;
 208
 209        err = of_modalias_node(client, name, sizeof(name));
 210        if (err)
 211                goto err;
 212
 213        err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
 214        if (err) {
 215                err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
 216                                                 &cl->rx_cfg.mode);
 217                if (err)
 218                        goto err;
 219
 220                err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
 221                                                 &cl->tx_cfg.mode);
 222                if (err)
 223                        goto err;
 224        } else {
 225                cl->rx_cfg.mode = mode;
 226                cl->tx_cfg.mode = mode;
 227        }
 228
 229        err = of_property_read_u32(client, "hsi-speed-kbps",
 230                                   &cl->tx_cfg.speed);
 231        if (err)
 232                goto err;
 233        cl->rx_cfg.speed = cl->tx_cfg.speed;
 234
 235        err = hsi_of_property_parse_flow(client, "hsi-flow",
 236                                         &cl->rx_cfg.flow);
 237        if (err)
 238                goto err;
 239
 240        err = hsi_of_property_parse_arb_mode(client, "hsi-arb-mode",
 241                                             &cl->rx_cfg.arb_mode);
 242        if (err)
 243                goto err;
 244
 245        prop = of_find_property(client, "hsi-channel-ids", &length);
 246        if (!prop) {
 247                err = -EINVAL;
 248                goto err;
 249        }
 250
 251        cells = length / sizeof(u32);
 252
 253        cl->rx_cfg.num_channels = cells;
 254        cl->tx_cfg.num_channels = cells;
 255        cl->rx_cfg.channels = kcalloc(cells, sizeof(channel), GFP_KERNEL);
 256        if (!cl->rx_cfg.channels) {
 257                err = -ENOMEM;
 258                goto err;
 259        }
 260
 261        cl->tx_cfg.channels = kcalloc(cells, sizeof(channel), GFP_KERNEL);
 262        if (!cl->tx_cfg.channels) {
 263                err = -ENOMEM;
 264                goto err2;
 265        }
 266
 267        max_chan = 0;
 268        for (i = 0; i < cells; i++) {
 269                err = of_property_read_u32_index(client, "hsi-channel-ids", i,
 270                                                 &channel.id);
 271                if (err)
 272                        goto err3;
 273
 274                err = of_property_read_string_index(client, "hsi-channel-names",
 275                                                    i, &channel.name);
 276                if (err)
 277                        channel.name = NULL;
 278
 279                if (channel.id > max_chan)
 280                        max_chan = channel.id;
 281
 282                cl->rx_cfg.channels[i] = channel;
 283                cl->tx_cfg.channels[i] = channel;
 284        }
 285
 286        cl->rx_cfg.num_hw_channels = max_chan + 1;
 287        cl->tx_cfg.num_hw_channels = max_chan + 1;
 288
 289        cl->device.bus = &hsi_bus_type;
 290        cl->device.parent = &port->device;
 291        cl->device.release = hsi_client_release;
 292        cl->device.of_node = client;
 293
 294        dev_set_name(&cl->device, "%s", name);
 295        if (device_register(&cl->device) < 0) {
 296                pr_err("hsi: failed to register client: %s\n", name);
 297                put_device(&cl->device);
 298        }
 299
 300        return;
 301
 302err3:
 303        kfree(cl->tx_cfg.channels);
 304err2:
 305        kfree(cl->rx_cfg.channels);
 306err:
 307        kfree(cl);
 308        pr_err("hsi client: missing or incorrect of property: err=%d\n", err);
 309}
 310
 311void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients)
 312{
 313        struct device_node *child;
 314
 315        /* register hsi-char device */
 316        hsi_new_client(port, &hsi_char_dev_info);
 317
 318        for_each_available_child_of_node(clients, child)
 319                hsi_add_client_from_dt(port, child);
 320}
 321EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt);
 322#endif
 323
 324int hsi_remove_client(struct device *dev, void *data __maybe_unused)
 325{
 326        device_unregister(dev);
 327
 328        return 0;
 329}
 330EXPORT_SYMBOL_GPL(hsi_remove_client);
 331
 332static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
 333{
 334        device_for_each_child(dev, NULL, hsi_remove_client);
 335        device_unregister(dev);
 336
 337        return 0;
 338}
 339
 340static void hsi_controller_release(struct device *dev)
 341{
 342        struct hsi_controller *hsi = to_hsi_controller(dev);
 343
 344        kfree(hsi->port);
 345        kfree(hsi);
 346}
 347
 348static void hsi_port_release(struct device *dev)
 349{
 350        kfree(to_hsi_port(dev));
 351}
 352
 353/**
 354 * hsi_port_unregister_clients - Unregister an HSI port
 355 * @port: The HSI port to unregister
 356 */
 357void hsi_port_unregister_clients(struct hsi_port *port)
 358{
 359        device_for_each_child(&port->device, NULL, hsi_remove_client);
 360}
 361EXPORT_SYMBOL_GPL(hsi_port_unregister_clients);
 362
 363/**
 364 * hsi_unregister_controller - Unregister an HSI controller
 365 * @hsi: The HSI controller to register
 366 */
 367void hsi_unregister_controller(struct hsi_controller *hsi)
 368{
 369        device_for_each_child(&hsi->device, NULL, hsi_remove_port);
 370        device_unregister(&hsi->device);
 371}
 372EXPORT_SYMBOL_GPL(hsi_unregister_controller);
 373
 374/**
 375 * hsi_register_controller - Register an HSI controller and its ports
 376 * @hsi: The HSI controller to register
 377 *
 378 * Returns -errno on failure, 0 on success.
 379 */
 380int hsi_register_controller(struct hsi_controller *hsi)
 381{
 382        unsigned int i;
 383        int err;
 384
 385        err = device_add(&hsi->device);
 386        if (err < 0)
 387                return err;
 388        for (i = 0; i < hsi->num_ports; i++) {
 389                hsi->port[i]->device.parent = &hsi->device;
 390                err = device_add(&hsi->port[i]->device);
 391                if (err < 0)
 392                        goto out;
 393        }
 394        /* Populate HSI bus with HSI clients */
 395        hsi_scan_board_info(hsi);
 396
 397        return 0;
 398out:
 399        while (i-- > 0)
 400                device_del(&hsi->port[i]->device);
 401        device_del(&hsi->device);
 402
 403        return err;
 404}
 405EXPORT_SYMBOL_GPL(hsi_register_controller);
 406
 407/**
 408 * hsi_register_client_driver - Register an HSI client to the HSI bus
 409 * @drv: HSI client driver to register
 410 *
 411 * Returns -errno on failure, 0 on success.
 412 */
 413int hsi_register_client_driver(struct hsi_client_driver *drv)
 414{
 415        drv->driver.bus = &hsi_bus_type;
 416
 417        return driver_register(&drv->driver);
 418}
 419EXPORT_SYMBOL_GPL(hsi_register_client_driver);
 420
 421static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)
 422{
 423        return 0;
 424}
 425
 426static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
 427{
 428        return 0;
 429}
 430
 431/**
 432 * hsi_put_controller - Free an HSI controller
 433 *
 434 * @hsi: Pointer to the HSI controller to freed
 435 *
 436 * HSI controller drivers should only use this function if they need
 437 * to free their allocated hsi_controller structures before a successful
 438 * call to hsi_register_controller. Other use is not allowed.
 439 */
 440void hsi_put_controller(struct hsi_controller *hsi)
 441{
 442        unsigned int i;
 443
 444        if (!hsi)
 445                return;
 446
 447        for (i = 0; i < hsi->num_ports; i++)
 448                if (hsi->port && hsi->port[i])
 449                        put_device(&hsi->port[i]->device);
 450        put_device(&hsi->device);
 451}
 452EXPORT_SYMBOL_GPL(hsi_put_controller);
 453
 454/**
 455 * hsi_alloc_controller - Allocate an HSI controller and its ports
 456 * @n_ports: Number of ports on the HSI controller
 457 * @flags: Kernel allocation flags
 458 *
 459 * Return NULL on failure or a pointer to an hsi_controller on success.
 460 */
 461struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
 462{
 463        struct hsi_controller   *hsi;
 464        struct hsi_port         **port;
 465        unsigned int            i;
 466
 467        if (!n_ports)
 468                return NULL;
 469
 470        hsi = kzalloc(sizeof(*hsi), flags);
 471        if (!hsi)
 472                return NULL;
 473        port = kcalloc(n_ports, sizeof(*port), flags);
 474        if (!port) {
 475                kfree(hsi);
 476                return NULL;
 477        }
 478        hsi->num_ports = n_ports;
 479        hsi->port = port;
 480        hsi->device.release = hsi_controller_release;
 481        device_initialize(&hsi->device);
 482
 483        for (i = 0; i < n_ports; i++) {
 484                port[i] = kzalloc(sizeof(**port), flags);
 485                if (port[i] == NULL)
 486                        goto out;
 487                port[i]->num = i;
 488                port[i]->async = hsi_dummy_msg;
 489                port[i]->setup = hsi_dummy_cl;
 490                port[i]->flush = hsi_dummy_cl;
 491                port[i]->start_tx = hsi_dummy_cl;
 492                port[i]->stop_tx = hsi_dummy_cl;
 493                port[i]->release = hsi_dummy_cl;
 494                mutex_init(&port[i]->lock);
 495                BLOCKING_INIT_NOTIFIER_HEAD(&port[i]->n_head);
 496                dev_set_name(&port[i]->device, "port%d", i);
 497                hsi->port[i]->device.release = hsi_port_release;
 498                device_initialize(&hsi->port[i]->device);
 499        }
 500
 501        return hsi;
 502out:
 503        hsi_put_controller(hsi);
 504
 505        return NULL;
 506}
 507EXPORT_SYMBOL_GPL(hsi_alloc_controller);
 508
 509/**
 510 * hsi_free_msg - Free an HSI message
 511 * @msg: Pointer to the HSI message
 512 *
 513 * Client is responsible to free the buffers pointed by the scatterlists.
 514 */
 515void hsi_free_msg(struct hsi_msg *msg)
 516{
 517        if (!msg)
 518                return;
 519        sg_free_table(&msg->sgt);
 520        kfree(msg);
 521}
 522EXPORT_SYMBOL_GPL(hsi_free_msg);
 523
 524/**
 525 * hsi_alloc_msg - Allocate an HSI message
 526 * @nents: Number of memory entries
 527 * @flags: Kernel allocation flags
 528 *
 529 * nents can be 0. This mainly makes sense for read transfer.
 530 * In that case, HSI drivers will call the complete callback when
 531 * there is data to be read without consuming it.
 532 *
 533 * Return NULL on failure or a pointer to an hsi_msg on success.
 534 */
 535struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags)
 536{
 537        struct hsi_msg *msg;
 538        int err;
 539
 540        msg = kzalloc(sizeof(*msg), flags);
 541        if (!msg)
 542                return NULL;
 543
 544        if (!nents)
 545                return msg;
 546
 547        err = sg_alloc_table(&msg->sgt, nents, flags);
 548        if (unlikely(err)) {
 549                kfree(msg);
 550                msg = NULL;
 551        }
 552
 553        return msg;
 554}
 555EXPORT_SYMBOL_GPL(hsi_alloc_msg);
 556
 557/**
 558 * hsi_async - Submit an HSI transfer to the controller
 559 * @cl: HSI client sending the transfer
 560 * @msg: The HSI transfer passed to controller
 561 *
 562 * The HSI message must have the channel, ttype, complete and destructor
 563 * fields set beforehand. If nents > 0 then the client has to initialize
 564 * also the scatterlists to point to the buffers to write to or read from.
 565 *
 566 * HSI controllers relay on pre-allocated buffers from their clients and they
 567 * do not allocate buffers on their own.
 568 *
 569 * Once the HSI message transfer finishes, the HSI controller calls the
 570 * complete callback with the status and actual_len fields of the HSI message
 571 * updated. The complete callback can be called before returning from
 572 * hsi_async.
 573 *
 574 * Returns -errno on failure or 0 on success
 575 */
 576int hsi_async(struct hsi_client *cl, struct hsi_msg *msg)
 577{
 578        struct hsi_port *port = hsi_get_port(cl);
 579
 580        if (!hsi_port_claimed(cl))
 581                return -EACCES;
 582
 583        WARN_ON_ONCE(!msg->destructor || !msg->complete);
 584        msg->cl = cl;
 585
 586        return port->async(msg);
 587}
 588EXPORT_SYMBOL_GPL(hsi_async);
 589
 590/**
 591 * hsi_claim_port - Claim the HSI client's port
 592 * @cl: HSI client that wants to claim its port
 593 * @share: Flag to indicate if the client wants to share the port or not.
 594 *
 595 * Returns -errno on failure, 0 on success.
 596 */
 597int hsi_claim_port(struct hsi_client *cl, unsigned int share)
 598{
 599        struct hsi_port *port = hsi_get_port(cl);
 600        int err = 0;
 601
 602        mutex_lock(&port->lock);
 603        if ((port->claimed) && (!port->shared || !share)) {
 604                err = -EBUSY;
 605                goto out;
 606        }
 607        if (!try_module_get(to_hsi_controller(port->device.parent)->owner)) {
 608                err = -ENODEV;
 609                goto out;
 610        }
 611        port->claimed++;
 612        port->shared = !!share;
 613        cl->pclaimed = 1;
 614out:
 615        mutex_unlock(&port->lock);
 616
 617        return err;
 618}
 619EXPORT_SYMBOL_GPL(hsi_claim_port);
 620
 621/**
 622 * hsi_release_port - Release the HSI client's port
 623 * @cl: HSI client which previously claimed its port
 624 */
 625void hsi_release_port(struct hsi_client *cl)
 626{
 627        struct hsi_port *port = hsi_get_port(cl);
 628
 629        mutex_lock(&port->lock);
 630        /* Allow HW driver to do some cleanup */
 631        port->release(cl);
 632        if (cl->pclaimed)
 633                port->claimed--;
 634        BUG_ON(port->claimed < 0);
 635        cl->pclaimed = 0;
 636        if (!port->claimed)
 637                port->shared = 0;
 638        module_put(to_hsi_controller(port->device.parent)->owner);
 639        mutex_unlock(&port->lock);
 640}
 641EXPORT_SYMBOL_GPL(hsi_release_port);
 642
 643static int hsi_event_notifier_call(struct notifier_block *nb,
 644                                unsigned long event, void *data __maybe_unused)
 645{
 646        struct hsi_client *cl = container_of(nb, struct hsi_client, nb);
 647
 648        (*cl->ehandler)(cl, event);
 649
 650        return 0;
 651}
 652
 653/**
 654 * hsi_register_port_event - Register a client to receive port events
 655 * @cl: HSI client that wants to receive port events
 656 * @handler: Event handler callback
 657 *
 658 * Clients should register a callback to be able to receive
 659 * events from the ports. Registration should happen after
 660 * claiming the port.
 661 * The handler can be called in interrupt context.
 662 *
 663 * Returns -errno on error, or 0 on success.
 664 */
 665int hsi_register_port_event(struct hsi_client *cl,
 666                        void (*handler)(struct hsi_client *, unsigned long))
 667{
 668        struct hsi_port *port = hsi_get_port(cl);
 669
 670        if (!handler || cl->ehandler)
 671                return -EINVAL;
 672        if (!hsi_port_claimed(cl))
 673                return -EACCES;
 674        cl->ehandler = handler;
 675        cl->nb.notifier_call = hsi_event_notifier_call;
 676
 677        return blocking_notifier_chain_register(&port->n_head, &cl->nb);
 678}
 679EXPORT_SYMBOL_GPL(hsi_register_port_event);
 680
 681/**
 682 * hsi_unregister_port_event - Stop receiving port events for a client
 683 * @cl: HSI client that wants to stop receiving port events
 684 *
 685 * Clients should call this function before releasing their associated
 686 * port.
 687 *
 688 * Returns -errno on error, or 0 on success.
 689 */
 690int hsi_unregister_port_event(struct hsi_client *cl)
 691{
 692        struct hsi_port *port = hsi_get_port(cl);
 693        int err;
 694
 695        WARN_ON(!hsi_port_claimed(cl));
 696
 697        err = blocking_notifier_chain_unregister(&port->n_head, &cl->nb);
 698        if (!err)
 699                cl->ehandler = NULL;
 700
 701        return err;
 702}
 703EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
 704
 705/**
 706 * hsi_event - Notifies clients about port events
 707 * @port: Port where the event occurred
 708 * @event: The event type
 709 *
 710 * Clients should not be concerned about wake line behavior. However, due
 711 * to a race condition in HSI HW protocol, clients need to be notified
 712 * about wake line changes, so they can implement a workaround for it.
 713 *
 714 * Events:
 715 * HSI_EVENT_START_RX - Incoming wake line high
 716 * HSI_EVENT_STOP_RX - Incoming wake line down
 717 *
 718 * Returns -errno on error, or 0 on success.
 719 */
 720int hsi_event(struct hsi_port *port, unsigned long event)
 721{
 722        return blocking_notifier_call_chain(&port->n_head, event, NULL);
 723}
 724EXPORT_SYMBOL_GPL(hsi_event);
 725
 726/**
 727 * hsi_get_channel_id_by_name - acquire channel id by channel name
 728 * @cl: HSI client, which uses the channel
 729 * @name: name the channel is known under
 730 *
 731 * Clients can call this function to get the hsi channel ids similar to
 732 * requesting IRQs or GPIOs by name. This function assumes the same
 733 * channel configuration is used for RX and TX.
 734 *
 735 * Returns -errno on error or channel id on success.
 736 */
 737int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name)
 738{
 739        int i;
 740
 741        if (!cl->rx_cfg.channels)
 742                return -ENOENT;
 743
 744        for (i = 0; i < cl->rx_cfg.num_channels; i++)
 745                if (!strcmp(cl->rx_cfg.channels[i].name, name))
 746                        return cl->rx_cfg.channels[i].id;
 747
 748        return -ENXIO;
 749}
 750EXPORT_SYMBOL_GPL(hsi_get_channel_id_by_name);
 751
 752static int __init hsi_init(void)
 753{
 754        return bus_register(&hsi_bus_type);
 755}
 756postcore_initcall(hsi_init);
 757
 758static void __exit hsi_exit(void)
 759{
 760        bus_unregister(&hsi_bus_type);
 761}
 762module_exit(hsi_exit);
 763
 764MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
 765MODULE_DESCRIPTION("High-speed Synchronous Serial Interface (HSI) framework");
 766MODULE_LICENSE("GPL v2");
 767