int (*hdev_detach)(struct hdac_device *hdev);
 };
 
-/*
- * Lowlevel I/O operators
- */
-struct hdac_io_ops {
-       /* mapped register accesses */
-       void (*reg_writel)(u32 value, u32 __iomem *addr);
-       u32 (*reg_readl)(u32 __iomem *addr);
-       void (*reg_writew)(u16 value, u16 __iomem *addr);
-       u16 (*reg_readw)(u16 __iomem *addr);
-       void (*reg_writeb)(u8 value, u8 __iomem *addr);
-       u8 (*reg_readb)(u8 __iomem *addr);
-};
-
 #define HDA_UNSOL_QUEUE_SIZE   64
 #define HDA_MAX_CODECS         8       /* limit by controller side */
 
 struct hdac_bus {
        struct device *dev;
        const struct hdac_bus_ops *ops;
-       const struct hdac_io_ops *io_ops;
        const struct hdac_ext_bus_ops *ext_ops;
 
        /* h/w resources */
 };
 
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
-                     const struct hdac_bus_ops *ops,
-                     const struct hdac_io_ops *io_ops);
+                     const struct hdac_bus_ops *ops);
 void snd_hdac_bus_exit(struct hdac_bus *bus);
 int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
                           unsigned int cmd, unsigned int *res);
 int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus);
 void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
 
+#ifdef CONFIG_SND_HDA_ALIGNED_MMIO
+unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask);
+void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
+                           unsigned int mask);
+#define snd_hdac_reg_writeb(v, addr)   snd_hdac_aligned_write(v, addr, 0xff)
+#define snd_hdac_reg_writew(v, addr)   snd_hdac_aligned_write(v, addr, 0xffff)
+#define snd_hdac_reg_readb(addr)       snd_hdac_aligned_read(addr, 0xff)
+#define snd_hdac_reg_readw(addr)       snd_hdac_aligned_read(addr, 0xffff)
+#else /* CONFIG_SND_HDA_ALIGNED_MMIO */
+#define snd_hdac_reg_writeb(val, addr) writeb(val, addr)
+#define snd_hdac_reg_writew(val, addr) writew(val, addr)
+#define snd_hdac_reg_readb(addr)       readb(addr)
+#define snd_hdac_reg_readw(addr)       readw(addr)
+#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
+#define snd_hdac_reg_writel(val, addr) writel(val, addr)
+#define snd_hdac_reg_readl(addr)       readl(addr)
+
 /*
  * macros for easy use
  */
 #define _snd_hdac_chip_writeb(chip, reg, value) \
-       ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg)))
+       snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg))
 #define _snd_hdac_chip_readb(chip, reg) \
-       ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg)))
+       snd_hdac_reg_readb((chip)->remap_addr + (reg))
 #define _snd_hdac_chip_writew(chip, reg, value) \
-       ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg)))
+       snd_hdac_reg_writew(value, (chip)->remap_addr + (reg))
 #define _snd_hdac_chip_readw(chip, reg) \
-       ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg)))
+       snd_hdac_reg_readw((chip)->remap_addr + (reg))
 #define _snd_hdac_chip_writel(chip, reg, value) \
-       ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg)))
+       snd_hdac_reg_writel(value, (chip)->remap_addr + (reg))
 #define _snd_hdac_chip_readl(chip, reg) \
-       ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg)))
+       snd_hdac_reg_readl((chip)->remap_addr + (reg))
 
 /* read/write a register, pass without AZX_REG_ prefix */
 #define snd_hdac_chip_writel(chip, reg, value) \
 /*
  * macros for easy use
  */
-#define _snd_hdac_stream_write(type, dev, reg, value)                  \
-       ((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg)))
-#define _snd_hdac_stream_read(type, dev, reg)                          \
-       ((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg)))
-
 /* read/write a register, pass without AZX_REG_ prefix */
 #define snd_hdac_stream_writel(dev, reg, value) \
-       _snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value)
+       snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg)
 #define snd_hdac_stream_writew(dev, reg, value) \
-       _snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value)
+       snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg)
 #define snd_hdac_stream_writeb(dev, reg, value) \
