| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HD-audio core bus driver |
|---|
| 3 | 4 | */ |
|---|
| 4 | 5 | |
|---|
| 5 | 6 | #include <linux/init.h> |
|---|
| 7 | +#include <linux/io.h> |
|---|
| 6 | 8 | #include <linux/device.h> |
|---|
| 7 | 9 | #include <linux/module.h> |
|---|
| 8 | 10 | #include <linux/export.h> |
|---|
| 9 | 11 | #include <sound/hdaudio.h> |
|---|
| 12 | +#include "local.h" |
|---|
| 10 | 13 | #include "trace.h" |
|---|
| 11 | 14 | |
|---|
| 12 | | -static void process_unsol_events(struct work_struct *work); |
|---|
| 15 | +static void snd_hdac_bus_process_unsol_events(struct work_struct *work); |
|---|
| 13 | 16 | |
|---|
| 14 | 17 | static const struct hdac_bus_ops default_ops = { |
|---|
| 15 | 18 | .command = snd_hdac_bus_send_cmd, |
|---|
| .. | .. |
|---|
| 19 | 22 | /** |
|---|
| 20 | 23 | * snd_hdac_bus_init - initialize a HD-audio bas bus |
|---|
| 21 | 24 | * @bus: the pointer to bus object |
|---|
| 25 | + * @dev: device pointer |
|---|
| 22 | 26 | * @ops: bus verb operators |
|---|
| 23 | | - * @io_ops: lowlevel I/O operators |
|---|
| 24 | 27 | * |
|---|
| 25 | 28 | * Returns 0 if successful, or a negative error code. |
|---|
| 26 | 29 | */ |
|---|
| 27 | 30 | int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, |
|---|
| 28 | | - const struct hdac_bus_ops *ops, |
|---|
| 29 | | - const struct hdac_io_ops *io_ops) |
|---|
| 31 | + const struct hdac_bus_ops *ops) |
|---|
| 30 | 32 | { |
|---|
| 31 | 33 | memset(bus, 0, sizeof(*bus)); |
|---|
| 32 | 34 | bus->dev = dev; |
|---|
| .. | .. |
|---|
| 34 | 36 | bus->ops = ops; |
|---|
| 35 | 37 | else |
|---|
| 36 | 38 | bus->ops = &default_ops; |
|---|
| 37 | | - bus->io_ops = io_ops; |
|---|
| 39 | + bus->dma_type = SNDRV_DMA_TYPE_DEV; |
|---|
| 38 | 40 | INIT_LIST_HEAD(&bus->stream_list); |
|---|
| 39 | 41 | INIT_LIST_HEAD(&bus->codec_list); |
|---|
| 40 | | - INIT_WORK(&bus->unsol_work, process_unsol_events); |
|---|
| 42 | + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); |
|---|
| 41 | 43 | spin_lock_init(&bus->reg_lock); |
|---|
| 42 | 44 | mutex_init(&bus->cmd_mutex); |
|---|
| 45 | + mutex_init(&bus->lock); |
|---|
| 46 | + INIT_LIST_HEAD(&bus->hlink_list); |
|---|
| 47 | + init_waitqueue_head(&bus->rirb_wq); |
|---|
| 43 | 48 | bus->irq = -1; |
|---|
| 49 | + |
|---|
| 50 | + /* |
|---|
| 51 | + * Default value of '8' is as per the HD audio specification (Rev 1.0a). |
|---|
| 52 | + * Following relation is used to derive STRIPE control value. |
|---|
| 53 | + * For sample rate <= 48K: |
|---|
| 54 | + * { ((num_channels * bits_per_sample) / number of SDOs) >= 8 } |
|---|
| 55 | + * For sample rate > 48K: |
|---|
| 56 | + * { ((num_channels * bits_per_sample * rate/48000) / |
|---|
| 57 | + * number of SDOs) >= 8 } |
|---|
| 58 | + */ |
|---|
| 59 | + bus->sdo_limit = 8; |
|---|
| 60 | + |
|---|
| 44 | 61 | return 0; |
|---|
| 45 | 62 | } |
|---|
| 46 | 63 | EXPORT_SYMBOL_GPL(snd_hdac_bus_init); |
|---|
| .. | .. |
|---|
| 60 | 77 | /** |
|---|
| 61 | 78 | * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus |
|---|
| 62 | 79 | * @bus: bus object |
|---|
| 80 | + * @addr: the HDAC device address |
|---|
| 63 | 81 | * @cmd: HD-audio encoded verb |
|---|
| 64 | 82 | * @res: pointer to store the response, NULL if performing asynchronously |
|---|
| 65 | 83 | * |
|---|
| .. | .. |
|---|
| 75 | 93 | mutex_unlock(&bus->cmd_mutex); |
|---|
| 76 | 94 | return err; |
|---|
| 77 | 95 | } |
|---|
| 78 | | -EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb); |
|---|
| 79 | 96 | |
|---|
| 80 | 97 | /** |
|---|
| 81 | 98 | * snd_hdac_bus_exec_verb_unlocked - unlocked version |
|---|
| 82 | 99 | * @bus: bus object |
|---|
| 100 | + * @addr: the HDAC device address |
|---|
| 83 | 101 | * @cmd: HD-audio encoded verb |
|---|
| 84 | 102 | * @res: pointer to store the response, NULL if performing asynchronously |
|---|
| 85 | 103 | * |
|---|
| .. | .. |
|---|
| 143 | 161 | |
|---|
| 144 | 162 | schedule_work(&bus->unsol_work); |
|---|
| 145 | 163 | } |
|---|
| 146 | | -EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); |
|---|
| 147 | 164 | |
|---|
| 148 | 165 | /* |
|---|
| 149 | 166 | * process queued unsolicited events |
|---|
| 150 | 167 | */ |
|---|
| 151 | | -static void process_unsol_events(struct work_struct *work) |
|---|
| 168 | +static void snd_hdac_bus_process_unsol_events(struct work_struct *work) |
|---|
| 152 | 169 | { |
|---|
| 153 | 170 | struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); |
|---|
| 154 | 171 | struct hdac_device *codec; |
|---|
| .. | .. |
|---|
| 199 | 216 | bus->num_codecs++; |
|---|
| 200 | 217 | return 0; |
|---|
| 201 | 218 | } |
|---|
| 202 | | -EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device); |
|---|
| 203 | 219 | |
|---|
| 204 | 220 | /** |
|---|
| 205 | 221 | * snd_hdac_bus_remove_device - Remove a codec from bus |
|---|
| .. | .. |
|---|
| 218 | 234 | bus->num_codecs--; |
|---|
| 219 | 235 | flush_work(&bus->unsol_work); |
|---|
| 220 | 236 | } |
|---|
| 221 | | -EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); |
|---|
| 237 | + |
|---|
| 238 | +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO |
|---|
| 239 | +/* Helpers for aligned read/write of mmio space, for Tegra */ |
|---|
| 240 | +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask) |
|---|
| 241 | +{ |
|---|
| 242 | + void __iomem *aligned_addr = |
|---|
| 243 | + (void __iomem *)((unsigned long)(addr) & ~0x3); |
|---|
| 244 | + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; |
|---|
| 245 | + unsigned int v; |
|---|
| 246 | + |
|---|
| 247 | + v = readl(aligned_addr); |
|---|
| 248 | + return (v >> shift) & mask; |
|---|
| 249 | +} |
|---|
| 250 | +EXPORT_SYMBOL_GPL(snd_hdac_aligned_read); |
|---|
| 251 | + |
|---|
| 252 | +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, |
|---|
| 253 | + unsigned int mask) |
|---|
| 254 | +{ |
|---|
| 255 | + void __iomem *aligned_addr = |
|---|
| 256 | + (void __iomem *)((unsigned long)(addr) & ~0x3); |
|---|
| 257 | + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; |
|---|
| 258 | + unsigned int v; |
|---|
| 259 | + |
|---|
| 260 | + v = readl(aligned_addr); |
|---|
| 261 | + v &= ~(mask << shift); |
|---|
| 262 | + v |= val << shift; |
|---|
| 263 | + writel(v, aligned_addr); |
|---|
| 264 | +} |
|---|
| 265 | +EXPORT_SYMBOL_GPL(snd_hdac_aligned_write); |
|---|
| 266 | +#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ |
|---|