From: <sle...@us...> - 2007-06-27 08:03:36
|
Revision: 1084 http://svn.sourceforge.net/hackndev/?rev=1084&view=rev Author: sleep_walker Date: 2007-06-27 01:03:31 -0700 (Wed, 27 Jun 2007) Log Message: ----------- palmtt3: suspend/resume fix backported to OUR 2.6.20 tsc2101 version, made up-to-date Modified Paths: -------------- linux4palm/linux/trunk/drivers/mfd/tsc2101.c linux4palm/linux/trunk/drivers/mfd/tsc2101.h Modified: linux4palm/linux/trunk/drivers/mfd/tsc2101.c =================================================================== --- linux4palm/linux/trunk/drivers/mfd/tsc2101.c 2007-06-27 05:35:39 UTC (rev 1083) +++ linux4palm/linux/trunk/drivers/mfd/tsc2101.c 2007-06-27 08:03:31 UTC (rev 1084) @@ -11,42 +11,579 @@ * */ +#define DEBUG + #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/soc/tsc2101.h> -#include <linux/irq.h> +#include <linux/soc/tsc2101.h> #include <linux/platform_device.h> +#include <sound/control.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irqs.h> #include "tsc2101.h" +#include <asm/arch/tps65010.h> -extern void tsc2101_ts_setup(struct platform_device *dev); -extern void tsc2101_ts_report(struct tsc2101_data *devdata, int x, int y, int p, int pendown); +// VF +#include <linux/platform_device.h> -static int tsc2101_regread(struct tsc2101_data *devdata, int regnum) +#include "../../sound/arm/pxa2xx-i2sound.h" + +static u32 tsc2101_regread(struct tsc2101_data *devdata, int regnum) { - int reg; + u32 reg; devdata->platform->send(TSC2101_READ, regnum, ®, 1); return reg; } -static void tsc2101_regwrite(struct tsc2101_data *devdata, int regnum, int value) +static void tsc2101_regwrite(struct tsc2101_data *devdata, int regnum, u32 value) { - int reg=value; + u32 reg; + devdata->platform->send(TSC2101_READ, regnum, ®, 1); + /*if(((regnum >> 11) & 0x0f) == 2) + { + printk("Changing %X: %04X to %04X\n", regnum, reg, value); + }*/ + reg = value; devdata->platform->send(TSC2101_WRITE, regnum, ®, 1); return; } - +/* static int tsc2101_ts_penup(struct tsc2101_data *devdata) { return !( tsc2101_regread(devdata, TSC2101_REG_STATUS) & TSC2101_STATUS_DAVAIL); } - +*/ #define TSC2101_ADC_DEFAULT (TSC2101_ADC_RES(TSC2101_ADC_RES_12BITP) | TSC2101_ADC_AVG(TSC2101_ADC_4AVG) | TSC2101_ADC_CL(TSC2101_ADC_CL_1MHZ_12BIT) | TSC2101_ADC_PV(TSC2101_ADC_PV_500us) | TSC2101_ADC_AVGFILT_MEAN) +/* + * Sound part + */ + +#define LIV_MAX 0x7F +#define VOLtoTSC(x) ((x * LIV_MAX) / 100) +#define TSCtoVOL(x) ((x * 100) / LIV_MAX) + +static struct tsc2101_data *snd_data; +static u8 flags; + +static void tsc2101_set_route(void) +{ + u32 reg; + + reg = tsc2101_regread(snd_data, TSC2101_REG_AUDIOCON7); + + if(reg & TSC2101_HDDETFL) //Headphones + { + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON5, TSC2101_DAC2SPK1(1) | TSC2101_DAC2SPK2(2) | TSC2101_MUTSPK1 | TSC2101_MUTSPK2); + + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON6, TSC2101_MUTCELL | TSC2101_MUTLSPK | TSC2101_LDSCPTC | TSC2101_CAPINTF); + + flags |= FLAG_HEADPHONES; + } + else //Loudspeaker + { + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON5, TSC2101_DAC2SPK1(3) | TSC2101_MUTSPK1 | TSC2101_MUTSPK2); + + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON6, TSC2101_MUTCELL | TSC2101_SPL2LSK | TSC2101_LDSCPTC | TSC2101_CAPINTF); + + flags &= ~FLAG_HEADPHONES; + } +} + +static irqreturn_t tsc2101_headset_int(int irq, void *dev_id) +{ + tsc2101_set_route(); + return IRQ_HANDLED; +} + +static int tsc2101_snd_activate(void) { + u32 data; + + if(snd_data == NULL) + return 1; + + snd_pxa2xx_i2sound_i2slink_get(); + + tsc2101_regwrite(snd_data, TSC2101_REG_PWRDOWN, 0xFFFC); //power down whole codec + + /*Mute Analog Sidetone */ + /*Select MIC_INHED input for headset */ + /*Cell Phone In not connected */ + tsc2101_regwrite(snd_data, TSC2101_REG_MIXERPGA, + TSC2101_ASTMU | TSC2101_ASTG(0x45) | TSC2101_MICADC | TSC2101_MICSEL(1) ); + + /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */ + /* 1dB AGC hysteresis */ + /* MICes bias 2V */ + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON4, TSC2101_MB_HED(0) | TSC2101_MB_HND | TSC2101_ADSTPD | + TSC2101_DASTPD | TSC2101_ASSTPD | TSC2101_CISTPD | TSC2101_BISTPD ); + + /* Set codec output volume */ + tsc2101_regwrite(snd_data, TSC2101_REG_DACPGA, ~(TSC2101_DALMU | TSC2101_DARMU) ); + + /* OUT8P/N muted, CPOUT muted */ + + /* Headset/Hook switch detect disabled */ + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON7, TSC2101_DETECT | TSC2101_HDDEBNPG(2) | TSC2101_DGPIO2); + + /*Mic support*/ + tsc2101_regwrite(snd_data, TSC2101_REG_MICAGC, TSC2101_MMPGA(0) | TSC2101_MDEBNS(0x03) | TSC2101_MDEBSN(0x03) ); + + + //Hack - PalmOS sets that, so cleaning it + tsc2101_regwrite(snd_data, TSC2101_REG_HEADSETPGA, 0x0000); + + data = request_irq (IRQ_GPIO(55), tsc2101_headset_int, SA_SAMPLE_RANDOM, "TSC2101 Headphones", (void*)55); + set_irq_type (IRQ_GPIO(55), IRQT_RISING); + + if(data) + return data; + + tsc2101_set_route(); + return 0; +} + +static void tsc2101_snd_deactivate(void) { + snd_pxa2xx_i2sound_i2slink_free(); + free_irq(IRQ_GPIO(55), (void*) 55); +} +// FIXME - is it really suspend == deactivate? +static int tsc2101_snd_suspend(pm_message_t state) { + tsc2101_snd_deactivate(); + return 0; +} + +static int tsc2101_snd_resume(void) { + tsc2101_snd_activate(); + return 0; +} + + +static int tsc2101_snd_set_rate(unsigned int rate) { + uint div, fs_44; + u32 data; + + printk("Rate: %d ", rate); + + if (rate >= 48000) + { div = 7; fs_44 = 1; } + else if (rate >= 44100) + { div = 7; fs_44 = 0; } + else if (rate >= 32000) + { div = 6; fs_44 = 1; } + else if (rate >= 29400) + { div = 6; fs_44 = 0; } + else if (rate >= 24000) + { div = 5; fs_44 = 1; } + else if (rate >= 22050) + { div = 5; fs_44 = 0; } + else if (rate >= 16000) + { div = 4; fs_44 = 1; } + else if (rate >= 14700) + { div = 4; fs_44 = 0; } + else if (rate >= 12000) + { div = 3; fs_44 = 1; } + else if (rate >= 11025) + { div = 3; fs_44 = 0; } + else if (rate >= 9600) + { div = 2; fs_44 = 1; } + else if (rate >= 8820) + { div = 2; fs_44 = 0; } + else if (rate >= 8727) + { div = 1; fs_44 = 1; } + else if (rate >= 8018) + { div = 1; fs_44 = 0; } + else if (rate >= 8000) + { div = 0; fs_44 = 1; } + else + { div = 0; fs_44 = 0; } + + /* wait for any frame to complete */ + udelay(125); + + /* Set AC1 */ + data = tsc2101_regread(snd_data, TSC2101_REG_AUDIOCON1); + /*Clear prev settings */ + data &= ~(TSC2101_DACFS(0xF) | TSC2101_ADCFS(0xF)); + data |= TSC2101_DACFS(div) | TSC2101_ADCFS(div); + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON1, data); + + /* Set the AC3 */ + data = tsc2101_regread(snd_data, TSC2101_REG_AUDIOCON3); + /*Clear prev settings */ + data &= ~(TSC2101_REFFS | TSC2101_SLVMS); + + data |= fs_44 ? TSC2101_REFFS : 0; + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON3, data); + + + /* program the PLLs */ + if (fs_44) { + /* 44.1 khz - 12 MHz Mclk */ + printk("selected 44.1khz PLL\n"); + tsc2101_regwrite(snd_data, TSC2101_REG_PLL1, TSC2101_PLL_ENABLE | TSC2101_PLL_PVAL(2) | TSC2101_PLL_JVAL(7)); + tsc2101_regwrite(snd_data, TSC2101_REG_PLL2, TSC2101_PLL2_DVAL(5740)); + } else { + /* 48 khz - 12 Mhz Mclk */ + printk("selected 48khz PLL\n"); + tsc2101_regwrite(snd_data, TSC2101_REG_PLL1, TSC2101_PLL_ENABLE | TSC2101_PLL_PVAL(1) | TSC2101_PLL_JVAL(8)); + tsc2101_regwrite(snd_data, TSC2101_REG_PLL2, TSC2101_PLL2_DVAL(1920)); + } + + return 0; +} + +static int tsc2101_snd_open_stream(int stream) { + u32 reg, pwdn; + + reg = tsc2101_regread(snd_data, TSC2101_REG_AUDIOCON5); + + if(stream == SNDRV_PCM_STREAM_PLAYBACK) { + if(flags & FLAG_HEADPHONES) { + reg &= ~(TSC2101_MUTSPK1 | TSC2101_MUTSPK2); + pwdn = TSC2101_MBIAS_HND | + TSC2101_MBIAS_HED | + TSC2101_ASTPWD | + TSC2101_ADPWDN | + TSC2101_VGPWDN | + TSC2101_COPWDN | + TSC2101_LSPWDN; + } else { + reg |= (TSC2101_MUTSPK1 | TSC2101_MUTSPK2); + pwdn = TSC2101_MBIAS_HND | + TSC2101_MBIAS_HED | + TSC2101_ASTPWD | + TSC2101_SPI1PWDN | + TSC2101_SPI2PWDN | + TSC2101_VGPWDN | + TSC2101_COPWDN; + } + + } else { + pwdn = TSC2101_ASTPWD | + TSC2101_MBIAS_HED | + TSC2101_DAPWDN | + TSC2101_SPI1PWDN | + TSC2101_SPI2PWDN | + TSC2101_VGPWDN | + TSC2101_COPWDN | + TSC2101_LSPWDN; + } + + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON5, reg); + tsc2101_regwrite(snd_data, TSC2101_REG_PWRDOWN, pwdn); + return 0; +} + +static void tsc2101_snd_close_stream(int stream) { + u32 reg; + + if(flags & FLAG_HEADPHONES) { + reg = tsc2101_regread(snd_data, TSC2101_REG_AUDIOCON5); + reg |= TSC2101_MUTSPK1 | TSC2101_MUTSPK2; + tsc2101_regwrite(snd_data, TSC2101_REG_AUDIOCON5, reg); + } + + tsc2101_regwrite(snd_data, TSC2101_REG_PWRDOWN, + ~(TSC2101_EFFCTL) ); +} + +static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + return 0; +} + +/* + * Alsa mixer interface function for getting the volume read from the DGC in a + * 0 -100 alsa mixer format. + */ +static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_DACPGA); + + ucontrol->value.integer.value[0] = 100 - TSCtoVOL(TSC2101_DALVLI(val) ); + ucontrol->value.integer.value[1] = 100 - TSCtoVOL(TSC2101_DARVLI(val) ); + + return 0; +} + +static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread (snd_data, TSC2101_REG_DACPGA); + + val &= ~(TSC2101_DALVL(0xFF) | TSC2101_DARVL(0xFF) ); + val |= TSC2101_DALVL(VOLtoTSC(100 - ucontrol->value.integer.value[0] ) - 2 ); + val |= TSC2101_DARVL(VOLtoTSC(100 - ucontrol->value.integer.value[1] ) - 2 ); + + tsc2101_regwrite(snd_data, TSC2101_REG_DACPGA, val); + return 2; +} + +static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/* + * When DGC_DALMU (bit 15) is 1, the left channel is muted. + * When DGC_DALMU is 0, left channel is not muted. + * Same logic apply also for the right channel. + */ +static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread (snd_data, TSC2101_REG_DACPGA); + + ucontrol->value.integer.value[0] = !(val & TSC2101_DALMU); + ucontrol->value.integer.value[1] = !(val & TSC2101_DARMU); + return 0; +} + +static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_DACPGA); + + // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on + // so if values are same, it's time to change the registry value. + if (!ucontrol->value.integer.value[0]) + val |= TSC2101_DALMU; // mute --> turn bit on + else + val &= ~TSC2101_DALMU; // unmute --> turn bit off + /* L */ + + if (!ucontrol->value.integer.value[1]) + val |= TSC2101_DARMU; // mute --> turn bit on + else + val &= ~TSC2101_DARMU; // unmute --> turn bit off + /* R */ + + tsc2101_regwrite(snd_data, TSC2101_REG_DACPGA, val); + return 2; +} + +static int __headset_playback_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + return 0; +} + +static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HEADSETPGA); + + ucontrol->value.integer.value[0] = TSCtoVOL(TSC2101_ADPGA_HEDI(val) ); + return 0; +} + +static int __headset_playback_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HEADSETPGA); + + val &= ~TSC2101_ADPGA_HED(0xFF); + val |= TSC2101_ADPGA_HED(VOLtoTSC(ucontrol->value.integer.value[0] ) ); + + tsc2101_regwrite(snd_data, TSC2101_REG_HEADSETPGA, val); + return 1; +} + +static int __headset_playback_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int __headset_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HEADSETPGA); + + ucontrol->value.integer.value[0] = !(val & TSC2101_ADMUT_HED); + return 0; +} + + // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on + // so if values are same, it's time to change the registry value... +static int __headset_playback_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HEADSETPGA); + + if (!ucontrol->value.integer.value[0]) + val = val | TSC2101_ADMUT_HED; // mute --> turn bit on + else + val = val & ~TSC2101_ADMUT_HED; // unmute --> turn bit off + + tsc2101_regwrite(snd_data, TSC2101_REG_HEADSETPGA, val); + return 1; +} + +static int __handset_playback_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + return 0; +} + +static int __handset_playback_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HANDSETPGA); + + ucontrol->value.integer.value[0] = TSCtoVOL(TSC2101_ADPGA_HNDI(val) ); + return 0; +} + +static int __handset_playback_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HANDSETPGA); + + val &= ~TSC2101_ADPGA_HND(0xFF); + val |= TSC2101_ADPGA_HND(VOLtoTSC(ucontrol->value.integer.value[0] ) ); + + tsc2101_regwrite(snd_data, TSC2101_REG_HANDSETPGA, val); + return 1; +} + +static int __handset_playback_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int __handset_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HANDSETPGA); + + ucontrol->value.integer.value[0] = !(val & TSC2101_ADMUT_HND); + return 0; +} + + // in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on + // so if values are same, it's time to change the registry value... +static int __handset_playback_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + u32 val = tsc2101_regread(snd_data, TSC2101_REG_HANDSETPGA); + + if (!ucontrol->value.integer.value[0]) + val = val | TSC2101_ADMUT_HND; // mute --> turn bit on + else + val = val & ~TSC2101_ADMUT_HND; // unmute --> turn bit off + + tsc2101_regwrite(snd_data, TSC2101_REG_HANDSETPGA, val); + return 1; +} + +static struct snd_kcontrol_new tsc2101_control[] __devinitdata={ + { + .name = "PCM Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __pcm_playback_volume_info, + .get = __pcm_playback_volume_get, + .put = __pcm_playback_volume_put, + }, { + .name = "PCM Playback Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __pcm_playback_switch_info, + .get = __pcm_playback_switch_get, + .put = __pcm_playback_switch_put, + }, { + .name = "Not Used Headset Input Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 1, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __headset_playback_volume_info, + .get = __headset_playback_volume_get, + .put = __headset_playback_volume_put, + }, { + .name = "Not Used Headset Input Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 1, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __headset_playback_switch_info, + .get = __headset_playback_switch_get, + .put = __headset_playback_switch_put, + }, { + .name = "Handset Input Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 2, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __handset_playback_volume_info, + .get = __handset_playback_volume_get, + .put = __handset_playback_volume_put, + }, { + .name = "Handset Input Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 2, + .access= SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = __handset_playback_switch_info, + .get = __handset_playback_switch_get, + .put = __handset_playback_switch_put, + } +}; + +static int tsc2101_snd_add_mixer_controls(struct snd_card *acard) { + int i; + int err = 0; + + for (i = 0; i < ARRAY_SIZE(tsc2101_control); i++) { + if ((err = snd_ctl_add(acard, snd_ctl_new1(&tsc2101_control[i], acard ) ) ) < 0) { + return err; + } + } + + return 0; +} + +static struct snd_pxa2xx_i2sound_board tsc2101_audio = { + .name = "tsc2101 Audio", + .desc = "TI tsc2101 Audio driver", + .acard_id = "tsc2101", + .info = SND_PXA2xx_I2SOUND_INFO_CAN_CAPTURE | SND_PXA2xx_I2SOUND_INFO_CLOCK_FROM_PXA | + SND_PXA2xx_I2SOUND_INFO_SYSCLOCK_DISABLE, + .activate = tsc2101_snd_activate, + .deactivate = tsc2101_snd_deactivate, + .set_rate = tsc2101_snd_set_rate, + .open_stream = tsc2101_snd_open_stream, + .close_stream = tsc2101_snd_close_stream, + .add_mixer_controls = tsc2101_snd_add_mixer_controls, + + .streams_hw = { + { + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + }, + { + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + } + }, +#ifdef CONFIG_PM + .suspend = tsc2101_snd_suspend, + .resume = tsc2101_snd_resume, +#endif +}; + + +/* + * Touchscreen part + */ + +extern void tsc2101_ts_setup(struct platform_device *dev); +extern void tsc2101_ts_report(struct tsc2101_data *devdata, int x, int y, int p, int pendown); + static void tsc2101_readdata(struct tsc2101_data *devdata, struct tsc2101_ts_event *ts_data) { int z1,z2,fixadc=0; @@ -142,7 +679,7 @@ tsc2101_regwrite(devdata, TSC2101_REG_ADC, 0x4000); } -static void ts_interrupt_main(struct tsc2101_data *devdata, int isTimer) +static void ts_interrupt_main(struct tsc2101_data *devdata, int isTimer, struct pt_regs *regs) { unsigned long flags; struct tsc2101_ts_event ts_data; @@ -181,7 +718,7 @@ { struct tsc2101_data *devdata = (struct tsc2101_data *) data; - ts_interrupt_main(devdata, 1); + ts_interrupt_main(devdata, 1, NULL); } static irqreturn_t tsc2101_handler(int irq, void *dev_id) @@ -189,7 +726,7 @@ struct tsc2101_data *devdata = dev_id; set_irq_type(devdata->platform->irq,IRQT_NOEDGE); - ts_interrupt_main(devdata, 0); + ts_interrupt_main(devdata, 0, NULL); return IRQ_HANDLED; } @@ -238,15 +775,16 @@ printk(KERN_ERR "TSC2101 Temp2: %04x\n",devdata->miscdata.temp2); } +#ifdef CONFIG_PM + static int tsc2101_suspend(struct platform_device *dev, pm_message_t state) { struct tsc2101_data *devdata = platform_get_drvdata(dev); -/* comment this out like in old driver, it's sick though */ -/* if (level == SUSPEND_POWER_DOWN) { */ +// if (level == SUSPEND_POWER_DOWN) { tsc2101_ts_disable(devdata); devdata->platform->suspend(); -/* } */ +// } return 0; } @@ -255,17 +793,20 @@ { struct tsc2101_data *devdata = platform_get_drvdata(dev); -/* comment this out like in old driver, it's sick though */ -/* if (level == RESUME_POWER_ON) { */ +// if (level == RESUME_POWER_ON) { devdata->platform->resume(); tsc2101_ts_enable(devdata); -/* } */ +// } return 0; } +#else +#define tsc2101_suspend NULL +#define tsc2101_resume NULL +#endif -static int tsc2101_probe(struct platform_device *dev) +static int __init tsc2101_probe(struct platform_device *dev) { struct tsc2101_data *devdata; struct tsc2101_ts_event ts_data; @@ -301,11 +842,13 @@ mod_timer(&(devdata->misc_timer), jiffies + HZ); + /* Sound driver */ + snd_data = devdata; return 0; } -static int tsc2101_remove(struct platform_device *dev) +static int __exit tsc2101_remove(struct platform_device *dev) { struct tsc2101_data *devdata = platform_get_drvdata(dev); @@ -315,6 +858,7 @@ input_unregister_device(devdata->inputdevice); tsc2101_ts_disable(devdata); kfree(devdata); + return 0; } @@ -322,9 +866,10 @@ .driver = { .name = "tsc2101", .owner = THIS_MODULE, + .bus = &platform_bus_type, }, -/* .bus = &platform_bus_type, */ .probe = tsc2101_probe, +/* .remove = __exit_p(tsc2101_remove),*/ .remove = tsc2101_remove, .suspend = tsc2101_suspend, .resume = tsc2101_resume, @@ -332,12 +877,19 @@ static int __init tsc2101_init(void) { - return platform_driver_register(&tsc2101_driver); + int ret; + ret = platform_driver_register(&tsc2101_driver); + /* Sound driver */ + snd_pxa2xx_i2sound_card_activate(&tsc2101_audio); + return ret; } static void __exit tsc2101_exit(void) { platform_driver_unregister(&tsc2101_driver); + + /* Sound driver */ + snd_pxa2xx_i2sound_card_deactivate(); } module_init(tsc2101_init); Modified: linux4palm/linux/trunk/drivers/mfd/tsc2101.h =================================================================== --- linux4palm/linux/trunk/drivers/mfd/tsc2101.h 2007-06-27 05:35:39 UTC (rev 1083) +++ linux4palm/linux/trunk/drivers/mfd/tsc2101.h 2007-06-27 08:03:31 UTC (rev 1084) @@ -72,7 +72,7 @@ #define TSC2101_REG_MICAGC TSC2101_P2_REG(0x26) #define TSC2101_REG_CELLAGC TSC2101_P2_REG(0x27) -/* Page 2 Registers */ +/* Page 3 Registers */ #define TSC2101_REG_BUFLOC(x) TSC2101_P3_REG(x) /* Status Register Masks */ @@ -152,3 +152,81 @@ #define TSC2101_KEY_SCS (1<<14) // keypad scan status +/* Sound */ +#define TSC2101_DACFS(x) ((x & 0x07) << 3) +#define TSC2101_ADCFS(x) (x & 0x07) +#define TSC2101_REFFS (1 << 13) +#define TSC2101_DAXFM (1 << 12) +#define TSC2101_SLVMS (1 << 11) +#define TSC2101_PLL_ENABLE (1 << 15) +#define TSC2101_PLL_QVAL(x) (x << 11) +#define TSC2101_PLL_PVAL(x) (x << 8) +#define TSC2101_PLL_JVAL(x) (x << 2) +#define TSC2101_PLL2_DVAL(x) (x << 2) + +#define TSC2101_ADMUT_HED (1 << 15) +#define TSC2101_ADPGA_HED(x) ((x & 0x7F) << 8) +#define TSC2101_ADPGA_HEDI(x) ((x >> 8) & 0x7F) + +#define TSC2101_ADMUT_HND (1 << 15) +#define TSC2101_ADPGA_HND(x) ((x & 0x7F) << 8) +#define TSC2101_ADPGA_HNDI(x) ((x >> 8) & 0x7F) + +#define TSC2101_DALMU (1 << 15) +#define TSC2101_DALVL(x) (((x) & 0x7F) << 8) +#define TSC2101_DALVLI(x) (((x) >> 8) & 0x7F) +#define TSC2101_DARMU (1 << 7) +#define TSC2101_DARVL(x) ((x) & 0x7F) +#define TSC2101_DARVLI(x) ((x) & 0x7F) + +#define TSC2101_ASTMU (1 << 15) +#define TSC2101_ASTG(x) (x << 8) +#define TSC2101_MICADC (1 << 4) +#define TSC2101_MICSEL(x) (x << 5) +#define TSC2101_MB_HED(x) ((x & 0x02) << 7) +#define TSC2101_MB_HND (1 << 6) +#define TSC2101_ADSTPD (1 << 15) +#define TSC2101_DASTPD (1 << 14) +#define TSC2101_ASSTPD (1 << 13) +#define TSC2101_CISTPD (1 << 12) +#define TSC2101_BISTPD (1 << 11) +#define TSC2101_DAC2SPK1(x) ((x & 0x03) << 13) +#define TSC2101_DAC2SPK2(x) ((x & 0x03) << 7) +#define TSC2101_AST2SPK1 (1 << 12) +#define TSC2101_AST2SPK2 (1 << 6) +#define TSC2101_KCL2SPK1 (1 << 10) +#define TSC2101_KCL2SPK2 (1 << 4) +#define TSC2101_HDSCPTC (1 << 0) + +#define TSC2101_MUTLSPK (1 << 7) +#define TSC2101_MUTCELL (1 << 6) +#define TSC2101_LDSCPTC (1 << 5) +#define TSC2101_VGNDSCPTC (1 << 4) +#define TSC2101_CAPINTF (1 << 3) +#define TSC2101_SPL2LSK (1 << 15) + +#define TSC2101_HDDETFL (1 << 12) +#define TSC2101_MUTSPK1 (1 << 2) +#define TSC2101_MUTSPK2 (1 << 1) + +#define TSC2101_DETECT (1 << 15) +#define TSC2101_HDDEBNPG(x) ((x & 0x03) << 9) +#define TSC2101_DGPIO2 (1 << 4) + +#define TSC2101_MBIAS_HND (1 << 15) +#define TSC2101_MBIAS_HED (1 << 14) +#define TSC2101_ASTPWD (1 << 13) +#define TSC2101_SPI1PWDN (1 << 12) +#define TSC2101_SPI2PWDN (1 << 11) +#define TSC2101_DAPWDN (1 << 10) +#define TSC2101_ADPWDN (1 << 9) +#define TSC2101_VGPWDN (1 << 8) +#define TSC2101_COPWDN (1 << 7) +#define TSC2101_LSPWDN (1 << 6) +#define TSC2101_EFFCTL (1 << 1) + +#define TSC2101_MMPGA(x) ((x & 0x7F) << 9) +#define TSC2101_MDEBNS(x) ((x & 0x07) << 6) +#define TSC2101_MDEBSN(x) ((x & 0x07) << 3) + +#define FLAG_HEADPHONES 0x01 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |