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