AC97+UCB1400驱动

sound/pci/ac97/ac97_codec.c

old new  
158158{ 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL,           NULL }, // only guess --jk 
159159{ 0x4e534331, 0xffffffff, "LM4549",             NULL,           NULL }, 
160160{ 0x4e534350, 0xffffffff, "LM4550",             patch_lm4550,   NULL }, // volume wrap fix  
161 { 0x50534304, 0xffffffff, "UCB1400",            patch_ucb1400,  NULL }, 
 161{ 0x50534304, 0xffffffff, "UCB1400",            patch_ucb1400,  NULL, AC97_HAS_NO_STD_PCM }, 
162162{ 0x53494c20, 0xffffffe0, "Si3036,8",           mpatch_si3036,  mpatch_si3036, AC97_MODEM_PATCH }, 
163163{ 0x54524102, 0xffffffff, "TR28022",            NULL,           NULL }, 
164164{ 0x54524106, 0xffffffff, "TR28026",            NULL,           NULL }, 
  • TabularUnifiedsound/pci/ac97/ac97_patch.c

    old new  
    2929#include <linux/slab.h> 
    3030#include <linux/mutex.h> 
    3131 
     32#include <linux/proc_fs.h> 
     33#include <linux/string.h> 
     34#include <linux/ctype.h> 
     35 
    3236#include <sound/core.h> 
    3337#include <sound/pcm.h> 
    3438#include <sound/control.h> 
     
    406410
    407411 
    408412/* 
     413 * UCB1400 codec 
     414 */ 
     415 
     416#define AC97_UCB1400_FCSR1      0x6a 
     417#define AC97_UCB1400_FCSR2      0x6c 
     418 
     419static const struct snd_kcontrol_new ucb1400_snd_ac97_controls[] = { 
     420        AC97_SINGLE("Tone Control - Bass", AC97_UCB1400_FCSR1, 11, 4, 0), 
     421        AC97_SINGLE("Tone Control - Treble", AC97_UCB1400_FCSR1, 9, 2, 0), 
     422        AC97_SINGLE("Headphone Playback Switch", AC97_UCB1400_FCSR1, 6, 1, 0), 
     423        AC97_SINGLE("De-emphasis", AC97_UCB1400_FCSR1, 5, 1, 0), 
     424        AC97_SINGLE("DC Filter", AC97_UCB1400_FCSR1, 4, 1, 0), 
     425        AC97_SINGLE("Hi-pass Filter", AC97_UCB1400_FCSR1, 3, 1, 0), 
     426        AC97_SINGLE("ADC Filter", AC97_UCB1400_FCSR2, 12, 1, 0), 
     427}; 
     428 
     429#define NUM_GPIO_LINES 10 
     430 
     431static struct proc_dir_entry *proc_gpio_parent; 
     432static struct proc_dir_entry *proc_gpios[NUM_GPIO_LINES]; 
     433 
     434typedef struct 
     435{ 
     436        int                     gpio; 
     437        char                    name[32]; 
     438        struct snd_ac97         *ac97; 
     439} gpio_summary_type; 
     440 
     441static gpio_summary_type gpio_summaries[NUM_GPIO_LINES] = 
     442{ 
     443        { 0,    "UCB1400-0-0" }, 
     444        { 1,    "UCB1400-0-1" }, 
     445        { 2,    "UCB1400-0-2" }, 
     446        { 3,    "UCB1400-0-3" }, 
     447        { 4,    "UCB1400-0-4" }, 
     448        { 5,    "UCB1400-0-5" }, 
     449        { 6,    "UCB1400-0-6" }, 
     450        { 7,    "UCB1400-0-7" }, 
     451        { 8,    "UCB1400-0-8" }, 
     452        { 9,    "UCB1400-0-9" } 
     453}; 
     454 
     455 
     456static int proc_ucb1400_ac97_gpio_write(struct file *file, const char __user *buf, 
     457                        unsigned long count, void *data) 
     458{ 
     459    char *cur, lbuf[count + 1]; 
     460    gpio_summary_type *summary = data; 
     461    u32 direction_is_out, operation_is_set; 
     462    int i = summary->gpio; 
     463    u16 dir, value; 
     464 
     465    if (!capable(CAP_SYS_ADMIN)) 
     466            return -EACCES; 
     467 
     468    memset(lbuf, 0, count + 1); 
     469 
     470    if (copy_from_user(lbuf, buf, count)) 
     471            return -EFAULT; 
     472 
     473    cur = lbuf; 
     474 
     475    // Get current values 
     476    direction_is_out = !!(snd_ac97_read(summary->ac97, 0x5c) & (0x0001 << i)); 
     477    operation_is_set = !!(snd_ac97_read(summary->ac97, 0x5a) & (0x0001 << i)); 
     478    while(1) 
     479    { 
     480            // We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out} 
     481            // Anything else is an error 
     482            while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]); 
     483 
     484            if('/0' == cur[0]) break; 
     485 
     486            // Ok, so now we're pointing at the start of something 
     487            switch(cur[0]) 
     488            { 
     489                    case 'G': 
     490                            // Check that next is "PIO" -- '/0' will cause safe short-circuit if end of buf 
     491                            if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error; 
     492                            cur = &(cur[4]); 
     493                            break; 
     494                    case 's': 
     495                            if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error; 
     496                            operation_is_set = 1; 
     497                            cur = &(cur[3]); 
     498                            break; 
     499                    case 'c': 
     500                            if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto 
     501parse_error; 
     502                            operation_is_set = 0; 
     503                            cur = &(cur[5]); 
     504                            break; 
     505                    case 'i': 
     506                            if(!(cur[1] == 'n')) goto parse_error; 
     507                            direction_is_out = 0; 
     508                            cur = &(cur[2]); 
     509                            break; 
     510                    case 'o': 
     511                            if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error; 
     512                            direction_is_out = 1; 
     513                            cur = &(cur[3]); 
     514                            break; 
     515                    default: goto parse_error; 
     516            } 
     517    } 
     518     
     519    // set/get value 
     520    dir = snd_ac97_read(summary->ac97, 0x5c); 
     521    value = snd_ac97_read(summary->ac97, 0x5a); 
     522    if (direction_is_out) 
     523    { 
     524            dir |= 0x0001 << i;          
     525            if (operation_is_set) 
     526            { 
     527                    value |= 0x0001 << i; 
     528            } 
     529            else 
     530            { 
     531                    value &= ~(0x0001 << i); 
     532            } 
     533 
     534            snd_ac97_write(summary->ac97, 0x5c, dir); 
     535            snd_ac97_write(summary->ac97, 0x5a, value); 
     536    } 
     537    else // direction in 
     538    { 
     539            dir &= ~(0x0001 << i); 
     540            snd_ac97_write(summary->ac97, 0x5c, dir); 
     541            operation_is_set = snd_ac97_read(summary->ac97, 0x5a) & ~(0x0001 << i); 
     542    } 
     543 
     544#ifdef CONFIG_PROC_GPIO_DEBUG 
     545    printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s/n", 
     546                            "GPIO", 
     547                            direction_is_out ? "out" : "in", 
     548                            operation_is_set ? "set" : "clear", 
     549                            summary->name); 
     550#endif 
     551 
     552    return count; 
     553 
     554parse_error: 
     555    printk(KERN_CRIT "Parse error: Expect /"GPIO|[set|clear]|[in|out] .../"/n"); 
     556    return -EINVAL; 
     557} 
     558 
     559static int proc_ucb1400_ac97_gpio_read(char *page, char **start, off_t off, 
     560                    int count, int *eof, void *data) 
     561{ 
     562    char *p = page; 
     563    gpio_summary_type *summary = data; 
     564    int len, i; /*, af;*/ 
     565    i = summary->gpio; 
     566 
     567    p += sprintf(p, "%d/t%s/t%s/t%s/n", i, 
     568                    "GPIO", 
     569                    (snd_ac97_read(summary->ac97, 0x5c) & (0x0001 << i)) ? "out" : "in", 
     570                    (snd_ac97_read(summary->ac97, 0x5a) & (0x0001 << i)) ? "set" : "clear"); 
     571     
     572    len = (p - page) - off; 
     573 
     574    if(len < 0) 
     575    { 
     576            len = 0; 
     577    } 
     578 
     579    *eof = (len <= count) ? 1 : 0; 
     580    *start = page + off; 
     581 
     582    return len; 
     583} 
     584 
     585int patch_ucb1400(struct snd_ac97 * ac97) 
     586{ 
     587        int err, i; 
     588 
     589        proc_gpio_parent = proc_mkdir("gpio", NULL); 
     590        if(!proc_gpio_parent) return 0; 
     591  
     592        for(i=0; i < NUM_GPIO_LINES; i++) 
     593        { 
     594                proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent); 
     595                if(proc_gpios[i]) 
     596                { 
     597                        gpio_summaries[i].ac97 = ac97; 
     598                        proc_gpios[i]->data = &gpio_summaries[i]; 
     599                        proc_gpios[i]->read_proc = proc_ucb1400_ac97_gpio_read; 
     600                        proc_gpios[i]->write_proc = proc_ucb1400_ac97_gpio_write; 
     601                } 
     602        } 
     603 
     604        for(i = 0; i < ARRAY_SIZE(ucb1400_snd_ac97_controls); i++) { 
     605                if((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&ucb1400_snd_ac97_controls[i], ac97))) < 0) 
     606                        return err; 
     607        } 
     608 
     609        snd_ac97_write_cache(ac97,  AC97_UCB1400_FCSR1, 
     610                        (0 << 11) |     // 0 base boost 
     611                        (0 << 9)  |     // 0 treble boost 
     612                        (0 << 7)  |     // Mode = flat 
     613                        (1 << 6)  |     // Headphones enable 
     614                        (0 << 5)  |     // De-emphasis disabled 
     615                        (1 << 4)  |     // DC filter enabled 
     616                        (1 << 3)  |     // Hi-pass filter enabled 
     617                        (0 << 2)  |     // disable interrupt signalling via GPIO_INT 
     618                        (1 << 0)        // clear ADC overflow status if set 
     619                ); 
     620 
     621        snd_ac97_write_cache(ac97, AC97_UCB1400_FCSR2, 
     622                        (0 << 15) |     // must be 0 
     623                        (0 << 13) |     // must be 0 
     624                        (1 << 12) |     // ADC filter enabled 
     625                        (0 << 10) |     // must be 0 
     626                        (0 << 4)  |     // Smart low power mode on neither Codec nor PLL 
     627                        (0 << 0)        // must be 0 
     628                ); 
     629 
     630        return 0; 
     631} 
     632 
     633/* 
    409634 * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com> 
    410635 *  removed broken wolfson00 patch. 
    411636 *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. 
     
    34083633        ac97->res_table = lm4550_restbl; 
    34093634        return 0; 
    34103635
    3411  
    3412 /*  
    3413  *  UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf) 
    3414  */ 
    3415 static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = { 
    3416 /* enable/disable headphone driver which allows direct connection to 
    3417    stereo headphone without the use of external DC blocking 
    3418    capacitors */ 
    3419 AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0), 
    3420 /* Filter used to compensate the DC offset is added in the ADC to remove idle 
    3421    tones from the audio band. */ 
    3422 AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0), 
    3423 /* Control smart-low-power mode feature. Allows automatic power down 
    3424    of unused blocks in the ADC analog front end and the PLL. */ 
    3425 AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0), 
    3426 }; 
    3427  
    3428 static int patch_ucb1400_specific(struct snd_ac97 * ac97) 
    3429 { 
    3430         int idx, err; 
    3431         for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) 
    3432                 if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0) 
    3433                         return err; 
    3434         return 0; 
    3435 } 
    3436  
    3437 static struct snd_ac97_build_ops patch_ucb1400_ops = { 
    3438         .build_specific = patch_ucb1400_specific, 
    3439 }; 
    3440  
    3441 int patch_ucb1400(struct snd_ac97 * ac97) 
    3442 { 
    3443         ac97->build_ops = &patch_ucb1400_ops; 
    3444         /* enable headphone driver and smart low power mode by default */ 
    3445         snd_ac97_write(ac97, 0x6a, 0x0050); 
    3446         snd_ac97_write(ac97, 0x6c, 0x0030); 
    3447         return 0; 
    3448 } 
  •  

    转自:https://dev.openwrt.org/browser/trunk/target/linux/pxa/patches-2.6.21/027-ucb1400-ac97-audio.patch?rev=10955

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值