2 * Audio support for HTC Universal
3 * It uses PXA2xx i2Sound and AK4641 modules
5 * Copyright (c) 2006 Oleg Gusev
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.
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>
27 #include <asm/mach-types.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)
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
;
80 set_irq_type(irq
, IRQ_TYPE_EDGE_RISING
);
82 set_irq_type(irq
, IRQ_TYPE_EDGE_FALLING
);
87 static irqreturn_t
snd_htcuniversal_audio_hp_isr (int isr
, void *data
)
89 snd_ak4641_hp_detected(&ak
, snd_htcuniversal_audio_hp_detect());
93 static void snd_htcuniversal_audio_hp_detection_on(void)
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)
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
;
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();
133 snd_pxa2xx_i2sound_i2slink_free();
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
);
161 static int snd_htcuniversal_audio_suspend(pm_message_t state
)
163 snd_htcuniversal_audio_hp_detection_off();
164 snd_ak4641_suspend(&ak
, state
);
168 static int snd_htcuniversal_audio_resume(void)
170 snd_ak4641_resume(&ak
);
171 snd_htcuniversal_audio_hp_detection_on();
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
,
188 .suspend
= snd_htcuniversal_audio_suspend
,
189 .resume
= snd_htcuniversal_audio_resume
193 static int __init
snd_htcuniversal_audio_init(void)
196 if (!machine_is_htcuniversal()) {
197 snd_printk(KERN_INFO
"Module snd-htcuniversal_audio: not a HTC Universal!\n");
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");