blob: ad1b55a1f045f8ed2cf295989afd2cbabba86bfa [file] [log] [blame]
Thomas Gleixner8e8e69d2019-05-29 07:17:59 -07001// SPDX-License-Identifier: GPL-2.0-only
Jeeja KPdfe66a12015-06-11 14:11:47 +05302/*
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 *
Jeeja KPdfe66a12015-06-11 14:11:47 +05309 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 */
11
12#include <linux/module.h>
13#include <linux/slab.h>
Vinod Koul42f2bb12015-10-13 14:57:49 +053014#include <linux/io.h>
Jeeja KPdfe66a12015-06-11 14:11:47 +053015#include <sound/hdaudio_ext.h>
16
17MODULE_DESCRIPTION("HDA extended core");
18MODULE_LICENSE("GPL v2");
19
Vinod Koul99463b32015-06-17 11:20:18 +053020static void hdac_ext_writel(u32 value, u32 __iomem *addr)
21{
22 writel(value, addr);
23}
24
25static u32 hdac_ext_readl(u32 __iomem *addr)
26{
27 return readl(addr);
28}
29
30static void hdac_ext_writew(u16 value, u16 __iomem *addr)
31{
32 writew(value, addr);
33}
34
35static u16 hdac_ext_readw(u16 __iomem *addr)
36{
37 return readw(addr);
38}
39
40static void hdac_ext_writeb(u8 value, u8 __iomem *addr)
41{
42 writeb(value, addr);
43}
44
45static u8 hdac_ext_readb(u8 __iomem *addr)
46{
47 return readb(addr);
48}
49
50static int hdac_ext_dma_alloc_pages(struct hdac_bus *bus, int type,
51 size_t size, struct snd_dma_buffer *buf)
52{
53 return snd_dma_alloc_pages(type, bus->dev, size, buf);
54}
55
56static void hdac_ext_dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
57{
58 snd_dma_free_pages(buf);
59}
60
61static const struct hdac_io_ops hdac_ext_default_io = {
62 .reg_writel = hdac_ext_writel,
63 .reg_readl = hdac_ext_readl,
64 .reg_writew = hdac_ext_writew,
65 .reg_readw = hdac_ext_readw,
66 .reg_writeb = hdac_ext_writeb,
67 .reg_readb = hdac_ext_readb,
68 .dma_alloc_pages = hdac_ext_dma_alloc_pages,
69 .dma_free_pages = hdac_ext_dma_free_pages,
70};
71
Jeeja KPdfe66a12015-06-11 14:11:47 +053072/**
73 * snd_hdac_ext_bus_init - initialize a HD-audio extended bus
74 * @ebus: the pointer to extended bus object
75 * @dev: device pointer
76 * @ops: bus verb operators
Vinod Koul99463b32015-06-17 11:20:18 +053077 * @io_ops: lowlevel I/O operators, can be NULL. If NULL core will use
78 * default ops
Jeeja KPdfe66a12015-06-11 14:11:47 +053079 *
80 * Returns 0 if successful, or a negative error code.
81 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050082int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
Jeeja KPdfe66a12015-06-11 14:11:47 +053083 const struct hdac_bus_ops *ops,
Rakesh Ughrejacb04ba32018-06-01 22:53:58 -050084 const struct hdac_io_ops *io_ops,
85 const struct hdac_ext_bus_ops *ext_ops)
Jeeja KPdfe66a12015-06-11 14:11:47 +053086{
87 int ret;
88 static int idx;
89
Vinod Koul99463b32015-06-17 11:20:18 +053090 /* check if io ops are provided, if not load the defaults */
91 if (io_ops == NULL)
92 io_ops = &hdac_ext_default_io;
93
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050094 ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
Jeeja KPdfe66a12015-06-11 14:11:47 +053095 if (ret < 0)
96 return ret;
97
Rakesh Ughrejacb04ba32018-06-01 22:53:58 -050098 bus->ext_ops = ext_ops;
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -050099 bus->idx = idx++;
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500100 bus->cmd_dma_state = true;
Vinod Koul4446085d2016-05-12 08:58:53 +0530101
Jeeja KPdfe66a12015-06-11 14:11:47 +0530102 return 0;
103}
104EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
105
106/**
107 * snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
108 * @ebus: the pointer to extended bus object
109 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500110void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
Jeeja KPdfe66a12015-06-11 14:11:47 +0530111{
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500112 snd_hdac_bus_exit(bus);
113 WARN_ON(!list_empty(&bus->hlink_list));
Jeeja KPdfe66a12015-06-11 14:11:47 +0530114}
115EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
116
117static void default_release(struct device *dev)
118{
119 snd_hdac_ext_bus_device_exit(container_of(dev, struct hdac_device, dev));
120}
121
122/**
Vinod Koula512f562015-08-21 15:47:41 +0530123 * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device
Jeeja KPdfe66a12015-06-11 14:11:47 +0530124 * @ebus: hdac extended bus to attach to
125 * @addr: codec address
126 *
127 * Returns zero for success or a negative error code.
128 */
Rakesh Ughreja62985422018-06-01 22:53:57 -0500129int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
130 struct hdac_device *hdev)
Jeeja KPdfe66a12015-06-11 14:11:47 +0530131{
Jeeja KPdfe66a12015-06-11 14:11:47 +0530132 char name[15];
133 int ret;
134
Rakesh Ughreja3787a392018-06-01 22:53:49 -0500135 hdev->bus = bus;
Jeeja KPdfe66a12015-06-11 14:11:47 +0530136
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500137 snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
Jeeja KPdfe66a12015-06-11 14:11:47 +0530138
139 ret = snd_hdac_device_init(hdev, bus, name, addr);
140 if (ret < 0) {
141 dev_err(bus->dev, "device init failed for hdac device\n");
142 return ret;
143 }
144 hdev->type = HDA_DEV_ASOC;
145 hdev->dev.release = default_release;
146
147 ret = snd_hdac_device_register(hdev);
148 if (ret) {
149 dev_err(bus->dev, "failed to register hdac device\n");
150 snd_hdac_ext_bus_device_exit(hdev);
151 return ret;
152 }
Vinod Koula512f562015-08-21 15:47:41 +0530153
Jeeja KPdfe66a12015-06-11 14:11:47 +0530154 return 0;
155}
156EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
157
158/**
159 * snd_hdac_ext_bus_device_exit - clean up a HD-audio extended codec base device
160 * @hdev: hdac device to clean up
161 */
162void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
163{
164 snd_hdac_device_exit(hdev);
Rakesh Ughreja3787a392018-06-01 22:53:49 -0500165 kfree(hdev);
Jeeja KPdfe66a12015-06-11 14:11:47 +0530166}
167EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
Vinod Koulee2d51b2015-08-21 15:47:40 +0530168
169/**
170 * snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices
171 *
172 * @ebus: HD-audio extended bus
173 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500174void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
Vinod Koulee2d51b2015-08-21 15:47:40 +0530175{
176 struct hdac_device *codec, *__codec;
177 /*
178 * we need to remove all the codec devices objects created in the
179 * snd_hdac_ext_bus_device_init
180 */
Rakesh Ughreja76f56fa2018-06-01 22:53:50 -0500181 list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
Vinod Koulee2d51b2015-08-21 15:47:40 +0530182 snd_hdac_device_unregister(codec);
183 put_device(&codec->dev);
184 }
185}
186EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
Vinod Kould51783c2015-08-21 15:47:42 +0530187#define dev_to_hdac(dev) (container_of((dev), \
188 struct hdac_device, dev))
189
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500190static inline struct hdac_driver *get_hdrv(struct device *dev)
Vinod Kould51783c2015-08-21 15:47:42 +0530191{
192 struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500193 return hdrv;
Vinod Kould51783c2015-08-21 15:47:42 +0530194}
195
Rakesh Ughreja3787a392018-06-01 22:53:49 -0500196static inline struct hdac_device *get_hdev(struct device *dev)
Vinod Kould51783c2015-08-21 15:47:42 +0530197{
198 struct hdac_device *hdev = dev_to_hdac_dev(dev);
Rakesh Ughreja3787a392018-06-01 22:53:49 -0500199 return hdev;
Vinod Kould51783c2015-08-21 15:47:42 +0530200}
201
202static int hda_ext_drv_probe(struct device *dev)
203{
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500204 return (get_hdrv(dev))->probe(get_hdev(dev));
Vinod Kould51783c2015-08-21 15:47:42 +0530205}
206
207static int hdac_ext_drv_remove(struct device *dev)
208{
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500209 return (get_hdrv(dev))->remove(get_hdev(dev));
Vinod Kould51783c2015-08-21 15:47:42 +0530210}
211
212static void hdac_ext_drv_shutdown(struct device *dev)
213{
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500214 return (get_hdrv(dev))->shutdown(get_hdev(dev));
Vinod Kould51783c2015-08-21 15:47:42 +0530215}
216
217/**
218 * snd_hda_ext_driver_register - register a driver for ext hda devices
219 *
220 * @drv: ext hda driver structure
221 */
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500222int snd_hda_ext_driver_register(struct hdac_driver *drv)
Vinod Kould51783c2015-08-21 15:47:42 +0530223{
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500224 drv->type = HDA_DEV_ASOC;
225 drv->driver.bus = &snd_hda_bus_type;
Vinod Kould51783c2015-08-21 15:47:42 +0530226 /* we use default match */
227
228 if (drv->probe)
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500229 drv->driver.probe = hda_ext_drv_probe;
Vinod Kould51783c2015-08-21 15:47:42 +0530230 if (drv->remove)
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500231 drv->driver.remove = hdac_ext_drv_remove;
Vinod Kould51783c2015-08-21 15:47:42 +0530232 if (drv->shutdown)
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500233 drv->driver.shutdown = hdac_ext_drv_shutdown;
Vinod Kould51783c2015-08-21 15:47:42 +0530234
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500235 return driver_register(&drv->driver);
Vinod Kould51783c2015-08-21 15:47:42 +0530236}
237EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
238
239/**
240 * snd_hda_ext_driver_unregister - unregister a driver for ext hda devices
241 *
242 * @drv: ext hda driver structure
243 */
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500244void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
Vinod Kould51783c2015-08-21 15:47:42 +0530245{
Rakesh Ughrejae1df9312018-06-01 22:53:51 -0500246 driver_unregister(&drv->driver);
Vinod Kould51783c2015-08-21 15:47:42 +0530247}
248EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);