hh.org updates
[hh.org.git] / sound / arm / htcuniversal_audio.c
blob725ade3b7d3494ad0922fdf08ece310c63a32c2f
1 /*
2 * Audio support for HTC Universal
3 * It uses PXA2xx i2Sound and AK4641 modules
5 * Copyright (c) 2006 Oleg Gusev
6 *
7 * Reference code: hx4700_audio.c
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation, or (at your option) any later version.
13 * History:
15 * 2006-07 Initial release -- Oleg Gusev
16 * 2006-09 Use new AK4641 code -- Giorgio Padrin
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/delay.h>
23 #include <linux/interrupt.h>
24 #include <linux/platform_device.h>
25 #include <asm/hardware.h>
26 #include <linux/pm.h>
27 #include <asm/mach-types.h>
28 #include <asm/irq.h>
29 #include <asm/mach/irq.h>
30 #include <asm/arch/pxa-regs.h>
31 #include <linux/soc/asic3_base.h>
32 #include <asm/arch/htcuniversal-gpio.h>
33 #include <asm/arch/htcuniversal-asic.h>
35 #include "pxa2xx-i2sound.h"
36 #include <sound/ak4641.h>
38 static struct snd_ak4641 ak;
40 static void snd_htcuniversal_audio_set_codec_power(int mode)
42 printk( KERN_NOTICE "snd_htcuniversal_audio_set_codec_power: %d\n", mode );
44 asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_AUDIO_PWR_ON , mode?(1<<GPIOA_AUDIO_PWR_ON):0);
47 static void snd_htcuniversal_audio_set_codec_reset(int mode)
49 printk( KERN_NOTICE "snd_htcuniversal_audio_set_codec_reset: %d\n", mode );
50 asic3_set_gpio_out_b(&htcuniversal_asic3.dev, 1<<GPIOB_CODEC_PDN , mode?0:(1<<GPIOB_CODEC_PDN));
53 static void snd_htcuniversal_audio_set_headphone_power(int mode)
55 printk( KERN_NOTICE "snd_htcuniversal_audio_set_headphone_power: %d\n", mode );
57 asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_EARPHONE_PWR_ON , mode?(1<<GPIOA_EARPHONE_PWR_ON):0);
60 static void snd_htcuniversal_audio_set_speaker_power(int mode)
62 /* speaker shutdown (0=shutdown)*/
63 printk( KERN_NOTICE "snd_htcuniversal_audio_set_speaker_power: %d\n", mode );
65 asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_SPK_PWR1_ON , mode?(1<<GPIOA_SPK_PWR1_ON):0);
66 asic3_set_gpio_out_a(&htcuniversal_asic3.dev, 1<<GPIOA_SPK_PWR2_ON , mode?(1<<GPIOA_SPK_PWR2_ON):0);
69 static inline int snd_htcuniversal_audio_hp_detect(void)
71 int irq, hp_in;
73 hp_in= (((asic3_get_gpio_status_b( &htcuniversal_asic3.dev )) & (1<<GPIOB_EARPHONE_N)) == 0);
75 printk( KERN_NOTICE "snd_htcuniversal_audio_set_headphone_detect: %d\n", hp_in);
77 irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOB_IRQ_BASE + GPIOB_EARPHONE_N;
79 if (hp_in)
80 set_irq_type(irq, IRQ_TYPE_EDGE_RISING );
81 else
82 set_irq_type(irq, IRQ_TYPE_EDGE_FALLING );
84 return hp_in;
87 static irqreturn_t snd_htcuniversal_audio_hp_isr (int isr, void *data)
89 snd_ak4641_hp_detected(&ak, snd_htcuniversal_audio_hp_detect());
90 return IRQ_HANDLED;
93 static void snd_htcuniversal_audio_hp_detection_on(void)
95 unsigned long flags;
96 int irq;
98 irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOB_IRQ_BASE + GPIOB_EARPHONE_N;
99 if (request_irq(irq, snd_htcuniversal_audio_hp_isr, SA_INTERRUPT | SA_SAMPLE_RANDOM,
100 "HTC Universal Headphone Jack", NULL) != 0)
101 return;
102 set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
104 local_irq_save(flags);
105 snd_ak4641_hp_detected(&ak, snd_htcuniversal_audio_hp_detect());
106 local_irq_restore(flags);
109 static void snd_htcuniversal_audio_hp_detection_off(void)
111 int irq = asic3_irq_base( &htcuniversal_asic3.dev ) + ASIC3_GPIOB_IRQ_BASE + GPIOB_EARPHONE_N;
112 free_irq(irq, NULL);
115 static struct snd_ak4641 ak = {
116 .power_on_chip = snd_htcuniversal_audio_set_codec_power,
117 .reset_pin = snd_htcuniversal_audio_set_codec_reset,
118 .headphone_out_on = snd_htcuniversal_audio_set_headphone_power,
119 .speaker_out_on = snd_htcuniversal_audio_set_speaker_power
122 static int snd_htcuniversal_audio_activate(void)
124 /* AK4641 on PXA2xx I2C bus */
125 ak.i2c_client.adapter = i2c_get_adapter(0);
127 snd_pxa2xx_i2sound_i2slink_get();
128 if (snd_ak4641_activate(&ak) == 0) {
129 snd_htcuniversal_audio_hp_detection_on();
130 return 0;
132 else {
133 snd_pxa2xx_i2sound_i2slink_free();
134 return -1;
138 static void snd_htcuniversal_audio_deactivate(void)
140 snd_htcuniversal_audio_hp_detection_off();
141 snd_ak4641_deactivate(&ak);
142 snd_pxa2xx_i2sound_i2slink_free();
145 static int snd_htcuniversal_audio_open_stream(int stream)
147 return snd_ak4641_open_stream(&ak, stream);
150 static void snd_htcuniversal_audio_close_stream(int stream)
152 snd_ak4641_close_stream(&ak, stream);
155 static int snd_htcuniversal_audio_add_mixer_controls(struct snd_card *acard)
157 return snd_ak4641_add_mixer_controls(&ak, acard);
160 #ifdef CONFIG_PM
161 static int snd_htcuniversal_audio_suspend(pm_message_t state)
163 snd_htcuniversal_audio_hp_detection_off();
164 snd_ak4641_suspend(&ak, state);
165 return 0;
168 static int snd_htcuniversal_audio_resume(void)
170 snd_ak4641_resume(&ak);
171 snd_htcuniversal_audio_hp_detection_on();
172 return 0;
174 #endif
176 static struct snd_pxa2xx_i2sound_board htcuniversal_audio = {
177 .name = "HTC Universal Audio",
178 .desc = "HTC Universal Audio [codec Asahi Kasei AK4641]",
179 .acard_id = "HTC Universal Audio",
180 .info = SND_PXA2xx_I2SOUND_INFO_CLOCK_FROM_PXA |
181 SND_PXA2xx_I2SOUND_INFO_CAN_CAPTURE,
182 .activate = snd_htcuniversal_audio_activate,
183 .deactivate = snd_htcuniversal_audio_deactivate,
184 .open_stream = snd_htcuniversal_audio_open_stream,
185 .close_stream = snd_htcuniversal_audio_close_stream,
186 .add_mixer_controls = snd_htcuniversal_audio_add_mixer_controls,
187 #ifdef CONFIG_PM
188 .suspend = snd_htcuniversal_audio_suspend,
189 .resume = snd_htcuniversal_audio_resume
190 #endif
193 static int __init snd_htcuniversal_audio_init(void)
195 /* check machine */
196 if (!machine_is_htcuniversal()) {
197 snd_printk(KERN_INFO "Module snd-htcuniversal_audio: not a HTC Universal!\n");
198 return -1;
201 request_module("i2c-pxa");
202 return snd_pxa2xx_i2sound_card_activate(&htcuniversal_audio);
205 static void __exit snd_htcuniversal_audio_exit(void)
207 snd_pxa2xx_i2sound_card_deactivate();
210 module_init(snd_htcuniversal_audio_init);
211 module_exit(snd_htcuniversal_audio_exit);
213 MODULE_AUTHOR("Oleg, Giorgio Padrin");
214 MODULE_DESCRIPTION("Audio support for HTC Universal");
215 MODULE_LICENSE("GPL");