Update olpc target kernel to 2.26.5.
[openwrt.git] / target / linux / olpc / patches-2.6.23 / 110-olpc_sound.patch
1 Index: linux-2.6.23.17/include/sound/ac97_codec.h
2 ===================================================================
3 --- linux-2.6.23.17.orig/include/sound/ac97_codec.h
4 +++ linux-2.6.23.17/include/sound/ac97_codec.h
5 @@ -281,10 +281,12 @@
6  /* specific - Analog Devices */
7  #define AC97_AD_TEST           0x5a    /* test register */
8  #define AC97_AD_TEST2          0x5c    /* undocumented test register 2 */
9 +#define AC97_AD_HPFD_SHIFT     12      /* High Pass Filter Disable */
10  #define AC97_AD_CODEC_CFG      0x70    /* codec configuration */
11  #define AC97_AD_JACK_SPDIF     0x72    /* Jack Sense & S/PDIF */
12  #define AC97_AD_SERIAL_CFG     0x74    /* Serial Configuration */
13  #define AC97_AD_MISC           0x76    /* Misc Control Bits */
14 +#define AC97_AD_VREFD_SHIFT    2       /* V_REFOUT Disable (AD1888) */
15  
16  /* specific - Cirrus Logic */
17  #define AC97_CSR_ACMODE                0x5e    /* AC Mode Register */
18 Index: linux-2.6.23.17/sound/pci/ac97/ac97_codec.c
19 ===================================================================
20 --- linux-2.6.23.17.orig/sound/pci/ac97/ac97_codec.c
21 +++ linux-2.6.23.17/sound/pci/ac97/ac97_codec.c
22 @@ -49,7 +49,7 @@ module_param(enable_loopback, bool, 0444
23  MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
24  
25  #ifdef CONFIG_SND_AC97_POWER_SAVE
26 -static int power_save;
27 +static int power_save = 1;
28  module_param(power_save, bool, 0644);
29  MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
30  #endif
31 Index: linux-2.6.23.17/sound/pci/ac97/ac97_patch.c
32 ===================================================================
33 --- linux-2.6.23.17.orig/sound/pci/ac97/ac97_patch.c
34 +++ linux-2.6.23.17/sound/pci/ac97/ac97_patch.c
35 @@ -1973,8 +1973,9 @@ static const struct snd_kcontrol_new snd
36                 .get = snd_ac97_ad1888_lohpsel_get,
37                 .put = snd_ac97_ad1888_lohpsel_put
38         },
39 -       AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
40 -       AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
41 +       AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
42 +       AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
43 +                       AC97_AD_HPFD_SHIFT, 1, 1),
44         AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
45         {
46                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
47 Index: linux-2.6.23.17/sound/pci/cs5535audio/Makefile
48 ===================================================================
49 --- linux-2.6.23.17.orig/sound/pci/cs5535audio/Makefile
50 +++ linux-2.6.23.17/sound/pci/cs5535audio/Makefile
51 @@ -8,5 +8,9 @@ ifeq ($(CONFIG_PM),y)
52  snd-cs5535audio-objs += cs5535audio_pm.o
53  endif
54  
55 +ifdef CONFIG_OLPC
56 +snd-cs5535audio-objs += cs5535audio_olpc.o
57 +endif
58 +
59  # Toplevel Module Dependency
60  obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
61 Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.c
62 ===================================================================
63 --- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio.c
64 +++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.c
65 @@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac
66         return snd_cs5535audio_codec_read(cs5535au, reg);
67  }
68  
69 -static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
70 +static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
71  {
72         struct snd_card *card = cs5535au->card;
73         struct snd_ac97_bus *pbus;
74 @@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct 
75                 return err;
76  
77         memset(&ac97, 0, sizeof(ac97));
78 -       ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
79 +       ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
80 +                       | AC97_SCAP_POWER_SAVE;
81         ac97.private_data = cs5535au;
82         ac97.pci = cs5535au->pci;
83  
84 +       /* olpc_prequirks is dummied out if not olpc */
85 +       olpc_prequirks(card, &ac97);
86 +
87         if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
88                 snd_printk(KERN_ERR "mixer failed\n");
89                 return err;
90 @@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct 
91  
92         snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
93  
94 +       /* olpc_quirks is dummied out if not olpc */
95 +       if (( err = olpc_quirks(card, cs5535au->ac97)) < 0) {
96 +               snd_printk(KERN_ERR "olpc quirks failed\n");
97 +               return err;
98 +       }
99 +
100         return 0;
101  }
102  
103 @@ -206,7 +216,6 @@ static void process_bm1_irq(struct cs553
104  static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
105  {
106         u16 acc_irq_stat;
107 -       u8 bm_stat;
108         unsigned char count;
109         struct cs5535audio *cs5535au = dev_id;
110  
111 @@ -217,7 +226,7 @@ static irqreturn_t snd_cs5535audio_inter
112  
113         if (!acc_irq_stat)
114                 return IRQ_NONE;
115 -       for (count = 0; count < 10; count++) {
116 +       for (count = 0; count < 4; count++) {
117                 if (acc_irq_stat & (1 << count)) {
118                         switch (count) {
119                         case IRQ_STS:
120 @@ -232,26 +241,9 @@ static irqreturn_t snd_cs5535audio_inter
121                         case BM1_IRQ_STS:
122                                 process_bm1_irq(cs5535au);
123                                 break;
124 -                       case BM2_IRQ_STS:
125 -                               bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS);
126 -                               break;
127 -                       case BM3_IRQ_STS:
128 -                               bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS);
129 -                               break;
130 -                       case BM4_IRQ_STS:
131 -                               bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS);
132 -                               break;
133 -                       case BM5_IRQ_STS:
134 -                               bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS);
135 -                               break;
136 -                       case BM6_IRQ_STS:
137 -                               bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS);
138 -                               break;
139 -                       case BM7_IRQ_STS:
140 -                               bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS);
141 -                               break;
142                         default:
143 -                               snd_printk(KERN_ERR "Unexpected irq src\n");
144 +                               snd_printk(KERN_ERR "Unexpected irq src: "
145 +                                               "0x%x\n", acc_irq_stat);
146                                 break;
147                         }
148                 }
149 Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.h
150 ===================================================================
151 --- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio.h
152 +++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.h
153 @@ -16,57 +16,28 @@
154  #define ACC_IRQ_STATUS                 0x12
155  #define ACC_BM0_CMD                    0x20
156  #define ACC_BM1_CMD                    0x28
157 -#define ACC_BM2_CMD                    0x30
158 -#define ACC_BM3_CMD                    0x38
159 -#define ACC_BM4_CMD                    0x40
160 -#define ACC_BM5_CMD                    0x48
161 -#define ACC_BM6_CMD                    0x50
162 -#define ACC_BM7_CMD                    0x58
163  #define ACC_BM0_PRD                    0x24
164  #define ACC_BM1_PRD                    0x2C
165 -#define ACC_BM2_PRD                    0x34
166 -#define ACC_BM3_PRD                    0x3C
167 -#define ACC_BM4_PRD                    0x44
168 -#define ACC_BM5_PRD                    0x4C
169 -#define ACC_BM6_PRD                    0x54
170 -#define ACC_BM7_PRD                    0x5C
171  #define ACC_BM0_STATUS                 0x21
172  #define ACC_BM1_STATUS                 0x29
173 -#define ACC_BM2_STATUS                 0x31
174 -#define ACC_BM3_STATUS                 0x39
175 -#define ACC_BM4_STATUS                 0x41
176 -#define ACC_BM5_STATUS                 0x49
177 -#define ACC_BM6_STATUS                 0x51
178 -#define ACC_BM7_STATUS                 0x59
179  #define ACC_BM0_PNTR                   0x60
180  #define ACC_BM1_PNTR                   0x64
181 -#define ACC_BM2_PNTR                   0x68
182 -#define ACC_BM3_PNTR                   0x6C
183 -#define ACC_BM4_PNTR                   0x70
184 -#define ACC_BM5_PNTR                   0x74
185 -#define ACC_BM6_PNTR                   0x78
186 -#define ACC_BM7_PNTR                   0x7C
187 +
188  /* acc_codec bar0 reg bits */
189  /* ACC_IRQ_STATUS */
190  #define IRQ_STS                        0
191  #define WU_IRQ_STS                     1
192  #define BM0_IRQ_STS                    2
193  #define BM1_IRQ_STS                    3
194 -#define BM2_IRQ_STS                    4
195 -#define BM3_IRQ_STS                    5
196 -#define BM4_IRQ_STS                    6
197 -#define BM5_IRQ_STS                    7
198 -#define BM6_IRQ_STS                    8
199 -#define BM7_IRQ_STS                    9
200  /* ACC_BMX_STATUS */
201  #define EOP                            (1<<0)
202  #define BM_EOP_ERR                     (1<<1)
203  /* ACC_BMX_CTL */
204 -#define BM_CTL_EN                      0x00000001
205 -#define BM_CTL_PAUSE                   0x00000011
206 -#define BM_CTL_DIS                     0x00000000
207 -#define BM_CTL_BYTE_ORD_LE             0x00000000
208 -#define BM_CTL_BYTE_ORD_BE             0x00000100
209 +#define BM_CTL_EN                      0x01
210 +#define BM_CTL_PAUSE                   0x03
211 +#define BM_CTL_DIS                     0x00
212 +#define BM_CTL_BYTE_ORD_LE             0x00
213 +#define BM_CTL_BYTE_ORD_BE             0x04
214  /* cs5535 specific ac97 codec register defines */
215  #define CMD_MASK                       0xFF00FFFF
216  #define CMD_NEW                                0x00010000
217 @@ -106,8 +77,8 @@ struct cs5535audio_dma {
218         struct snd_pcm_substream *substream;
219         unsigned int buf_addr, buf_bytes;
220         unsigned int period_bytes, periods;
221 -       int suspended;
222         u32 saved_prd;
223 +       int pcm_open_flag;
224  };
225  
226  struct cs5535audio {
227 @@ -123,8 +94,21 @@ struct cs5535audio {
228         struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
229  };
230  
231 +#ifdef CONFIG_PM
232  int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
233  int snd_cs5535audio_resume(struct pci_dev *pci);
234 +#endif
235 +
236 +#ifdef CONFIG_OLPC
237 +void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) __devinit;
238 +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) __devinit;
239 +int olpc_ai_enable(struct snd_ac97 *ac97, u8 val);
240 +#else
241 +#define olpc_prequirks(arg,arg2)       do {} while (0)
242 +#define olpc_quirks(arg,arg2)          (0)
243 +#define olpc_ai_enable(a, v) (0)
244 +#endif
245 +
246  int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
247  
248  #endif /* __SOUND_CS5535AUDIO_H */
249 Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pcm.c
250 ===================================================================
251 --- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio_pcm.c
252 +++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pcm.c
253 @@ -164,6 +164,7 @@ static int cs5535audio_build_dma_packets
254         jmpprd_addr = cpu_to_le32(lastdesc->addr +
255                                   (sizeof(struct cs5535audio_dma_desc)*periods));
256  
257 +       dma->substream = substream;
258         dma->period_bytes = period_bytes;
259         dma->periods = periods;
260         spin_lock_irq(&cs5535au->reg_lock);
261 @@ -241,6 +242,7 @@ static void cs5535audio_clear_dma_packet
262  {
263         snd_dma_free_pages(&dma->desc_buf);
264         dma->desc_buf.area = NULL;
265 +       dma->substream = NULL;
266  }
267  
268  static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream,
269 @@ -260,6 +262,9 @@ static int snd_cs5535audio_hw_params(str
270         err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
271                                             params_periods(hw_params),
272                                             params_period_bytes(hw_params));
273 +       if (!err)
274 +               dma->pcm_open_flag = 1;
275 +
276         return err;
277  }
278  
279 @@ -268,6 +273,15 @@ static int snd_cs5535audio_hw_free(struc
280         struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
281         struct cs5535audio_dma *dma = substream->runtime->private_data;
282  
283 +       if (dma->pcm_open_flag) {
284 +               if (substream == cs5535au->playback_substream)
285 +                       snd_ac97_update_power(cs5535au->ac97,
286 +                                       AC97_PCM_FRONT_DAC_RATE, 0);
287 +               else
288 +                       snd_ac97_update_power(cs5535au->ac97,
289 +                                       AC97_PCM_LR_ADC_RATE, 0);
290 +               dma->pcm_open_flag = 0;
291 +       }
292         cs5535audio_clear_dma_packets(cs5535au, dma, substream);
293         return snd_pcm_lib_free_pages(substream);
294  }
295 @@ -298,14 +312,12 @@ static int snd_cs5535audio_trigger(struc
296                 break;
297         case SNDRV_PCM_TRIGGER_RESUME:
298                 dma->ops->enable_dma(cs5535au);
299 -               dma->suspended = 0;
300                 break;
301         case SNDRV_PCM_TRIGGER_STOP:
302                 dma->ops->disable_dma(cs5535au);
303                 break;
304         case SNDRV_PCM_TRIGGER_SUSPEND:
305                 dma->ops->disable_dma(cs5535au);
306 -               dma->suspended = 1;
307                 break;
308         default:
309                 snd_printk(KERN_ERR "unhandled trigger\n");
310 @@ -344,6 +356,7 @@ static int snd_cs5535audio_capture_open(
311         int err;
312         struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
313         struct snd_pcm_runtime *runtime = substream->runtime;
314 +       struct snd_ac97 *ac97 = cs5535au->ac97;
315  
316         runtime->hw = snd_cs5535audio_capture;
317         cs5535au->capture_substream = substream;
318 @@ -352,11 +365,29 @@ static int snd_cs5535audio_capture_open(
319         if ((err = snd_pcm_hw_constraint_integer(runtime,
320                                          SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
321                 return err;
322 -       return 0;
323 +
324 +#ifdef CONFIG_OLPC
325 +       /* Disable Analog Input */
326 +       olpc_ai_enable(ac97, 0);
327 +       /* Enable V_ref bias while recording. */
328 +       snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT, 0);
329 +#endif
330 +       return err;
331  }
332  
333  static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
334  {
335 +#ifdef CONFIG_OLPC
336 +       struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
337 +       struct snd_ac97 *ac97 = cs5535au->ac97;
338 +
339 +       /* Disable Analog Input */
340 +       olpc_ai_enable(ac97, 0);
341 +       /* Disable V_ref bias. */
342 +       snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT,
343 +                       1<<AC97_AD_VREFD_SHIFT);
344 +#endif
345 +
346         return 0;
347  }
348  
349 Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pm.c
350 ===================================================================
351 --- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio_pm.c
352 +++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pm.c
353 @@ -64,18 +64,21 @@ int snd_cs5535audio_suspend(struct pci_d
354         int i;
355  
356         snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
357 +       snd_pcm_suspend_all(cs5535au->pcm);
358 +       snd_ac97_suspend(cs5535au->ac97);
359         for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
360                 struct cs5535audio_dma *dma = &cs5535au->dmas[i];
361 -               if (dma && dma->substream && !dma->suspended) 
362 +               if (dma && dma->substream)
363                         dma->saved_prd = dma->ops->read_prd(cs5535au);
364         }
365 -       snd_pcm_suspend_all(cs5535au->pcm);
366 -       snd_ac97_suspend(cs5535au->ac97);
367         /* save important regs, then disable aclink in hw */
368         snd_cs5535audio_stop_hardware(cs5535au);
369  
370 +       if (pci_save_state(pci)) {
371 +               printk(KERN_ERR "cs5535audio: pci_save_state failed!\n");
372 +               return -EIO;
373 +       }
374         pci_disable_device(pci);
375 -       pci_save_state(pci);
376         pci_set_power_state(pci, pci_choose_state(pci, state));
377         return 0;
378  }
379 @@ -89,7 +92,12 @@ int snd_cs5535audio_resume(struct pci_de
380         int i;
381  
382         pci_set_power_state(pci, PCI_D0);
383 -       pci_restore_state(pci);
384 +       if (pci_restore_state(pci) < 0) {
385 +               printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
386 +                      "disabling device\n");
387 +               snd_card_disconnect(card);
388 +               return -EIO;
389 +       }
390         if (pci_enable_device(pci) < 0) {
391                 printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
392                        "disabling device\n");
393 @@ -112,17 +120,17 @@ int snd_cs5535audio_resume(struct pci_de
394         if (!timeout)
395                 snd_printk(KERN_ERR "Failure getting AC Link ready\n");
396  
397 -       /* we depend on ac97 to perform the codec power up */
398 -       snd_ac97_resume(cs5535au->ac97);
399         /* set up rate regs, dma. actual initiation is done in trig */
400         for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
401                 struct cs5535audio_dma *dma = &cs5535au->dmas[i];
402 -               if (dma && dma->substream && dma->suspended) {
403 +               if (dma && dma->substream) {
404                         dma->substream->ops->prepare(dma->substream);
405                         dma->ops->setup_prd(cs5535au, dma->saved_prd);
406                 }
407         }
408 -               
409 +
410 +       /* we depend on ac97 to perform the codec power up */
411 +       snd_ac97_resume(cs5535au->ac97);
412         snd_power_change_state(card, SNDRV_CTL_POWER_D0);
413  
414         return 0;