diff -NruP kernel26/.config kernel2616hh5/.config --- kernel26/.config 2006-07-29 19:42:54.000000000 +0100 +++ kernel2616hh5/.config 2006-08-04 20:34:39.000000000 +0100 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16-hh5 -# Sat Jul 29 19:42:54 2006 +# Fri Aug 4 20:34:39 2006 # CONFIG_ARM=y CONFIG_MMU=y @@ -1048,15 +1048,18 @@ # CONFIG_SND_A716 is not set # CONFIG_SND_H1910 is not set # CONFIG_SND_H2200 is not set +CONFIG_SND_H4000=m # CONFIG_SND_HTCMAGICIAN is not set # CONFIG_SND_HX4700 is not set # CONFIG_SND_HTCUNIVERSAL is not set # CONFIG_SND_H5XXX_AK4535 is not set +CONFIG_SND_PXA2xx_I2SOUND=m # CONFIG_SND_PXA2XX_AC97 is not set # # PCMCIA devices # +CONFIG_SND_UDA1380=m # # Open Sound System diff -NruP kernel26/.version kernel2616hh5/.version --- kernel26/.version 2006-07-29 19:49:00.000000000 +0100 +++ kernel2616hh5/.version 2006-08-04 20:39:54.000000000 +0100 @@ -1 +1 @@ -5 +7 diff -NruP kernel26/include/config/snd/h4000/module.h kernel2616hh5/include/config/snd/h4000/module.h --- kernel26/include/config/snd/h4000/module.h 1970-01-01 01:00:00.000000000 +0100 +++ kernel2616hh5/include/config/snd/h4000/module.h 2006-08-04 19:20:21.000000000 +0100 @@ -0,0 +1 @@ +#define CONFIG_SND_H4000_MODULE 1 diff -NruP kernel26/include/config/snd/pxa2xx/i2sound/module.h kernel2616hh5/include/config/snd/pxa2xx/i2sound/module.h --- kernel26/include/config/snd/pxa2xx/i2sound/module.h 1970-01-01 01:00:00.000000000 +0100 +++ kernel2616hh5/include/config/snd/pxa2xx/i2sound/module.h 2006-08-04 19:20:21.000000000 +0100 @@ -0,0 +1 @@ +#define CONFIG_SND_PXA2xx_I2SOUND_MODULE 1 diff -NruP kernel26/include/config/snd/uda1380/module.h kernel2616hh5/include/config/snd/uda1380/module.h --- kernel26/include/config/snd/uda1380/module.h 1970-01-01 01:00:00.000000000 +0100 +++ kernel2616hh5/include/config/snd/uda1380/module.h 2006-08-04 19:20:21.000000000 +0100 @@ -0,0 +1 @@ +#define CONFIG_SND_UDA1380_MODULE 1 diff -NruP kernel26/include/linux/autoconf.h kernel2616hh5/include/linux/autoconf.h --- kernel26/include/linux/autoconf.h 2006-07-29 19:42:54.000000000 +0100 +++ kernel2616hh5/include/linux/autoconf.h 2006-08-04 20:34:39.000000000 +0100 @@ -1,7 +1,7 @@ /* * Automatically generated C config: don't edit * Linux kernel version: 2.6.16-hh5 - * Sat Jul 29 19:42:54 2006 + * Fri Aug 4 20:34:39 2006 */ #define AUTOCONF_INCLUDED #define CONFIG_ARM 1 @@ -1049,15 +1049,18 @@ #undef CONFIG_SND_A716 #undef CONFIG_SND_H1910 #undef CONFIG_SND_H2200 +#define CONFIG_SND_H4000_MODULE 1 #undef CONFIG_SND_HTCMAGICIAN #undef CONFIG_SND_HX4700 #undef CONFIG_SND_HTCUNIVERSAL #undef CONFIG_SND_H5XXX_AK4535 +#define CONFIG_SND_PXA2xx_I2SOUND_MODULE 1 #undef CONFIG_SND_PXA2XX_AC97 /* * PCMCIA devices */ +#define CONFIG_SND_UDA1380_MODULE 1 /* * Open Sound System diff -NruP kernel26/sound/arm/Kconfig kernel2616hh5/sound/arm/Kconfig --- kernel26/sound/arm/Kconfig 2006-07-28 11:18:47.000000000 +0100 +++ kernel2616hh5/sound/arm/Kconfig 2006-08-04 19:19:42.000000000 +0100 @@ -27,6 +27,14 @@ help Say Y or M if you have an HP iPAQ H22xx and want audio support +config SND_H4000 + tristate "iPAQ h4000 driver" + depends on ARCH_PXA && SND && I2C + select SND_PXA2xx_I2SOUND + select SND_UDA1380 + help + Say Y or M if you have an HP iPAQ H4xxx and want audio support + config SND_HTCMAGICIAN tristate "HTC Magician driver" depends on ARCH_PXA && SND && I2C diff -NruP kernel26/sound/arm/Makefile kernel2616hh5/sound/arm/Makefile --- kernel26/sound/arm/Makefile 2006-07-28 11:18:47.000000000 +0100 +++ kernel2616hh5/sound/arm/Makefile 2006-08-04 19:19:42.000000000 +0100 @@ -6,6 +6,7 @@ snd-a716_audio-objs := a716_audio.o snd-h1910_audio-objs := h1910_audio.o snd-h2200_audio-objs := h2200_audio.o +snd-h4000_audio-objs := h4000_audio.o snd-htcmagician_audio-objs := htcmagician_audio.o snd-hx4700_audio-objs := hx4700_audio.o snd-htcuniversal_audio-objs := htcuniversal_audio.o @@ -24,6 +25,7 @@ obj-$(CONFIG_SND_A716) += snd-a716_audio.o obj-$(CONFIG_SND_H1910) += snd-h1910_audio.o obj-$(CONFIG_SND_H2200) += snd-h2200_audio.o +obj-$(CONFIG_SND_H4000) += snd-h4000_audio.o obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o obj-$(CONFIG_SND_UDA1341) += snd-uda1341.o obj-$(CONFIG_SND_SA11X0_SSP) += snd-sa11x0-ssp.o diff -NruP kernel26/sound/arm/h4000_audio.c kernel2616hh5/sound/arm/h4000_audio.c --- kernel26/sound/arm/h4000_audio.c 1970-01-01 01:00:00.000000000 +0100 +++ kernel2616hh5/sound/arm/h4000_audio.c 2006-08-04 20:33:03.000000000 +0100 @@ -0,0 +1,177 @@ +/* + * Audio support for iPAQ h4000 + * It uses PXA2xx i2Sound and UDA1380 modules + * + * Copyright (c) 2006 Andy Potter + * + * Reference code: h1910_audio.c + * Copyright (c) 2005 Pawel Kolodziejski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pxa2xx-i2sound.h" +#include + +static struct snd_uda1380 uda; + +extern struct platform_device h4000_asic3; +#define asic3 &h4000_asic3.dev + +static void snd_h4000_audio_set_codec_power(int mode) { + if (mode == 1) + ipaq_asic3_set_gpio_out_c(asic3, GPIOC_AUD_POWER_ON, GPIOC_AUD_POWER_ON); + else + ipaq_asic3_set_gpio_out_c(asic3, GPIOC_AUD_POWER_ON, 0); +} +static void snd_h4000_audio_set_codec_reset(int mode) { + if (mode == 1) + GPSR(GPIO_NR_H4000_CODEC_RST) = GPIO_bit(GPIO_NR_H4000_CODEC_RST); + else + GPCR(GPIO_NR_H4000_CODEC_RST) = GPIO_bit(GPIO_NR_H4000_CODEC_RST); +} + +static void snd_h4000_audio_set_mic_power(int mode) {} + +static void snd_h4000_audio_set_speaker_power(int mode) { + if (mode == 1) + ipaq_asic3_set_gpio_out_d(asic3, GPIOD_SPK_EN, GPIOD_SPK_EN); + else + ipaq_asic3_set_gpio_out_d(asic3, GPIOD_SPK_EN, 0); +} + +static inline int snd_h4000_audio_hp_detect(void) { +// return 0; + return ((GPLR(GPIOD_HEADPHONE_IN_N) & GPIO_bit(GPIOD_HEADPHONE_IN_N)) == 0) ? 1 : 0; +} + + +static irqreturn_t snd_h4000_audio_hp_isr(int isr, void *data, struct pt_regs *regs) { + snd_uda1380_hp_detected(&uda, snd_h4000_audio_hp_detect()); + return IRQ_HANDLED; +} + +static void snd_h4000_audio_hp_detection_on(void) { + unsigned long flags; + + set_irq_type(IRQ_GPIO(GPIOD_HEADPHONE_IN_N), IRQT_BOTHEDGE); + request_irq(IRQ_GPIO(GPIOD_HEADPHONE_IN_N), snd_h4000_audio_hp_isr, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "earphone jack", NULL); + + local_irq_save(flags); + snd_uda1380_hp_detected(&uda, snd_h4000_audio_hp_detect()); + local_irq_restore(flags); + +} + +static void snd_h4000_audio_hp_detection_off(void) { + free_irq(IRQ_GPIO(GPIOD_HEADPHONE_IN_N), NULL); +} + +static struct snd_uda1380 uda = { + .line_in_connected = 0, + .mic_connected = 1, + .hp_or_line_out = 1, + .capture_source = SND_UDA1380_CAP_SOURCE_MIC, + .power_on_chip = snd_h4000_audio_set_codec_power, + .reset_pin = snd_h4000_audio_set_codec_reset, + .line_out_on = snd_h4000_audio_set_speaker_power, + .mic_on = snd_h4000_audio_set_mic_power +}; + +static int snd_h4000_audio_activate(void) { + /* UDA1380 at address 0x1a on PXA2xx I2C bus */ + uda.i2c_client.adapter = i2c_get_adapter(0); + uda.i2c_client.addr = 0x1a; + + if (snd_uda1380_activate(&uda) == 0) { + snd_h4000_audio_hp_detection_on(); + return 0; + } else + return -1; +} + +static void snd_h4000_audio_deactivate(void) { + snd_h4000_audio_hp_detection_off(); + snd_uda1380_deactivate(&uda); +} + +static int snd_h4000_audio_open_stream(int stream) + { return snd_uda1380_open_stream(&uda, stream); } + +static void snd_h4000_audio_close_stream(int stream) + { snd_uda1380_close_stream(&uda, stream); } + +static int snd_h4000_audio_add_mixer_controls(struct snd_card *acard) { + return snd_uda1380_add_mixer_controls(&uda, acard); +} + +#ifdef CONFIG_PM +static int snd_h4000_audio_suspend(pm_message_t state) { + snd_h4000_audio_hp_detection_off(); + snd_uda1380_suspend(&uda, state); + return 0; +} + +static int snd_h4000_audio_resume(void) { + snd_uda1380_resume(&uda); + snd_h4000_audio_hp_detection_on(); + return 0; +} +#endif + +static struct snd_pxa2xx_i2sound_board h4000_audio = { + .name = "h4000 Audio", + .desc = "iPAQ h4000 Audio [codec Philips UDA1380]", + .acard_id = "h4000 Audio", + .info = SND_PXA2xx_I2SOUND_INFO_CLOCK_FROM_PXA | + SND_PXA2xx_I2SOUND_INFO_CAN_CAPTURE, + .activate = snd_h4000_audio_activate, + .deactivate = snd_h4000_audio_deactivate, + .open_stream = snd_h4000_audio_open_stream, + .close_stream = snd_h4000_audio_close_stream, + .add_mixer_controls = snd_h4000_audio_add_mixer_controls, +#ifdef CONFIG_PM + .suspend = snd_h4000_audio_suspend, + .resume = snd_h4000_audio_resume +#endif +}; + +static int __init snd_h4000_audio_init(void) { + /* check machine */ + if (!machine_is_h4000()) { + snd_printk(KERN_INFO "Module snd-h4000_audio: not an iPAQ h4000!\n"); + return -1; + } + + request_module("i2c-pxa"); + return snd_pxa2xx_i2sound_card_activate(&h4000_audio); +} + +static void __exit snd_h4000_audio_exit(void) { + snd_pxa2xx_i2sound_card_deactivate(); +} + +module_init(snd_h4000_audio_init); +module_exit(snd_h4000_audio_exit); + +MODULE_AUTHOR("Andy Potter, Pawel Kolodziejski, Giorgio Padrin, Matthew Reimer"); +MODULE_DESCRIPTION("Audio support for iPAQ h4000"); +MODULE_LICENSE("GPL");