File Index
Files and directories
Sign in
FILE

acpi.c

File preview with syntax highlighting.

linux-6.19.14/sound/hda/controllers/acpi.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * ALSA driver for ACPI-based HDA Controllers.
  4 */
  5
  6#include <linux/module.h>
  7#include <linux/platform_device.h>
  8#include <linux/acpi.h>
  9
 10#include <sound/hda_codec.h>
 11
 12#include "hda_controller.h"
 13
 14struct hda_acpi {
 15	struct azx azx;
 16	struct snd_card *card;
 17	struct platform_device *pdev;
 18	void __iomem *regs;
 19	struct work_struct probe_work;
 20	const struct hda_data *data;
 21};
 22
 23/**
 24 * struct hda_data - Optional device-specific data
 25 * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME
 26 * @long_name:  Used for longer description; defaults to short_name
 27 * @flags:      Passed to &azx->driver_caps
 28 *
 29 * A pointer to a record of this type may be stored in the
 30 * &acpi_device_id->driver_data field of an ACPI match table entry in order to
 31 * customize the naming and behavior of a particular device. All fields are
 32 * optional and sensible defaults will be selected in their absence.
 33 */
 34struct hda_data {
 35	const char *short_name;
 36	const char *long_name;
 37	unsigned long flags;
 38};
 39
 40static int hda_acpi_dev_disconnect(struct snd_device *device)
 41{
 42	struct azx *chip = device->device_data;
 43
 44	chip->bus.shutdown = 1;
 45	return 0;
 46}
 47
 48static int hda_acpi_dev_free(struct snd_device *device)
 49{
 50	struct azx *azx = device->device_data;
 51	struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx);
 52
 53	cancel_work_sync(&hda->probe_work);
 54	if (azx_bus(azx)->chip_init) {
 55		azx_stop_all_streams(azx);
 56		azx_stop_chip(azx);
 57	}
 58
 59	azx_free_stream_pages(azx);
 60	azx_free_streams(azx);
 61	snd_hdac_bus_exit(azx_bus(azx));
 62
 63	return 0;
 64}
 65
 66static int hda_acpi_init(struct hda_acpi *hda)
 67{
 68	struct hdac_bus *bus = azx_bus(&hda->azx);
 69	struct snd_card *card = hda->azx.card;
 70	struct device *dev = &hda->pdev->dev;
 71	struct azx *azx = &hda->azx;
 72	struct resource *res;
 73	unsigned short gcap;
 74	const char *sname, *lname;
 75	int err, irq;
 76
 77	/* The base address for the HDA registers and the interrupt are wrapped
 78	 * in an ACPI _CRS object which can be parsed by platform_get_irq() and
 79	 * devm_platform_get_and_ioremap_resource()
 80	 */
 81
 82	irq = platform_get_irq(hda->pdev, 0);
 83	if (irq < 0)
 84		return irq;
 85
 86	hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res);
 87	if (IS_ERR(hda->regs))
 88		return PTR_ERR(hda->regs);
 89
 90	bus->remap_addr = hda->regs;
 91	bus->addr = res->start;
 92
 93	err = devm_request_irq(dev, irq, azx_interrupt,
 94			       IRQF_SHARED, KBUILD_MODNAME, azx);
 95	if (err) {
 96		dev_err(dev, "unable to request IRQ %d, disabling device\n",
 97			irq);
 98		return err;
 99	}
