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        dev_set_name(&cl->device, "%s", name);
 214
 215        err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
 216        if (err) {
 217                err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
 218                                                 &cl->rx_cfg.mode);
 219                if (err)
 220                        goto err;
 221
 222                err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
 223                                                 &cl->tx_cfg.mode);
 224                if (err)
 225                        goto err;
 226        } else {
 227                cl->rx_cfg.mode = mode;
 228                cl->tx_cfg.mode = mode;
 229        }
 230
 231        err = of_property_read_u32(client, "hsi-speed-kbps",
 232                                   &cl->tx_cfg.speed);
 233        if (err)
 234                goto err;
 235        cl->rx_cfg.speed = cl->tx_cfg.speed;
 236
 237        err = hsi_of_property_parse_flow(client, "hsi-flow",
 238                                         &cl->rx_cfg.flow);
 239        if (err)
 240                goto err;
 241
 242        err = hsi_of_property_parse_arb_mode(client, "hsi-arb-mode",
 243                                             &cl->rx_cfg.arb_mode);
 244        if (err)
 245                goto err;
 246
 247        prop = of_find_property(client, "hsi-channel-ids", &length);
 248        if (!prop) {
 249                err = -EINVAL;
 250                goto err;
 251        }
 252
 253        cells = length / sizeof(u32);
 254
 255        cl->rx_cfg.num_channels = cells;
 256        cl->tx_cfg.num_channels = cells;
 257        cl->rx_cfg.channels = kcalloc(cells, sizeof(channel), GFP_KERNEL);
 258        if (!cl->rx_cfg.channels) {
 259                err = -ENOMEM;
 260                goto err;
 261        }
 262
 263        cl->tx_cfg.channels = kcalloc(cells, sizeof(channel), GFP_KERNEL);
 264        if (!cl->tx_cfg.channels) {
 265                err = -ENOMEM;
 266                goto err2;
 267        }
 268
 269        max_chan = 0;
 270        for (i = 0; i < cells; i++) {
 271                err = of_property_read_u32_index(client, "hsi-channel-ids", i,
 272                                                 &channel.id);
 273                if (err)
 274                        goto err3;
 275
 276                err = of_property_read_string_index(client, "hsi-channel-names",
 277                                                    i, &channel.name);
 278                if (err)
 279                        channel.name = NULL;
 280
 281                if (channel.id > max_chan)
 282                        max_chan = channel.id;
 283
 284                cl->rx_cfg.channels[i] = channel;
 285                cl->tx_cfg.channels[i] = channel;
 286        }
 287
 288        cl->rx_cfg.num_hw_channels = max_chan + 1;
 289        cl->tx_cfg.num_hw_channels = max_chan + 1;
 290
 291        cl->device.bus = &hsi_bus_type;
 292        cl->device.parent = &port->device;
 293        cl->device.release = hsi_client_release;
 294        cl->device.of_node = client;
 295
 296        if (device_register(&cl->device) < 0) {
 297                pr_err("hsi: failed to register client: %s\n", name);
 298                put_device(&cl->device);
 299        }
 300
 301        return;
 302
 303err3:
 304        kfree(cl->tx_cfg.channels);
 305err2:
 306        kfree(cl->rx_cfg.channels);
 307err:
 308        kfree(cl);
 309        pr_err("hsi client: missing or incorrect of property: err=%d\n", err);
 310}
 311
 312void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients)
 313{
 314        struct device_node *child;
 315
 316        /* register hsi-char device */
 317        hsi_new_client(port, &hsi_char_dev_info);
 318
 319        for_each_available_child_of_node(clients, child)
 320                hsi_add_client_from_dt(port, child);
 321}
 322EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt);
 323#endif
 324
 325int hsi_remove_client(struct device *dev, void *data __maybe_unused)
 326{
 327        device_unregister(dev);
 328
 329        return 0;
 330}
 331EXPORT_SYMBOL_GPL(hsi_remove_client);
 332
 333static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
 334{
 335        device_for_each_child(dev, NULL, hsi_remove_client);
 336        device_unregister(dev);
 337
 338        return 0;
 339}
 340
 341static void hsi_controller_release(struct device *dev)
 342{
 343        struct hsi_controller *hsi = to_hsi_controller(dev);
 344
 345        kfree(hsi->port);
 346        kfree(hsi);
 347}
 348
 349static void hsi_port_release(struct device *dev)
 350{
 351        kfree(to_hsi_port(dev));
 352}
 353
 354/**
 355 * hsi_unregister_port - Unregister an HSI port
 356 * @port: The HSI port to unregister
 357 */
 358void hsi_port_unregister_clients(struct hsi_port *port)
 359{
 360        device_for_each_child(&port->device, NULL, hsi_remove_client);
 361}
 362EXPORT_SYMBOL_GPL(hsi_port_unregister_clients);
 363
 364/**
 365 * hsi_unregister_controller - Unregister an HSI controller
 366 * @hsi: The HSI controller to register
 367 */
 368void hsi_unregister_controller(struct hsi_controller *hsi)
 369{
 370        device_for_each_child(&hsi->device, NULL, hsi_remove_port);
 371        device_unregister(&hsi->device);
 372}
 373EXPORT_SYMBOL_GPL(hsi_unregister_controller);
 374
 375/**
 376 * hsi_register_controller - Register an HSI controller and its ports
 377 * @hsi: The HSI controller to register
 378 *
 379 * Returns -errno on failure, 0 on success.
 380 */
 381int hsi_register_controller(struct hsi_controller *hsi)
 382{
 383        unsigned int i;
 384        int err;
 385
 386        err = device_add(&hsi->device);
 387        if (err < 0)
 388                return err;
 389        for (i = 0; i < hsi->num_ports; i++) {
 390                hsi->port[i]->device.parent = &hsi->device;
 391                err = device_add(&hsi->port[i]->device);
 392                if (err < 0)
 393                        goto out;
 394        }
 395        /* Populate HSI bus with HSI clients */
 396        hsi_scan_board_info(hsi);
 397
 398        return 0;
 399out:
 400        while (i-- > 0)
 401                device_del(&hsi->port[i]->device);
 402        device_del(&hsi->device);
 403
 404        return err;
 405}
 406EXPORT_SYMBOL_GPL(hsi_register_controller);
 407
 408/**
 409 * hsi_register_client_driver - Register an HSI client to the HSI bus
 410 * @drv: HSI client driver to register
 411 *
 412 * Returns -errno on failure, 0 on success.
 413 */
 414int hsi_register_client_driver(struct hsi_client_driver *drv)
 415{
 416        drv->driver.bus = &hsi_bus_type;
 417
 418        return driver_register(&drv->driver);
 419}
 420EXPORT_SYMBOL_GPL(hsi_register_client_driver);
 421
 422static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)
 423{
 424        return 0;
 425}
 426
 427static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
 428{
 429        return 0;
 430}
 431
 432/**
 433 * hsi_put_controller - Free an HSI controller
 434 *
 435 * @hsi: Pointer to the HSI controller to freed
 436 *
 437 * HSI controller drivers should only use this function if they need
 438 * to free their allocated hsi_controller structures before a successful
 439 * call to hsi_register_controller. Other use is not allowed.
 440 */
 441void hsi_put_controller(struct hsi_controller *hsi)
 442{
 443        unsigned int i;
 444
 445        if (!hsi)
 446                return;
 447
 448        for (i = 0; i < hsi->num_ports; i++)
 449                if (hsi->port && hsi->port[i])
 450                        put_device(&hsi->port[i]->device);
 451        put_device(&hsi->device);
 452}
 453EXPORT_SYMBOL_GPL(hsi_put_controller);
 454
 455/**
 456 * hsi_alloc_controller - Allocate an HSI controller and its ports
 457 * @n_ports: Number of ports on the HSI controller
 458 * @flags: Kernel allocation flags
 459 *
 460 * Return NULL on failure or a pointer to an hsi_controller on success.
 461 */
 462struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
 463{
 464        struct hsi_controller   *hsi;
 465        struct hsi_port         **port;
 466        unsigned int            i;
 467
 468        if (!n_ports)
 469                return NULL;
 470
 471        hsi = kzalloc(sizeof(*hsi), flags);
 472        if (!hsi)
 473                return NULL;
 474        port = kcalloc(n_ports, sizeof(*port), flags);
 475        if (!port) {
 476                kfree(hsi);
 477                return NULL;
 478        }
 479        hsi->num_ports = n_ports;
 480        hsi->port = port;
 481        hsi->device.release = hsi_controller_release;
 482        device_initialize(&hsi->device);
 483
 484        for (i = 0; i < n_ports; i++) {
 485                port[i] = kzalloc(sizeof(**port), flags);
 486                if (port[i] == NULL)
 487                        goto out;
 488                port[i]->num = i;
 489                port[i]->async = hsi_dummy_msg;
 490                port[i]->setup = hsi_dummy_cl;
 491                port[i]->flush = hsi_dummy_cl;
 492                port[i]->start_tx = hsi_dummy_cl;
 493                port[i]->stop_tx = hsi_dummy_cl;
 494                port[i]->release = hsi_dummy_cl;
 495                mutex_init(&port[i]->lock);
 496                BLOCKING_INIT_NOTIFIER_HEAD(&port[i]->n_head);
 497                dev_set_name(&port[i]->device, "port%d", i);
 498                hsi->port[i]->device.release = hsi_port_release;
 499                device_initialize(&hsi->port[i]->device);
 500        }
 501
 502        return hsi;
 503out:
 504        hsi_put_controller(hsi);
 505
 506        return NULL;
 507}
 508EXPORT_SYMBOL_GPL(hsi_alloc_controller);
 509
 510/**
 511 * hsi_free_msg - Free an HSI message
 512 * @msg: Pointer to the HSI message
 513 *
 514 * Client is responsible to free the buffers pointed by the scatterlists.
 515 */
 516void hsi_free_msg(struct hsi_msg *msg)
 517{
 518        if (!msg)
 519                return;
 520        sg_free_table(&msg->sgt);
 521        kfree(msg);
 522}
 523EXPORT_SYMBOL_GPL(hsi_free_msg);
 524
 525/**
 526 * hsi_alloc_msg - Allocate an HSI message
 527 * @nents: Number of memory entries
 528 * @flags: Kernel allocation flags
 529 *
 530 * nents can be 0. This mainly makes sense for read transfer.
 531 * In that case, HSI drivers will call the complete callback when
 532 * there is data to be read without consuming it.
 533 *
 534 * Return NULL on failure or a pointer to an hsi_msg on success.
 535 */
 536struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags)
 537{
 538        struct hsi_msg *msg;
 539        int err;
 540
 541        msg = kzalloc(sizeof(*msg), flags);
 542        if (!msg)
 543                return NULL;
 544
 545        if (!nents)
 546                return msg;
 547
 548        err = sg_alloc_table(&msg->sgt, nents, flags);
 549        if (unlikely(err)) {
 550                kfree(msg);
 551                msg = NULL;
 552        }
 553
 554        return msg;
 555}
 556EXPORT_SYMBOL_GPL(hsi_alloc_msg);
 557
 558/**
 559 * hsi_async - Submit an HSI transfer to the controller
 560 * @cl: HSI client sending the transfer
 561 * @msg: The HSI transfer passed to controller
 562 *
 563 * The HSI message must have the channel, ttype, complete and destructor
 564 * fields set beforehand. If nents > 0 then the client has to initialize
 565 * also the scatterlists to point to the buffers to write to or read from.
 566 *
 567 * HSI controllers relay on pre-allocated buffers from their clients and they
 568 * do not allocate buffers on their own.
 569 *
 570 * Once the HSI message transfer finishes, the HSI controller calls the
 571 * complete callback with the status and actual_len fields of the HSI message
 572 * updated. The complete callback can be called before returning from
 573 * hsi_async.
 574 *
 575 * Returns -errno on failure or 0 on success
 576 */
 577int hsi_async(struct hsi_client *cl, struct hsi_msg *msg)
 578{
 579        struct hsi_port *port = hsi_get_port(cl);
 580
 581        if (!hsi_port_claimed(cl))
 582                return -EACCES;
 583
 584        WARN_ON_ONCE(!msg->destructor || !msg->complete);
 585        msg->cl = cl;
 586
 587        return port->async(msg);
 588}
 589EXPORT_SYMBOL_GPL(hsi_async);
 590
 591/**
 592 * hsi_claim_port - Claim the HSI client's port
 593 * @cl: HSI client that wants to claim its port
 594 * @share: Flag to indicate if the client wants to share the port or not.
 595 *
 596 * Returns -errno on failure, 0 on success.
 597 */
 598int hsi_claim_port(struct hsi_client *cl, unsigned int share)
 599{
 600        struct hsi_port *port = hsi_get_port(cl);
 601        int err = 0;
 602
 603        mutex_lock(&port->lock);
 604        if ((port->claimed) && (!port->shared || !share)) {
 605                err = -EBUSY;
 606                goto out;
 607        }
 608        if (!try_module_get(to_hsi_controller(port->device.parent)->owner)) {
 609                err = -ENODEV;
 610                goto out;
 611        }
 612        port->claimed++;
 613        port->shared = !!share;
 614        cl->pclaimed = 1;
 615out:
 616        mutex_unlock(&port->lock);
 617
 618        return err;
 619}
 620EXPORT_SYMBOL_GPL(hsi_claim_port);
 621
 622/**
 623 * hsi_release_port - Release the HSI client's port
 624 * @cl: HSI client which previously claimed its port
 625 */
 626void hsi_release_port(struct hsi_client *cl)
 627{
 628        struct hsi_port *port = hsi_get_port(cl);
 629
 630        mutex_lock(&port->lock);
 631        /* Allow HW driver to do some cleanup */
 632        port->release(cl);
 633        if (cl->pclaimed)
 634                port->claimed--;
 635        BUG_ON(port->claimed < 0);
 636        cl->pclaimed = 0;
 637        if (!port->claimed)
 638                port->shared = 0;
 639        module_put(to_hsi_controller(port->device.parent)->owner);
 640        mutex_unlock(&port->lock);
 641}
 642EXPORT_SYMBOL_GPL(hsi_release_port);
 643
 644static int hsi_event_notifier_call(struct notifier_block *nb,
 645                                unsigned long event, void *data __maybe_unused)
 646{
 647        struct hsi_client *cl = container_of(nb, struct hsi_client, nb);
 648
 649        (*cl->ehandler)(cl, event);
 650
 651        return 0;
 652}
 653
 654/**
 655 * hsi_register_port_event - Register a client to receive port events
 656 * @cl: HSI client that wants to receive port events
 657 * @handler: Event handler callback
 658 *
 659 * Clients should register a callback to be able to receive
 660 * events from the ports. Registration should happen after
 661 * claiming the port.
 662 * The handler can be called in interrupt context.
 663 *
 664 * Returns -errno on error, or 0 on success.
 665 */
 666int hsi_register_port_event(struct hsi_client *cl,
 667                        void (*handler)(struct hsi_client *, unsigned long))
 668{
 669        struct hsi_port *port = hsi_get_port(cl);
 670
 671        if (!handler || cl->ehandler)
 672                return -EINVAL;
 673        if (!hsi_port_claimed(cl))
 674                return -EACCES;
 675        cl->ehandler = handler;
 676        cl->nb.notifier_call = hsi_event_notifier_call;
 677
 678        return blocking_notifier_chain_register(&port->n_head, &cl->nb);
 679}
 680EXPORT_SYMBOL_GPL(hsi_register_port_event);
 681
 682/**
 683 * hsi_unregister_port_event - Stop receiving port events for a client
 684 * @cl: HSI client that wants to stop receiving port events
 685 *
 686 * Clients should call this function before releasing their associated
 687 * port.
 688 *
 689 * Returns -errno on error, or 0 on success.
 690 */
 691int hsi_unregister_port_event(struct hsi_client *cl)
 692{
 693        struct hsi_port *port = hsi_get_port(cl);
 694        int err;
 695
 696        WARN_ON(!hsi_port_claimed(cl));
 697
 698        err = blocking_notifier_chain_unregister(&port->n_head, &cl->nb);
 699        if (!err)
 700                cl->ehandler = NULL;
 701
 702        return err;
 703}
 704EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
 705
 706/**
 707 * hsi_event - Notifies clients about port events
 708 * @port: Port where the event occurred
 709 * @event: The event type
 710 *
 711 * Clients should not be concerned about wake line behavior. However, due
 712 * to a race condition in HSI HW protocol, clients need to be notified
 713 * about wake line changes, so they can implement a workaround for it.
 714 *
 715 * Events:
 716 * HSI_EVENT_START_RX - Incoming wake line high
 717 * HSI_EVENT_STOP_RX - Incoming wake line down
 718 *
 719 * Returns -errno on error, or 0 on success.
 720 */
 721int hsi_event(struct hsi_port *port, unsigned long event)
 722{
 723        return blocking_notifier_call_chain(&port->n_head, event, NULL);
 724}
 725EXPORT_SYMBOL_GPL(hsi_event);
 726
 727/**
 728 * hsi_get_channel_id_by_name - acquire channel id by channel name
 729 * @cl: HSI client, which uses the channel
 730 * @name: name the channel is known under
 731 *
 732 * Clients can call this function to get the hsi channel ids similar to
 733 * requesting IRQs or GPIOs by name. This function assumes the same
 734 * channel configuration is used for RX and TX.
 735 *
 736 * Returns -errno on error or channel id on success.
 737 */
 738int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name)
 739{
 740        int i;
 741
 742        if (!cl->rx_cfg.channels)
 743                return -ENOENT;
 744
 745        for (i = 0; i < cl->rx_cfg.num_channels; i++)
 746                if (!strcmp(cl->rx_cfg.channels[i].name, name))
 747                        return cl->rx_cfg.channels[i].id;
 748
 749        return -ENXIO;
 750}
 751EXPORT_SYMBOL_GPL(hsi_get_channel_id_by_name);
 752
 753static int __init hsi_init(void)
 754{
 755        return bus_register(&hsi_bus_type);
 756}
 757postcore_initcall(hsi_init);
 758
 759static void __exit hsi_exit(void)
 760{
 761        bus_unregister(&hsi_bus_type);
 762}
 763module_exit(hsi_exit);
 764
 765MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
 766MODULE_DESCRIPTION("High-speed Synchronous Serial Interface (HSI) framework");
 767MODULE_LICENSE("GPL v2");
 768