xref: /openbmc/linux/sound/aoa/codecs/toonie.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
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