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(SNDRV_DEV_CODEC, toonie, &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(aoa_get_card(), 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(sizeof(struct toonie), GFP_KERNEL); 125 126 if (!toonie) 127 return -ENOMEM; 128 129 strlcpy(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(&toonie->codec)) { 135 kfree(toonie); 136 return -EINVAL; 137 } 138 139 return 0; 140 } 141 142 static void __exit toonie_exit(void) 143 { 144 aoa_codec_unregister(&toonie->codec); 145 kfree(toonie); 146 } 147 148 module_init(toonie_init); 149 module_exit(toonie_exit); 150