📄 akt50-sound.c
字号:
//#define DEBUG 1#include "debug.h"#include <linux/autoconf.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/device.h>#include <linux/pm.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/initval.h>#include "algo-bit.h"#include <asm/system.h>#include <asm/hardware.h>#include <asm/mach-types.h>#include <asm/arch/regs-gpio.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/arch/regs-iis.h>#include "audio.h"#include "s3c24xx-iis.h"#include "uda1341.h"#ifdef DEBUG#undef pr_debug#define pr_debug(fmt,arg...) printk(fmt,##arg)#endif/* l3 operations */#define L3NAME "l3-bit-akt50-gpio"struct bit_data { unsigned int sda; unsigned int scl; unsigned int l3_mode;};static int getsda(void *data){ struct bit_data *bits = data; return s3c2410_gpio_getpin(bits->sda);}static DECLARE_MUTEX(l3_lock);#define LOCK &l3_lockstatic void l3_setscl(void *data, int state){ struct bit_data *bits = data; unsigned long flags;// pr_debug("--- %s\n", __FUNCTION__); local_irq_save(flags); if (state) s3c2410_gpio_setpin(bits->scl,1); else s3c2410_gpio_setpin(bits->scl,0); s3c2410_gpio_cfgpin(bits->scl, S3C2410_GPIO_OUTPUT); local_irq_restore(flags);}static void l3_setsda(void *data, int state){ struct bit_data *bits = data;// pr_debug("--- %s\n", __FUNCTION__); if (state) s3c2410_gpio_setpin(bits->sda,1); else s3c2410_gpio_setpin(bits->sda,0);}static void l3_setdir(void *data, int in){ struct bit_data *bits = data; unsigned long flags;// pr_debug("--- %s\n", __FUNCTION__); local_irq_save(flags); if (in) { s3c2410_gpio_cfgpin(bits->sda, S3C2410_GPIO_INPUT); } else s3c2410_gpio_cfgpin(bits->sda, S3C2410_GPIO_OUTPUT); local_irq_restore(flags);}static void l3_setmode(void *data, int state){ struct bit_data *bits = data;// pr_debug("--- %s\n", __FUNCTION__); if (state) s3c2410_gpio_setpin(bits->l3_mode,1); else s3c2410_gpio_setpin(bits->l3_mode,0);}static struct l3_algo_bit_data l3_bit_data = { .data = NULL, .setdat = l3_setsda, .setclk = l3_setscl, .setmode = l3_setmode, .setdir = l3_setdir, .getdat = getsda, .data_hold = 1, .data_setup = 1, .clock_high = 1, .mode_hold = 1, .mode_setup = 1,};static struct l3_adapter l3_adapter = { .owner = THIS_MODULE, .name = L3NAME, .algo_data = &l3_bit_data, .lock = LOCK,};static int __init l3_init(struct bit_data *bits){ l3_bit_data.data = bits; pr_debug("--- %s\n", __FUNCTION__); return l3_bit_add_bus(&l3_adapter);}static void __exit l3_exit(void){ pr_debug("--- %s\n", __FUNCTION__); l3_bit_del_bus(&l3_adapter);}static struct bit_data bit_data;/* codec operations */struct akt50_sound_s { struct s3c24xx_iis_ops ops; s3c24xx_card_t *card; struct device *dev; struct uda1341 *uda1341;} ;static struct uda1341 *ops_to_uda(struct s3c24xx_iis_ops *ops){ struct akt50_sound_s *akt50_sound; pr_debug("--- %s\n", __FUNCTION__); akt50_sound = container_of(ops, struct akt50_sound_s, ops); return akt50_sound->uda1341;}static s3c24xx_card_t *ops_to_card(struct s3c24xx_iis_ops *ops){ struct akt50_sound_s *akt50_sound; pr_debug("--- %s\n", __FUNCTION__); akt50_sound = container_of(ops, struct akt50_sound_s, ops); return akt50_sound->card;}static int akt50_sound_open(struct s3c24xx_iis_ops *ops, snd_pcm_substream_t *stream){ pr_debug("--- %s\n", __FUNCTION__); return uda1341_open(ops_to_uda(ops));}static int akt50_sound_close(struct s3c24xx_iis_ops *ops, snd_pcm_substream_t *stream){ struct uda1341_cfg conf; pr_debug("--- %s\n", __FUNCTION__); if (stream->stream == SNDRV_PCM_STREAM_CAPTURE) { conf.record = 1; conf.play = 0; } else { conf.play = 1; conf.record = 0; } uda1341_close(ops_to_uda(ops), &conf); return 0;}static int akt50_sound_prepare(struct s3c24xx_iis_ops *ops, snd_pcm_substream_t *stream, snd_pcm_runtime_t *run){ struct uda1341_cfg conf; s3c24xx_card_t *card; pr_debug("--- %s\n", __FUNCTION__); card = ops_to_card(ops); if (card->is_384) conf.fs = 384; else conf.fs = 256; conf.format = FMT_I2S; if (stream->stream == SNDRV_PCM_STREAM_CAPTURE) { conf.record = 1; conf.play = 0; } else { conf.play = 1; conf.record = 0; } uda1341_configure(ops_to_uda(ops), &conf); return 0;}static int akt50_sound_startup(struct s3c24xx_iis_ops *ops){ pr_debug("--- %s\n", __FUNCTION__); /* nothing */ return 0;}/* sound card operations */struct s3c24xx_iis_ops akt50_sound_ops = { .owner = THIS_MODULE, .startup = akt50_sound_startup, .open = akt50_sound_open, .close = akt50_sound_close, .prepare = akt50_sound_prepare,};static void akt50_sound_free(struct akt50_sound_s * akt50_sound){ pr_debug("--- %s\n", __FUNCTION__); kfree(akt50_sound);}static int akt50_sound_remove(struct device *dev){ pr_debug("--- %s\n", __FUNCTION__); /* shouldn't happen */ return 0;}static struct device *audio_dev;static int akt50_sound_probe(struct device *dev){ pr_debug("--- %s\n", __FUNCTION__); audio_dev = dev; return 0;}static struct device_driver akt50_sound_driver = { .name = "akt50-sound", .bus = &platform_bus_type, .probe = akt50_sound_probe, .remove = akt50_sound_remove,};static int akt50_sound_codec_probe(struct device *dev) { struct akt50_sound_s *akt50_sound; int err; pr_debug("--- %s\n", __FUNCTION__); if (audio_dev == NULL) { printk("null audio dev!\n"); err = -EINVAL; goto finish2; } dev_info(dev, "attached akt50-sound driver\n"); /* allocate sound device */ akt50_sound = kmalloc(sizeof(struct akt50_sound_s), GFP_KERNEL); if (akt50_sound == NULL) { err = -ENOMEM; goto finish2; } memset(akt50_sound, 0, sizeof(struct akt50_sound_s)); akt50_sound->dev = dev; akt50_sound->card = s3c24xx_iis_probe(audio_dev); if (IS_ERR(akt50_sound->card)) { printk("Cannot probe iis device!\n"); err = PTR_ERR(akt50_sound->card); goto finish3; } akt50_sound->ops = akt50_sound_ops; akt50_sound->card->chip_ops = &akt50_sound->ops; akt50_sound->card->client = akt50_sound; strcpy(akt50_sound->card->card->driver, "akt50-sound"); strcpy(akt50_sound->card->card->shortname, "akt50"); strcpy(akt50_sound->card->card->longname, "S3C241X UDA1341"); snd_card_set_dev(akt50_sound->card->card, audio_dev); akt50_sound->uda1341 = uda1341_create(akt50_sound->card->card, L3NAME); if (IS_ERR(akt50_sound->uda1341)) { printk("Cannot creade UDA1341\n"); err = PTR_ERR(akt50_sound->uda1341); goto finish4; } /* default configuration for IIS */ s3c24xx_iismod_cfg(akt50_sound->card, S3C2410_IISMOD_16BIT, 0x0); s3c24xx_iismod_cfg(akt50_sound->card, S3C2410_IISMOD_32FS, 0x0); s3c24xx_iismod_cfg(akt50_sound->card, S3C2410_IISMOD_384FS, 0x0); err = s3c24xx_iis_cfgclksrc(akt50_sound->card, "cdclk"); if (err) { printk("Cannot setpu iis clock!\n"); goto finish5; } err = snd_card_register(akt50_sound->card->card); if (err) { printk("Cannot register sound card!\n"); goto finish5; } return 0; finish5: /* uda should be automaticaly freed */ finish4: akt50_sound_remove(dev); finish3: akt50_sound_free(akt50_sound); finish2: return err;}static int akt50_sound_codec_remove(struct device *dev){ s3c24xx_card_t *card; struct akt50_sound_s *client; pr_debug("--- %s\n", __FUNCTION__); card = dev_get_drvdata(dev); if (card != NULL) { client = card->client; s3c24xx_iis_remove(dev); akt50_sound_free(client); } return 0;}struct device_driver akt50_sound_codecdrv = { .name = "uda1341", .bus = &platform_bus_type, .probe = akt50_sound_codec_probe, .remove = akt50_sound_codec_remove,};static int __init akt50_sound_init(void){ struct bit_data *bit = &bit_data; unsigned long flags; int ret; pr_debug("--- %s\n", __FUNCTION__);#ifdef CONFIG_ARCH_ATK50 bit->sda = S3C2410_GPB5; bit->scl = S3C2410_GPB6; bit->l3_mode = S3C2410_GPB7;#elif defined(CONFIG_ARCH_SMDK2410) bit->scl = S3C2410_GPB4; bit->sda = S3C2410_GPB3; bit->l3_mode = S3C2410_GPB2;#endif if (!bit->sda) return -ENODEV; /* * Default level for L3 mode is low. * We set SCL and SDA high (i2c idle state). */ local_irq_save(flags); s3c2410_gpio_cfgpin(bit->scl, S3C2410_GPIO_OUTPUT); s3c2410_gpio_cfgpin(bit->sda, S3C2410_GPIO_OUTPUT); s3c2410_gpio_cfgpin(bit->l3_mode, S3C2410_GPIO_OUTPUT); local_irq_restore(flags); /* if needed */ ret = l3_init(bit); if (ret) { printk("Failed to init L3!\n"); goto finish1; } /* register iis device and codec */ if (driver_register(&akt50_sound_driver)<0) { printk("Registration of akt50 sound driver failed!\n"); } if (driver_register(&akt50_sound_codecdrv)<0) { printk("Registration of akt50 codec driver failed!\n"); } return 0; finish1: return ret;}static void __exit akt50_sound_exit(void){ pr_debug("--- %s\n", __FUNCTION__); driver_unregister(&akt50_sound_codecdrv); driver_unregister(&akt50_sound_driver); l3_exit();}module_init(akt50_sound_init);module_exit(akt50_sound_exit);/* TODO: suspend and resume! */MODULE_LICENSE("GPL");MODULE_DESCRIPTION("S3C4XX / UDA1341 Audio driver");MODULE_AUTHOR("Christian Pellegrin <chri@evolware.com>");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -