cb01d2c658c0377a1d1ec122fb9c0bece5d0d760
[openwrt.git] / target / linux / pxa / patches-2.6.21 / 027-ucb1400-ac97-audio.patch
1 Index: linux-2.6.21gum/sound/pci/ac97/ac97_codec.c
2 ===================================================================
3 --- linux-2.6.21gum.orig/sound/pci/ac97/ac97_codec.c
4 +++ linux-2.6.21gum/sound/pci/ac97/ac97_codec.c
5 @@ -158,7 +158,7 @@ static const struct ac97_codec_id snd_ac
6  { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48",        NULL,           NULL }, // only guess --jk
7  { 0x4e534331, 0xffffffff, "LM4549",            NULL,           NULL },
8  { 0x4e534350, 0xffffffff, "LM4550",            patch_lm4550,   NULL }, // volume wrap fix 
9 -{ 0x50534304, 0xffffffff, "UCB1400",           patch_ucb1400,  NULL },
10 +{ 0x50534304, 0xffffffff, "UCB1400",           patch_ucb1400,  NULL, AC97_HAS_NO_STD_PCM },
11  { 0x53494c20, 0xffffffe0, "Si3036,8",          mpatch_si3036,  mpatch_si3036, AC97_MODEM_PATCH },
12  { 0x54524102, 0xffffffff, "TR28022",           NULL,           NULL },
13  { 0x54524106, 0xffffffff, "TR28026",           NULL,           NULL },
14 Index: linux-2.6.21gum/sound/pci/ac97/ac97_patch.c
15 ===================================================================
16 --- linux-2.6.21gum.orig/sound/pci/ac97/ac97_patch.c
17 +++ linux-2.6.21gum/sound/pci/ac97/ac97_patch.c
18 @@ -29,6 +29,10 @@
19  #include <linux/slab.h>
20  #include <linux/mutex.h>
21  
22 +#include <linux/proc_fs.h>
23 +#include <linux/string.h>
24 +#include <linux/ctype.h>
25 +
26  #include <sound/core.h>
27  #include <sound/pcm.h>
28  #include <sound/control.h>
29 @@ -406,6 +410,227 @@ int patch_yamaha_ymf753(struct snd_ac97 
30  }
31  
32  /*
33 + * UCB1400 codec
34 + */
35 +
36 +#define AC97_UCB1400_FCSR1     0x6a
37 +#define AC97_UCB1400_FCSR2     0x6c
38 +
39 +static const struct snd_kcontrol_new ucb1400_snd_ac97_controls[] = {
40 +       AC97_SINGLE("Tone Control - Bass", AC97_UCB1400_FCSR1, 11, 4, 0),
41 +       AC97_SINGLE("Tone Control - Treble", AC97_UCB1400_FCSR1, 9, 2, 0),
42 +       AC97_SINGLE("Headphone Playback Switch", AC97_UCB1400_FCSR1, 6, 1, 0),
43 +       AC97_SINGLE("De-emphasis", AC97_UCB1400_FCSR1, 5, 1, 0),
44 +       AC97_SINGLE("DC Filter", AC97_UCB1400_FCSR1, 4, 1, 0),
45 +       AC97_SINGLE("Hi-pass Filter", AC97_UCB1400_FCSR1, 3, 1, 0),
46 +       AC97_SINGLE("ADC Filter", AC97_UCB1400_FCSR2, 12, 1, 0),
47 +};
48 +
49 +#define NUM_GPIO_LINES 10
50 +
51 +static struct proc_dir_entry *proc_gpio_parent;
52 +static struct proc_dir_entry *proc_gpios[NUM_GPIO_LINES];
53 +
54 +typedef struct
55 +{
56 +       int                     gpio;
57 +       char                    name[32];
58 +       struct snd_ac97         *ac97;
59 +} gpio_summary_type;
60 +
61 +static gpio_summary_type gpio_summaries[NUM_GPIO_LINES] =
62 +{
63 +       { 0,    "UCB1400-0-0" },
64 +       { 1,    "UCB1400-0-1" },
65 +       { 2,    "UCB1400-0-2" },
66 +       { 3,    "UCB1400-0-3" },
67 +       { 4,    "UCB1400-0-4" },
68 +       { 5,    "UCB1400-0-5" },
69 +       { 6,    "UCB1400-0-6" },
70 +       { 7,    "UCB1400-0-7" },
71 +       { 8,    "UCB1400-0-8" },
72 +       { 9,    "UCB1400-0-9" }
73 +};
74 +
75 +
76 +static int proc_ucb1400_ac97_gpio_write(struct file *file, const char __user *buf,
77 +                        unsigned long count, void *data)
78 +{
79 +    char *cur, lbuf[count + 1];
80 +    gpio_summary_type *summary = data;
81 +    u32 direction_is_out, operation_is_set;
82 +    int i = summary->gpio;
83 +    u16 dir, value;
84 +
85 +    if (!capable(CAP_SYS_ADMIN))
86 +            return -EACCES;
87 +
88 +    memset(lbuf, 0, count + 1);
89 +
90 +    if (copy_from_user(lbuf, buf, count))
91 +            return -EFAULT;
92 +
93 +    cur = lbuf;
94 +
95 +    // Get current values
96 +    direction_is_out = !!(snd_ac97_read(summary->ac97, 0x5c) & (0x0001 << i));
97 +    operation_is_set = !!(snd_ac97_read(summary->ac97, 0x5a) & (0x0001 << i));
98 +    while(1)
99 +    {
100 +            // We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out}
101 +            // Anything else is an error
102 +            while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]);
103 +
104 +            if('\0' == cur[0]) break;
105 +
106 +            // Ok, so now we're pointing at the start of something
107 +            switch(cur[0])
108 +            {
109 +                    case 'G':
110 +                            // Check that next is "PIO" -- '\0' will cause safe short-circuit if end of buf
111 +                            if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error;
112 +                            cur = &(cur[4]);
113 +                            break;
114 +                    case 's':
115 +                            if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error;
116 +                            operation_is_set = 1;
117 +                            cur = &(cur[3]);
118 +                            break;
119 +                    case 'c':
120 +                            if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto
121 +parse_error;
122 +                            operation_is_set = 0;
123 +                            cur = &(cur[5]);
124 +                            break;
125 +                    case 'i':
126 +                            if(!(cur[1] == 'n')) goto parse_error;
127 +                            direction_is_out = 0;
128 +                            cur = &(cur[2]);
129 +                            break;
130 +                    case 'o':
131 +                            if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error;
132 +                            direction_is_out = 1;
133 +                            cur = &(cur[3]);
134 +                            break;
135 +                    default: goto parse_error;
136 +            }
137 +    }
138 +    
139 +    // set/get value
140 +    dir = snd_ac97_read(summary->ac97, 0x5c);
141 +    value = snd_ac97_read(summary->ac97, 0x5a);
142 +    if (direction_is_out)
143 +    {
144 +            dir |= 0x0001 << i;                
145 +            if (operation_is_set)
146 +            {
147 +                    value |= 0x0001 << i;
148 +            }
149 +            else
150 +            {
151 +                    value &= ~(0x0001 << i);
152 +            }
153 +
154 +            snd_ac97_write(summary->ac97, 0x5c, dir);
155 +            snd_ac97_write(summary->ac97, 0x5a, value);
156 +    }
157 +    else // direction in
158 +    {
159 +            dir &= ~(0x0001 << i);
160 +            snd_ac97_write(summary->ac97, 0x5c, dir);
161 +            operation_is_set = snd_ac97_read(summary->ac97, 0x5a) & ~(0x0001 << i);
162 +    }
163 +
164 +#ifdef CONFIG_PROC_GPIO_DEBUG
165 +    printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s\n",
166 +                            "GPIO",
167 +                            direction_is_out ? "out" : "in",
168 +                            operation_is_set ? "set" : "clear",
169 +                            summary->name);
170 +#endif
171 +
172 +    return count;
173 +
174 +parse_error:
175 +    printk(KERN_CRIT "Parse error: Expect \"GPIO|[set|clear]|[in|out] ...\"\n");
176 +    return -EINVAL;
177 +}
178 +
179 +static int proc_ucb1400_ac97_gpio_read(char *page, char **start, off_t off,
180 +                    int count, int *eof, void *data)
181 +{
182 +    char *p = page;
183 +    gpio_summary_type *summary = data;
184 +    int len, i; /*, af;*/
185 +    i = summary->gpio;
186 +
187 +    p += sprintf(p, "%d\t%s\t%s\t%s\n", i,
188 +                    "GPIO",
189 +                    (snd_ac97_read(summary->ac97, 0x5c) & (0x0001 << i)) ? "out" : "in",
190 +                    (snd_ac97_read(summary->ac97, 0x5a) & (0x0001 << i)) ? "set" : "clear");
191 +    
192 +    len = (p - page) - off;
193 +
194 +    if(len < 0)
195 +    {
196 +            len = 0;
197 +    }
198 +
199 +    *eof = (len <= count) ? 1 : 0;
200 +    *start = page + off;
201 +
202 +    return len;
203 +}
204 +
205 +int patch_ucb1400(struct snd_ac97 * ac97)
206 +{
207 +       int err, i;
208 +
209 +       proc_gpio_parent = proc_mkdir("gpio", NULL);
210 +       if(!proc_gpio_parent) return 0;
211
212 +       for(i=0; i < NUM_GPIO_LINES; i++)
213 +       {
214 +               proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent);
215 +               if(proc_gpios[i])
216 +               {
217 +                       gpio_summaries[i].ac97 = ac97;
218 +                       proc_gpios[i]->data = &gpio_summaries[i];
219 +                       proc_gpios[i]->read_proc = proc_ucb1400_ac97_gpio_read;
220 +                       proc_gpios[i]->write_proc = proc_ucb1400_ac97_gpio_write;
221 +               }
222 +       }
223 +
224 +       for(i = 0; i < ARRAY_SIZE(ucb1400_snd_ac97_controls); i++) {
225 +               if((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&ucb1400_snd_ac97_controls[i], ac97))) < 0)
226 +                       return err;
227 +       }
228 +
229 +       snd_ac97_write_cache(ac97,  AC97_UCB1400_FCSR1,
230 +                       (0 << 11) |     // 0 base boost
231 +                       (0 << 9)  |     // 0 treble boost
232 +                       (0 << 7)  |     // Mode = flat
233 +                       (1 << 6)  |     // Headphones enable
234 +                       (0 << 5)  |     // De-emphasis disabled
235 +                       (1 << 4)  |     // DC filter enabled
236 +                       (1 << 3)  |     // Hi-pass filter enabled
237 +                       (0 << 2)  |     // disable interrupt signalling via GPIO_INT
238 +                       (1 << 0)        // clear ADC overflow status if set
239 +               );
240 +
241 +       snd_ac97_write_cache(ac97, AC97_UCB1400_FCSR2,
242 +                       (0 << 15) |     // must be 0
243 +                       (0 << 13) |     // must be 0
244 +                       (1 << 12) |     // ADC filter enabled
245 +                       (0 << 10) |     // must be 0
246 +                       (0 << 4)  |     // Smart low power mode on neither Codec nor PLL
247 +                       (0 << 0)        // must be 0
248 +               );
249 +
250 +       return 0;
251 +}
252 +
253 +/*
254   * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
255   *  removed broken wolfson00 patch.
256   *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
257 @@ -3408,41 +3633,3 @@ int patch_lm4550(struct snd_ac97 *ac97)
258         ac97->res_table = lm4550_restbl;
259         return 0;
260  }
261 -
262 -/* 
263 - *  UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf)
264 - */
265 -static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = {
266 -/* enable/disable headphone driver which allows direct connection to
267 -   stereo headphone without the use of external DC blocking
268 -   capacitors */
269 -AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0),
270 -/* Filter used to compensate the DC offset is added in the ADC to remove idle
271 -   tones from the audio band. */
272 -AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0),
273 -/* Control smart-low-power mode feature. Allows automatic power down
274 -   of unused blocks in the ADC analog front end and the PLL. */
275 -AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0),
276 -};
277 -
278 -static int patch_ucb1400_specific(struct snd_ac97 * ac97)
279 -{
280 -       int idx, err;
281 -       for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++)
282 -               if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0)
283 -                       return err;
284 -       return 0;
285 -}
286 -
287 -static struct snd_ac97_build_ops patch_ucb1400_ops = {
288 -       .build_specific = patch_ucb1400_specific,
289 -};
290 -
291 -int patch_ucb1400(struct snd_ac97 * ac97)
292 -{
293 -       ac97->build_ops = &patch_ucb1400_ops;
294 -       /* enable headphone driver and smart low power mode by default */
295 -       snd_ac97_write(ac97, 0x6a, 0x0050);
296 -       snd_ac97_write(ac97, 0x6c, 0x0030);
297 -       return 0;
298 -}