162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Apple Onboard Audio driver for Toonie codec 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This is a driver for the toonie codec chip. This chip is present 862306a36Sopenharmony_ci * on the Mac Mini and is nothing but a DAC. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ciMODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); 1462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1562306a36Sopenharmony_ciMODULE_DESCRIPTION("toonie codec driver for snd-aoa"); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "../aoa.h" 1862306a36Sopenharmony_ci#include "../soundbus/soundbus.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define PFX "snd-aoa-codec-toonie: " 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct toonie { 2462306a36Sopenharmony_ci struct aoa_codec codec; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci#define codec_to_toonie(c) container_of(c, struct toonie, codec) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int toonie_dev_register(struct snd_device *dev) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return 0; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const struct snd_device_ops ops = { 3462306a36Sopenharmony_ci .dev_register = toonie_dev_register, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic struct transfer_info toonie_transfers[] = { 3862306a36Sopenharmony_ci /* This thing *only* has analog output, 3962306a36Sopenharmony_ci * the rates are taken from Info.plist 4062306a36Sopenharmony_ci * from Darwin. */ 4162306a36Sopenharmony_ci { 4262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_BE | 4362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_BE, 4462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | 4562306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | 4662306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | 4762306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 | 4862306a36Sopenharmony_ci SNDRV_PCM_RATE_96000, 4962306a36Sopenharmony_ci }, 5062306a36Sopenharmony_ci {} 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int toonie_usable(struct codec_info_item *cii, 5462306a36Sopenharmony_ci struct transfer_info *ti, 5562306a36Sopenharmony_ci struct transfer_info *out) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return 1; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef CONFIG_PM 6162306a36Sopenharmony_cistatic int toonie_suspend(struct codec_info_item *cii, pm_message_t state) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci /* can we turn it off somehow? */ 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int toonie_resume(struct codec_info_item *cii) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci#endif /* CONFIG_PM */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic struct codec_info toonie_codec_info = { 7462306a36Sopenharmony_ci .transfers = toonie_transfers, 7562306a36Sopenharmony_ci .sysclock_factor = 256, 7662306a36Sopenharmony_ci .bus_factor = 64, 7762306a36Sopenharmony_ci .owner = THIS_MODULE, 7862306a36Sopenharmony_ci .usable = toonie_usable, 7962306a36Sopenharmony_ci#ifdef CONFIG_PM 8062306a36Sopenharmony_ci .suspend = toonie_suspend, 8162306a36Sopenharmony_ci .resume = toonie_resume, 8262306a36Sopenharmony_ci#endif 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int toonie_init_codec(struct aoa_codec *codec) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct toonie *toonie = codec_to_toonie(codec); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* nothing connected? what a joke! */ 9062306a36Sopenharmony_ci if (toonie->codec.connected != 1) 9162306a36Sopenharmony_ci return -ENOTCONN; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (aoa_snd_device_new(SNDRV_DEV_CODEC, toonie, &ops)) { 9462306a36Sopenharmony_ci printk(KERN_ERR PFX "failed to create toonie snd device!\n"); 9562306a36Sopenharmony_ci return -ENODEV; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev, 9962306a36Sopenharmony_ci aoa_get_card(), 10062306a36Sopenharmony_ci &toonie_codec_info, toonie)) { 10162306a36Sopenharmony_ci printk(KERN_ERR PFX "error creating toonie pcm\n"); 10262306a36Sopenharmony_ci snd_device_free(aoa_get_card(), toonie); 10362306a36Sopenharmony_ci return -ENODEV; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void toonie_exit_codec(struct aoa_codec *codec) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct toonie *toonie = codec_to_toonie(codec); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!toonie->codec.soundbus_dev) { 11462306a36Sopenharmony_ci printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n"); 11562306a36Sopenharmony_ci return; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct toonie *toonie; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int __init toonie_init(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!toonie) 12762306a36Sopenharmony_ci return -ENOMEM; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci strscpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name)); 13062306a36Sopenharmony_ci toonie->codec.owner = THIS_MODULE; 13162306a36Sopenharmony_ci toonie->codec.init = toonie_init_codec; 13262306a36Sopenharmony_ci toonie->codec.exit = toonie_exit_codec; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (aoa_codec_register(&toonie->codec)) { 13562306a36Sopenharmony_ci kfree(toonie); 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void __exit toonie_exit(void) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci aoa_codec_unregister(&toonie->codec); 14562306a36Sopenharmony_ci kfree(toonie); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cimodule_init(toonie_init); 14962306a36Sopenharmony_cimodule_exit(toonie_exit); 150