linux/sound/hda/ext/hdac_ext_bus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  hdac-ext-bus.c - HD-audio extended core bus functions.
   4 *
   5 *  Copyright (C) 2014-2015 Intel Corp
   6 *  Author: Jeeja KP <jeeja.kp@intel.com>
   7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/slab.h>
  14#include <linux/io.h>
  15#include <sound/hdaudio_ext.h>
  16
  17MODULE_DESCRIPTION("HDA extended core");
  18MODULE_LICENSE("GPL v2");
  19
  20/**
  21 * snd_hdac_ext_bus_init - initialize a HD-audio extended bus
  22 * @ebus: the pointer to extended bus object
  23 * @dev: device pointer
  24 * @ops: bus verb operators
  25 * default ops
  26 *
  27 * Returns 0 if successful, or a negative error code.
  28 */
  29int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
  30                        const struct hdac_bus_ops *ops,
  31                        const struct hdac_ext_bus_ops *ext_ops)
  32{
  33        int ret;
  34
  35        ret = snd_hdac_bus_init(bus, dev, ops);
  36        if (ret < 0)
  37                return ret;
  38
  39        bus->ext_ops = ext_ops;
  40        /* FIXME:
  41         * Currently only one bus is supported, if there is device with more
  42         * buses, bus->idx should be greater than 0, but there needs to be a
  43         * reliable way to always assign same number.
  44         */
  45        bus->idx = 0;
  46        bus->cmd_dma_state = true;
  47
  48        return 0;
  49}
  50EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
  51
  52/**
  53 * snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
  54 * @ebus: the pointer to extended bus object
  55 */
  56void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
  57{
  58        snd_hdac_bus_exit(bus);
  59        WARN_ON(!list_empty(&bus->hlink_list));
  60}
  61EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
  62
  63static void default_release(struct device *dev)
  64{
  65        snd_hdac_ext_bus_device_exit(container_of(dev, struct hdac_device, dev));
  66}
  67
  68/**
  69 * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device
  70 * @ebus: hdac extended bus to attach to
  71 * @addr: codec address
  72 *
  73 * Returns zero for success or a negative error code.
  74 */
  75int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
  76                                        struct hdac_device *hdev)
  77{
  78        char name[15];
  79        int ret;
  80
  81        hdev->bus = bus;
  82
  83        snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
  84
  85        ret  = snd_hdac_device_init(hdev, bus, name, addr);
  86        if (ret < 0) {
  87                dev_err(bus->dev, "device init failed for hdac device\n");
  88                return ret;
  89        }
  90        hdev->type = HDA_DEV_ASOC;
  91        hdev->dev.release = default_release;
  92
  93        ret = snd_hdac_device_register(hdev);
  94        if (ret) {
  95                dev_err(bus->dev, "failed to register hdac device\n");
  96                snd_hdac_ext_bus_device_exit(hdev);
  97                return ret;
  98        }
  99
 100        return 0;
 101}
 102EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
 103
 104/**
 105 * snd_hdac_ext_bus_device_exit - clean up a HD-audio extended codec base device
 106 * @hdev: hdac device to clean up
 107 */
 108void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
 109{
 110        snd_hdac_device_exit(hdev);
 111}
 112EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
 113
 114/**
 115 * snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices
 116 *
 117 * @ebus: HD-audio extended bus
 118 */
 119void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
 120{
 121        struct hdac_device *codec, *__codec;
 122        /*
 123         * we need to remove all the codec devices objects created in the
 124         * snd_hdac_ext_bus_device_init
 125         */
 126        list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
 127                snd_hdac_device_unregister(codec);
 128                put_device(&codec->dev);
 129        }
 130}
 131EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
 132#define dev_to_hdac(dev) (container_of((dev), \
 133                        struct hdac_device, dev))
 134
 135static inline struct hdac_driver *get_hdrv(struct device *dev)
 136{
 137        struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
 138        return hdrv;
 139}
 140
 141static inline struct hdac_device *get_hdev(struct device *dev)
 142{
 143        struct hdac_device *hdev = dev_to_hdac_dev(dev);
 144        return hdev;
 145}
 146
 147static int hda_ext_drv_probe(struct device *dev)
 148{
 149        return (get_hdrv(dev))->probe(get_hdev(dev));
 150}
 151
 152static int hdac_ext_drv_remove(struct device *dev)
 153{
 154        return (get_hdrv(dev))->remove(get_hdev(dev));
 155}
 156
 157static void hdac_ext_drv_shutdown(struct device *dev)
 158{
 159        return (get_hdrv(dev))->shutdown(get_hdev(dev));
 160}
 161
 162/**
 163 * snd_hda_ext_driver_register - register a driver for ext hda devices
 164 *
 165 * @drv: ext hda driver structure
 166 */
 167int snd_hda_ext_driver_register(struct hdac_driver *drv)
 168{
 169        drv->type = HDA_DEV_ASOC;
 170        drv->driver.bus = &snd_hda_bus_type;
 171        /* we use default match */
 172
 173        if (drv->probe)
 174                drv->driver.probe = hda_ext_drv_probe;
 175        if (drv->remove)
 176                drv->driver.remove = hdac_ext_drv_remove;
 177        if (drv->shutdown)
 178                drv->driver.shutdown = hdac_ext_drv_shutdown;
 179
 180        return driver_register(&drv->driver);
 181}
 182EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
 183
 184/**
 185 * snd_hda_ext_driver_unregister - unregister a driver for ext hda devices
 186 *
 187 * @drv: ext hda driver structure
 188 */
 189void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
 190{
 191        driver_unregister(&drv->driver);
 192}
 193EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
 194