-       _snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value)
+       snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg)
 #define snd_hdac_stream_readl(dev, reg) \
-       _snd_hdac_stream_read(l, dev, AZX_REG_ ## reg)
+       snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg)
 #define snd_hdac_stream_readw(dev, reg) \
-       _snd_hdac_stream_read(w, dev, AZX_REG_ ## reg)
+       snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg)
 #define snd_hdac_stream_readb(dev, reg) \
-       _snd_hdac_stream_read(b, dev, AZX_REG_ ## reg)
+       snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg)
 
 /* update a register, pass without AZX_REG_ prefix */
 #define snd_hdac_stream_updatel(dev, reg, mask, val) \
 
 
 int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
                      const struct hdac_bus_ops *ops,
-                     const struct hdac_io_ops *io_ops,
                      const struct hdac_ext_bus_ops *ext_ops);
 
 void snd_hdac_ext_bus_exit(struct hdac_bus *bus);
 
 config SND_HDA_DSP_LOADER
        bool
 
+config SND_HDA_ALIGNED_MMIO
+       bool
+
 config SND_HDA_COMPONENT
        bool
 
 
 MODULE_DESCRIPTION("HDA extended core");
 MODULE_LICENSE("GPL v2");
 
-static void hdac_ext_writel(u32 value, u32 __iomem *addr)
-{
-       writel(value, addr);
-}
-
-static u32 hdac_ext_readl(u32 __iomem *addr)
-{
-       return readl(addr);
-}
-
-static void hdac_ext_writew(u16 value, u16 __iomem *addr)
-{
-       writew(value, addr);
-}
-
-static u16 hdac_ext_readw(u16 __iomem *addr)
-{
-       return readw(addr);
-}
-
-static void hdac_ext_writeb(u8 value, u8 __iomem *addr)
-{
-       writeb(value, addr);
-}
-
-static u8 hdac_ext_readb(u8 __iomem *addr)
-{
-       return readb(addr);
-}
-
-static const struct hdac_io_ops hdac_ext_default_io = {
-       .reg_writel = hdac_ext_writel,
-       .reg_readl = hdac_ext_readl,
-       .reg_writew = hdac_ext_writew,
-       .reg_readw = hdac_ext_readw,
-       .reg_writeb = hdac_ext_writeb,
-       .reg_readb = hdac_ext_readb,
-};
-
 /**
  * snd_hdac_ext_bus_init - initialize a HD-audio extended bus
  * @ebus: the pointer to extended bus object
  * @dev: device pointer
  * @ops: bus verb operators
- * @io_ops: lowlevel I/O operators, can be NULL. If NULL core will use
  * default ops
  *
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
                        const struct hdac_bus_ops *ops,
-                       const struct hdac_io_ops *io_ops,
                        const struct hdac_ext_bus_ops *ext_ops)
 {
        int ret;
 
-       /* check if io ops are provided, if not load the defaults */
-       if (io_ops == NULL)
-               io_ops = &hdac_ext_default_io;
-
-       ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
+       ret = snd_hdac_bus_init(bus, dev, ops);
        if (ret < 0)
                return ret;
 
 
  * snd_hdac_bus_init - initialize a HD-audio bas bus
  * @bus: the pointer to bus object
  * @ops: bus verb operators
- * @io_ops: lowlevel I/O operators
  *
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
-                     const struct hdac_bus_ops *ops,
-                     const struct hdac_io_ops *io_ops)
+                     const struct hdac_bus_ops *ops)
 {
        memset(bus, 0, sizeof(*bus));
        bus->dev = dev;
                bus->ops = ops;
        else
                bus->ops = &default_ops;
-       bus->io_ops = io_ops;
        bus->dma_type = SNDRV_DMA_TYPE_DEV;
        INIT_LIST_HEAD(&bus->stream_list);
        INIT_LIST_HEAD(&bus->codec_list);
        flush_work(&bus->unsol_work);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device);
