📄 akt50-sound_c.txt
字号:
//#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_lock
static 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 + -