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