+
+#ifdef CONFIG_SND_HDA_ALIGNED_MMIO
+/* Helpers for aligned read/write of mmio space, for Tegra */
+unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask)
+{
+       void __iomem *aligned_addr =
+               (void __iomem *)((unsigned long)(addr) & ~0x3);
+       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
+       unsigned int v;
+
+       v = readl(aligned_addr);
+       return (v >> shift) & mask;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_aligned_read);
+
+void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
+                           unsigned int mask)
+{
+       void __iomem *aligned_addr =
+               (void __iomem *)((unsigned long)(addr) & ~0x3);
+       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
+       unsigned int v;
+
+       v = readl(aligned_addr);
+       v &= ~(mask << shift);
+       v |= val << shift;
+       writel(v, aligned_addr);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_aligned_write);
+#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
 
        tristate "NVIDIA Tegra HD Audio"
        depends on ARCH_TEGRA
        select SND_HDA
+       select SND_HDA_ALIGNED_MMIO
        help
          Say Y here to support the HDA controller present in NVIDIA
          Tegra SoCs
 
 }
 
 /* HD-audio bus initialization */
-int azx_bus_init(struct azx *chip, const char *model,
-                const struct hdac_io_ops *io_ops)
+int azx_bus_init(struct azx *chip, const char *model)
 {
        struct hda_bus *bus = &chip->bus;
        int err;
 
-       err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops,
-                               io_ops);
+       err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops);
        if (err < 0)
                return err;
 
 
 irqreturn_t azx_interrupt(int irq, void *dev_id);
 
 /* Codec interface */
-int azx_bus_init(struct azx *chip, const char *model,
-                const struct hdac_io_ops *io_ops);
+int azx_bus_init(struct azx *chip, const char *model);
 int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
 int azx_codec_configure(struct azx *chip);
 int azx_init_streams(struct azx *chip);
 
 /*
  * constructor
  */
