1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HD-audio core bus driver 4 */ 5 6 #include <linux/init.h> 7 #include <linux/io.h> 8 #include <linux/device.h> 9 #include <linux/module.h> 10 #include <linux/export.h> 11 #include <sound/hdaudio.h> 12 #include "local.h" 13 #include "trace.h" 14 15 static void snd_hdac_bus_process_unsol_events(struct work_struct *work); 16 17 static const struct hdac_bus_ops default_ops = { 18 .command = snd_hdac_bus_send_cmd, 19 .get_response = snd_hdac_bus_get_response, 20 }; 21 22 /** 23 * snd_hdac_bus_init - initialize a HD-audio bas bus 24 * @bus: the pointer to bus object 25 * @ops: bus verb operators 26 * 27 * Returns 0 if successful, or a negative error code. 28 */ 29 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, 30 const struct hdac_bus_ops *ops) 31 { 32 memset(bus, 0, sizeof(*bus)); 33 bus->dev = dev; 34 if (ops) 35 bus->ops = ops; 36 else 37 bus->ops = &default_ops; 38 bus->dma_type = SNDRV_DMA_TYPE_DEV; 39 INIT_LIST_HEAD(&bus->stream_list); 40 INIT_LIST_HEAD(&bus->codec_list); 41 INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); 42 spin_lock_init(&bus->reg_lock); 43 mutex_init(&bus->cmd_mutex); 44 mutex_init(&bus->lock); 45 INIT_LIST_HEAD(&bus->hlink_list); 46 init_waitqueue_head(&bus->rirb_wq); 47 bus->irq = -1; 48 return 0; 49 } 50 EXPORT_SYMBOL_GPL(snd_hdac_bus_init); 51 52 /** 53 * snd_hdac_bus_exit - clean up a HD-audio bas bus 54 * @bus: the pointer to bus object 55 */ 56 void snd_hdac_bus_exit(struct hdac_bus *bus) 57 { 58 WARN_ON(!list_empty(&bus->stream_list)); 59 WARN_ON(!list_empty(&bus->codec_list)); 60 cancel_work_sync(&bus->unsol_work); 61 } 62 EXPORT_SYMBOL_GPL(snd_hdac_bus_exit); 63 64 /** 65 * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus 66 * @bus: bus object 67 * @cmd: HD-audio encoded verb 68 * @res: pointer to store the response, NULL if performing asynchronously 69 * 70 * Returns 0 if successful, or a negative error code. 71 */ 72 int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, 73 unsigned int cmd, unsigned int *res) 74 { 75 int err; 76 77 mutex_lock(&bus->cmd_mutex); 78 err = snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res); 79 mutex_unlock(&bus->cmd_mutex); 80 return err; 81 } 82 EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb); 83 84 /** 85 * snd_hdac_bus_exec_verb_unlocked - unlocked version 86 * @bus: bus object 87 * @cmd: HD-audio encoded verb 88 * @res: pointer to store the response, NULL if performing asynchronously 89 * 90 * Returns 0 if successful, or a negative error code. 91 */ 92 int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, 93 unsigned int cmd, unsigned int *res) 94 { 95 unsigned int tmp; 96 int err; 97 98 if (cmd == ~0) 99 return -EINVAL; 100 101 if (res) 102 *res = -1; 103 else if (bus->sync_write) 104 res = &tmp; 105 for (;;) { 106 trace_hda_send_cmd(bus, cmd); 107 err = bus->ops->command(bus, cmd); 108 if (err != -EAGAIN) 109 break; 110 /* process pending verbs */ 111 err = bus->ops->get_response(bus, addr, &tmp); 112 if (err) 113 break; 114 } 115 if (!err && res) { 116 err = bus->ops->get_response(bus, addr, res); 117 trace_hda_get_response(bus, addr, *res); 118 } 119 return err; 120 } 121 EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb_unlocked); 122 123 /** 124 * snd_hdac_bus_queue_event - add an unsolicited event to queue 125 * @bus: the BUS 126 * @res: unsolicited event (lower 32bit of RIRB entry) 127 * @res_ex: codec addr and flags (upper 32bit or RIRB entry) 128 * 129 * Adds the given event to the queue. The events are processed in 130 * the workqueue asynchronously. Call this function in the interrupt 131 * hanlder when RIRB receives an unsolicited event. 132 */ 133 void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex) 134 { 135 unsigned int wp; 136 137 if (!bus) 138 return; 139 140 trace_hda_unsol_event(bus, res, res_ex); 141 wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE; 142 bus->unsol_wp = wp; 143 144 wp <<= 1; 145 bus->unsol_queue[wp] = res; 146 bus->unsol_queue[wp + 1] = res_ex; 147 148 schedule_work(&bus->unsol_work); 149 } 150 EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); 151 152 /* 153 * process queued unsolicited events 154 */ 155 static void snd_hdac_bus_process_unsol_events(struct work_struct *work) 156 { 157 struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); 158 struct hdac_device *codec; 159 struct hdac_driver *drv; 160 unsigned int rp, caddr, res; 161 162 while (bus->unsol_rp != bus->unsol_wp) { 163 rp = (bus->unsol_rp + 1) % HDA_UNSOL_QUEUE_SIZE; 164 bus->unsol_rp = rp; 165 rp <<= 1; 166 res = bus->unsol_queue[rp]; 167 caddr = bus->unsol_queue[rp + 1]; 168 if (!(caddr & (1 << 4))) /* no unsolicited event? */ 169 continue; 170 codec = bus->caddr_tbl[caddr & 0x0f]; 171 if (!codec || !codec->dev.driver) 172 continue; 173 drv = drv_to_hdac_driver(codec->dev.driver); 174 if (drv->unsol_event) 175 drv->unsol_event(codec, res); 176 } 177 } 178 179 /** 180 * snd_hdac_bus_add_device - Add a codec to bus 181 * @bus: HDA core bus 182 * @codec: HDA core device to add 183 * 184 * Adds the given codec to the list in the bus. The caddr_tbl array 185 * and codec_powered bits are updated, as well. 186 * Returns zero if success, or a negative error code. 187 */ 188 int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec) 189 { 190 if (bus->caddr_tbl[codec->addr]) { 191 dev_err(bus->dev, "address 0x%x is already occupied\n", 192 codec->addr); 193 return -EBUSY; 194 } 195 196 list_add_tail(&codec->list, &bus->codec_list); 197 bus->caddr_tbl[codec->addr] = codec; 198 set_bit(codec->addr, &bus->codec_powered); 199 bus->num_codecs++; 200 return 0; 201 } 202 203 /** 204 * snd_hdac_bus_remove_device - Remove a codec from bus 205 * @bus: HDA core bus 206 * @codec: HDA core device to remove 207 */ 208 void snd_hdac_bus_remove_device(struct hdac_bus *bus, 209 struct hdac_device *codec) 210 { 211 WARN_ON(bus != codec->bus); 212 if (list_empty(&codec->list)) 213 return; 214 list_del_init(&codec->list); 215 bus->caddr_tbl[codec->addr] = NULL; 216 clear_bit(codec->addr, &bus->codec_powered); 217 bus->num_codecs--; 218 flush_work(&bus->unsol_work); 219 } 220 221 #ifdef CONFIG_SND_HDA_ALIGNED_MMIO 222 /* Helpers for aligned read/write of mmio space, for Tegra */ 223 unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask) 224 { 225 void __iomem *aligned_addr = 226 (void __iomem *)((unsigned long)(addr) & ~0x3); 227 unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; 228 unsigned int v; 229 230 v = readl(aligned_addr); 231 return (v >> shift) & mask; 232 } 233 EXPORT_SYMBOL_GPL(snd_hdac_aligned_read); 234 235 void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, 236 unsigned int mask) 237 { 238 void __iomem *aligned_addr = 239 (void __iomem *)((unsigned long)(addr) & ~0x3); 240 unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; 241 unsigned int v; 242 243 v = readl(aligned_addr); 244 v &= ~(mask << shift); 245 v |= val << shift; 246 writel(v, aligned_addr); 247 } 248 EXPORT_SYMBOL_GPL(snd_hdac_aligned_write); 249 #endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ 250