1d6869352SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2888dcb7cSJohannes Berg /*
3888dcb7cSJohannes Berg * Apple Onboard Audio driver for Toonie codec
4888dcb7cSJohannes Berg *
5888dcb7cSJohannes Berg * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
6888dcb7cSJohannes Berg *
7888dcb7cSJohannes Berg * This is a driver for the toonie codec chip. This chip is present
8888dcb7cSJohannes Berg * on the Mac Mini and is nothing but a DAC.
9888dcb7cSJohannes Berg */
10888dcb7cSJohannes Berg #include <linux/delay.h>
11888dcb7cSJohannes Berg #include <linux/module.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
13888dcb7cSJohannes Berg MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
14888dcb7cSJohannes Berg MODULE_LICENSE("GPL");
15888dcb7cSJohannes Berg MODULE_DESCRIPTION("toonie codec driver for snd-aoa");
16888dcb7cSJohannes Berg
17888dcb7cSJohannes Berg #include "../aoa.h"
18888dcb7cSJohannes Berg #include "../soundbus/soundbus.h"
19888dcb7cSJohannes Berg
20888dcb7cSJohannes Berg
21888dcb7cSJohannes Berg #define PFX "snd-aoa-codec-toonie: "
22888dcb7cSJohannes Berg
23888dcb7cSJohannes Berg struct toonie {
24888dcb7cSJohannes Berg struct aoa_codec codec;
25888dcb7cSJohannes Berg };
26888dcb7cSJohannes Berg #define codec_to_toonie(c) container_of(c, struct toonie, codec)
27888dcb7cSJohannes Berg
toonie_dev_register(struct snd_device * dev)28888dcb7cSJohannes Berg static int toonie_dev_register(struct snd_device *dev)
29888dcb7cSJohannes Berg {
30888dcb7cSJohannes Berg return 0;
31888dcb7cSJohannes Berg }
32888dcb7cSJohannes Berg
33e6f2a617STakashi Iwai static const struct snd_device_ops ops = {
34888dcb7cSJohannes Berg .dev_register = toonie_dev_register,
35888dcb7cSJohannes Berg };
36888dcb7cSJohannes Berg
37888dcb7cSJohannes Berg static struct transfer_info toonie_transfers[] = {
38888dcb7cSJohannes Berg /* This thing *only* has analog output,
39888dcb7cSJohannes Berg * the rates are taken from Info.plist
40888dcb7cSJohannes Berg * from Darwin. */
41888dcb7cSJohannes Berg {
42888dcb7cSJohannes Berg .formats = SNDRV_PCM_FMTBIT_S16_BE |
43888dcb7cSJohannes Berg SNDRV_PCM_FMTBIT_S24_BE,
44888dcb7cSJohannes Berg .rates = SNDRV_PCM_RATE_32000 |
45888dcb7cSJohannes Berg SNDRV_PCM_RATE_44100 |
46888dcb7cSJohannes Berg SNDRV_PCM_RATE_48000 |
47888dcb7cSJohannes Berg SNDRV_PCM_RATE_88200 |
48888dcb7cSJohannes Berg SNDRV_PCM_RATE_96000,
49888dcb7cSJohannes Berg },
50888dcb7cSJohannes Berg {}
51888dcb7cSJohannes Berg };
52888dcb7cSJohannes Berg
toonie_usable(struct codec_info_item * cii,struct transfer_info * ti,struct transfer_info * out)53888dcb7cSJohannes Berg static int toonie_usable(struct codec_info_item *cii,
54888dcb7cSJohannes Berg struct transfer_info *ti,
55888dcb7cSJohannes Berg struct transfer_info *out)
56888dcb7cSJohannes Berg {
57888dcb7cSJohannes Berg return 1;
58888dcb7cSJohannes Berg }
59888dcb7cSJohannes Berg
60888dcb7cSJohannes Berg #ifdef CONFIG_PM
toonie_suspend(struct codec_info_item * cii,pm_message_t state)61888dcb7cSJohannes Berg static int toonie_suspend(struct codec_info_item *cii, pm_message_t state)
62888dcb7cSJohannes Berg {
63888dcb7cSJohannes Berg /* can we turn it off somehow? */
64888dcb7cSJohannes Berg return 0;
65888dcb7cSJohannes Berg }
66888dcb7cSJohannes Berg
toonie_resume(struct codec_info_item * cii)67888dcb7cSJohannes Berg static int toonie_resume(struct codec_info_item *cii)
68888dcb7cSJohannes Berg {
69888dcb7cSJohannes Berg return 0;
70888dcb7cSJohannes Berg }
71888dcb7cSJohannes Berg #endif /* CONFIG_PM */
72888dcb7cSJohannes Berg
73888dcb7cSJohannes Berg static struct codec_info toonie_codec_info = {
74888dcb7cSJohannes Berg .transfers = toonie_transfers,
75888dcb7cSJohannes Berg .sysclock_factor = 256,
76888dcb7cSJohannes Berg .bus_factor = 64,
77888dcb7cSJohannes Berg .owner = THIS_MODULE,
78888dcb7cSJohannes Berg .usable = toonie_usable,
79888dcb7cSJohannes Berg #ifdef CONFIG_PM
80888dcb7cSJohannes Berg .suspend = toonie_suspend,
81888dcb7cSJohannes Berg .resume = toonie_resume,
82888dcb7cSJohannes Berg #endif
83888dcb7cSJohannes Berg };
84888dcb7cSJohannes Berg
toonie_init_codec(struct aoa_codec * codec)85888dcb7cSJohannes Berg static int toonie_init_codec(struct aoa_codec *codec)
86888dcb7cSJohannes Berg {
87888dcb7cSJohannes Berg struct toonie *toonie = codec_to_toonie(codec);
88888dcb7cSJohannes Berg
89888dcb7cSJohannes Berg /* nothing connected? what a joke! */
90888dcb7cSJohannes Berg if (toonie->codec.connected != 1)
91888dcb7cSJohannes Berg return -ENOTCONN;
92888dcb7cSJohannes Berg
93d9151783STakashi Iwai if (aoa_snd_device_new(SNDRV_DEV_CODEC, toonie, &ops)) {
94888dcb7cSJohannes Berg printk(KERN_ERR PFX "failed to create toonie snd device!\n");
95888dcb7cSJohannes Berg return -ENODEV;
96888dcb7cSJohannes Berg }
97888dcb7cSJohannes Berg
98888dcb7cSJohannes Berg if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev,
99888dcb7cSJohannes Berg aoa_get_card(),
100888dcb7cSJohannes Berg &toonie_codec_info, toonie)) {
101888dcb7cSJohannes Berg printk(KERN_ERR PFX "error creating toonie pcm\n");
102888dcb7cSJohannes Berg snd_device_free(aoa_get_card(), toonie);
103888dcb7cSJohannes Berg return -ENODEV;
104888dcb7cSJohannes Berg }
105888dcb7cSJohannes Berg
106888dcb7cSJohannes Berg return 0;
107888dcb7cSJohannes Berg }
108888dcb7cSJohannes Berg
toonie_exit_codec(struct aoa_codec * codec)109888dcb7cSJohannes Berg static void toonie_exit_codec(struct aoa_codec *codec)
110888dcb7cSJohannes Berg {
111888dcb7cSJohannes Berg struct toonie *toonie = codec_to_toonie(codec);
112888dcb7cSJohannes Berg
113888dcb7cSJohannes Berg if (!toonie->codec.soundbus_dev) {
114888dcb7cSJohannes Berg printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n");
115888dcb7cSJohannes Berg return;
116888dcb7cSJohannes Berg }
117888dcb7cSJohannes Berg toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie);
118888dcb7cSJohannes Berg }
119888dcb7cSJohannes Berg
120888dcb7cSJohannes Berg static struct toonie *toonie;
121888dcb7cSJohannes Berg
toonie_init(void)122888dcb7cSJohannes Berg static int __init toonie_init(void)
123888dcb7cSJohannes Berg {
124888dcb7cSJohannes Berg toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL);
125888dcb7cSJohannes Berg
126888dcb7cSJohannes Berg if (!toonie)
127888dcb7cSJohannes Berg return -ENOMEM;
128888dcb7cSJohannes Berg
129*75b1a8f9SJoe Perches strscpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
130888dcb7cSJohannes Berg toonie->codec.owner = THIS_MODULE;
131888dcb7cSJohannes Berg toonie->codec.init = toonie_init_codec;
132888dcb7cSJohannes Berg toonie->codec.exit = toonie_exit_codec;
133888dcb7cSJohannes Berg
134888dcb7cSJohannes Berg if (aoa_codec_register(&toonie->codec)) {
135888dcb7cSJohannes Berg kfree(toonie);
136888dcb7cSJohannes Berg return -EINVAL;
137888dcb7cSJohannes Berg }
138888dcb7cSJohannes Berg
139888dcb7cSJohannes Berg return 0;
140888dcb7cSJohannes Berg }
141888dcb7cSJohannes Berg
toonie_exit(void)142888dcb7cSJohannes Berg static void __exit toonie_exit(void)
143888dcb7cSJohannes Berg {
144888dcb7cSJohannes Berg aoa_codec_unregister(&toonie->codec);
145888dcb7cSJohannes Berg kfree(toonie);
146888dcb7cSJohannes Berg }
147888dcb7cSJohannes Berg
148888dcb7cSJohannes Berg module_init(toonie_init);
149888dcb7cSJohannes Berg module_exit(toonie_exit);
150