-static const struct hdac_io_ops pci_hda_io_ops;
 static const struct hda_controller_ops pci_hda_ops;
 
 static int azx_create(struct snd_card *card, struct pci_dev *pci,
        else
                chip->bdl_pos_adj = bdl_pos_adj[dev];
 
-       err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
+       err = azx_bus_init(chip, model[dev]);
        if (err < 0) {
                kfree(hda);
                pci_disable_device(pci);
 }
 #endif
 
-/*
- * HDA controller ops.
- */
-
-/* PCI register access. */
-static void pci_azx_writel(u32 value, u32 __iomem *addr)
-{
-       writel(value, addr);
-}
-
-static u32 pci_azx_readl(u32 __iomem *addr)
-{
-       return readl(addr);
-}
-
-static void pci_azx_writew(u16 value, u16 __iomem *addr)
-{
-       writew(value, addr);
-}
-
-static u16 pci_azx_readw(u16 __iomem *addr)
-{
-       return readw(addr);
-}
-
-static void pci_azx_writeb(u8 value, u8 __iomem *addr)
-{
-       writeb(value, addr);
-}
-
-static u8 pci_azx_readb(u8 __iomem *addr)
-{
-       return readb(addr);
-}
-
 static int disable_msi_reset_irq(struct azx *chip)
 {
        struct hdac_bus *bus = azx_bus(chip);
 #endif
 }
 
-static const struct hdac_io_ops pci_hda_io_ops = {
-       .reg_writel = pci_azx_writel,
-       .reg_readl = pci_azx_readl,
-       .reg_writew = pci_azx_writew,
-       .reg_readw = pci_azx_readw,
-       .reg_writeb = pci_azx_writeb,
-       .reg_readb = pci_azx_readb,
-};
-
 static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
        .pcm_mmap_prepare = pcm_mmap_prepare,
 
 #define power_save     0
 #endif
 
-/*
- * Register access ops. Tegra HDA register access is DWORD only.
- */
-static void hda_tegra_writel(u32 value, u32 __iomem *addr)
-{
-       writel(value, addr);
-}
-
-static u32 hda_tegra_readl(u32 __iomem *addr)
-{
-       return readl(addr);
-}
-
-static void hda_tegra_writew(u16 value, u16 __iomem  *addr)
-{
-       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
-       void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
-       u32 v;
-
-       v = readl(dword_addr);
-       v &= ~(0xffff << shift);
-       v |= value << shift;
-       writel(v, dword_addr);
-}
-
-static u16 hda_tegra_readw(u16 __iomem *addr)
-{
-       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
-       void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
-       u32 v;
-
-       v = readl(dword_addr);
-       return (v >> shift) & 0xffff;
-}
-
-static void hda_tegra_writeb(u8 value, u8 __iomem *addr)
-{
-       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
-       void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
-       u32 v;
-
-       v = readl(dword_addr);
-       v &= ~(0xff << shift);
-       v |= value << shift;
-       writel(v, dword_addr);
-}
-
-static u8 hda_tegra_readb(u8 __iomem *addr)
-{
-       unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
-       void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
-       u32 v;
-
-       v = readl(dword_addr);
-       return (v >> shift) & 0xff;
-}
-
-static const struct hdac_io_ops hda_tegra_io_ops = {
-       .reg_writel = hda_tegra_writel,
-       .reg_readl = hda_tegra_readl,
-       .reg_writew = hda_tegra_writew,
-       .reg_readw = hda_tegra_readw,
-       .reg_writeb = hda_tegra_writeb,
-       .reg_readb = hda_tegra_readb,
-};
-
 static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
 
 static void hda_tegra_init(struct hda_tegra *hda)
 
        INIT_WORK(&hda->probe_work, hda_tegra_probe_work);
 
-       err = azx_bus_init(chip, NULL, &hda_tegra_io_ops);
+       err = azx_bus_init(chip, NULL);
        if (err < 0)
                return err;
 
 
 
        /* Reset stream-to-link mapping */
        list_for_each_entry(hlink, &bus->hlink_list, list)
-               bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+               writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
 
        skl_enable_miscbdcge(bus->dev, true);
 
  * constructor
  */
 static int skl_create(struct pci_dev *pci,
-                     const struct hdac_io_ops *io_ops,
                      struct skl **rskl)
 {
        struct hdac_ext_bus_ops *ext_ops = NULL;
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
        ext_ops = snd_soc_hdac_hda_get_ops();
 #endif
-       snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops);
+       snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, ext_ops);
        bus->use_posbuf = 1;
        skl->pci = pci;
        INIT_WORK(&skl->probe_work, skl_probe_work);
        }
 
        /* we use ext core ops, so provide NULL for ops here */
-       err = skl_create(pci, NULL, &skl);
+       err = skl_create(pci, &skl);
        if (err < 0)
                return err;
 
 
 
 #endif
 
-static void sof_hda_writel(u32 value, u32 __iomem *addr)
-{
-       writel(value, addr);
-}
-
-static u32 sof_hda_readl(u32 __iomem *addr)
-{
-       return readl(addr);
-}
-
-static void sof_hda_writew(u16 value, u16 __iomem *addr)
-{
-       writew(value, addr);
-}
-
-static u16 sof_hda_readw(u16 __iomem *addr)
-{
-       return readw(addr);
-}
-
-static void sof_hda_writeb(u8 value, u8 __iomem *addr)
-{
-       writeb(value, addr);
-}
-
-static u8 sof_hda_readb(u8 __iomem *addr)
-{
-       return readb(addr);
-}
-
-static const struct hdac_io_ops io_ops = {
-       .reg_writel = sof_hda_writel,
-       .reg_readl = sof_hda_readl,
-       .reg_writew = sof_hda_writew,
-       .reg_readw = sof_hda_readw,
-       .reg_writeb = sof_hda_writeb,
-       .reg_readb = sof_hda_readb,
-};
-
 /*
  * This can be used for both with/without hda link support.
  */
        memset(bus, 0, sizeof(*bus));
        bus->dev = dev;
 
-       bus->io_ops = &io_ops;
        INIT_LIST_HEAD(&bus->stream_list);
 
        bus->irq = -1;
 
 
        /* Reset stream-to-link mapping */
        list_for_each_entry(hlink, &bus->hlink_list, list)
-               bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+               writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
 
        hda_dsp_ctrl_misc_clock_gating(sdev, true);
 #else