100	bus->irq = irq;
101	bus->dma_stop_delay = 100;
102	card->sync_irq = bus->irq;
103
104	gcap = azx_readw(azx, GCAP);
105	dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap);
106
107	azx->align_buffer_size = 1;
108
109	azx->capture_streams = (gcap >> 8) & 0x0f;
110	azx->playback_streams = (gcap >> 12) & 0x0f;
111
112	azx->capture_index_offset = 0;
113	azx->playback_index_offset = azx->capture_streams;
114	azx->num_streams = azx->playback_streams + azx->capture_streams;
115
116	err = azx_init_streams(azx);
117	if (err < 0) {
118		dev_err(dev, "failed to initialize streams: %d\n", err);
119		return err;
120	}
121
122	err = azx_alloc_stream_pages(azx);
123	if (err < 0) {
124		dev_err(dev, "failed to allocate stream pages: %d\n", err);
125		return err;
126	}
127
128	azx_init_chip(azx, 1);
129
130	if (!bus->codec_mask) {
131		dev_err(dev, "no codecs found!\n");
132		return -ENODEV;
133	}
134
135	strscpy(card->driver, "hda-acpi");
136
137	sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME;
138
139	if (strlen(sname) > sizeof(card->shortname))
140		dev_info(dev, "truncating shortname for card %s\n", sname);
141	strscpy(card->shortname, sname);
142
143	lname = hda->data->long_name ? hda->data->long_name : sname;
144
145	snprintf(card->longname, sizeof(card->longname),
146		 "%s at 0x%lx irq %i", lname, bus->addr, bus->irq);
147
148	return 0;
149}
150
151static void hda_acpi_probe_work(struct work_struct *work)
152{
153	struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work);
154	struct azx *chip = &hda->azx;
155	int err;
156
157	err = hda_acpi_init(hda);
158	if (err < 0)
159		return;
160
161	err = azx_probe_codecs(chip, 8);
162	if (err < 0)
163		return;
164
165	err = azx_codec_configure(chip);
166	if (err < 0)
167		return;
168
169	err = snd_card_register(chip->card);
170	if (err < 0)
171		return;
172
173	chip->running = 1;
174}
175
176static int hda_acpi_create(struct hda_acpi *hda)
177{
178	static const struct snd_device_ops ops = {
179		.dev_disconnect = hda_acpi_dev_disconnect,
180		.dev_free = hda_acpi_dev_free,
181	};
182	static const struct hda_controller_ops null_ops;
183	struct azx *azx = &hda->azx;
184	int err;
185
186	mutex_init(&azx->open_mutex);
187	azx->card = hda->card;
188	INIT_LIST_HEAD(&azx->pcm_list);
189
190	azx->ops = &null_ops;
191	azx->driver_caps = hda->data->flags;
192	azx->driver_type = hda->data->flags & 0xff;
193	azx->codec_probe_mask = -1;
194
195	err = azx_bus_init(azx, NULL);
196	if (err < 0)
197		return err;
198
199	err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops);
200	if (err < 0) {
201		dev_err(&hda->pdev->dev, "Error creating device\n");
202		return err;
203	}
204
205	return 0;
206}
207
208static int hda_acpi_probe(struct platform_device *pdev)
209{
210	struct hda_acpi *hda;
211	int err;
212
213	hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
214	if (!hda)
215		return -ENOMEM;
216
217	hda->pdev = pdev;
218	hda->data = acpi_device_get_match_data(&pdev->dev);
219
220	/* Fall back to defaults if the table didn't have a *struct hda_data */
221	if (!hda->data)
222		hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data),
223					 GFP_KERNEL);
224	if (!hda->data)
225		return -ENOMEM;
226
227	err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
228			   THIS_MODULE, 0, &hda->card);
229	if (err < 0) {
230		dev_err(&pdev->dev, "Error creating card!\n");
231		return err;
232	}
233
234	INIT_WORK(&hda->probe_work, hda_acpi_probe_work);
235
236	err = hda_acpi_create(hda);
237	if (err < 0)
238		goto out_free;
239	hda->card->private_data = &hda->azx;
240
241	dev_set_drvdata(&pdev->dev, hda->card);
242
243	schedule_work(&hda->probe_work);
244
245	return 0;
246
247out_free:
248	snd_card_free(hda->card);
249	return err;
250}
251
252static void hda_acpi_remove(struct platform_device *pdev)
253{
254	snd_card_free(dev_get_drvdata(&pdev->dev));
255}
256
257static void hda_acpi_shutdown(struct platform_device *pdev)
258{
259	struct snd_card *card = dev_get_drvdata(&pdev->dev);
260	struct azx *chip;
261
262	if (!card)
263		return;
264	chip = card->private_data;
265	if (chip && chip->running)
266		azx_stop_chip(chip);
267}
268
269static int hda_acpi_suspend(struct device *dev)
270{
271	struct snd_card *card = dev_get_drvdata(dev);
272	int rc;
273
274	rc = pm_runtime_force_suspend(dev);
275	if (rc < 0)
276		return rc;
277	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
278
279	return 0;
280}
281
282static int hda_acpi_resume(struct device *dev)
283{
284	struct snd_card *card = dev_get_drvdata(dev);
285	int rc;
286
287	rc = pm_runtime_force_resume(dev);
288	if (rc < 0)
289		return rc;
290	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
291
292	return 0;
293}
294
295static const struct dev_pm_ops hda_acpi_pm = {
296	SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume)
297};
298
299static const struct hda_data nvidia_hda_data = {
300	.short_name = "NVIDIA",
301	.long_name = "NVIDIA HDA Controller",
302	.flags = AZX_DCAPS_CORBRP_SELF_CLEAR,
303};
304
305static const struct acpi_device_id hda_acpi_match[] = {
306	{ .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data },
307	{ .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data },
308	{},
309};
310MODULE_DEVICE_TABLE(acpi, hda_acpi_match);
311
312static struct platform_driver hda_acpi_platform_driver = {
313	.driver = {
314		.name = KBUILD_MODNAME,
315		.pm = &hda_acpi_pm,
316		.acpi_match_table = hda_acpi_match,
317	},
318	.probe = hda_acpi_probe,
319	.remove = hda_acpi_remove,
320	.shutdown = hda_acpi_shutdown,
321};
322module_platform_driver(hda_acpi_platform_driver);
323
324MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers");
325MODULE_LICENSE("GPL");
~/ Read-only file preview.