···11-/*22- * linux/include/linux/l3/uda1341.h33- *44- * Philips UDA1341 mixer device driver for ALSA55- *66- * Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>77- *88- * This program is free software; you can redistribute it and/or99- * modify it under the terms of the GNU General Public License.1010- *1111- * History:1212- *1313- * 2002-03-13 Tomas Kasparek Initial release - based on uda1341.h from OSS1414- * 2002-03-30 Tomas Kasparek Proc filesystem support, complete mixer and DSP1515- * features support1616- */1717-1818-#define UDA1341_ALSA_NAME "snd-uda1341"1919-2020-/*2121- * Default rate set after inicialization2222- */2323-#define AUDIO_RATE_DEFAULT 441002424-2525-/*2626- * UDA1341 L3 address and command types2727- */2828-#define UDA1341_L3ADDR 52929-#define UDA1341_DATA0 (UDA1341_L3ADDR << 2 | 0)3030-#define UDA1341_DATA1 (UDA1341_L3ADDR << 2 | 1)3131-#define UDA1341_STATUS (UDA1341_L3ADDR << 2 | 2)3232-3333-enum uda1341_onoff {3434- OFF=0,3535- ON,3636-};3737-3838-enum uda1341_format {3939- I2S=0,4040- LSB16,4141- LSB18,4242- LSB20,4343- MSB,4444- LSB16MSB,4545- LSB18MSB,4646- LSB20MSB, 4747-};4848-4949-enum uda1341_fs {5050- F512=0,5151- F384,5252- F256,5353- Funused,5454-};5555-5656-enum uda1341_peak {5757- BEFORE=0,5858- AFTER,5959-};6060-6161-enum uda1341_filter {6262- FLAT=0,6363- MIN,6464- MIN2,6565- MAX,6666-};6767-6868-enum uda1341_mixer {6969- DOUBLE,7070- LINE,7171- MIC,7272- MIXER,7373-};7474-7575-enum uda1341_deemp {7676- NONE,7777- D32,7878- D44,7979- D48,8080-};8181-8282-enum uda1341_config {8383- CMD_READ_REG = 0,8484- CMD_RESET,8585- CMD_FS,8686- CMD_FORMAT,8787- CMD_OGAIN,8888- CMD_IGAIN,8989- CMD_DAC,9090- CMD_ADC,9191- CMD_VOLUME,9292- CMD_BASS,9393- CMD_TREBBLE,9494- CMD_PEAK,9595- CMD_DEEMP,9696- CMD_MUTE, 9797- CMD_FILTER,9898- CMD_CH1,9999- CMD_CH2,100100- CMD_MIC, 101101- CMD_MIXER,102102- CMD_AGC,103103- CMD_IG,104104- CMD_AGC_TIME,105105- CMD_AGC_LEVEL,106106-#ifdef CONFIG_PM107107- CMD_SUSPEND,108108- CMD_RESUME,109109-#endif110110- CMD_LAST,111111-};112112-113113-enum write_through {114114- //used in update_bits (write_cfg) to avoid l3_write - just update local copy of regs.115115- REGS_ONLY=0,116116- //update local regs and write value to uda1341 - do l3_write117117- FLUSH,118118-};119119-120120-int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **clnt);121121-122122-/*123123- * Local variables:124124- * indent-tabs-mode: t125125- * End:126126- */
-11
sound/arm/Kconfig
···11111212if SND_ARM13131414-config SND_SA11XX_UDA13411515- tristate "SA11xx UDA1341TS driver (iPaq H3600)"1616- depends on ARCH_SA1100 && L31717- select SND_PCM1818- help1919- Say Y here if you have a Compaq iPaq H3x00 handheld computer2020- and want to use its Philips UDA 1341 audio chip.2121-2222- To compile this driver as a module, choose M here: the module2323- will be called snd-sa11xx-uda1341.2424-2514config SND_ARMAACI2615 tristate "ARM PrimeCell PL041 AC Link support"2716 depends on ARM_AMBA
···11-/*22- * Driver for Philips UDA1341TS on Compaq iPAQ H3600 soundcard33- * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>44- *55- * This program is free software; you can redistribute it and/or modify66- * it under the terms of the GNU General Public License.77- * 88- * History:99- *1010- * 2002-03-13 Tomas Kasparek initial release - based on h3600-uda1341.c from OSS1111- * 2002-03-20 Tomas Kasparek playback over ALSA is working1212- * 2002-03-28 Tomas Kasparek playback over OSS emulation is working1313- * 2002-03-29 Tomas Kasparek basic capture is working (native ALSA)1414- * 2002-03-29 Tomas Kasparek capture is working (OSS emulation)1515- * 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates)1616- * 2003-02-14 Brian Avery fixed full duplex mode, other updates1717- * 2003-02-20 Tomas Kasparek merged updates by Brian (except HAL)1818- * 2003-04-19 Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel1919- * working suspend and resume2020- * 2003-04-28 Tomas Kasparek updated work by Jaroslav to compile it under 2.5.x again2121- * merged HAL layer (patches from Brian)2222- */2323-2424-/***************************************************************************************************2525-*2626-* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai2727-* available in the Alsa doc section on the website 2828-* 2929-* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.3030-* We are using SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated3131-* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.3232-* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the3333-* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which3434-* is a mem loc that always decodes to 0's w/ no off chip access.3535-*3636-* Some alsa terminology:3737-* frame => num_channels * sample_size e.g stereo 16 bit is 2 * 16 = 32 bytes3838-* period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte3939-* buffer and 4 periods in the runtime structure this means we'll get an int every 2564040-* bytes or 4 times per buffer.4141-* A number of the sizes are in frames rather than bytes, use frames_to_bytes and4242-* bytes_to_frames to convert. The easiest way to tell the units is to look at the4343-* type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t4444-* 4545-* Notes about the pointer fxn:4646-* The pointer fxn needs to return the offset into the dma buffer in frames.4747-* Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.4848-*4949-* Notes about pause/resume5050-* Implementing this would be complicated so it's skipped. The problem case is:5151-* A full duplex connection is going, then play is paused. At this point you need to start xmitting5252-* 0's to keep the record active which means you cant just freeze the dma and resume it later you'd5353-* need to save off the dma info, and restore it properly on a resume. Yeach!5454-*5555-* Notes about transfer methods:5656-* The async write calls fail. I probably need to implement something else to support them?5757-* 5858-***************************************************************************************************/5959-6060-#include <linux/module.h>6161-#include <linux/moduleparam.h>6262-#include <linux/init.h>6363-#include <linux/err.h>6464-#include <linux/platform_device.h>6565-#include <linux/errno.h>6666-#include <linux/ioctl.h>6767-#include <linux/delay.h>6868-#include <linux/slab.h>6969-7070-#ifdef CONFIG_PM7171-#include <linux/pm.h>7272-#endif7373-7474-#include <mach/hardware.h>7575-#include <mach/h3600.h>7676-#include <asm/mach-types.h>7777-#include <asm/dma.h>7878-7979-#include <sound/core.h>8080-#include <sound/pcm.h>8181-#include <sound/initval.h>8282-8383-#include <linux/l3/l3.h>8484-8585-#undef DEBUG_MODE8686-#undef DEBUG_FUNCTION_NAMES8787-#include <sound/uda1341.h>8888-8989-/*9090- * FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels?9191- * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this9292- * module for Familiar 0.6.19393- */9494-9595-/* {{{ Type definitions */9696-9797-MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");9898-MODULE_LICENSE("GPL");9999-MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");100100-MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");101101-102102-static char *id; /* ID for this card */103103-104104-module_param(id, charp, 0444);105105-MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");106106-107107-struct audio_stream {108108- char *id; /* identification string */109109- int stream_id; /* numeric identification */ 110110- dma_device_t dma_dev; /* device identifier for DMA */111111-#ifdef HH_VERSION112112- dmach_t dmach; /* dma channel identification */113113-#else114114- dma_regs_t *dma_regs; /* points to our DMA registers */115115-#endif116116- unsigned int active:1; /* we are using this stream for transfer now */117117- int period; /* current transfer period */118118- int periods; /* current count of periods registerd in the DMA engine */119119- int tx_spin; /* are we recoding - flag used to do DMA trans. for sync */120120- unsigned int old_offset;121121- spinlock_t dma_lock; /* for locking in DMA operations (see dma-sa1100.c in the kernel) */122122- struct snd_pcm_substream *stream;123123-};124124-125125-struct sa11xx_uda1341 {126126- struct snd_card *card;127127- struct l3_client *uda1341;128128- struct snd_pcm *pcm;129129- long samplerate;130130- struct audio_stream s[2]; /* playback & capture */131131-};132132-133133-static unsigned int rates[] = {134134- 8000, 10666, 10985, 14647,135135- 16000, 21970, 22050, 24000,136136- 29400, 32000, 44100, 48000,137137-};138138-139139-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {140140- .count = ARRAY_SIZE(rates),141141- .list = rates,142142- .mask = 0,143143-};144144-145145-static struct platform_device *device;146146-147147-/* }}} */148148-149149-/* {{{ Clock and sample rate stuff */150150-151151-/*152152- * Stop-gap solution until rest of hh.org HAL stuff is merged.153153- */154154-#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12)155155-#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13)156156-157157-#ifdef CONFIG_SA1100_H3XXX158158-#define clr_sa11xx_uda1341_egpio(x) clr_h3600_egpio(x)159159-#define set_sa11xx_uda1341_egpio(x) set_h3600_egpio(x)160160-#else161161-#error This driver could serve H3x00 handhelds only!162162-#endif163163-164164-static void sa11xx_uda1341_set_audio_clock(long val)165165-{166166- switch (val) {167167- case 24000: case 32000: case 48000: /* 00: 12.288 MHz */168168- GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;169169- break;170170-171171- case 22050: case 29400: case 44100: /* 01: 11.2896 MHz */172172- GPSR = GPIO_H3600_CLK_SET0;173173- GPCR = GPIO_H3600_CLK_SET1;174174- break;175175-176176- case 8000: case 10666: case 16000: /* 10: 4.096 MHz */177177- GPCR = GPIO_H3600_CLK_SET0;178178- GPSR = GPIO_H3600_CLK_SET1;179179- break;180180-181181- case 10985: case 14647: case 21970: /* 11: 5.6245 MHz */182182- GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;183183- break;184184- }185185-}186186-187187-static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, long rate)188188-{189189- int clk_div = 0;190190- int clk=0;191191-192192- /* We don't want to mess with clocks when frames are in flight */193193- Ser4SSCR0 &= ~SSCR0_SSE;194194- /* wait for any frame to complete */195195- udelay(125);196196-197197- /*198198- * We have the following clock sources:199199- * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz200200- * Those can be divided either by 256, 384 or 512.201201- * This makes up 12 combinations for the following samplerates...202202- */203203- if (rate >= 48000)204204- rate = 48000;205205- else if (rate >= 44100)206206- rate = 44100;207207- else if (rate >= 32000)208208- rate = 32000;209209- else if (rate >= 29400)210210- rate = 29400;211211- else if (rate >= 24000)212212- rate = 24000;213213- else if (rate >= 22050)214214- rate = 22050;215215- else if (rate >= 21970)216216- rate = 21970;217217- else if (rate >= 16000)218218- rate = 16000;219219- else if (rate >= 14647)220220- rate = 14647;221221- else if (rate >= 10985)222222- rate = 10985;223223- else if (rate >= 10666)224224- rate = 10666;225225- else226226- rate = 8000;227227-228228- /* Set the external clock generator */229229-230230- sa11xx_uda1341_set_audio_clock(rate);231231-232232- /* Select the clock divisor */233233- switch (rate) {234234- case 8000:235235- case 10985:236236- case 22050:237237- case 24000:238238- clk = F512;239239- clk_div = SSCR0_SerClkDiv(16);240240- break;241241- case 16000:242242- case 21970:243243- case 44100:244244- case 48000:245245- clk = F256;246246- clk_div = SSCR0_SerClkDiv(8);247247- break;248248- case 10666:249249- case 14647:250250- case 29400:251251- case 32000:252252- clk = F384;253253- clk_div = SSCR0_SerClkDiv(12);254254- break;255255- }256256-257257- /* FMT setting should be moved away when other FMTs are added (FIXME) */258258- l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);259259-260260- l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk); 261261- Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;262262- sa11xx_uda1341->samplerate = rate;263263-}264264-265265-/* }}} */266266-267267-/* {{{ HW init and shutdown */268268-269269-static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341)270270-{271271- unsigned long flags;272272-273273- /* Setup DMA stuff */274274- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out";275275- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;276276- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr;277277-278278- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in";279279- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;280280- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd;281281-282282- /* Initialize the UDA1341 internal state */283283-284284- /* Setup the uarts */285285- local_irq_save(flags);286286- GAFR |= (GPIO_SSP_CLK);287287- GPDR &= ~(GPIO_SSP_CLK);288288- Ser4SSCR0 = 0;289289- Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);290290- Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;291291- Ser4SSCR0 |= SSCR0_SSE;292292- local_irq_restore(flags);293293-294294- /* Enable the audio power */295295-296296- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);297297- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);298298- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);299299-300300- /* Wait for the UDA1341 to wake up */301301- mdelay(1); //FIXME - was removed by Perex - Why?302302-303303- /* Initialize the UDA1341 internal state */304304- l3_open(sa11xx_uda1341->uda1341);305305-306306- /* external clock configuration (after l3_open - regs must be initialized */307307- sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate);308308-309309- /* Wait for the UDA1341 to wake up */310310- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);311311- mdelay(1); 312312-313313- /* make the left and right channels unswapped (flip the WS latch) */314314- Ser4SSDR = 0;315315-316316- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);317317-}318318-319319-static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341)320320-{321321- /* mute on */322322- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);323323-324324- /* disable the audio power and all signals leading to the audio chip */325325- l3_close(sa11xx_uda1341->uda1341);326326- Ser4SSCR0 = 0;327327- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);328328-329329- /* power off and mute off */330330- /* FIXME - is muting off necesary??? */331331-332332- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);333333- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);334334-}335335-336336-/* }}} */337337-338338-/* {{{ DMA staff */339339-340340-/*341341- * these are the address and sizes used to fill the xmit buffer342342- * so we can get a clock in record only mode343343- */344344-#define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS345345-#define FORCE_CLOCK_SIZE 4096 // was 2048346346-347347-// FIXME Why this value exactly - wrote comment348348-#define DMA_BUF_SIZE 8176 /* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */349349-350350-#ifdef HH_VERSION351351-352352-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *, int))353353-{354354- int ret;355355-356356- ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev);357357- if (ret < 0) {358358- printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);359359- return ret;360360- }361361- sa1100_dma_set_callback(s->dmach, callback);362362- return 0;363363-}364364-365365-static inline void audio_dma_free(struct audio_stream *s)366366-{367367- sa1100_free_dma(s->dmach);368368- s->dmach = -1;369369-}370370-371371-#else372372-373373-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *))374374-{375375- int ret;376376-377377- ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs);378378- if (ret < 0)379379- printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);380380- return ret;381381-}382382-383383-static void audio_dma_free(struct audio_stream *s)384384-{385385- sa1100_free_dma(s->dma_regs);386386- s->dma_regs = 0;387387-}388388-389389-#endif390390-391391-static u_int audio_get_dma_pos(struct audio_stream *s)392392-{393393- struct snd_pcm_substream *substream = s->stream;394394- struct snd_pcm_runtime *runtime = substream->runtime;395395- unsigned int offset;396396- unsigned long flags;397397- dma_addr_t addr;398398-399399- // this must be called w/ interrupts locked out see dma-sa1100.c in the kernel400400- spin_lock_irqsave(&s->dma_lock, flags);401401-#ifdef HH_VERSION 402402- sa1100_dma_get_current(s->dmach, NULL, &addr);403403-#else404404- addr = sa1100_get_dma_pos((s)->dma_regs);405405-#endif406406- offset = addr - runtime->dma_addr;407407- spin_unlock_irqrestore(&s->dma_lock, flags);408408-409409- offset = bytes_to_frames(runtime,offset);410410- if (offset >= runtime->buffer_size)411411- offset = 0;412412-413413- return offset;414414-}415415-416416-/*417417- * this stops the dma and clears the dma ptrs418418- */419419-static void audio_stop_dma(struct audio_stream *s)420420-{421421- unsigned long flags;422422-423423- spin_lock_irqsave(&s->dma_lock, flags); 424424- s->active = 0;425425- s->period = 0;426426- /* this stops the dma channel and clears the buffer ptrs */427427-#ifdef HH_VERSION428428- sa1100_dma_flush_all(s->dmach);429429-#else430430- sa1100_clear_dma(s->dma_regs); 431431-#endif432432- spin_unlock_irqrestore(&s->dma_lock, flags);433433-}434434-435435-static void audio_process_dma(struct audio_stream *s)436436-{437437- struct snd_pcm_substream *substream = s->stream;438438- struct snd_pcm_runtime *runtime;439439- unsigned int dma_size; 440440- unsigned int offset;441441- int ret;442442-443443- /* we are requested to process synchronization DMA transfer */444444- if (s->tx_spin) {445445- if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))446446- return;447447- /* fill the xmit dma buffers and return */448448-#ifdef HH_VERSION449449- sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);450450-#else451451- while (1) {452452- ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);453453- if (ret)454454- return; 455455- }456456-#endif457457- return;458458- }459459-460460- /* must be set here - only valid for running streams, not for forced_clock dma fills */461461- runtime = substream->runtime;462462- while (s->active && s->periods < runtime->periods) {463463- dma_size = frames_to_bytes(runtime, runtime->period_size);464464- if (s->old_offset) {465465- /* a little trick, we need resume from old position */466466- offset = frames_to_bytes(runtime, s->old_offset - 1);467467- s->old_offset = 0;468468- s->periods = 0;469469- s->period = offset / dma_size;470470- offset %= dma_size;471471- dma_size = dma_size - offset;472472- if (!dma_size)473473- continue; /* special case */474474- } else {475475- offset = dma_size * s->period;476476- snd_BUG_ON(dma_size > DMA_BUF_SIZE);477477- }478478-#ifdef HH_VERSION479479- ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);480480- if (ret)481481- return; //FIXME482482-#else483483- ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);484484- if (ret) {485485- printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);486486- return;487487- }488488-#endif489489-490490- s->period++;491491- s->period %= runtime->periods;492492- s->periods++;493493- }494494-}495495-496496-#ifdef HH_VERSION497497-static void audio_dma_callback(void *data, int size)498498-#else499499-static void audio_dma_callback(void *data)500500-#endif501501-{502502- struct audio_stream *s = data;503503-504504- /* 505505- * If we are getting a callback for an active stream then we inform506506- * the PCM middle layer we've finished a period507507- */508508- if (s->active)509509- snd_pcm_period_elapsed(s->stream);510510-511511- spin_lock(&s->dma_lock);512512- if (!s->tx_spin && s->periods > 0)513513- s->periods--;514514- audio_process_dma(s);515515- spin_unlock(&s->dma_lock);516516-}517517-518518-/* }}} */519519-520520-/* {{{ PCM setting */521521-522522-/* {{{ trigger & timer */523523-524524-static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd)525525-{526526- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);527527- int stream_id = substream->pstr->stream;528528- struct audio_stream *s = &chip->s[stream_id];529529- struct audio_stream *s1 = &chip->s[stream_id ^ 1];530530- int err = 0;531531-532532- /* note local interrupts are already disabled in the midlevel code */533533- spin_lock(&s->dma_lock);534534- switch (cmd) {535535- case SNDRV_PCM_TRIGGER_START:536536- /* now we need to make sure a record only stream has a clock */537537- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {538538- /* we need to force fill the xmit DMA with zeros */539539- s1->tx_spin = 1;540540- audio_process_dma(s1);541541- }542542- /* this case is when you were recording then you turn on a543543- * playback stream so we stop (also clears it) the dma first,544544- * clear the sync flag and then we let it turned on545545- */ 546546- else {547547- s->tx_spin = 0;548548- }549549-550550- /* requested stream startup */551551- s->active = 1;552552- audio_process_dma(s);553553- break;554554- case SNDRV_PCM_TRIGGER_STOP:555555- /* requested stream shutdown */556556- audio_stop_dma(s);557557-558558- /*559559- * now we need to make sure a record only stream has a clock560560- * so if we're stopping a playback with an active capture561561- * we need to turn the 0 fill dma on for the xmit side562562- */563563- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {564564- /* we need to force fill the xmit DMA with zeros */565565- s->tx_spin = 1;566566- audio_process_dma(s);567567- }568568- /*569569- * we killed a capture only stream, so we should also kill570570- * the zero fill transmit571571- */572572- else {573573- if (s1->tx_spin) {574574- s1->tx_spin = 0;575575- audio_stop_dma(s1);576576- }577577- }578578-579579- break;580580- case SNDRV_PCM_TRIGGER_SUSPEND:581581- s->active = 0;582582-#ifdef HH_VERSION 583583- sa1100_dma_stop(s->dmach);584584-#else585585- //FIXME - DMA API586586-#endif 587587- s->old_offset = audio_get_dma_pos(s) + 1;588588-#ifdef HH_VERSION 589589- sa1100_dma_flush_all(s->dmach);590590-#else591591- //FIXME - DMA API592592-#endif 593593- s->periods = 0;594594- break;595595- case SNDRV_PCM_TRIGGER_RESUME:596596- s->active = 1;597597- s->tx_spin = 0;598598- audio_process_dma(s);599599- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {600600- s1->tx_spin = 1;601601- audio_process_dma(s1);602602- }603603- break;604604- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:605605-#ifdef HH_VERSION 606606- sa1100_dma_stop(s->dmach);607607-#else608608- //FIXME - DMA API609609-#endif610610- s->active = 0;611611- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {612612- if (s1->active) {613613- s->tx_spin = 1;614614- s->old_offset = audio_get_dma_pos(s) + 1;615615-#ifdef HH_VERSION 616616- sa1100_dma_flush_all(s->dmach);617617-#else618618- //FIXME - DMA API619619-#endif 620620- audio_process_dma(s);621621- }622622- } else {623623- if (s1->tx_spin) {624624- s1->tx_spin = 0;625625-#ifdef HH_VERSION 626626- sa1100_dma_flush_all(s1->dmach);627627-#else628628- //FIXME - DMA API629629-#endif 630630- }631631- }632632- break;633633- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:634634- s->active = 1;635635- if (s->old_offset) {636636- s->tx_spin = 0;637637- audio_process_dma(s);638638- break;639639- }640640- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {641641- s1->tx_spin = 1;642642- audio_process_dma(s1);643643- }644644-#ifdef HH_VERSION 645645- sa1100_dma_resume(s->dmach);646646-#else647647- //FIXME - DMA API648648-#endif649649- break;650650- default:651651- err = -EINVAL;652652- break;653653- }654654- spin_unlock(&s->dma_lock); 655655- return err;656656-}657657-658658-static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream)659659-{660660- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);661661- struct snd_pcm_runtime *runtime = substream->runtime;662662- struct audio_stream *s = &chip->s[substream->pstr->stream];663663-664664- /* set requested samplerate */665665- sa11xx_uda1341_set_samplerate(chip, runtime->rate);666666-667667- /* set requestd format when available */668668- /* set FMT here !!! FIXME */669669-670670- s->period = 0;671671- s->periods = 0;672672-673673- return 0;674674-}675675-676676-static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream)677677-{678678- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);679679- return audio_get_dma_pos(&chip->s[substream->pstr->stream]);680680-}681681-682682-/* }}} */683683-684684-static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =685685-{686686- .info = (SNDRV_PCM_INFO_INTERLEAVED |687687- SNDRV_PCM_INFO_BLOCK_TRANSFER |688688- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |689689- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),690690- .formats = SNDRV_PCM_FMTBIT_S16_LE,691691- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\692692- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\693693- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\694694- SNDRV_PCM_RATE_KNOT),695695- .rate_min = 8000,696696- .rate_max = 48000,697697- .channels_min = 2,698698- .channels_max = 2,699699- .buffer_bytes_max = 64*1024,700700- .period_bytes_min = 64,701701- .period_bytes_max = DMA_BUF_SIZE,702702- .periods_min = 2,703703- .periods_max = 255,704704- .fifo_size = 0,705705-};706706-707707-static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =708708-{709709- .info = (SNDRV_PCM_INFO_INTERLEAVED |710710- SNDRV_PCM_INFO_BLOCK_TRANSFER |711711- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |712712- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),713713- .formats = SNDRV_PCM_FMTBIT_S16_LE,714714- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\715715- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\716716- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\717717- SNDRV_PCM_RATE_KNOT),718718- .rate_min = 8000,719719- .rate_max = 48000,720720- .channels_min = 2,721721- .channels_max = 2,722722- .buffer_bytes_max = 64*1024,723723- .period_bytes_min = 64,724724- .period_bytes_max = DMA_BUF_SIZE,725725- .periods_min = 2,726726- .periods_max = 255,727727- .fifo_size = 0,728728-};729729-730730-static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)731731-{732732- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);733733- struct snd_pcm_runtime *runtime = substream->runtime;734734- int stream_id = substream->pstr->stream;735735- int err;736736-737737- chip->s[stream_id].stream = substream;738738-739739- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)740740- runtime->hw = snd_sa11xx_uda1341_playback;741741- else742742- runtime->hw = snd_sa11xx_uda1341_capture;743743- if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)744744- return err;745745- if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)746746- return err;747747-748748- return 0;749749-}750750-751751-static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)752752-{753753- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);754754-755755- chip->s[substream->pstr->stream].stream = NULL;756756- return 0;757757-}758758-759759-/* {{{ HW params & free */760760-761761-static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream,762762- struct snd_pcm_hw_params *hw_params)763763-{764764-765765- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));766766-}767767-768768-static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream)769769-{770770- return snd_pcm_lib_free_pages(substream);771771-}772772-773773-/* }}} */774774-775775-static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {776776- .open = snd_card_sa11xx_uda1341_open,777777- .close = snd_card_sa11xx_uda1341_close,778778- .ioctl = snd_pcm_lib_ioctl,779779- .hw_params = snd_sa11xx_uda1341_hw_params,780780- .hw_free = snd_sa11xx_uda1341_hw_free,781781- .prepare = snd_sa11xx_uda1341_prepare,782782- .trigger = snd_sa11xx_uda1341_trigger,783783- .pointer = snd_sa11xx_uda1341_pointer,784784-};785785-786786-static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {787787- .open = snd_card_sa11xx_uda1341_open,788788- .close = snd_card_sa11xx_uda1341_close,789789- .ioctl = snd_pcm_lib_ioctl,790790- .hw_params = snd_sa11xx_uda1341_hw_params,791791- .hw_free = snd_sa11xx_uda1341_hw_free,792792- .prepare = snd_sa11xx_uda1341_prepare,793793- .trigger = snd_sa11xx_uda1341_trigger,794794- .pointer = snd_sa11xx_uda1341_pointer,795795-};796796-797797-static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)798798-{799799- struct snd_pcm *pcm;800800- int err;801801-802802- if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)803803- return err;804804-805805- /*806806- * this sets up our initial buffers and sets the dma_type to isa.807807- * isa works but I'm not sure why (or if) it's the right choice808808- * this may be too large, trying it for now809809- */810810- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 811811- snd_dma_isa_data(),812812- 64*1024, 64*1024);813813-814814- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);815815- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);816816- pcm->private_data = sa11xx_uda1341;817817- pcm->info_flags = 0;818818- strcpy(pcm->name, "UDA1341 PCM");819819-820820- sa11xx_uda1341_audio_init(sa11xx_uda1341);821821-822822- /* setup DMA controller */823823- audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);824824- audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);825825-826826- sa11xx_uda1341->pcm = pcm;827827-828828- return 0;829829-}830830-831831-/* }}} */832832-833833-/* {{{ module init & exit */834834-835835-#ifdef CONFIG_PM836836-837837-static int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,838838- pm_message_t state)839839-{840840- struct snd_card *card = platform_get_drvdata(devptr);841841- struct sa11xx_uda1341 *chip = card->private_data;842842-843843- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);844844- snd_pcm_suspend_all(chip->pcm);845845-#ifdef HH_VERSION846846- sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);847847- sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);848848-#else849849- //FIXME850850-#endif851851- l3_command(chip->uda1341, CMD_SUSPEND, NULL);852852- sa11xx_uda1341_audio_shutdown(chip);853853-854854- return 0;855855-}856856-857857-static int snd_sa11xx_uda1341_resume(struct platform_device *devptr)858858-{859859- struct snd_card *card = platform_get_drvdata(devptr);860860- struct sa11xx_uda1341 *chip = card->private_data;861861-862862- sa11xx_uda1341_audio_init(chip);863863- l3_command(chip->uda1341, CMD_RESUME, NULL);864864-#ifdef HH_VERSION 865865- sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);866866- sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);867867-#else868868- //FIXME869869-#endif870870- snd_power_change_state(card, SNDRV_CTL_POWER_D0);871871- return 0;872872-}873873-#endif /* COMFIG_PM */874874-875875-void snd_sa11xx_uda1341_free(struct snd_card *card)876876-{877877- struct sa11xx_uda1341 *chip = card->private_data;878878-879879- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);880880- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);881881-}882882-883883-static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)884884-{885885- int err;886886- struct snd_card *card;887887- struct sa11xx_uda1341 *chip;888888-889889- /* register the soundcard */890890- err = snd_card_create(-1, id, THIS_MODULE,891891- sizeof(struct sa11xx_uda1341), &card);892892- if (err < 0)893893- return err;894894-895895- chip = card->private_data;896896- spin_lock_init(&chip->s[0].dma_lock);897897- spin_lock_init(&chip->s[1].dma_lock);898898-899899- card->private_free = snd_sa11xx_uda1341_free;900900- chip->card = card;901901- chip->samplerate = AUDIO_RATE_DEFAULT;902902-903903- // mixer904904- if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))905905- goto nodev;906906-907907- // PCM908908- if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)909909- goto nodev;910910-911911- strcpy(card->driver, "UDA1341");912912- strcpy(card->shortname, "H3600 UDA1341TS");913913- sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");914914-915915- snd_card_set_dev(card, &devptr->dev);916916-917917- if ((err = snd_card_register(card)) == 0) {918918- printk(KERN_INFO "iPAQ audio support initialized\n");919919- platform_set_drvdata(devptr, card);920920- return 0;921921- }922922-923923- nodev:924924- snd_card_free(card);925925- return err;926926-}927927-928928-static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)929929-{930930- snd_card_free(platform_get_drvdata(devptr));931931- platform_set_drvdata(devptr, NULL);932932- return 0;933933-}934934-935935-#define SA11XX_UDA1341_DRIVER "sa11xx_uda1341"936936-937937-static struct platform_driver sa11xx_uda1341_driver = {938938- .probe = sa11xx_uda1341_probe,939939- .remove = __devexit_p(sa11xx_uda1341_remove),940940-#ifdef CONFIG_PM941941- .suspend = snd_sa11xx_uda1341_suspend,942942- .resume = snd_sa11xx_uda1341_resume,943943-#endif944944- .driver = {945945- .name = SA11XX_UDA1341_DRIVER,946946- },947947-};948948-949949-static int __init sa11xx_uda1341_init(void)950950-{951951- int err;952952-953953- if (!machine_is_h3xxx())954954- return -ENODEV;955955- if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)956956- return err;957957- device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);958958- if (!IS_ERR(device)) {959959- if (platform_get_drvdata(device))960960- return 0;961961- platform_device_unregister(device);962962- err = -ENODEV;963963- } else964964- err = PTR_ERR(device);965965- platform_driver_unregister(&sa11xx_uda1341_driver);966966- return err;967967-}968968-969969-static void __exit sa11xx_uda1341_exit(void)970970-{971971- platform_device_unregister(device);972972- platform_driver_unregister(&sa11xx_uda1341_driver);973973-}974974-975975-module_init(sa11xx_uda1341_init);976976-module_exit(sa11xx_uda1341_exit);977977-978978-/* }}} */979979-980980-/*981981- * Local variables:982982- * indent-tabs-mode: t983983- * End:984984- */