1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Apple Onboard Audio driver for Toonie codec |
4 | * |
5 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> |
6 | * |
7 | * This is a driver for the toonie codec chip. This chip is present |
8 | * on the Mac Mini and is nothing but a DAC. |
9 | */ |
10 | #include <linux/delay.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>" ); |
14 | MODULE_LICENSE("GPL" ); |
15 | MODULE_DESCRIPTION("toonie codec driver for snd-aoa" ); |
16 | |
17 | #include "../aoa.h" |
18 | #include "../soundbus/soundbus.h" |
19 | |
20 | |
21 | #define PFX "snd-aoa-codec-toonie: " |
22 | |
23 | struct toonie { |
24 | struct aoa_codec codec; |
25 | }; |
26 | #define codec_to_toonie(c) container_of(c, struct toonie, codec) |
27 | |
28 | static int toonie_dev_register(struct snd_device *dev) |
29 | { |
30 | return 0; |
31 | } |
32 | |
33 | static const struct snd_device_ops ops = { |
34 | .dev_register = toonie_dev_register, |
35 | }; |
36 | |
37 | static struct transfer_info toonie_transfers[] = { |
38 | /* This thing *only* has analog output, |
39 | * the rates are taken from Info.plist |
40 | * from Darwin. */ |
41 | { |
42 | .formats = SNDRV_PCM_FMTBIT_S16_BE | |
43 | SNDRV_PCM_FMTBIT_S24_BE, |
44 | .rates = SNDRV_PCM_RATE_32000 | |
45 | SNDRV_PCM_RATE_44100 | |
46 | SNDRV_PCM_RATE_48000 | |
47 | SNDRV_PCM_RATE_88200 | |
48 | SNDRV_PCM_RATE_96000, |
49 | }, |
50 | {} |
51 | }; |
52 | |
53 | static int toonie_usable(struct codec_info_item *cii, |
54 | struct transfer_info *ti, |
55 | struct transfer_info *out) |
56 | { |
57 | return 1; |
58 | } |
59 | |
60 | #ifdef CONFIG_PM |
61 | static int toonie_suspend(struct codec_info_item *cii, pm_message_t state) |
62 | { |
63 | /* can we turn it off somehow? */ |
64 | return 0; |
65 | } |
66 | |
67 | static int toonie_resume(struct codec_info_item *cii) |
68 | { |
69 | return 0; |
70 | } |
71 | #endif /* CONFIG_PM */ |
72 | |
73 | static struct codec_info toonie_codec_info = { |
74 | .transfers = toonie_transfers, |
75 | .sysclock_factor = 256, |
76 | .bus_factor = 64, |
77 | .owner = THIS_MODULE, |
78 | .usable = toonie_usable, |
79 | #ifdef CONFIG_PM |
80 | .suspend = toonie_suspend, |
81 | .resume = toonie_resume, |
82 | #endif |
83 | }; |
84 | |
85 | static int toonie_init_codec(struct aoa_codec *codec) |
86 | { |
87 | struct toonie *toonie = codec_to_toonie(codec); |
88 | |
89 | /* nothing connected? what a joke! */ |
90 | if (toonie->codec.connected != 1) |
91 | return -ENOTCONN; |
92 | |
93 | if (aoa_snd_device_new(type: SNDRV_DEV_CODEC, device_data: toonie, ops: &ops)) { |
94 | printk(KERN_ERR PFX "failed to create toonie snd device!\n" ); |
95 | return -ENODEV; |
96 | } |
97 | |
98 | if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev, |
99 | aoa_get_card(), |
100 | &toonie_codec_info, toonie)) { |
101 | printk(KERN_ERR PFX "error creating toonie pcm\n" ); |
102 | snd_device_free(card: aoa_get_card(), device_data: toonie); |
103 | return -ENODEV; |
104 | } |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | static void toonie_exit_codec(struct aoa_codec *codec) |
110 | { |
111 | struct toonie *toonie = codec_to_toonie(codec); |
112 | |
113 | if (!toonie->codec.soundbus_dev) { |
114 | printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n" ); |
115 | return; |
116 | } |
117 | toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie); |
118 | } |
119 | |
120 | static struct toonie *toonie; |
121 | |
122 | static int __init toonie_init(void) |
123 | { |
124 | toonie = kzalloc(size: sizeof(struct toonie), GFP_KERNEL); |
125 | |
126 | if (!toonie) |
127 | return -ENOMEM; |
128 | |
129 | strscpy(toonie->codec.name, "toonie" , sizeof(toonie->codec.name)); |
130 | toonie->codec.owner = THIS_MODULE; |
131 | toonie->codec.init = toonie_init_codec; |
132 | toonie->codec.exit = toonie_exit_codec; |
133 | |
134 | if (aoa_codec_register(codec: &toonie->codec)) { |
135 | kfree(objp: toonie); |
136 | return -EINVAL; |
137 | } |
138 | |
139 | return 0; |
140 | } |
141 | |
142 | static void __exit toonie_exit(void) |
143 | { |
144 | aoa_codec_unregister(codec: &toonie->codec); |
145 | kfree(objp: toonie); |
146 | } |
147 | |
148 | module_init(toonie_init); |
149 | module_exit(toonie_exit); |
150 | |