* Lite5200B I2S driver
@ 2006-12-12 15:47 Pedro Luis D. L.
2006-12-12 19:22 ` Sylvain Munaut
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Pedro Luis D. L. @ 2006-12-12 15:47 UTC (permalink / raw)
To: linuxppc-embedded
Hi all,
I´m working with a Lite5200B EVB, trying to atach an audio output to a PCM
1680 from Texas Instruments.
At this moment I am using the patched 2.6.16.11-rt18 kernel that comes with
Freescale BSP.
I´ve tried to develop an I2S driver for the platform with no results. I´m
afraid that my driver devolping skills are still too low.
Anybody knows a working I2S driver for this board that can throw any
audiooutput through PSCs?
Any help or indication would be apreciated.
Pedro Dominguez.
_________________________________________________________________
Acepta el reto MSN Premium: Protección para tus hijos en internet.
Descárgalo y pruébalo 2 meses gratis.
http://join.msn.com?XAPID=1697&DI=1055&HL=Footer_mailsenviados_proteccioninfantil
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-12 15:47 Lite5200B I2S driver Pedro Luis D. L.
@ 2006-12-12 19:22 ` Sylvain Munaut
2006-12-13 9:31 ` Pedro Luis D. L.
2006-12-13 9:10 ` Roman Fietze
2006-12-17 8:03 ` Grant Likely
2 siblings, 1 reply; 13+ messages in thread
From: Sylvain Munaut @ 2006-12-12 19:22 UTC (permalink / raw)
To: Pedro Luis D. L.; +Cc: linuxppc-embedded
Pedro Luis D. L. wrote:
> Hi all,
>
> I´m working with a Lite5200B EVB, trying to atach an audio output to a PCM
> 1680 from Texas Instruments.
> At this moment I am using the patched 2.6.16.11-rt18 kernel that comes with
> Freescale BSP.
> I´ve tried to develop an I2S driver for the platform with no results. I´m
> afraid that my driver devolping skills are still too low.
>
> Anybody knows a working I2S driver for this board that can throw any
> audiooutput through PSCs?
>
> Any help or indication would be apreciated
I've never seen one.
I'm currently working on a AC97 driver, maybe once it's done you can use
it as a base.
It's pretty early so don't excepect anything before a while ;)
I'm pretty sure some part could be shared between the two ...
Sylvain
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-12 15:47 Lite5200B I2S driver Pedro Luis D. L.
2006-12-12 19:22 ` Sylvain Munaut
@ 2006-12-13 9:10 ` Roman Fietze
2006-12-13 9:39 ` Pedro Luis D. L.
2006-12-17 8:03 ` Grant Likely
2 siblings, 1 reply; 13+ messages in thread
From: Roman Fietze @ 2006-12-13 9:10 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 810 bytes --]
Hi Pedro,
On Tuesday 12 December 2006 16:47, Pedro Luis D. L. wrote:
> I´m working with a Lite5200B EVB, trying to atach an audio output to
> a PCM 1680 from Texas Instruments.
I've got a fully working GPL ALSA driver for the MPC5200 PSC's using
I2S as well as the ALSA controls for an UDA1380 codec connected via
I2C. This code is written for ALSA 1.0.8 and the 2.4.25 from Wolfgang.
I'm sorry not to be able to provide a patchset for either ALSA nor the
2.6. If you are interested in this code I will post it here.
A question to the mailing pro's: should I post source as attachments
or inlined?
Roman
--
Roman Fietze Telemotive AG Büro Mühlhausen
Breitwiesen 73347 Mühlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-12 19:22 ` Sylvain Munaut
@ 2006-12-13 9:31 ` Pedro Luis D. L.
0 siblings, 0 replies; 13+ messages in thread
From: Pedro Luis D. L. @ 2006-12-13 9:31 UTC (permalink / raw)
To: linuxppc-embedded
Sylvain Munaut wrote:
>Pedro Luis D. L. wrote:
> > Hi all,
> >
> > I´m working with a Lite5200B EVB, trying to atach an audio output to a
>PCM
> > 1680 from Texas Instruments.
> > At this moment I am using the patched 2.6.16.11-rt18 kernel that comes
>with
> > Freescale BSP.
> > I´ve tried to develop an I2S driver for the platform with no results.
>I´m
> > afraid that my driver devolping skills are still too low.
> >
> > Anybody knows a working I2S driver for this board that can throw any
> > audiooutput through PSCs?
> >
> > Any help or indication would be apreciated
>I've never seen one.
>
>I'm currently working on a AC97 driver, maybe once it's done you can use
>it as a base.
>It's pretty early so don't excepect anything before a while ;)
>
>I'm pretty sure some part could be shared between the two ...
>
>
> Sylvain
That would be a nice point to start.
Thx.
Pedro.
_________________________________________________________________
Acepta el reto MSN Premium: Correos más divertidos con fotos y textos
increíbles en MSN Premium. Descárgalo y pruébalo 2 meses gratis.
http://join.msn.com?XAPID=1697&DI=1055&HL=Footer_mailsenviados_correosmasdivertidos
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 9:10 ` Roman Fietze
@ 2006-12-13 9:39 ` Pedro Luis D. L.
2006-12-13 12:56 ` Roman Fietze
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Pedro Luis D. L. @ 2006-12-13 9:39 UTC (permalink / raw)
To: linuxppc-embedded
------------------------------------------------------------------
Todas mis chorradas alemanas en:
http://carcadiz.blogspot.com
------------------------------------------------------------------
On Wed, 13 Dec 2006, Roman Fietze wrote:
>Hi Pedro,
>
>On Tuesday 12 December 2006 16:47, Pedro Luis D. L. wrote:
>
> > I´m working with a Lite5200B EVB, trying to atach an audio output to
> > a PCM 1680 from Texas Instruments.
>
>I've got a fully working GPL ALSA driver for the MPC5200 PSC's using
>I2S as well as the ALSA controls for an UDA1380 codec connected via
>I2C. This code is written for ALSA 1.0.8 and the 2.4.25 from Wolfgang.
>
>I'm sorry not to be able to provide a patchset for either ALSA nor the
>2.6. If you are interested in this code I will post it here.
>
>A question to the mailing pro's: should I post source as attachments
>or inlined?
>
>
>Roman
Hi Roman,
for sure. I´m interested in the code. Maybe I can adapt this code or migrate
the application to 2.4 from Wolfgang. At this moment, I´m quite focus on
make something sounds through the audio board.
Thx.
Pedro.
_________________________________________________________________
Moda para esta temporada. Ponte al día de todas las tendencias.
http://www.msn.es/Mujer/moda/default.asp
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 9:39 ` Pedro Luis D. L.
@ 2006-12-13 12:56 ` Roman Fietze
2006-12-18 13:47 ` Stefan Strobl
2006-12-13 12:58 ` Roman Fietze
2006-12-13 13:15 ` Roman Fietze
2 siblings, 1 reply; 13+ messages in thread
From: Roman Fietze @ 2006-12-13 12:56 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 1742 bytes --]
Hello Pedro,
On Wednesday 13 December 2006 10:39, Pedro Luis D. L. wrote:
> for sure. I´m interested in the code. Maybe I can adapt this code or
> migrate the application to 2.4 from Wolfgang. At this moment, I´m
> quite focus on make something sounds through the audio board.
See what you can achive with the code in the attachments of the two
posts. They are
alsa/alsa-kernel/i2c/mpc5200-uda1380.c ALSA PCM driver
alsa/alsa-kernel/ppc/uda1380.[hc] ALSA Codec Controls
And in the second post the kernel patch.
linux/include/asm-ppc/mpc5xxx.h MPC5200 constants
arch/ppc/5xxx_io/snd-psc.c Kernel side of ALSA sound driver
I'va also attached mpc5xxx.h, I think I used some additional constants
which I added there. I had to separate the ALSA and kernel parts of
the PCM driver, so I could more easily manage it.
The driver uses some modified bestcomm code, because the original
bestcomm code from Freescale is, ahem, not very well designed, one of
the reasons for the new design in the 2.6. The changes were done in
the code image 2. They are a more generic approach for the PSC tasks,
so I can more easily switch PSC's. You should easily be able to modify
the kernel part of the driver, to use the bestcomm code from
Wolfgang's 2.4.25 git kernel tree. If not, please contact me and I
will send you the sources of my bestcomm/ subdirectory, or anybody
else of course.
One day, when we have the 2.6 running, I will try to get the code
upstream to ALSA and the powerpc kernel.
Roman
--
Roman Fietze Telemotive AG Büro Mühlhausen
Breitwiesen 73347 Mühlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
[-- Attachment #1.2: uda1380.c --]
[-- Type: text/x-csrc, Size: 23641 bytes --]
/*
* Sound driver for Philips uda1380 - i2c related stuff
*
* Copyright (C) 2005 Roman Fietze <roman.fietze@telemotive.de>
* Copyright (C) 2004 Giorgio Padrin
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* based on code by:
*
* 2004-03 Mattew Reimer
* Copyright (C) 2003 Christian Pellegrin
* Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
* Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
* Copyright (c) 2002 Hewlett-Packard Company
* Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
*/
#undef UDA1380_DEBUG
// #define UDA1380_DEBUG
#include <sound/driver.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/soundcard.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/info.h>
#include "uda1380.h"
#include <asm/uaccess.h>
static int debug = -1;
#if defined(UDA1380_DEBUG)
#define PRDEBUG(level, format, x... ) do {if (level <= debug) printk(KERN_INFO format, ## x );} while (0)
static inline void DBGDELAY(int _level, unsigned long _ms)
{
if (_ms && _level <= debug)
{
wait_queue_head_t wait;
init_waitqueue_head(&wait);
interruptible_sleep_on_timeout(&wait, (HZ * _ms) / 1000UL);
}
}
#else
#define PRDEBUG(level, format, x... ) do {} while(0)
#define DBGDELAY(t) do {} while(0)
#endif
static struct i2c_driver uda1380_driver;
static struct uda1380_reg_info {
unsigned short num;
unsigned short default_value;
} uda1380_reg_info[] = {
{
EMCS_REG,
EMCS_REG_SC_256FS | EMCS_REG_DAC_USE_WSPLL | EMCS_REG_ADC_USE_WSPLL |
EMCS_REG_PLL_25TO50 | EMCS_REG_EN_ADC | EMCS_REG_EN_DEC | EMCS_REG_EN_DAC | EMCS_REG_EN_INT
},
{
I2S_REG,
(FMT_I2S << I2S_REG_SFORO_SHIFT) | (FMT_I2S << I2S_REG_SFORI_SHIFT) |
I2S_REG_SEL_DECIMATOR | I2S_REG_SIM_SLAVE
},
{
PWR_REG,
PWR_REG_PON_PLL |
PWR_REG_PON_DAC | PWR_REG_PON_BIAS | PWR_REG_PON_HP |
PWR_REG_EN_AVC | PWR_REG_PON_AVC | PWR_REG_PON_LNA | PWR_REG_PON_ADCL | PWR_REG_PON_ADCR |
PWR_REG_PON_PGAL | PWR_REG_PON_PGAR
},
{
AMIX_REG,
AMIX_AVCL(0x3F) | AMIX_AVCR(0x3F)
},
{
MASTER_VOL_REG,
MASTER_VCL(0) | MASTER_VCR(0)
},
{
MIXER_VOL_REG,
MIXER_VC_CH1(00) | MIXER_VC_CH2(0xff)
},
{
MBT_REG,
0x00
},
{
MMCDM_REG,
MMCDM_MASTER_MUTE| MMCDM_CHANNEL2_MUTE
},
{
MIXER_CTL_REG,
0x00
},
{
DEC_VOL_REG,
DEC_VCL(0) | DEC_VCR(0)
},
{
DPM_REG,
DPM_MUTE_ADC
},
{
DEC_ADC_REG,
0x050c
},
{
DEC_AGC_REG,
0x00
}
};
typedef unsigned int uda1380_enumerated_t;
typedef long uda1380_value_t;
typedef struct _uda1380_lr_value
{
uda1380_value_t left;
uda1380_value_t right;
} uda1380_lr_value_t;
typedef struct _uda1380
{
uint16_t regs[REG_MAX];
int mic_enable;
int mod_cnt;
uda1380_enumerated_t deemp;
uda1380_enumerated_t strength;
uda1380_value_t playback_mute;
uda1380_value_t mic_gain;
uda1380_value_t mic_sw;
uda1380_value_t line_mute;
uda1380_lr_value_t line_gain;
uda1380_lr_value_t master_playback_volume;
uda1380_lr_value_t analog_playback_volume;
uda1380_lr_value_t pcm_capture_volume;
uda1380_lr_value_t bass;
uda1380_lr_value_t treble;
struct i2c_client client;
} uda1380_t;
#if defined(UDA1380_DEBUG) && 0
static void uda1380_dump(int level, const uda1380_t *uda1380)
{
PRDEBUG(level, "uda1380: volume=%u bass=%u treble=%u line=%u mic=%u\n",
uda1380->volume, uda1380->bass, uda1380->treble, uda1380->line, uda1380->mic);
PRDEBUG(level, "uda1380: mod_cnt=%d client=%p\n",
uda1380->mod_cnt, &uda1380->client);
}
#endif
static int uda1380_write_reg(struct i2c_client *client, uda1380_t *uda1380, int regaddr)
{
uint8_t buffer[3];
int r;
PRDEBUG(3, "%s(): [%u] = %04x\n", __FUNCTION__, regaddr, uda1380->regs[regaddr]);
buffer[0] = regaddr;
buffer[1] = uda1380->regs[regaddr] >> 8;
buffer[2] = uda1380->regs[regaddr] & 0xff;
r = i2c_master_send(client, buffer, 3);
if (r == 3)
r = 0;
else if (r >= 0)
r = -EIO;
return r;
}
void uda1380_configure(struct i2c_client *client, long rate)
{
uda1380_t *uda1380 = container_of(client, uda1380_t, client);
uint16_t pll;
PRDEBUG(2, "%s(%p,%ld) uda1380=%p\n", __FUNCTION__, client, rate, uda1380);
if (!rate) {
PRDEBUG(2, "%s: rate set to default of 44100\n", __FUNCTION__);
rate = 44100;
}
if (rate > 50000)
pll = EMCS_REG_PLL_50TO100;
if (rate >= 25000)
pll = EMCS_REG_PLL_25TO50;
else if (rate >= 12000)
pll = EMCS_REG_PLL_12TO25;
else
pll = EMCS_REG_PLL_6TO12;
uda1380->regs[EMCS_REG] &= ~(EMCS_REG_SC_MASK | EMCS_REG_PLL_MASK);
uda1380->regs[EMCS_REG] |= EMCS_REG_SC_256FS;
uda1380->regs[EMCS_REG] |= pll;
uda1380_write_reg(client, uda1380, EMCS_REG);
PRDEBUG(3, "%s: %u\n", __FUNCTION__, __LINE__);
uda1380->regs[I2S_REG] = ((uda1380->regs[I2S_REG] & ~(I2S_REG_SFORO_MASK | I2S_REG_SFORI_MASK)) |
(FMT_I2S << I2S_REG_SFORO_SHIFT) | (FMT_I2S << I2S_REG_SFORI_SHIFT));
uda1380_write_reg(client, uda1380, I2S_REG);
PRDEBUG(3, "%s: %u\n", __FUNCTION__, __LINE__);
uda1380->regs[PWR_REG] &= ~PWR_REG_PON_PLL;
uda1380_write_reg(client, uda1380, PWR_REG);
PRDEBUG(3, "%s: %u\n", __FUNCTION__, __LINE__);
mdelay(5);
uda1380->regs[PWR_REG] |= PWR_REG_PON_PLL;
uda1380_write_reg(client, uda1380, PWR_REG);
PRDEBUG(3, "%s: %u\n", __FUNCTION__, __LINE__);
mdelay(5);
}
int uda1380_mute(struct i2c_client *client, int mute)
{
int ret;
uda1380_t *uda1380 = container_of(client, uda1380_t, client);
PRDEBUG(2, "%s(client=%p,mute=%d) uda1380=%p\n", __FUNCTION__, client, mute, uda1380);
ret = (uda1380->regs[MMCDM_REG] & MMCDM_MASTER_MUTE) > 0;
if (mute)
uda1380->regs[MMCDM_REG] |= MMCDM_MASTER_MUTE;
else
uda1380->regs[MMCDM_REG] &= ~MMCDM_MASTER_MUTE;
uda1380_write_reg(client, uda1380, MMCDM_REG);
PRDEBUG(3, "%s: %u\n", __FUNCTION__, __LINE__);
return ret;
}
/* The private value of the controls. */
enum
{
UDAC_MASTER_PLAYBACK_VOLUME,
UDAC_MASTER_PLAYBACK_MUTE,
UDAC_ANALOG_PLAYBACK_VOLUME,
UDAC_STRENGTH,
UDAC_BASS,
UDAC_TREBLE,
UDAC_DEEMP,
UDAC_PCM_CAPTURE_VOLUME,
UDAC_MIC_GAIN,
UDAC_LINE_GAIN,
UDAC_LINE_MUTE,
UDAC_MIC_SW,
UDAC_LAST
};
static int
snd_uda1380_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
static const char *strengths[] = {"minimum", "flat", "maximum"};
static const char *deemps[] = {"off", "32kHz", "44.1kHz", "48kHz", "96kHz"};
PRDEBUG(4, "%s(%p,%p) private_value=%ld\n",
__FUNCTION__,
kcontrol, uinfo,
kcontrol->private_value);
switch (kcontrol->private_value) {
case UDAC_MASTER_PLAYBACK_VOLUME:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xFF;
return 0;
case UDAC_PCM_CAPTURE_VOLUME:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = -128;
uinfo->value.integer.max = 0x30;
return 0;
case UDAC_MASTER_PLAYBACK_MUTE:
case UDAC_LINE_MUTE:
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
case UDAC_ANALOG_PLAYBACK_VOLUME:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0x3F;
return 0;
case UDAC_BASS:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0x0F;
return 0;
case UDAC_TREBLE:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0x03;
return 0;
case UDAC_STRENGTH:
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = ARRAY_SIZE(strengths);
if (uinfo->value.enumerated.item >= ARRAY_SIZE(strengths))
uinfo->value.enumerated.item = ARRAY_SIZE(strengths) - 1;
strncpy(uinfo->value.enumerated.name,
strengths[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
return 0;
case UDAC_LINE_GAIN:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 8;
return 0;
case UDAC_MIC_GAIN:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 15;
return 0;
case UDAC_DEEMP:
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = ARRAY_SIZE(deemps);
if (uinfo->value.enumerated.item >= ARRAY_SIZE(deemps))
uinfo->value.enumerated.item = ARRAY_SIZE(deemps) - 1;
strncpy(uinfo->value.enumerated.name,
deemps[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
return 0;
case UDAC_MIC_SW:
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
printk(KERN_WARNING "%s called with bad private info: %ld\n", __FUNCTION__, kcontrol->private_value);
return -EINVAL;
}
#if defined(UDA1380_DEBUG)
static const char *kontrol_value_names[] = {
"MASTER_PLAYBACK_VOLUME",
"MASTER_PLAYBACK_MUTE",
"ANALOG_PLAYBACK_VOLUME",
"STRENGTH",
"BASS",
"TREBLE",
"DEEMP",
"PCM_CAPTURE_VOLUME",
"MIC_GAIN",
"LINE_GAIN",
"LINE_MUTE",
"MIC_SW",
"LAST",
"<INVALID>"
};
#endif
static int
snd_uda1380_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
uda1380_t *uda1380 = snd_kcontrol_chip(kcontrol);
struct i2c_client *client = &uda1380->client;
uint8_t newregnum;
uint16_t val;
#if defined(UDA1380_DEBUG)
if (4 <= debug)
{
size_t i = kcontrol->private_value;
if (i >= ARRAY_SIZE(kontrol_value_names))
i = ARRAY_SIZE(kontrol_value_names) - 1;
PRDEBUG(4, "%s(%p,%p) value=%s int_values=%ld/%ld uda1380=%p client=%p\n",
__FUNCTION__,
kcontrol, ucontrol,
kontrol_value_names[i],
ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
uda1380, client);
}
#endif
switch (kcontrol->private_value)
{
case UDAC_STRENGTH:
switch (uda1380->strength = ucontrol->value.integer.value[0])
{
case 0:
val = 1;
break;
case 2:
val = 3;
break;
default:
val = 0;
break;
}
uda1380->regs[MBT_REG] &= ~(MBT_MODE_MASK);
uda1380->regs[MBT_REG] |= val << MBT_MODE_SHIFT;
newregnum = MBT_REG;
break;
case UDAC_DEEMP:
val = uda1380->deemp = ucontrol->value.enumerated.item[0];
if (val > 4)
val = 4;
uda1380->regs[MMCDM_REG] &= ~(MMCDM_CHANNEL1_DEEMPHASIS_MASK | MMCDM_CHANNEL2_DEEMPHASIS_MASK);
uda1380->regs[MMCDM_REG] |= (val << MMCDM_CHANNEL2_DEEMPHASIS_SHIFT) | (val << MMCDM_CHANNEL1_DEEMPHASIS_SHIFT);
newregnum = MMCDM_REG;
return 0;
case UDAC_MASTER_PLAYBACK_MUTE:
if ((uda1380->playback_mute = ucontrol->value.integer.value[0]))
uda1380->regs[MMCDM_REG] &= ~MMCDM_MASTER_MUTE;
else
uda1380->regs[MMCDM_REG] |= MMCDM_MASTER_MUTE;
newregnum = MMCDM_REG;
break;
case UDAC_MIC_GAIN:
uda1380->mic_gain = ucontrol->value.integer.value[0] & 0x0F;
uda1380->regs[DEC_ADC_REG] &= ~DEC_ADC_VGA_CTRL_MASK;
uda1380->regs[DEC_ADC_REG] |= DEC_ADC_VGA_CTRL(uda1380->mic_gain);
if (uda1380->mic_gain)
uda1380->regs[DEC_ADC_REG] |= DEC_ADC_SEL_LNA | DEC_ADC_SEL_MIC;
else
uda1380->regs[DEC_ADC_REG] &= ~ (DEC_ADC_SEL_LNA | DEC_ADC_SEL_MIC);
newregnum = DEC_ADC_REG;
break;
case UDAC_MIC_SW:
if ((uda1380->mic_sw = ucontrol->value.integer.value[0]))
uda1380->regs[DEC_ADC_REG] |= DEC_ADC_SEL_LNA | DEC_ADC_SEL_MIC;
else
uda1380->regs[DEC_ADC_REG] &= ~ (DEC_ADC_SEL_LNA | DEC_ADC_SEL_MIC);
newregnum = DEC_ADC_REG;
break;
case UDAC_LINE_MUTE:
if ((uda1380->line_mute = ucontrol->value.integer.value[0]))
uda1380->regs[DPM_REG] &= ~DPM_MUTE_ADC;
else
uda1380->regs[DPM_REG] |= DPM_MUTE_ADC;
newregnum = DPM_REG;
break;
case UDAC_MASTER_PLAYBACK_VOLUME:
uda1380->master_playback_volume.left = ucontrol->value.integer.value[0] & 0xFF;
uda1380->master_playback_volume.right = ucontrol->value.integer.value[1] & 0xFF;
uda1380->regs[MASTER_VOL_REG] = (MASTER_VCL(0xFF - uda1380->master_playback_volume.left) |
MASTER_VCR(0xFF - uda1380->master_playback_volume.right));
newregnum = MASTER_VOL_REG;
break;
case UDAC_ANALOG_PLAYBACK_VOLUME:
uda1380->analog_playback_volume.left = ucontrol->value.integer.value[0] & 0x3F;
uda1380->analog_playback_volume.right = ucontrol->value.integer.value[1] & 0x3F;
uda1380->regs[AMIX_REG] = (AMIX_AVCL(0x3F - uda1380->analog_playback_volume.left) |
AMIX_AVCR(0x3F - uda1380->analog_playback_volume.right));
newregnum = AMIX_REG;
break;
case UDAC_PCM_CAPTURE_VOLUME:
uda1380->pcm_capture_volume.left = ucontrol->value.integer.value[0];
if (uda1380->pcm_capture_volume.left < -128)
uda1380->pcm_capture_volume.left = -128;
else if (uda1380->pcm_capture_volume.left > 0x30)
uda1380->pcm_capture_volume.left = 0x30;
uda1380->pcm_capture_volume.right = ucontrol->value.integer.value[1];
if (uda1380->pcm_capture_volume.right < -128)
uda1380->pcm_capture_volume.right = -128;
else if (uda1380->pcm_capture_volume.right > 0x30)
uda1380->pcm_capture_volume.right = 0x30;
uda1380->regs[DEC_VOL_REG] &= ~(DEC_VCL_MASK | DEC_VCR_MASK);
val = uda1380->pcm_capture_volume.left & 0xFF;
uda1380->regs[DEC_VOL_REG] |= DEC_VCL(val);
val = uda1380->pcm_capture_volume.right & 0xFF;
uda1380->regs[DEC_VOL_REG] |= DEC_VCR(val);
newregnum = DEC_VOL_REG;
break;
case UDAC_BASS:
uda1380->bass.left = ucontrol->value.integer.value[0] & 0x0F;
uda1380->bass.right = ucontrol->value.integer.value[1] & 0x0F;
uda1380->regs[MBT_REG] &= ~(MBT_BBL_MASK | MBT_BBR_MASK);
uda1380->regs[MBT_REG] |= MBT_BBL(uda1380->bass.left) | MBT_BBR(uda1380->bass.right);
newregnum = MBT_REG;
break;
case UDAC_TREBLE:
uda1380->treble.left = ucontrol->value.integer.value[0] & 0x03;
uda1380->treble.right = ucontrol->value.integer.value[1] & 0x03;
uda1380->regs[MBT_REG] &= ~(MBT_TRL_MASK | MBT_TRR_MASK);
uda1380->regs[MBT_REG] |= MBT_TRL(uda1380->treble.left) | MBT_TRR(uda1380->treble.right);
newregnum = MBT_REG;
break;
case UDAC_LINE_GAIN:
uda1380->line_gain.left = ucontrol->value.integer.value[0] & 0x0F;
uda1380->line_gain.right = ucontrol->value.integer.value[1] & 0x0F;
uda1380->regs[DPM_REG] &= ~(DPM_GAINL_MASK | DPM_GAINR_MASK);
uda1380->regs[DPM_REG] |= DPM_GAINL(uda1380->line_gain.left) | DPM_GAINR(uda1380->line_gain.right);
newregnum = DPM_REG;
break;
default:
return -EINVAL;
}
return uda1380_write_reg(client, uda1380, newregnum);
}
static int
snd_uda1380_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
uda1380_t *uda1380 = snd_kcontrol_chip(kcontrol);
PRDEBUG(4, "%s(%p,%p) value=%ld uda1380=%p\n",
__FUNCTION__,
kcontrol, ucontrol,
kcontrol->private_value,
uda1380);
switch (kcontrol->private_value)
{
case UDAC_STRENGTH:
ucontrol->value.enumerated.item[0] = uda1380->strength;
return 0;
case UDAC_DEEMP:
ucontrol->value.enumerated.item[0] = uda1380->deemp;
return 0;
case UDAC_MASTER_PLAYBACK_MUTE:
ucontrol->value.enumerated.item[0] = uda1380->playback_mute;
return 0;
case UDAC_MIC_GAIN:
ucontrol->value.integer.value[0] = uda1380->mic_gain;
return 0;
case UDAC_MIC_SW:
ucontrol->value.integer.value[0] = uda1380->mic_sw;
return 0;
case UDAC_LINE_MUTE:
ucontrol->value.integer.value[0] = uda1380->line_mute;
return 0;
case UDAC_MASTER_PLAYBACK_VOLUME:
ucontrol->value.integer.value[0] = uda1380->master_playback_volume.left;
ucontrol->value.integer.value[1] = uda1380->master_playback_volume.right;
return 0;
case UDAC_ANALOG_PLAYBACK_VOLUME:
ucontrol->value.integer.value[0] = uda1380->analog_playback_volume.left;
ucontrol->value.integer.value[1] = uda1380->analog_playback_volume.right;
return 0;
case UDAC_PCM_CAPTURE_VOLUME:
ucontrol->value.integer.value[0] = uda1380->pcm_capture_volume.left;
ucontrol->value.integer.value[1] = uda1380->pcm_capture_volume.right;
return 0;
case UDAC_BASS:
ucontrol->value.integer.value[0] = uda1380->bass.left;
ucontrol->value.integer.value[1] = uda1380->bass.right;
return 0;
case UDAC_TREBLE:
ucontrol->value.integer.value[0] = uda1380->treble.left;
ucontrol->value.integer.value[1] = uda1380->treble.right;
return 0;
case UDAC_LINE_GAIN:
ucontrol->value.integer.value[0] = uda1380->line_gain.left;
ucontrol->value.integer.value[1] = uda1380->line_gain.right;
return 0;
}
printk(KERN_WARNING "%s called with bad private info: %ld\n", __FUNCTION__, kcontrol->private_value);
return -EINVAL;
}
#define UDA1380(xname, pvt_value) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.info = snd_uda1380_info, \
.get = snd_uda1380_get, \
.put = snd_uda1380_put, \
.private_value = pvt_value \
}
static snd_kcontrol_new_t snd_uda1380_controls[] =
{
UDA1380("Master Playback Volume", UDAC_MASTER_PLAYBACK_VOLUME),
UDA1380("Master Playback Switch", UDAC_MASTER_PLAYBACK_MUTE),
UDA1380("Line Bypass Playback Volume", UDAC_ANALOG_PLAYBACK_VOLUME),
UDA1380("Tone Control - Strenght", UDAC_STRENGTH),
UDA1380("Tone Control - Bass", UDAC_BASS),
UDA1380("Tone Control - Treble", UDAC_TREBLE),
UDA1380("De-emphasis", UDAC_DEEMP),
UDA1380("Capture Volume", UDAC_PCM_CAPTURE_VOLUME),
UDA1380("Mic Capture Gain", UDAC_MIC_GAIN),
UDA1380("Line Capture Volume", UDAC_LINE_GAIN),
UDA1380("Line Capture Switch", UDAC_LINE_MUTE),
UDA1380("Mic Capture Switch", UDAC_MIC_SW),
};
/* initialization stuff */
static struct i2c_client client_template = {
name: "(unset)",
flags: I2C_CLIENT_ALLOW_USE,
driver: &uda1380_driver
};
static int uda1380_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int zero_or_minus_one)
{
uda1380_t *uda1380;
struct i2c_client *client;
int i;
PRDEBUG(2,
"%s(adap=%p,addr=%02x,flags=%u,zomo=%d)\n",
__FUNCTION__,
adap, addr, flags, zero_or_minus_one);
uda1380 = kmalloc(sizeof(*uda1380), GFP_KERNEL);
if (!uda1380)
return -ENODEV;
PRDEBUG(2, "%s: uda1380=%p created\n", __FUNCTION__, uda1380);
memset(uda1380, 0, sizeof(*uda1380));
/* set default values of registers */
for (i = 0; i < ARRAY_SIZE(uda1380_reg_info); i++)
{
PRDEBUG(3, "%s: reg[%u] = 0x%04x\n",
__FUNCTION__,
uda1380_reg_info[i].num, uda1380_reg_info[i].default_value);
uda1380->regs[uda1380_reg_info[i].num] = uda1380_reg_info[i].default_value;
}
client = &uda1380->client;
memcpy(client, &client_template, sizeof(*client));
client->adapter = adap;
client->addr = addr;
strcpy(client->name, "uda1380");
i2c_attach_client(client);
return 0;
}
static int uda1380_detach_client(struct i2c_client *client)
{
uda1380_t *uda1380 = container_of(client, uda1380_t, client);
PRDEBUG(2, "%s(%p) uda1380=%p\n", __FUNCTION__, client, uda1380);
i2c_detach_client(client);
PRDEBUG(2, "%s: freeing %p\n", __FUNCTION__, uda1380);
kfree(uda1380);
PRDEBUG(2, "%s: freed %p\n", __FUNCTION__, uda1380);
return 0;
}
#define UDA1380_I2C_DEFAULT_ADDRESS (0x30U >> 1)
/* Addresses to scan */
static unsigned short normal_i2c[] = {UDA1380_I2C_DEFAULT_ADDRESS, I2C_CLIENT_END};
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
static unsigned short probe[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short probe_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short ignore[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short ignore_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short force[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
normal_i2c, normal_i2c_range,
probe, probe_range,
ignore, ignore_range,
force
};
static int uda1380_attach_adapter(struct i2c_adapter *adap)
{
PRDEBUG(2, "%s(adap=%p)\n", __FUNCTION__, adap);
return i2c_probe(adap, &addr_data, uda1380_attach);
}
static void uda1380_inc_use(struct i2c_client *client)
{
PRDEBUG(2, "%s:\n", __FUNCTION__);
MOD_INC_USE_COUNT;
}
static void uda1380_dec_use(struct i2c_client *client)
{
PRDEBUG(2, "%s:\n", __FUNCTION__);
MOD_DEC_USE_COUNT;
}
static struct i2c_driver uda1380_driver =
{
.name = "UDA1380",
.id = I2C_DRIVERID_UDA1380,
.flags = I2C_DF_NOTIFY,
.attach_adapter = uda1380_attach_adapter,
.detach_client = uda1380_detach_client,
.inc_use = uda1380_inc_use,
.dec_use = uda1380_dec_use
};
int snd_chip_uda1380_mixer_new(snd_card_t *_card, struct i2c_client **_client, int _mic_enable)
{
size_t i;
size_t n = 0;
int err;
struct i2c_client *client;
uda1380_t *uda1380;
MOD_INC_USE_COUNT;
PRDEBUG(2, "%s(card=%p,_client=%p)\n", __FUNCTION__, _card, _client);
snd_assert(_card != NULL, return -EINVAL);
client = i2c_get_client(I2C_DRIVERID_UDA1380, I2C_ALGO_MPC5xxx, NULL);
*_client = client;
if (!client)
{
printk(KERN_ERR "uda1380: error: cannot get i2c client\n");
MOD_DEC_USE_COUNT;
return -ENODEV;
}
uda1380 = container_of(client, uda1380_t, client);
uda1380->mic_enable = _mic_enable;
PRDEBUG(1, "%s: i2c_get_client returned client=%p uda1380=%p\n", __FUNCTION__, client, uda1380);
for (i = 0; i < ARRAY_SIZE(snd_uda1380_controls); i++) {
if ((snd_uda1380_controls[i].private_value != UDAC_MIC_SW &&
snd_uda1380_controls[i].private_value != UDAC_MIC_GAIN) ||
_mic_enable)
{
if ((err = snd_ctl_add(_card, snd_ctl_new1(&snd_uda1380_controls[i], uda1380))) < 0)
{
MOD_DEC_USE_COUNT;
return err;
}
n++;
}
}
PRDEBUG(2, "added %u controls\n", n);
strncpy(_card->mixername, "UDA1380 Mixer", sizeof(_card->mixername));
return 0;
}
void snd_chip_uda1380_mixer_del(snd_card_t *_card, struct i2c_client *_client)
{
PRDEBUG(2, "%s(%p,%p)\n", __FUNCTION__, _card, _client);
MOD_DEC_USE_COUNT;
}
static int __init uda1380_init(void)
{
PRDEBUG(2, "%s\n", __FUNCTION__);
#if defined(UDA1380_DEBUG)
printk(KERN_INFO "%s: debug=%d\n", __FUNCTION__, debug);
#else
if (debug != -1)
printk(KERN_WARNING "%s: compiled without debug support\n", __FUNCTION__);
#endif
return i2c_add_driver(&uda1380_driver);
}
static void __exit uda1380_exit(void)
{
PRDEBUG(2, "%s\n", __FUNCTION__);
i2c_del_driver(&uda1380_driver);
}
module_init(uda1380_init);
module_exit(uda1380_exit);
EXPORT_SYMBOL(uda1380_mute);
EXPORT_SYMBOL(uda1380_configure);
EXPORT_SYMBOL(snd_chip_uda1380_mixer_new);
EXPORT_SYMBOL(snd_chip_uda1380_mixer_del);
MODULE_AUTHOR("Giorgio Padrin");
MODULE_DESCRIPTION("Philips UDA1380 codec driver");
MODULE_LICENSE("GPL");
#if defined(UDA1380_DEBUG)
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "debug level (0-6)");
#endif
[-- Attachment #1.3: uda1380.h --]
[-- Type: text/x-chdr, Size: 6146 bytes --]
/*
* Sound driver for Philips uda1380 - i2c related stuff
*
* Copyright (C) 2005 Roman Fietze <roman.fietze@telemotive.de>
* Copyright (C) 2004 Giorgio Padrin
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* based on code by:
*
* Copyright (c) 2002 Hewlett-Packard Company
* Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
*/
#ifndef _UDA1380_H_
#define _UDA1380_H_
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/info.h>
#include <linux/i2c.h>
#ifndef container_of
#define container_of list_entry
#endif
#define FMT_I2S 0
#define FMT_LSB16 1
#define FMT_LSB18 2
#define FMT_LSB20 3
#define FMT_MSB 5
#define REG_MAX 0x24
#define EMCS_REG 0x00
#define EMCS_REG_EN_ADC (1 << 11)
#define EMCS_REG_EN_DEC (1 << 10)
#define EMCS_REG_EN_DAC (1 << 9)
#define EMCS_REG_EN_INT (1 << 8)
#define EMCS_REG_ADC_USE_WSPLL (1 << 5)
#define EMCS_REG_ADC_USE_SYSCLK (0 << 5)
#define EMCS_REG_DAC_USE_WSPLL (1 << 4)
#define EMCS_REG_DAC_USE_SYSCLK (0 << 4)
#define EMCS_REG_SC_MASK (3 << 2)
#define EMCS_REG_SC_768FS (3 << 2)
#define EMCS_REG_SC_512FS (2 << 2)
#define EMCS_REG_SC_384FS (1 << 2)
#define EMCS_REG_SC_256FS (0 << 2)
#define EMCS_REG_PLL_MASK (3 << 0)
#define EMCS_REG_PLL_6TO12 (0 << 0)
#define EMCS_REG_PLL_12TO25 (1 << 0)
#define EMCS_REG_PLL_25TO50 (2 << 0)
#define EMCS_REG_PLL_50TO100 (3 << 0)
#define I2S_REG 0x01
#define I2S_REG_SFORO_MASK (7 << 0)
#define I2S_REG_SFORO_SHIFT 0
#define I2S_REG_SFORI_MASK (7 << 8)
#define I2S_REG_SFORI_SHIFT 8
#define I2S_REG_SEL_DECIMATOR (0 << 6)
#define I2S_REG_SEL_MIXER (1 << 6)
#define I2S_REG_SIM_SLAVE (0 << 4)
#define I2S_REG_SIM_MASTER (1 << 4)
#define PWR_REG 0x02
#define PWR_REG_PON_PLL (1 << 15)
#define PWR_REG_PON_HP (1 << 13)
#define PWR_REG_PON_DAC (1 << 10)
#define PWR_REG_PON_BIAS (1 << 8)
#define PWR_REG_EN_AVC (1 << 7)
#define PWR_REG_PON_AVC (1 << 6)
#define PWR_REG_PON_LNA (1 << 4)
#define PWR_REG_PON_PGAL (1 << 3)
#define PWR_REG_PON_ADCL (1 << 2)
#define PWR_REG_PON_PGAR (1 << 1)
#define PWR_REG_PON_ADCR (1 << 0)
/* analog mixer */
#define AMIX_REG 0x03
#define AMIX_AVCL(x) (((x) & 0x3f) << 8)
#define AMIX_AVCL_MASK (0x3f << 8)
#define AMIX_AVCR(x) (((x) & 0x3f) << 0)
#define AMIX_AVCR_MASK (0x3f << 0)
/* digital master volume control register */
#define MASTER_VOL_REG 0x10
#define MASTER_VCL(x) (((x) & 0xff) << 8)
#define MASTER_VCL_MASK (0xff << 8)
#define MASTER_VCR(x) (((x) & 0xff) << 0)
#define MASTER_VCR_MASK (0xff << 0)
/* digital mixer control register */
#define MIXER_VOL_REG 0x11
#define MIXER_VC_CH2(x) (((x) & 0xff) << 8)
#define MIXER_VC_CH2_MASK (0xff << 8)
#define MIXER_VC_CH1(x) (((x) & 0xff) << 0)
#define MIXER_VC_CH1_MASK (0xff << 0)
/* mode, bass boost, treble */
#define MBT_REG 0x12
#define MBT_MODE_MASK (3 << 14)
#define MBT_MODE_FLAT (0 << 14)
#define MBT_MODE_MIN (1 << 14)
#define MBT_MODE_MAX (3 << 14)
#define MBT_MODE_SHIFT (14)
#define MBT_TRL_WIDTH 2
#define MBT_TRL_MASK (3 << 12)
#define MBT_TRL(x) ((x) << 12)
#define MBT_TRR_MASK (3 << 4)
#define MBT_TRR(x) ((x) << 4)
#define MBT_BBL_WIDTH 4
#define MBT_BBL_MASK (0xf << 8)
#define MBT_BBL(x) ((x) << 8)
#define MBT_BBR_MASK (0xf << 0)
#define MBT_BBR(x) ((x) << 0)
/* channel2 is from decimation filter */
/* channel1 is from digital data from I2S */
#define MMCDM_REG 0x13
#define MMCDM_MASTER_MUTE (1 << 14)
#define MMCDM_CHANNEL2_MUTE (1 << 11)
#define MMCDM_CHANNEL2_DEEMPHASIS_OFF (0 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_32KHZ (1 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_44KHZ (2 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_48KHZ (3 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_96KHZ (4 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_MASK (7 << 8)
#define MMCDM_CHANNEL2_DEEMPHASIS_SHIFT (8)
#define MMCDM_CHANNEL1_MUTE (1 << 3)
#define MMCDM_CHANNEL1_DEEMPHASIS_32KHZ (1 << 0)
#define MMCDM_CHANNEL1_DEEMPHASIS_44KHZ (2 << 0)
#define MMCDM_CHANNEL1_DEEMPHASIS_48KHZ (3 << 0)
#define MMCDM_CHANNEL1_DEEMPHASIS_96KHZ (4 << 0)
#define MMCDM_CHANNEL1_DEEMPHASIS_MASK (7 << 0)
#define MMCDM_CHANNEL1_DEEMPHASIS_SHIFT (0)
#define MIXER_CTL_REG 0x14
#define MIXER_CTL_DAC_POLARITY_INVERT (1 << 15)
#define MIXER_CTL_SEL_5TH_ORDER_NS (1 << 14)
#define MIXER_CTL_MIX_POS (1 << 13)
#define MIXER_CTL_MIX (1 << 12)
#define MIXER_CTL_SILENCE (1 << 7)
#define MIXER_CTL_SDET_ON (1 << 6)
#define MIXER_CTL_SDET_VALUE_MASK (3 << 4)
#define MIXER_CTL_SDET_VALUE_SHIFT 4
#define MIXER_CTL_OVERSAMPLING_MASK (3 << 0)
#define MIXER_CTL_OVERSAMPLING_SHIFT 0
#define DEC_VOL_REG 0x20
#define DEC_VCL(x) (((x) & 0xff) << 8)
#define DEC_VCL_MASK (0xff << 8)
#define DEC_VCR(x) (((x) & 0xff) << 0)
#define DEC_VCR_MASK (0xff << 0)
#define DPM_REG 0x21
#define DPM_MUTE_ADC (1 << 15)
#define DPM_GAINL(x) (((x) & 0xf) << 8)
#define DPM_GAINL_MASK (0xf << 8)
#define DPM_GAINR(x) (((x) & 0xf) << 0)
#define DPM_GAINR_MASK (0xf << 0)
#define DEC_ADC_REG 0x22
#define DEC_ADC_POL_INV (1 << 12)
#define DEC_ADC_VGA_CTRL(x) ((x) << 8)
#define DEC_ADC_VGA_CTRL_MASK (0xf << 8)
#define DEC_ADC_SEL_LNA (1 << 3)
#define DEC_ADC_SEL_MIC (1 << 2)
#define DEC_ADC_SKIP_DCFIL (1 << 1)
#define DEC_ADC_EN_DCFIL (1 << 0)
#define DEC_AGC_REG 0x23
#define DEC_AGC_EN (1 << 0)
int snd_chip_uda1380_mixer_new(snd_card_t *card, struct i2c_client **clnt, int _mic_enable);
void snd_chip_uda1380_mixer_del(snd_card_t *card, struct i2c_client *clnt);
// int uda1380_configure(struct i2c_client *client, struct uda1380_cfg *conf);
void uda1380_configure(struct i2c_client *client, long rate);
int uda1380_mute(struct i2c_client *clnt, int mute);
#endif /* _UDA1380_H_ */
[-- Attachment #1.4: mpc5200-uda1380.c --]
[-- Type: text/x-csrc, Size: 23735 bytes --]
/*
Copyright (C) 2005 Roman Fietze, Telemotive AG
Audio driver for the FreeScale MPC5200 PSC in I2S codec
mode. Optionally using I2C to an UDA1380 to control the Codec.
This code is released under GPL (GNU Public License) with absolutely
no warranty. Please see http://www.gnu.org/ for a complete discussion
of the GPL.
based on code by:
Copyright (C) 2003 Christian Pellegrin
Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
Copyright (c) 2002 Hewlett-Packard Company
Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
*/
/*
mpc5200-uda1380.c
*/
#include <linux/module.h>
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/i2c.h>
#include <linux/kmod.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include "../i2c/uda1380.h"
#include <asm/mpc5xxx_snd.h>
#undef SND_MPC5200_DEBUG
// #define SND_MPC5200_DEBUG
// #undef SND_MPC5200_SIMPLE_PROC
#define SND_MPC5200_SIMPLE_PROC
#if defined(SND_MPC5200_DEBUG)
#define PRDEBUG(level, format, x... ) do {if (level <= debug) printk(KERN_INFO format, ## x );} while (0)
#else
#define PRDEBUG(level, format, x... ) do {} while(0)
#endif
enum
{
CMD_EXTSW /* optional */
};
typedef enum _stream_id
{
PLAYBACK = 0, /* playback stream index */
CAPTURE, /* capture stream index */
NUM_STREAMS /* every "card" or PSC can have up to two (snd_pcm_sub)streams */
} stream_id_t;
typedef struct _mpc5200_uda1380
{
snd_card_t *card;
snd_pcm_t *pcm;
int cardid;
struct i2c_client *uda1380; /* optional, no mixer if NULL */
int extsw;
snd_info_entry_t *extsw_proc_entry;
#if !defined(SND_MPC5200_SIMPLE_PROC)
wait_queue_head_t extsw_wait;
#endif
long samplerate;
snd_mpc5xxx_i2s_card_t *i2s_card;
snd_mpc5xxx_i2s_substream_t *i2s_substreams[NUM_STREAMS];
} mpc5200_uda1380_t;
static const char DRIVER_KERNEL_NAME[] = "snd-mpc5200";
static const char DRIVER_NAME[] = "MPC5xxx I2S UDA1380";
static int debug = -1;
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int uda[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int slave[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int spi[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int mic[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int extsw[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static int loopback[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
static snd_card_t *cards[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* initialize to NULL */
static const int allowed[SNDRV_CARDS] = {0, 1, 1, 1, 0, 0, 1, 0}; /* allow PSC 1,2,3,6 */
#if !defined(SND_MPC5200_SIMPLE_PROC)
static char snd_mpc5200_extsw_data[2] = {'0', '\n'};
#endif
static void snd_mpc5200_uda1380_set_samplerate(mpc5200_uda1380_t *chip, long rate)
{
struct i2c_client *uda1380 = chip->uda1380;
int mute;
PRDEBUG(1,
"%s(id=%d,rate=%ld) chip->samplerate=%ld\n",
__FUNCTION__,
chip->cardid, rate,
chip->samplerate);
if (rate == chip->samplerate)
return;
mute = uda1380_mute(uda1380, 1);
chip->samplerate = rate;
udelay(125);
uda1380_configure(uda1380, chip->samplerate = rate);
uda1380_mute(uda1380, mute);
PRDEBUG(1, "%s done\n", __FUNCTION__);
}
static const snd_pcm_hardware_t snd_mpc5200_playback_capture =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_BE,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = SND_PSC_AUDIO_RATE_MIN,
.rate_max = SND_PSC_AUDIO_RATE_MAX,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = SND_PSC_MAX_BUFFER_SIZE,
.period_bytes_min = SND_PSC_MIN_PERIOD_SIZE,
.period_bytes_max = SND_PSC_MAX_PERIOD_SIZE,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
#if 0
static const snd_pcm_hardware_t snd_mpc5200_playback =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_BE,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = SND_PSC_AUDIO_RATE_MIN,
.rate_max = SND_PSC_AUDIO_RATE_MAX,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = SND_PSC_MAX_BUFFER_SIZE,
.period_bytes_min = SND_PSC_MIN_PERIOD_SIZE,
.period_bytes_max = SND_PSC_MAX_PERIOD_SIZE,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
#endif
static int snd_card_mpc5200_playback_open(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
PRDEBUG(1, "%s\n", __FUNCTION__);
runtime->hw = snd_mpc5200_playback_capture;
err = snd_psc_substream_open(chip->i2s_substreams[PLAYBACK], substream);
if (err < 0)
return err;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
return 0;
}
static int snd_card_mpc5200_playback_close(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
PRDEBUG(1, "%s\n", __FUNCTION__);
return snd_psc_substream_close(chip->i2s_substreams[PLAYBACK]);
}
static int snd_card_mpc5200_playback_ioctl(snd_pcm_substream_t *substream,
unsigned int cmd,
void *arg)
{
PRDEBUG(1, "%s(cmd=%d)\n", __FUNCTION__, cmd);
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
static int snd_card_mpc5200_playback_hw_params(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *hw_params)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
{
if (err < 0)
printk(KERN_ERR "%s: memory allocation failed\n", DRIVER_NAME);
return err;
}
/* set requested samplerate on an optional UDA1380 */
if (chip->uda1380)
snd_mpc5200_uda1380_set_samplerate(chip, runtime->rate);
return snd_psc_substream_params(chip->i2s_substreams[PLAYBACK],
runtime->rate,
runtime->channels,
snd_pcm_format_width(runtime->format),
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream));
}
static int snd_card_mpc5200_playback_prepare(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
/* set requested samplerate on an optional UDA1380 */
if (chip->uda1380)
snd_mpc5200_uda1380_set_samplerate(chip, runtime->rate);
return snd_psc_substream_params(chip->i2s_substreams[PLAYBACK],
runtime->rate,
runtime->channels,
snd_pcm_format_width(runtime->format),
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream));
}
static int snd_card_mpc5200_playback_trigger(snd_pcm_substream_t *substream, int cmd)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
switch (cmd)
{
case SNDRV_PCM_TRIGGER_START:
PRDEBUG(1, "%s(%p,START)\n", __FUNCTION__, substream);
return snd_psc_substream_start(chip->i2s_substreams[PLAYBACK],
substream->runtime->dma_addr);
case SNDRV_PCM_TRIGGER_STOP:
PRDEBUG(1, "%s(%p,STOP)\n", __FUNCTION__, substream);
return snd_psc_substream_stop(chip->i2s_substreams[PLAYBACK]);
}
return -EINVAL;
}
static snd_pcm_uframes_t snd_card_mpc5200_playback_pointer(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
size_t ret = snd_psc_get_substream_pos(chip->i2s_substreams[PLAYBACK]);
PRDEBUG(3, "%s returns %u\n", __FUNCTION__, ret);
return bytes_to_frames(substream->runtime, ret);
}
static void snd_card_mpc5200_playback_capture_irq(void *_substream)
{
snd_pcm_substream_t *substream = _substream;
PRDEBUG(3, "%s(%p)\n", __FUNCTION__, substream);
snd_pcm_period_elapsed(substream);
return IRQ_HANDLED;
}
static int snd_card_mpc5200_capture_open(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
PRDEBUG(1, "%s\n", __FUNCTION__);
runtime->hw = snd_mpc5200_playback_capture;
err = snd_psc_substream_open(chip->i2s_substreams[CAPTURE], substream);
if (err < 0)
return err;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
return 0;
}
static int snd_card_mpc5200_capture_close(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
PRDEBUG(1, "%s:\n", __FUNCTION__);
return snd_psc_substream_close(chip->i2s_substreams[CAPTURE]);
}
static int snd_card_mpc5200_capture_ioctl(snd_pcm_substream_t *substream,
unsigned int cmd, void *arg)
{
PRDEBUG(1, "%s:\n", __FUNCTION__);
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
static int snd_card_mpc5200_capture_hw_params(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *hw_params)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
{
if (err < 0)
printk(KERN_ERR "%s: memory allocation failed\n", DRIVER_NAME);
return err;
}
/* set requested samplerate on an optional UDA1380 */
if (chip->uda1380)
snd_mpc5200_uda1380_set_samplerate(chip, runtime->rate);
return snd_psc_substream_params(chip->i2s_substreams[CAPTURE],
runtime->rate,
runtime->channels,
snd_pcm_format_width(runtime->format),
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream));
}
static int snd_card_mpc5200_capture_prepare(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
/* set requested samplerate on an optional UDA1380 */
if (chip->uda1380)
snd_mpc5200_uda1380_set_samplerate(chip, runtime->rate);
return snd_psc_substream_params(chip->i2s_substreams[CAPTURE],
runtime->rate,
runtime->channels,
snd_pcm_format_width(runtime->format),
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream));
}
static int snd_card_mpc5200_capture_trigger(snd_pcm_substream_t *substream, int cmd)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
switch (cmd)
{
case SNDRV_PCM_TRIGGER_START:
PRDEBUG(1, "%s(%p,START)\n", __FUNCTION__, substream);
return snd_psc_substream_start(chip->i2s_substreams[CAPTURE],
substream->runtime->dma_addr);
case SNDRV_PCM_TRIGGER_STOP:
PRDEBUG(1, "%s(%p,STOP)\n", __FUNCTION__, substream);
return snd_psc_substream_stop(chip->i2s_substreams[CAPTURE]);
}
return -EINVAL;
}
static snd_pcm_uframes_t snd_card_mpc5200_capture_pointer(snd_pcm_substream_t *substream)
{
mpc5200_uda1380_t *chip = snd_pcm_substream_chip(substream);
size_t ret = snd_psc_get_substream_pos(chip->i2s_substreams[CAPTURE]);
PRDEBUG(3, "%s returns %u\n", __FUNCTION__, ret);
return bytes_to_frames(substream->runtime, ret);
}
static int snd_mpc5200_hw_free(snd_pcm_substream_t *substream)
{
PRDEBUG(1, "%s\n", __FUNCTION__);
return snd_pcm_lib_free_pages(substream);
}
static snd_pcm_ops_t snd_card_mpc5200_playback_ops =
{
.open = snd_card_mpc5200_playback_open,
.close = snd_card_mpc5200_playback_close,
.ioctl = snd_card_mpc5200_playback_ioctl,
.hw_params = snd_card_mpc5200_playback_hw_params,
.hw_free = snd_mpc5200_hw_free,
.prepare = snd_card_mpc5200_playback_prepare,
.trigger = snd_card_mpc5200_playback_trigger,
.pointer = snd_card_mpc5200_playback_pointer,
};
static snd_pcm_ops_t snd_card_mpc5200_capture_ops =
{
.open = snd_card_mpc5200_capture_open,
.close = snd_card_mpc5200_capture_close,
.ioctl = snd_card_mpc5200_capture_ioctl,
.hw_params = snd_card_mpc5200_capture_hw_params,
.hw_free = snd_mpc5200_hw_free,
.prepare = snd_card_mpc5200_capture_prepare,
.trigger = snd_card_mpc5200_capture_trigger,
.pointer = snd_card_mpc5200_capture_pointer,
};
static void snd_mpc5200_pcm_free(snd_pcm_t *pcm)
{
mpc5200_uda1380_t *chip = snd_pcm_chip(pcm);
snd_psc_substream_free(chip->i2s_substreams[PLAYBACK]);
chip->i2s_substreams[PLAYBACK] = NULL;
snd_psc_substream_free(chip->i2s_substreams[CAPTURE]);
chip->i2s_substreams[CAPTURE] = NULL;
}
static int __init snd_mpc5200_pcm_create(mpc5200_uda1380_t *chip, int cardid)
{
static char pcm_name[] = "PSC?_I2S_PCM";
static char playback_name[] = "PSC?_I2S_PLAYBACK";
static char capture_name[] = "PSC?_I2S_CAPTURE";
int err;
pcm_name[3] = '0' + cardid;
playback_name[3] = '0' + cardid;
capture_name[3] = '0' + cardid;
PRDEBUG(1, "%s\n", __FUNCTION__);
// audio power is turned on and a clock is set at the same time so this gives us a default
// starting rate
chip->samplerate = 0;
if ((err = snd_pcm_new(chip->card, pcm_name, 0, 1, 1, &(chip->pcm))) < 0)
return err;
snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_mpc5200_playback_ops);
snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_mpc5200_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(chip->pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 0x10000, 0x10000);
chip->pcm->private_data = chip;
chip->pcm->private_free = snd_mpc5200_pcm_free;
chip->pcm->info_flags = 0;
/* setup playback and capture */
strncpy(chip->pcm->name, pcm_name, sizeof(chip->pcm->name));
/* setup DMA structures */
err = snd_psc_substream_create(chip->i2s_substreams + PLAYBACK,
chip->i2s_card,
playback_name,
PLAYBACK,
snd_card_mpc5200_playback_capture_irq);
if (err < 0)
return err;
err = snd_psc_substream_create(chip->i2s_substreams + CAPTURE,
chip->i2s_card,
capture_name,
CAPTURE,
snd_card_mpc5200_playback_capture_irq);
if (err < 0)
return err;
return 0;
}
static int
snd_mpc5200_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
static const char *extsws[] = {"Line", "Ext.Mic"};
PRDEBUG(2, "%s(%p,%p)\n", __FUNCTION__, kcontrol, uinfo);
switch (kcontrol->private_value)
{
case CMD_EXTSW:
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = ARRAY_SIZE(extsws);
if (uinfo->value.enumerated.item >= ARRAY_SIZE(extsws))
uinfo->value.enumerated.item = ARRAY_SIZE(extsws) - 1;
strncpy(uinfo->value.enumerated.name,
extsws[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
return 0;
}
printk(KERN_WARNING "%s called with bad private info: %ld\n", __FUNCTION__, kcontrol->private_value);
return -EINVAL;
}
static int
snd_mpc5200_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
mpc5200_uda1380_t *chip = snd_kcontrol_chip(kcontrol);
PRDEBUG(2, "%s(%p,%p) value=%lu chip=%p\n",
__FUNCTION__,
kcontrol, ucontrol,
kcontrol->private_value,
chip);
switch (kcontrol->private_value)
{
case CMD_EXTSW:
if (!extsw[chip->cardid])
ucontrol->value.enumerated.item[0] = 0;
chip->extsw = ucontrol->value.enumerated.item[0];
PRDEBUG(2, "%s: extsw=%d\n", __FUNCTION__, chip->extsw);
#if !defined(SND_MPC5200_SIMPLE_PROC)
if (chip->extsw_proc_entry)
{
snd_mpc5200_extsw_data[0] = chip->extsw ? '1' : '0';
wake_up(&chip->extsw_wait);
}
#endif
return 0;
}
printk(KERN_WARNING "%s called with bad private info: %ld\n", __FUNCTION__, kcontrol->private_value);
return -EINVAL;
}
static int
snd_mpc5200_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
mpc5200_uda1380_t *chip = snd_kcontrol_chip(kcontrol);
PRDEBUG(3, "%s(%p,%p) private_value=%ld\n",
__FUNCTION__,
kcontrol, ucontrol,
kcontrol->private_value);
switch (kcontrol->private_value)
{
case CMD_EXTSW:
ucontrol->value.enumerated.item[0] = chip->extsw;
PRDEBUG(2, "%s: extsw=%d\n", __FUNCTION__, chip->extsw);
return 0;
}
printk(KERN_WARNING "%s called with bad private info: %ld\n", __FUNCTION__, kcontrol->private_value);
return -EINVAL;
}
#define MPC5200(xname, pvt_value) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.info = snd_mpc5200_info, \
.get = snd_mpc5200_get_single, \
.put = snd_mpc5200_put_single, \
.private_value = pvt_value \
}
/* The name "Capture Source" seems to confuse ALSA. Name it differently. */
static snd_kcontrol_new_t snd_mpc5200_extsw_controls = MPC5200("Line MUX", CMD_EXTSW);
#if defined(SND_MPC5200_SIMPLE_PROC)
static void snd_mpc5200_extsw_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
{
mpc5200_uda1380_t *chip = entry->private_data;
PRDEBUG(2, "%s(%p,%p) cs=%d\n", __FUNCTION__, entry, buffer, chip->extsw);
snd_iprintf(buffer, "%d\n", chip->extsw);
}
#else
static unsigned int snd_mpc5200_extsw_poll(snd_info_entry_t *entry,
void *private,
struct file *file,
poll_table *wait)
{
mpc5200_uda1380_t *chip = entry->private_data;
PRDEBUG(2, "%s(%p,%p,%p,%p)\n",
__FUNCTION__,
entry, private, file, wait);
poll_wait(file, &chip->extsw_wait, wait);
PRDEBUG(2, "%s: return from poll_wait\n", __FUNCTION__);
return POLLIN | POLLRDNORM;
}
static long snd_mpc5200_extsw_read(snd_info_entry_t *entry,
void *private,
struct file *file,
char *buf, unsigned long count, unsigned long pos)
{
mpc5200_uda1380_t *chip = entry->private_data;
unsigned long size = count;
PRDEBUG(2, "%s(%p,%p,%p,%p,%lu,%lu) cs=%d\n",
__FUNCTION__,
entry, private, file, buf, count, pos,
chip->extsw);
if (pos + size > sizeof(snd_mpc5200_extsw_data))
size = sizeof(snd_mpc5200_extsw_data) - pos;
if (copy_to_user(buf, snd_mpc5200_extsw_data + pos, size))
return -EFAULT;
return size;
}
static long long snd_mpc5200_extsw_llseek(snd_info_entry_t *entry, void *private,
struct file *file, long long offset, int orig)
{
PRDEBUG(2, "%s(%p,%p,%p,%Lu,%d)\n",
__FUNCTION__,
entry, private, file, offset, orig);
if (orig == 0 && offset >= 0)
return file->f_pos = offset;
else
return -EINVAL;
}
static struct snd_info_entry_ops snd_mpc5200_extsw_ops =
{
.read = snd_mpc5200_extsw_read,
.poll = snd_mpc5200_extsw_poll,
.llseek = snd_mpc5200_extsw_llseek
};
#endif
static void snd_mpc5200_card_free(snd_card_t *card)
{
mpc5200_uda1380_t *chip = card->private_data;
PRDEBUG(1, "%s(%p) chip=%p\n", __FUNCTION__, card, chip);
if (chip->uda1380)
snd_chip_uda1380_mixer_del(card, chip->uda1380);
snd_psc_card_free(chip->i2s_card);
kfree(chip);
card->private_data = NULL;
#ifdef SND_DELAY_ON_EXIT
snd_psc_delay(__FUNCTION__, 4000, 1);
#endif
PRDEBUG(1, "%s done\n", __FUNCTION__);
}
static int __init snd_mpc5200_card_create(int cardid)
{
snd_card_t *card;
mpc5200_uda1380_t *chip;
int err;
PRDEBUG(1, "%s(%d)\n", __FUNCTION__, cardid);
/* register the soundcard */
card = snd_card_new(index[cardid], id[cardid], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
PRDEBUG(2, "%s: card=%p created\n", __FUNCTION__, card);
chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
{
snd_card_free(card);
return -ENOMEM;
}
PRDEBUG(2, "%s: chip=%p created\n", __FUNCTION__, chip);
card->private_data = chip;
card->private_free = snd_mpc5200_card_free;
chip->card = card;
chip->cardid = cardid;
#if !defined(SND_MPC5200_SIMPLE_PROC)
init_waitqueue_head(&chip->extsw_wait);
#endif
if (uda[cardid])
{
PRDEBUG(2, "%s: card %u: checking for UDA1380\n", __FUNCTION__, cardid);
// mixer
err = snd_chip_uda1380_mixer_new(chip->card, &chip->uda1380, mic[cardid]);
if (err < 0)
{
printk(KERN_ERR "%s: cannot create or find mixer for card id=%d!\n", DRIVER_NAME, cardid);
snd_card_free(card);
return err;
}
else
{
// init mixer with default values
uda1380_configure(chip->uda1380, chip->samplerate = SND_PSC_AUDIO_RATE_DEFAULT);
}
snprintf(card->mixername, sizeof(card->mixername), "MPC5xxx_UDA_PSC%u", cardid);
if (extsw[cardid])
{
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_mpc5200_extsw_controls, chip))) < 0)
return err;
if ((err = snd_card_proc_new(card, "extsw", &chip->extsw_proc_entry)) < 0)
return err;
#if defined(SND_MPC5200_SIMPLE_PROC)
snd_info_set_text_ops(chip->extsw_proc_entry, chip, 64, snd_mpc5200_extsw_read);
#else
chip->extsw_proc_entry->content = SNDRV_INFO_CONTENT_DATA;
chip->extsw_proc_entry->private_data = chip;
chip->extsw_proc_entry->c.ops = &snd_mpc5200_extsw_ops;
chip->extsw_proc_entry->size = 8;
chip->extsw_proc_entry->mode = S_IFREG | S_IRUGO;
#endif
}
snprintf(card->longname, sizeof(card->longname),
"Telemotive Board with I2S on PSC%u + Philips UDA1380", cardid);
}
else
{
chip->uda1380 = NULL;
chip->extsw_proc_entry = NULL;
snprintf(card->longname, sizeof(card->longname),
"Telemotive Board with I2S on PSC%u", cardid);
}
err = snd_psc_card_create(&chip->i2s_card, cardid,
slave[cardid], spi[cardid], loopback[cardid]);
if (err < 0)
{
snd_card_free(card);
return err;
}
if ((err = snd_mpc5200_pcm_create(chip, cardid)) < 0)
{
snd_card_free(card);
return err;
}
strcpy(card->driver, "mpc5200-uda1380");
snprintf(card->shortname, sizeof(card->shortname), "PSC%u", cardid);
if ((err = snd_card_register(card)) < 0)
{
snd_card_free(card);
return err;
}
cards[cardid] = card;
return err;
}
static int __init snd_mpc5200_init(void)
{
int err;
size_t i;
PRDEBUG(1, "%s\n", __FUNCTION__);
#if !defined(SND_MPC5200_DEBUG)
if (debug != -1)
printk(KERN_WARNING "%s: compiled without debug support\n", __FUNCTION__);
#endif
/* be lazy */
for (i = 0; i < SNDRV_CARDS; i++)
{
if (allowed[i] && enable[i])
{
err = snd_mpc5200_card_create(i);
if (err < 0)
return err;
}
}
return 0;
}
static void __exit snd_mpc5200_exit(void)
{
size_t cardid;
PRDEBUG(1, "%s\n", __FUNCTION__);
for (cardid = 0; cardid < SNDRV_CARDS; cardid++)
{
PRDEBUG(3, "%s: cardid=%u\n", __FUNCTION__, cardid);
if (cards[cardid])
{
snd_card_free(cards[cardid]);
cards[cardid] = NULL;
#ifdef SND_DELAY_ON_EXIT
snd_psc_delay(__FUNCTION__, 4000, 1);
#endif
}
PRDEBUG(3, "%s: cardid=%u done\n", __FUNCTION__, cardid);
}
PRDEBUG(1, "%s exit\n", __FUNCTION__);
}
module_init(snd_mpc5200_init);
module_exit(snd_mpc5200_exit);
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "debug level (0-6)");
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for MPC5xxx soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for MPC5xxx soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable MPC5xxx soundcard.");
module_param_array(uda, bool, NULL, 0444);
MODULE_PARM_DESC(uda, "I2C adress of UDA1380 for MPC5xxx soundcard.");
module_param_array(slave, bool, NULL, 0444);
MODULE_PARM_DESC(slave, "Run I2S port in slave mode.");
module_param_array(spi, bool, NULL, 0444);
MODULE_PARM_DESC(spi, "Use SPI instead of I2S to communicate via the PSC.");
module_param_array(mic, bool, NULL, 0444);
MODULE_PARM_DESC(mic, "Microphone connected [0=no Mic,1=Mic].");
module_param_array(extsw, bool, NULL, 0444);
MODULE_PARM_DESC(extsw, "Enable external capture switch via GPIO.");
module_param_array(loopback, bool, NULL, 0444);
MODULE_PARM_DESC(loopback, "Enable MPC5xxx local loopback mode.");
MODULE_LICENSE("GPL");
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 9:39 ` Pedro Luis D. L.
2006-12-13 12:56 ` Roman Fietze
@ 2006-12-13 12:58 ` Roman Fietze
2006-12-13 13:15 ` Roman Fietze
2 siblings, 0 replies; 13+ messages in thread
From: Roman Fietze @ 2006-12-13 12:58 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 244 bytes --]
Hello Pedro,
Here the kernel part of the driver.
Roman
--
Roman Fietze Telemotive AG Büro Mühlhausen
Breitwiesen 73347 Mühlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
[-- Attachment #1.2: mpc5xxx.h --]
[-- Type: text/x-chdr, Size: 47498 bytes --]
/*
* include/asm-ppc/mpc5xxx.h
*
* Prototypes, etc. for the Motorola MPC5xxx embedded cpu chips
*
* Author: Dale Farnsworth <dfarnsworth@mvista.com>
*
* 2003 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#ifndef __ASM_MPC5XXX_H
#define __ASM_MPC5XXX_H
#define MPC5xxx_FEC_DEBUG 0
#define MPC5xxx_SDMA_DEBUG 2
#ifndef __ASSEMBLY__
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/config.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/machdep.h>
#endif /* __ASSEMBLY */
#define MPC5xxx_MBAR 0xf0000000
#define MPC5xxx_MBAR_SIZE 0x10000000
#define MPC5xxx_SDRAM_START (MPC5xxx_MBAR + 0x0034)
#define MPC5xxx_SDRAM_CONFIG_0 (MPC5xxx_MBAR + 0x0034)
#define MPC5xxx_SDRAM_STOP (MPC5xxx_MBAR + 0x0038)
#define MPC5xxx_SDRAM_CONFIG_1 (MPC5xxx_MBAR + 0x0038)
#define MPC5xxx_ADREN (MPC5xxx_MBAR + 0x0054)
#define MPC5xxx_CDM (MPC5xxx_MBAR + 0x0200)
#define MPC5xxx_SFTRST (MPC5xxx_MBAR + 0x0220)
#define MPC5xxx_SFTRST_BIT 0x01000000
#define MPC5xxx_CSC (MPC5xxx_MBAR + 0x0300)
#define MPC5xxx_CS0CFG (MPC5xxx_MBAR + 0x0300)
#define MPC5xxx_INTR (MPC5xxx_MBAR + 0x0500)
#define MPC5xxx_GPT (MPC5xxx_MBAR + 0x0600) /* General Purpose Timers 0..7 */
#define MPC5xxx_GPT0 (MPC5xxx_MBAR + 0x0600) /* General Purpose Timers 0..7 */
#define MPC5xxx_GPT1 (MPC5xxx_MBAR + 0x0610)
#define MPC5xxx_GPT2 (MPC5xxx_MBAR + 0x0620)
#define MPC5xxx_GPT3 (MPC5xxx_MBAR + 0x0630)
#define MPC5xxx_GPT4 (MPC5xxx_MBAR + 0x0640)
#define MPC5xxx_GPT5 (MPC5xxx_MBAR + 0x0650)
#define MPC5xxx_GPT6 (MPC5xxx_MBAR + 0x0660)
#define MPC5xxx_GPT7 (MPC5xxx_MBAR + 0x0670)
#define MPC5xxx_MSCAN1 (MPC5xxx_MBAR + 0x0900) /* MSCAN Module 1 */
#define MPC5xxx_MSCAN2 (MPC5xxx_MBAR + 0x0980) /* MSCAN Module 2 */
#define MPC5xxx_GPIO (MPC5xxx_MBAR + 0x0b00)
#define MPC5xxx_WU_GPIO (MPC5xxx_MBAR + 0x0c00)
#define MPC5xxx_PCI (MPC5xxx_MBAR + 0x0d00)
#define MPC5xxx_SPI (MPC5xxx_MBAR + 0x0f00)
#define MPC5xxx_USB_OHCI (MPC5xxx_MBAR + 0x1000)
#define MPC5xxx_SDMA (MPC5xxx_MBAR + 0x1200)
#define MPC5xxx_XLB (MPC5xxx_MBAR + 0x1f00)
#define MPC5xxx_PSC1 (MPC5xxx_MBAR + 0x2000)
#define MPC5xxx_PSC2 (MPC5xxx_MBAR + 0x2200)
#define MPC5xxx_PSC3 (MPC5xxx_MBAR + 0x2400)
#define MPC5xxx_PSC4 (MPC5xxx_MBAR + 0x2600)
#define MPC5xxx_PSC5 (MPC5xxx_MBAR + 0x2800)
#define MPC5xxx_PSC6 (MPC5xxx_MBAR + 0x2C00)
#define MPC5xxx_FEC (MPC5xxx_MBAR + 0x3000)
#define MPC5xxx_PCI_MCTI (MPC5xxx_MBAR + 0x3800)
#define MPC5xxx_ATA (MPC5xxx_MBAR + 0x3a00)
#define MPC5xxx_I2C1 (MPC5xxx_MBAR + 0x3d00)
#define MPC5xxx_I2C_MICR (MPC5xxx_MBAR + 0x3d20)
#define MPC5xxx_I2C2 (MPC5xxx_MBAR + 0x3d40)
#ifdef CONFIG_MPC5100
#define MPC5xxx_SRAM (MPC5xxx_MBAR + 0x4000)
#define MPC5xxx_SRAM_SIZE (8*1024)
#define MPC5xxx_SDMA_MAX_TASKS 8
#elif defined(CONFIG_MPC5200)
#define MPC5xxx_SRAM (MPC5xxx_MBAR + 0x8000)
#define MPC5xxx_SRAM_SIZE (16*1024)
#define MPC5xxx_SDMA_MAX_TASKS 16
#define MPC5xxx_SDMA_MAX_INITIATORS 32
#endif
/* Bit definitions for PCI window configuration regsiers.
*
* Attention: here Motorola/FreeScale suddenly counts bits from right to left as all the others
* do! */
#define MPC5xxx_INIT_WINDOW_DISABLE (0U << 0)
#define MPC5xxx_INIT_WINDOW_ENABLE (1U << 0)
#define MPC5xxx_INIT_WINDOW_READ (0U << 1)
#define MPC5xxx_INIT_WINDOW_READ_LINE (1U << 1)
#define MPC5xxx_INIT_WINDOW_READ_MULTIPLE (2U << 1)
#define MPC5xxx_INIT_WINDOW_MEM (0U << 3)
#define MPC5xxx_INIT_WINDOW_IO (1U << 3)
/* Interrupt priority register bits */
#define MPC5xxx_PERPRI_MASK(x) (0xF0000000U >> (((x) & 0x07U) * (uint32_t)4))
#define MPC5xxx_PERPRI_PRI(x,p) (((p) & 0x0FU) << ((7UL - ((x) & 0x07U)) * (uint32_t)4))
#define MPC5xxx_PERPRI_REG(x) ((&((struct mpc5xxx_intr *)MPC5xxx_INTR)->per_pri1) + ((x) / 8U))
#define MPC5xxx_PERPRI_SET(x,p) do{*MPC5xxx_PERPRI_REG(x)=(*MPC5xxx_PERPRI_REG(x)&~MPC5xxx_PERPRI_MASK(x))|MPC5xxx_PERPRI_PRI((x),(p));} while(0)
/* GPT General Purpose Timers registers */
/* GPT Counter Input Register */
#define MPC5xxx_GPT_CIR_PRESCALE(prescale) ((uint32_t)((prescale) & 0xFFFFU) << 16)
#define MPC5xxx_GPT_CIR_COUNT(count) ((count) & 0xFFFFU)
/* GPT PWM Configuration Register */
#define MPC5xxx_GPT_PWMCR_WIDTH(width) ((uint32_t)((width) & 0xFFFFU) << 16)
#define MPC5xxx_GPT_PWMCR_PWMOP (1U << 16)
#define MPC5xxx_GPT_PWMCR_LOAD (1U << 0)
/* GPT Enable and Mode Select Register */
#define MPC5xxx_GPT_EMSR_WDEN (1U << 15)
#define MPC5xxx_GPT_EMSR_CE (1U << 12)
#define MPC5xxx_GPT_EMSR_OPEN_DRAIN (1U << 9)
#define MPC5xxx_GPT_EMSR_GPIO(x) (((x) & 0x03U) << 4)
#define MPC5xxx_GPT_EMSR_GPIO_MASK MPC5xxx_GPT_EMSR_GPIO(3)
#define MPC5xxx_GPT_EMSR_GPIO_INPUT MPC5xxx_GPT_EMSR_GPIO(0)
#define MPC5xxx_GPT_EMSR_GPIO_OUTPUT_0 MPC5xxx_GPT_EMSR_GPIO(2)
#define MPC5xxx_GPT_EMSR_GPIO_OUTPUT_1 MPC5xxx_GPT_EMSR_GPIO(3)
#define MPC5xxx_GPT_EMSR_TIMER_MS(x) (((x) & 0x07U) << 0)
#define MPC5xxx_GPT_EMSR_TIMER_DISABLED MPC5xxx_GPT_EMSR_TIMER_MS(0)
#define MPC5xxx_GPT_EMSR_TIMER_INPUT_CAPTURE MPC5xxx_GPT_EMSR_TIMER_MS(1)
#define MPC5xxx_GPT_EMSR_TIMER_OUTPUT_COMPARE MPC5xxx_GPT_EMSR_TIMER_MS(2)
#define MPC5xxx_GPT_EMSR_TIMER_PWM MPC5xxx_GPT_EMSR_TIMER_MS(3)
#define MPC5xxx_GPT_EMSR_TIMER_GPIO MPC5xxx_GPT_EMSR_TIMER_MS(4)
#define MPC5xxx_GPT_EMSR_TIMER_PIN (1U << 8)
/* MSCAN control register 0 (CANCTL0) bits */
#define MPC5xxx_MSCAN_RXFRM (1U << 7)
#define MPC5xxx_MSCAN_RXACT (1U << 6)
#define MPC5xxx_MSCAN_CSWAI (1U << 5)
#define MPC5xxx_MSCAN_SYNCH (1U << 4)
#define MPC5xxx_MSCAN_TIME (1U << 3)
#define MPC5xxx_MSCAN_WUPE (1U << 2)
#define MPC5xxx_MSCAN_SLPRQ (1U << 1)
#define MPC5xxx_MSCAN_INITRQ (1U << 0)
/* MSCAN control register 1 (CANCTL1) bits */
#define MPC5xxx_MSCAN_CANE (1U << 7)
#define MPC5xxx_MSCAN_CLKSRC (1U << 6)
#define MPC5xxx_MSCAN_LOOPB (1U << 5)
#define MPC5xxx_MSCAN_LISTEN (1U << 4)
#define MPC5xxx_MSCAN_WUPM (1U << 2)
#define MPC5xxx_MSCAN_SLPAK (1U << 1)
#define MPC5xxx_MSCAN_INITAK (1U << 0)
/* MSCAN receiver flag register (CANRFLG) bits */
#define MPC5xxx_MSCAN_WUPIF (1U << 7)
#define MPC5xxx_MSCAN_CSCIF (1U << 6)
#define MPC5xxx_MSCAN_RSTAT1 (1U << 5)
#define MPC5xxx_MSCAN_RSTAT0 (1U << 4)
#define MPC5xxx_MSCAN_TSTAT1 (1U << 3)
#define MPC5xxx_MSCAN_TSTAT0 (1U << 2)
#define MPC5xxx_MSCAN_OVRIF (1U << 1)
#define MPC5xxx_MSCAN_RXF (1U << 0)
/* MSCAN receiver interrupt enable register (CANRIER) bits */
#define MPC5xxx_MSCAN_WUPIE (1U << 7)
#define MPC5xxx_MSCAN_CSCIE (1U << 6)
#define MPC5xxx_MSCAN_RSTATE1 (1U << 5)
#define MPC5xxx_MSCAN_RSTATE0 (1U << 4)
#define MPC5xxx_MSCAN_TSTATE1 (1U << 3)
#define MPC5xxx_MSCAN_TSTATE0 (1U << 2)
#define MPC5xxx_MSCAN_OVRIE (1U << 1)
#define MPC5xxx_MSCAN_RXFIE (1U << 0)
/* MSCAN transmitter flag register (CANTFLG) bits */
#define MPC5xxx_MSCAN_TXE2 (1U << 2)
#define MPC5xxx_MSCAN_TXE1 (1U << 1)
#define MPC5xxx_MSCAN_TXE0 (1U << 0)
#define MPC5xxx_MSCAN_TXE (MPC5xxx_MSCAN_TXE2 | MPC5xxx_MSCAN_TXE1 | MPC5xxx_MSCAN_TXE0)
/* MSCAN transmitter interrupt enable register (CANTIER) bits */
#define MPC5xxx_MSCAN_TXIE2 MPC5xxx_MSCAN_TXE2
#define MPC5xxx_MSCAN_TXIE1 MPC5xxx_MSCAN_TXE1
#define MPC5xxx_MSCAN_TXIE0 MPC5xxx_MSCAN_TXIE0
#define MPC5xxx_MSCAN_TXIE MPC5xxx_MSCAN_TXE
/* MSCAN transmitter message abort request (CANTARQ) bits */
#define MPC5xxx_MSCAN_ABTRQ2 MPC5xxx_MSCAN_TXE2
#define MPC5xxx_MSCAN_ABTRQ1 MPC5xxx_MSCAN_TXE1
#define MPC5xxx_MSCAN_ABTRQ0 MPC5xxx_MSCAN_TXE0
/* MSCAN transmitter message abort ack (CANTAAK) bits */
#define MPC5xxx_MSCAN_ABTAK2 MPC5xxx_MSCAN_TXE2
#define MPC5xxx_MSCAN_ABTAK1 MPC5xxx_MSCAN_TXE1
#define MPC5xxx_MSCAN_ABTAK0 MPC5xxx_MSCAN_TXE0
/* MSCAN transmit buffer selection (CANTBSEL) bits */
#define MPC5xxx_MSCAN_TX2 MPC5xxx_MSCAN_TXE2
#define MPC5xxx_MSCAN_TX1 MPC5xxx_MSCAN_TXE1
#define MPC5xxx_MSCAN_TX0 MPC5xxx_MSCAN_TXE0
/* MSCAN ID acceptance control register (CANIDAC) bits */
#define MPC5xxx_MSCAN_IDAM1 (1U << 5)
#define MPC5xxx_MSCAN_IDAM0 (1U << 4)
#define MPC5xxx_MSCAN_IDHIT2 MPC5xxx_MSCAN_TXE2
#define MPC5xxx_MSCAN_IDHIT1 MPC5xxx_MSCAN_TXE1
#define MPC5xxx_MSCAN_IDHIT0 MPC5xxx_MSCAN_TXE0
/* SDMA bits */
#define MPC5xxx_SDMA_IPR_HOLD (1U << 7)
/* XLB bits */
#define MPC5xxx_XLB_CONFIG_PLDIS (1U << 31)
#define MPC5xxx_XLB_CONFIG_USE_WWF (1U << 14)
/* CDM bits */
/* CDM clock enable register bits */
#define MPC5xxx_CDM_CER_PSC6 (1U << 4)
#define MPC5xxx_CDM_CER_PSC1 (1U << 5)
#define MPC5xxx_CDM_CER_PSC2 (1U << 6)
#define MPC5xxx_CDM_CER_PSC345 (1U << 7)
#define MPC5xxx_CDM_PCI_CLK (1U << 18)
/* GPIO port_config bits */
#define MPC5xxx_GPIO_PC_PSC1(x) (((x) & 0x0FU) << 0)
#define MPC5xxx_GPIO_PC_PSC1_MASK MPC5xxx_GPIO_PC_PSC1(0xFU)
#define MPC5xxx_GPIO_PC_PSC1_CODEC1_USB2 MPC5xxx_GPIO_PC_PSC1(0x1U)
#define MPC5xxx_GPIO_PC_PSC1_UART_NO_CD MPC5xxx_GPIO_PC_PSC1(0x4U)
#define MPC5xxx_GPIO_PC_PSC1_UART_CD MPC5xxx_GPIO_PC_PSC1(0x5U)
#define MPC5xxx_GPIO_PC_PSC1_CODEC1 MPC5xxx_GPIO_PC_PSC1(0x6U)
#define MPC5xxx_GPIO_PC_PSC1_CODEC1_MCLK MPC5xxx_GPIO_PC_PSC1(0x7U)
#define MPC5xxx_GPIO_PC_PSC2(x) (((x) & 0x0FU) << 4)
#define MPC5xxx_GPIO_PC_PSC2_MASK MPC5xxx_GPIO_PC_PSC2(0xFU)
#define MPC5xxx_GPIO_PC_PSC2_GPIO MPC5xxx_GPIO_PC_PSC3(0x0U)
#define MPC5xxx_GPIO_PC_PSC2_CAN MPC5xxx_GPIO_PC_PSC2(0x1U)
#define MPC5xxx_GPIO_PC_PSC2_AC97 MPC5xxx_GPIO_PC_PSC2(0x2U)
#define MPC5xxx_GPIO_PC_PSC2_UART_NO_CD MPC5xxx_GPIO_PC_PSC2(0x4U)
#define MPC5xxx_GPIO_PC_PSC2_UART_CD MPC5xxx_GPIO_PC_PSC2(0x5U)
#define MPC5xxx_GPIO_PC_PSC2_CODEC2 MPC5xxx_GPIO_PC_PSC2(0x6U)
#define MPC5xxx_GPIO_PC_PSC2_CODEC2_MCLK MPC5xxx_GPIO_PC_PSC2(0x7U)
#define MPC5xxx_GPIO_PC_PSC3(x) (((x) & 0x0FU) << 8)
#define MPC5xxx_GPIO_PC_PSC3_MASK MPC5xxx_GPIO_PC_PSC3(0xFU)
#define MPC5xxx_GPIO_PC_PSC3_GPIO MPC5xxx_GPIO_PC_PSC3(0x0U)
#define MPC5xxx_GPIO_PC_PSC3_USB2 MPC5xxx_GPIO_PC_PSC3(0x1U)
#define MPC5xxx_GPIO_PC_PSC3_UART_NO_CD MPC5xxx_GPIO_PC_PSC3(0x4U)
#define MPC5xxx_GPIO_PC_PSC3_UART_CD MPC5xxx_GPIO_PC_PSC3(0x5U)
#define MPC5xxx_GPIO_PC_PSC3_CODEC3 MPC5xxx_GPIO_PC_PSC3(0x6U)
#define MPC5xxx_GPIO_PC_PSC3_CODEC3_MCLK MPC5xxx_GPIO_PC_PSC3(0x7U)
#define MPC5xxx_GPIO_PC_PSC3_SPI MPC5xxx_GPIO_PC_PSC3(0x8U)
#define MPC5xxx_GPIO_PC_USB(x) (((x) & 0x03U) << 12)
#define MPC5xxx_GPIO_PC_USB_MASK MPC5xxx_GPIO_PC_USB(0x3U)
#define MPC5xxx_GPIO_PC_USB_GPIO MPC5xxx_GPIO_PC_USB(0x0U)
#define MPC5xxx_GPIO_PC_USB_USB MPC5xxx_GPIO_PC_USB(0x1U)
#define MPC5xxx_GPIO_PC_USB_UARTS MPC5xxx_GPIO_PC_USB(0x2U)
#define MPC5xxx_GPIO_PC_USB_SE (1U << 14)
#define MPC5xxx_GPIO_PC_PCI_DIS (1U << 15)
#define MPC5xxx_GPIO_PC_PSC6(x) (((x) & 0x07U) << 20)
#define MPC5xxx_GPIO_PC_PSC6_MASK MPC5xxx_GPIO_PC_PSC6(0x7U)
#define MPC5xxx_GPIO_PC_PSC6_UART_NO_CD MPC5xxx_GPIO_PC_PSC6(0x5U)
#define MPC5xxx_GPIO_PC_PSC6_CODEC6 MPC5xxx_GPIO_PC_PSC6(0x7U)
#define MPC5xxx_GPIO_PC_IR_USB_CLK (1U << 23)
#define MPC5xxx_GPIO_PC_ATA(x) (((x) & 0x03U) << 24)
#define MPC5xxx_GPIO_PC_ATA_MASK MPC5xxx_GPIO_PC_PSC2(0x3U)
#define MPC5xxx_GPIO_PC_ATA_NONE MPC5xxx_GPIO_PC_PSC2(0x0U)
#define MPC5xxx_GPIO_PC_ATA_CSB45 MPC5xxx_GPIO_PC_PSC2(0x1U)
#define MPC5xxx_GPIO_PC_ATA_I2C2 MPC5xxx_GPIO_PC_PSC2(0x2U)
#define MPC5xxx_GPIO_PC_ATA_TMR01 MPC5xxx_GPIO_PC_PSC2(0x3U)
#define MPC5xxx_GPIO_PC_ALT(x) (((x) & 0x03U) << 28)
#define MPC5xxx_GPIO_PC_ALT_MASK MPC5xxx_GPIO_PC_ALT(0x3U)
#define MPC5xxx_GPIO_PC_ALT_NONE MPC5xxx_GPIO_PC_ALT(0x0U)
#define MPC5xxx_GPIO_PC_ALT_CAN MPC5xxx_GPIO_PC_ALT(0x1U)
#define MPC5xxx_GPIO_PC_ALT_SPI MPC5xxx_GPIO_PC_ALT(0x2U)
#define MPC5xxx_GPIO_PC_ALT_BOTH MPC5xxx_GPIO_PC_ALT(0x3U)
/* GPIO Simple GPIO bits, bit numbers are pin numbers, Valid for
* simple_gpioe, simple_ode, simple_ddr, simple_dvo and simple_ival in
* mpc5xxx_gpio.
*/
#define MPC5xxx_GPIO_BIT_PSC2_2 (1U << 6)
#define MPC5xxx_GPIO_BIT_PSC3_6 (1U << 12)
#define MPC5xxx_GPIO_BIT_PSC3_7 (1U << 13)
#define MPC5xxx_GPIO_BIT_USB1_0 (1U << 16)
/* GPIO Simple Interrupt bits
*/
#define MPC5xxx_GPIO_SINT_0 (1U << 0)
#define MPC5xxx_GPIO_SINT_1 (1U << 1)
#define MPC5xxx_GPIO_SINT_2 (1U << 2)
#define MPC5xxx_GPIO_SINT_3 (1U << 3)
/* Wakeup GPIO bits
*/
#define MPC5xxx_WU_GPIO_0 (1U << 0)
#define MPC5xxx_WU_GPIO_2 (1U << 2)
#define MPC5xxx_WU_GPIO_6 (1U << 6)
#define MPC5xxx_WU_GPIO_7 (1U << 7)
/* PSC definitions */
#define MPC5xxx_PSC_FIFO_SIZE (512U)
/* PSC CTUR bits */
#define MPC5xxx_PSC_CTUR_CODEC(x) ((x) & 0xFFU)
/* PSC CTLR bits */
#define MPC5xxx_PSC_CTLR_CODEC(x) ((x) & 0xFFU)
/* PSC CCR bits */
#define MPC5xxx_PSC_CCR_CODEC(fsd,bcd) ((((uint16_t)(fsd) & 0xFFU) << 8) | ((bcd) & 0xFFU))
/* PSC MCLOCK */
#define MPC5xxx_PSC_MCLOCK_ENABLE (1U << 15)
#define MPC5xxx_PSC_MCLOCK_MCLKDIV(x) ((uint16_t)(x) & 0x1FFU)
/* PSC SICR bits */
#define MPC5xxx_PSC_SICR_DTS1_AFTER (1UL << 29)
#define MPC5xxx_PSC_SICR_SHDIR_LSB (1UL << 28)
#define MPC5xxx_PSC_SICR_SIM(x) (((uint32_t)(x) & 0x0FU) << 24)
#define MPC5xxx_PSC_SICR_SIM_UART MPC5xxx_PSC_SICR_SIM(0U)
#define MPC5xxx_PSC_SICR_SIM_CODEC_8 MPC5xxx_PSC_SICR_SIM(1U)
#define MPC5xxx_PSC_SICR_SIM_CODEC_16 MPC5xxx_PSC_SICR_SIM(2U)
#define MPC5xxx_PSC_SICR_SIM_AC97 MPC5xxx_PSC_SICR_SIM(3U)
#define MPC5xxx_PSC_SICR_SIM_SIR MPC5xxx_PSC_SICR_SIM(4U)
#define MPC5xxx_PSC_SICR_SIM_MIR MPC5xxx_PSC_SICR_SIM(5U)
#define MPC5xxx_PSC_SICR_SIM_FIR MPC5xxx_PSC_SICR_SIM(6U)
#define MPC5xxx_PSC_SICR_SIM_CODEC_24 MPC5xxx_PSC_SICR_SIM(7U)
#define MPC5xxx_PSC_SICR_SIM_UART_DCD MPC5xxx_PSC_SICR_SIM(8U)
#define MPC5xxx_PSC_SICR_SIM_SIR_DCD MPC5xxx_PSC_SICR_SIM(12U)
#define MPC5xxx_PSC_SICR_SIM_CODEC_32 MPC5xxx_PSC_SICR_SIM(15U)
#define MPC5xxx_PSC_SICR_GENCLK_INT (1UL << 23)
#define MPC5xxx_PSC_SICR_MULTIWD (1UL << 22)
#define MPC5xxx_PSC_SICR_CLKPOL_RISE (1UL << 21)
#define MPC5xxx_PSC_SICR_SYNCPOL_RISE (1UL << 20)
#define MPC5xxx_PSC_SICR_SPI (1UL << 15)
#define MPC5xxx_PSC_SICR_MSTR (1UL << 14)
#define MPC5xxx_PSC_SICR_CPOL (1UL << 13)
#define MPC5xxx_PSC_SICR_CPHA (1UL << 12)
#define MPC5xxx_PSC_SICR_USEEOF (1UL << 11)
/* SPI control1 bits */
#define MPC5xxx_SPI_CONTROL1_LSBFE (1U << 0)
#define MPC5xxx_SPI_CONTROL1_SSOE (1U << 1)
#define MPC5xxx_SPI_CONTROL1_CPHA (1U << 2)
#define MPC5xxx_SPI_CONTROL1_CPOL (1U << 3)
#define MPC5xxx_SPI_CONTROL1_MSTR (1U << 4)
#define MPC5xxx_SPI_CONTROL1_SPE (1U << 6)
#define MPC5xxx_SPI_CONTROL1_SPIE (1U << 7)
/* SPI control2 bits */
#define MPC5xxx_SPI_CONTROL2_SPC0 (1U << 0)
#define MPC5xxx_SPI_CONTROL2_SPISWAI (1U << 1)
/* SPI baud bits */
#define MPC5xxx_SPI_BAUD_SPR(x) (((x) & 0x07U) << 0)
#define MPC5xxx_SPI_BAUD_SPPR(x) (((x) & 0x07U) << 4)
/* SPI status bits */
#define MPC5xxx_SPI_STATUS_MODF (1U << 4)
#define MPC5xxx_SPI_STATUS_WCOL (1U << 6)
#define MPC5xxx_SPI_STATUS_SPIF (1U << 7)
/* I2Cn address register */
#define MPC5xxx_I2C_ADDR(x) (((x) & 0x7FU) << 25)
/* I2Cn frequency divider register possible values */
#define MPC5xxx_I2C_100HZ 0x1F /* 100HZ Clock */
/* I2Cn control register bits */
#define MPC5xxx_I2C_EN 0x80 /* Enable I2Cn module */
#define MPC5xxx_I2C_IEN 0x40 /* Enable interrupt from I2Cn module */
#define MPC5xxx_I2C_STA 0x20 /* Master/Slave mode select */
#define MPC5xxx_I2C_TX 0x10 /* Transmit/Receive mode select */
#define MPC5xxx_I2C_TXAK 0x08 /* Transmit ack enable */
#define MPC5xxx_I2C_RSTA 0x04 /* Repeat start */
#define MPC5xxx_I2C_INIT_MASK (MPC5xxx_I2C_EN | MPC5xxx_I2C_STA | MPC5xxx_I2C_TX | MPC5xxx_I2C_RSTA)
/* I2Cn status register bits */
#define MPC5xxx_I2C_CF 0x80 /* Data transferring */
#define MPC5xxx_I2C_AAS 0x40 /* Addressed as slave */
#define MPC5xxx_I2C_BB 0x20 /* Bus busy */
#define MPC5xxx_I2C_AL 0x10 /* Arbitration lost */
#define MPC5xxx_I2C_SRW 0x04 /* Slave Read/Write */
#define MPC5xxx_I2C_IF 0x02 /* I2Cn Interrupt */
#define MPC5xxx_I2C_RXAK 0x01 /* Receive ack */
/* Programmable Serial Controller (PSC) status register bits */
#define MPC5xxx_PSC_SR_CDE 0x0080
#define MPC5xxx_PSC_SR_RXRDY 0x0100
#define MPC5xxx_PSC_SR_RXFULL 0x0200
#define MPC5xxx_PSC_SR_TXRDY 0x0400
#define MPC5xxx_PSC_SR_TXEMP 0x0800
#define MPC5xxx_PSC_SR_OE 0x1000
#define MPC5xxx_PSC_SR_PE 0x2000
#define MPC5xxx_PSC_SR_FE 0x4000
#define MPC5xxx_PSC_SR_RB 0x8000
/* PSC Command values */
#define MPC5xxx_PSC_RX_ENABLE 0x0001
#define MPC5xxx_PSC_RX_DISABLE 0x0002
#define MPC5xxx_PSC_TX_ENABLE 0x0004
#define MPC5xxx_PSC_TX_DISABLE 0x0008
#define MPC5xxx_PSC_SEL_MODE_REG_1 0x0010
#define MPC5xxx_PSC_RST_RX 0x0020
#define MPC5xxx_PSC_RST_TX 0x0030
#define MPC5xxx_PSC_RST_ERR_STAT 0x0040
#define MPC5xxx_PSC_RST_BRK_CHG_INT 0x0050
#define MPC5xxx_PSC_START_BRK 0x0060
#define MPC5xxx_PSC_STOP_BRK 0x0070
/* PSC FIFO status bits */
#define MPC5xxx_PSC_FIFO_ERR (1U << 6)
#define MPC5xxx_PSC_FIFO_UF (1U << 5)
#define MPC5xxx_PSC_FIFO_OF (1U << 4)
#define MPC5xxx_PSC_FIFO_FR (1U << 3)
#define MPC5xxx_PSC_FIFO_FULL (1U << 2)
#define MPC5xxx_PSC_FIFO_ALARM (1U << 1)
#define MPC5xxx_PSC_FIFO_EMPTY (1U << 0)
/* Programmable Serial Controller (PSC) interrupt status register bits */
#define MPC5xxx_PSC_ISR_DEOF (1U << 7)
#define MPC5xxx_PSC_ISR_TXRDY (1U << 8)
#define MPC5xxx_PSC_ISR_RXRDY (1U << 9)
#define MPC5xxx_PSC_ISR_DB (1U << 10)
#define MPC5xxx_PSC_ISR_URERR (1U << 11)
#define MPC5xxx_PSC_ISR_ORERR (1U << 12)
#define MPC5xxx_PSC_ISR_IPC (1U << 15)
/* PSC interrupt mask bits */
#define MPC5xxx_PSC_IMR_TXRDY MPC5xxx_PSC_ISR_TXRDY
#define MPC5xxx_PSC_IMR_RXRDY MPC5xxx_PSC_ISR_RXRDY
#define MPC5xxx_PSC_IMR_DB MPC5xxx_PSC_ISR_DB
#define MPC5xxx_PSC_IMR_URERR MPC5xxx_PSC_ISR_URERR
#define MPC5xxx_PSC_IMR_ORERR MPC5xxx_PSC_ISR_ORERR
#define MPC5xxx_PSC_IMR_IPC MPC5xxx_PSC_ISR_IPC
/* PSC input port change bit */
#define MPC5xxx_PSC_CTS 0x01
#define MPC5xxx_PSC_DCD 0x02
#define MPC5xxx_PSC_D_CTS 0x10
#define MPC5xxx_PSC_D_DCD 0x20
/* PSC mode fields */
/* MR1 */
#define MPC5xxx_PSC_MODE_5_BITS 0x00
#define MPC5xxx_PSC_MODE_6_BITS 0x01
#define MPC5xxx_PSC_MODE_7_BITS 0x02
#define MPC5xxx_PSC_MODE_8_BITS 0x03
#define MPC5xxx_PSC_MODE_PAREVEN 0x00
#define MPC5xxx_PSC_MODE_PARODD 0x04
#define MPC5xxx_PSC_MODE_PARFORCE 0x08
#define MPC5xxx_PSC_MODE_PARNONE 0x10
#define MPC5xxx_PSC_MODE_RESERVED 0x20
#define MPC5xxx_PSC_MODE_FFULL 0x40
#define MPC5xxx_PSC_MODE_RXRTS 0x80
/* MR2 */
#define MPC5xxx_PSC_MODE2_TXCTS (1U << 4)
#define MPC5xxx_PSC_MODE2_TXRTS (1U << 5)
#define MPC5xxx_PSC_MODE2_SB(n) (((n) & 0x0FU) << 0)
#define MPC5xxx_PSC_MODE2_ONE_STOP_5_BITS MPC5xxx_PSC_MODE2_SB(0)
#define MPC5xxx_PSC_MODE2_ONE_STOP MPC5xxx_PSC_MODE2_SB(7)
#define MPC5xxx_PSC_MODE2_TWO_STOP MPC5xxx_PSC_MODE2_SB(15)
#define MPC5xxx_PSC_RFNUM_MASK 0x01ff
/* Memory allocation block size */
#define MPC5xxx_SDRAM_UNIT 0x8000 /* 32K byte */
#define MPC5xxx_CRIT_IRQ_NUM 4
#define MPC5xxx_MAIN_IRQ_NUM 17
#define MPC5xxx_SDMA_IRQ_NUM 17
#define MPC5xxx_PERP_IRQ_NUM 22
#define MPC5xxx_CRIT_IRQ_BASE 0
#define MPC5xxx_MAIN_IRQ_BASE (MPC5xxx_CRIT_IRQ_BASE + MPC5xxx_CRIT_IRQ_NUM)
#define MPC5xxx_SDMA_IRQ_BASE (MPC5xxx_MAIN_IRQ_BASE + MPC5xxx_MAIN_IRQ_NUM)
#define MPC5xxx_PERP_IRQ_BASE (MPC5xxx_SDMA_IRQ_BASE + MPC5xxx_SDMA_IRQ_NUM)
#define MPC5xxx_IRQ0 (MPC5xxx_CRIT_IRQ_BASE + 0)
#define MPC5xxx_SLICE_TIMER_0_IRQ (MPC5xxx_CRIT_IRQ_BASE + 1)
#define MPC5xxx_HI_INT_IRQ (MPC5xxx_CRIT_IRQ_BASE + 2)
#define MPC5xxx_CCS_IRQ (MPC5xxx_CRIT_IRQ_BASE + 3)
#define MPC5xxx_IRQ1 (MPC5xxx_MAIN_IRQ_BASE + 1)
#define MPC5xxx_IRQ2 (MPC5xxx_MAIN_IRQ_BASE + 2)
#define MPC5xxx_IRQ3 (MPC5xxx_MAIN_IRQ_BASE + 3)
#define MPC5xxx_SDMA_IRQ (MPC5xxx_PERP_IRQ_BASE + 0)
#define MPC5xxx_PSC1_IRQ (MPC5xxx_PERP_IRQ_BASE + 1)
#define MPC5xxx_PSC2_IRQ (MPC5xxx_PERP_IRQ_BASE + 2)
#define MPC5xxx_PSC3_IRQ (MPC5xxx_PERP_IRQ_BASE + 3)
#define MPC5xxx_PSC6_IRQ (MPC5xxx_PERP_IRQ_BASE + 4)
#define MPC5xxx_IRDA_IRQ (MPC5xxx_PSC6_IRQ)
#define MPC5xxx_FEC_IRQ (MPC5xxx_PERP_IRQ_BASE + 5)
#define MPC5xxx_USB_IRQ (MPC5xxx_PERP_IRQ_BASE + 6)
#define MPC5xxx_ATA_IRQ (MPC5xxx_PERP_IRQ_BASE + 7)
#define MPC5xxx_PCI_CNTRL_IRQ (MPC5xxx_PERP_IRQ_BASE + 8)
#define MPC5xxx_PCI_SCIRX_IRQ (MPC5xxx_PERP_IRQ_BASE + 9)
#define MPC5xxx_PCI_SCITX_IRQ (MPC5xxx_PERP_IRQ_BASE + 10)
#define MPC5xxx_PSC4_IRQ (MPC5xxx_PERP_IRQ_BASE + 11)
#define MPC5xxx_PSC5_IRQ (MPC5xxx_PERP_IRQ_BASE + 12)
#define MPC5xxx_SPI_MODF_IRQ (MPC5xxx_PERP_IRQ_BASE + 13)
#define MPC5xxx_SPI_SPIF_IRQ (MPC5xxx_PERP_IRQ_BASE + 14)
#define MPC5xxx_I2C1_IRQ (MPC5xxx_PERP_IRQ_BASE + 15)
#define MPC5xxx_I2C2_IRQ (MPC5xxx_PERP_IRQ_BASE + 16)
#define MPC5xxx_CAN1_IRQ (MPC5xxx_PERP_IRQ_BASE + 17)
#define MPC5xxx_CAN2_IRQ (MPC5xxx_PERP_IRQ_BASE + 18)
#define MPC5xxx_IR_RX_IRQ (MPC5xxx_PERP_IRQ_BASE + 19)
#define MPC5xxx_IR_TX_IRQ (MPC5xxx_PERP_IRQ_BASE + 20)
#define MPC5xxx_XLB_ARB_IRQ (MPC5xxx_PERP_IRQ_BASE + 21)
#define PCI_WINDOW_TRANSLATION(proc_start, proc_end, pci_start, pci_end) \
((((proc_start >> 24) & 0xff) << 24) | \
((((proc_end - proc_start) >> 24) & 0xff) << 16) | \
(((pci_start >> 24) & 0xff) << 8))
#define PCI_WINDOW_CONTROL(win0, win1, win2) (((win0) << 24) | ((win1) << 16) | ((win2) << 8))
#ifndef __ASSEMBLY__
#define MPC5xxx_PCI_FIFO_SIZE (512U)
struct mpc5xxx_pci {
volatile uint32_t idr; /* PCI + 0x00 */
volatile uint32_t scr; /* PCI + 0x04 */
volatile uint32_t ccrir; /* PCI + 0x08 */
volatile uint32_t cr1; /* PCI + 0x0C */
volatile uint32_t bar0; /* PCI + 0x10 */
volatile uint32_t bar1; /* PCI + 0x14 */
volatile uint8_t reserved1[16]; /* PCI + 0x18 */
volatile uint32_t ccpr; /* PCI + 0x28 */
volatile uint32_t sid; /* PCI + 0x2C */
volatile uint32_t erbar; /* PCI + 0x30 */
volatile uint32_t cpr; /* PCI + 0x34 */
volatile uint8_t reserved2[4]; /* PCI + 0x38 */
volatile uint32_t cr2; /* PCI + 0x3C */
volatile uint8_t reserved3[32]; /* PCI + 0x40 */
volatile uint32_t gscr; /* PCI + 0x60 */
volatile uint32_t tbatr0; /* PCI + 0x64 */
volatile uint32_t tbatr1; /* PCI + 0x68 */
volatile uint32_t tcr; /* PCI + 0x6C */
volatile uint32_t iw0btar; /* PCI + 0x70 */
volatile uint32_t iw1btar; /* PCI + 0x74 */
volatile uint32_t iw2btar; /* PCI + 0x78 */
volatile uint8_t reserved4[4]; /* PCI + 0x7C */
volatile uint32_t iwcr; /* PCI + 0x80 */
volatile uint32_t icr; /* PCI + 0x84 */
volatile uint32_t isr; /* PCI + 0x88 */
volatile uint32_t arb; /* PCI + 0x8C */
volatile uint8_t reserved5[104]; /* PCI + 0x90 */
volatile uint32_t car; /* PCI + 0xF8 */
volatile uint8_t reserved6[4]; /* PCI + 0xFC */
};
struct mpc5xxx_pci_mcti {
volatile uint16_t pcitpsr; /* PCI_MCTI + 0x00 */
volatile uint16_t reservedtpsr; /* PCI_MCTI + 0x02 */
volatile uint32_t pcitsar; /* PCI_MCTI + 0x04 */
volatile uint32_t pcittcr; /* PCI_MCTI + 0x08 */
volatile uint16_t pciter; /* PCI_MCTI + 0x0C */
volatile uint16_t reservedter; /* PCI_MCTI + 0x0E */
volatile uint32_t pcitnar; /* PCI_MCTI + 0x10 */
volatile uint32_t pcitlwr; /* PCI_MCTI + 0x14 */
volatile uint16_t pcitdcr_bd; /* PCI_MCTI + 0x18 */
volatile uint16_t pcitdcr_pd; /* PCI_MCTI + 0x1A */
volatile uint16_t pcitsr; /* PCI_MCTI + 0x1C */
volatile uint16_t reservedtsr; /* PCI_MCTI + 0x1A */
volatile uint32_t reservedt[8]; /* PCI_MCTI + 0x20 */
volatile uint32_t pcitfdr; /* PCI_MCTI + 0x40 */
volatile uint16_t pcitfsr; /* PCI_MCTI + 0x44 */
volatile uint16_t reservedtfsr; /* PCI_MCTI + 0x46 */
volatile uint16_t pcitfcr; /* PCI_MCTI + 0x48 */
volatile uint16_t reservedtfcr; /* PCI_MCTI + 0x4A */
volatile uint32_t pcitfar; /* PCI_MCTI + 0x4C */
volatile uint32_t pcitfrpr; /* PCI_MCTI + 0x50 */
volatile uint32_t pcitfwpr; /* PCI_MCTI + 0x54 */
volatile uint32_t reserved[10]; /* PCI_MCTI + 0x58 */
volatile uint16_t pcirpsr; /* PCI_MCTI + 0x80 */
volatile uint16_t reservedrpsr; /* PCI_MCTI + 0x82 */
volatile uint32_t pcirsar; /* PCI_MCTI + 0x84 */
volatile uint32_t pcirtcr; /* PCI_MCTI + 0x88 */
volatile uint16_t pcirer; /* PCI_MCTI + 0x8C */
volatile uint16_t reservedrer; /* PCI_MCTI + 0x8E */
volatile uint32_t pcirnar; /* PCI_MCTI + 0x90 */
volatile uint32_t pcirlwr; /* PCI_MCTI + 0x94 */
volatile uint16_t pcirdcr_bd; /* PCI_MCTI + 0x98 */
volatile uint16_t pcirdcr_pd; /* PCI_MCTI + 0x9A */
volatile uint16_t pcirsr; /* PCI_MCTI + 0x9C */
volatile uint16_t reservedrsr; /* PCI_MCTI + 0x9C */
volatile uint32_t reservedr[8]; /* PCI_MCTI + 0xA0 */
volatile uint32_t pcirfdr; /* PCI_MCTI + 0xC0 */
volatile uint16_t pcirfsr; /* PCI_MCTI + 0xC4 */
volatile uint16_t reservedrfsr; /* PCI_MCTI + 0xC6 */
volatile uint16_t pcirfcr; /* PCI_MCTI + 0xC8 */
volatile uint16_t reservedrfcr; /* PCI_MCTI + 0xCA */
volatile uint32_t pcirfar; /* PCI_MCTI + 0xCC */
volatile uint32_t pcirfrpr; /* PCI_MCTI + 0xD0 */
volatile uint32_t pcirfwpr; /* PCI_MCTI + 0xD4 */
};
struct mpc5xxx_psc {
volatile uint8_t mode; /* PSC + 0x00 */
volatile uint8_t reserved0[3];
union { /* PSC + 0x04 */
volatile uint16_t status;
volatile uint16_t clock_select;
} sr_csr;
#define mpc5xxx_psc_status sr_csr.status
#define mpc5xxx_psc_clock_select sr_csr.clock_select
volatile uint16_t reserved1;
volatile uint8_t command; /* PSC + 0x08 */
volatile uint8_t reserved2[3];
union { /* PSC + 0x0c */
volatile uint8_t buffer_8;
volatile uint16_t buffer_16;
volatile uint32_t buffer_32;
} buffer;
#define mpc5xxx_psc_buffer_8 buffer.buffer_8
#define mpc5xxx_psc_buffer_16 buffer.buffer_16
#define mpc5xxx_psc_buffer_32 buffer.buffer_32
union { /* PSC + 0x10 */
volatile uint8_t ipcr;
volatile uint8_t acr;
} ipcr_acr;
#define mpc5xxx_psc_ipcr ipcr_acr.ipcr
#define mpc5xxx_psc_acr ipcr_acr.acr
volatile uint8_t reserved3[3];
union { /* PSC + 0x14 */
volatile uint16_t isr;
volatile uint16_t imr;
} isr_imr;
#define mpc5xxx_psc_isr isr_imr.isr
#define mpc5xxx_psc_imr isr_imr.imr
volatile uint16_t reserved4;
volatile uint8_t ctur; /* PSC + 0x18 */
volatile uint8_t reserved5[3];
volatile uint8_t ctlr; /* PSC + 0x1c */
volatile uint8_t reserved6[3];
volatile uint16_t ccr; /* PSC + 0x20 */
volatile uint8_t reserved7[14];
volatile uint8_t ivr; /* PSC + 0x30 */
volatile uint8_t reserved8[3];
volatile uint8_t ip; /* PSC + 0x34 */
volatile uint8_t reserved9[3];
volatile uint8_t op1; /* PSC + 0x38 */
volatile uint8_t reserved10[3];
volatile uint8_t op0; /* PSC + 0x3c */
volatile uint8_t reserved11[3];
volatile uint32_t sicr; /* PSC + 0x40 */
volatile uint8_t ircr1; /* PSC + 0x44 */
volatile uint8_t reserved13[3];
volatile uint8_t ircr2; /* PSC + 0x44 */
volatile uint8_t reserved14[3];
volatile uint8_t irsdr; /* PSC + 0x4c */
volatile uint8_t reserved15[3];
volatile uint8_t irmdr; /* PSC + 0x50 */
volatile uint8_t reserved16[3];
volatile uint8_t irfdr; /* PSC + 0x54 */
volatile uint8_t reserved17[3];
volatile uint16_t rfnum; /* PSC + 0x58 */
volatile uint16_t reserved18;
volatile uint16_t tfnum; /* PSC + 0x5c */
volatile uint16_t reserved19;
volatile uint32_t rfdata; /* PSC + 0x60 */
volatile uint16_t rfstat; /* PSC + 0x64 */
volatile uint16_t reserved20;
volatile uint8_t rfcntl; /* PSC + 0x68 */
volatile uint8_t reserved21[5];
volatile uint16_t rfalarm; /* PSC + 0x6e */
volatile uint16_t reserved22;
volatile uint16_t rfrptr; /* PSC + 0x72 */
volatile uint16_t reserved23;
volatile uint16_t rfwptr; /* PSC + 0x76 */
volatile uint16_t reserved24;
volatile uint16_t rflrfptr; /* PSC + 0x7a */
volatile uint16_t reserved25;
volatile uint16_t rflwfptr; /* PSC + 0x7e */
volatile uint32_t tfdata; /* PSC + 0x80 */
volatile uint16_t tfstat; /* PSC + 0x84 */
volatile uint16_t reserved26;
volatile uint8_t tfcntl; /* PSC + 0x88 */
volatile uint8_t reserved27[5];
volatile uint16_t tfalarm; /* PSC + 0x8e */
volatile uint16_t reserved28;
volatile uint16_t tfrptr; /* PSC + 0x92 */
volatile uint16_t reserved29;
volatile uint16_t tfwptr; /* PSC + 0x96 */
volatile uint16_t reserved30;
volatile uint16_t tflrfptr; /* PSC + 0x9a */
volatile uint16_t reserved31;
volatile uint16_t tflwfptr; /* PSC + 0x9e */
};
#define PSC_ADDRESS(num) ((struct mpc5xxx_psc *)(MPC5xxx_PSC1 + (((num) - 1) * 0x200)))
struct mpc5xxx_spi {
volatile uint8_t control1; /* SPI + 0x00 */
volatile uint8_t control2; /* SPI + 0x01 */
volatile uint8_t reserved0[2]; /* SPI + 0x02 */
volatile uint8_t baud; /* SPI + 0x04 */
volatile uint8_t status; /* SPI + 0x05 */
volatile uint8_t reserved1[3]; /* SPI + 0x06 */
volatile uint8_t data; /* SPI + 0x09 */
volatile uint8_t reserved2[3]; /* SPI + 0x0a */
volatile uint8_t port; /* SPI + 0x0d */
volatile uint8_t reserved3[2]; /* SPI + 0x0e */
volatile uint8_t dir; /* SPI + 0x10 */
};
struct mpc5xxx_intr {
volatile uint32_t per_mask; /* INTR + 0x00 */
volatile uint32_t per_pri1; /* INTR + 0x04 */
volatile uint32_t per_pri2; /* INTR + 0x08 */
volatile uint32_t per_pri3; /* INTR + 0x0c */
volatile uint32_t ctrl; /* INTR + 0x10 */
volatile uint32_t main_mask; /* INTR + 0x14 */
volatile uint32_t main_pri1; /* INTR + 0x18 */
volatile uint32_t main_pri2; /* INTR + 0x1c */
volatile uint32_t reserved1; /* INTR + 0x20 */
volatile uint32_t enc_status; /* INTR + 0x24 */
volatile uint32_t crit_status; /* INTR + 0x28 */
volatile uint32_t main_status; /* INTR + 0x2c */
volatile uint32_t per_status; /* INTR + 0x30 */
volatile uint32_t reserved2; /* INTR + 0x34 */
volatile uint32_t per_error; /* INTR + 0x38 */
};
struct mpc5xxx_gpio {
volatile uint32_t port_config; /* GPIO + 0x00 */
volatile uint32_t simple_gpioe; /* GPIO + 0x04 */
volatile uint32_t simple_ode; /* GPIO + 0x08 */
volatile uint32_t simple_ddr; /* GPIO + 0x0c */
volatile uint32_t simple_dvo; /* GPIO + 0x10 */
volatile uint32_t simple_ival; /* GPIO + 0x14 */
volatile uint8_t outo_gpioe; /* GPIO + 0x18 */
volatile uint8_t reserved1[3]; /* GPIO + 0x19 */
volatile uint8_t outo_dvo; /* GPIO + 0x1c */
volatile uint8_t reserved2[3]; /* GPIO + 0x1d */
volatile uint8_t sint_gpioe; /* GPIO + 0x20 */
volatile uint8_t reserved3[3]; /* GPIO + 0x21 */
volatile uint8_t sint_ode; /* GPIO + 0x24 */
volatile uint8_t reserved4[3]; /* GPIO + 0x25 */
volatile uint8_t sint_ddr; /* GPIO + 0x28 */
volatile uint8_t reserved5[3]; /* GPIO + 0x29 */
volatile uint8_t sint_dvo; /* GPIO + 0x2c */
volatile uint8_t reserved6[3]; /* GPIO + 0x2d */
volatile uint8_t sint_inten; /* GPIO + 0x30 */
volatile uint8_t reserved7[3]; /* GPIO + 0x31 */
volatile uint16_t sint_itype; /* GPIO + 0x34 */
volatile uint16_t reserved8; /* GPIO + 0x36 */
volatile uint8_t gpio_control; /* GPIO + 0x38 */
volatile uint8_t reserved9[3]; /* GPIO + 0x39 */
volatile uint8_t sint_istat; /* GPIO + 0x3c */
volatile uint8_t sint_ival; /* GPIO + 0x3d */
volatile uint8_t bus_errs; /* GPIO + 0x3e */
volatile uint8_t reserved10; /* GPIO + 0x3f */
};
struct mpc5xxx_wu_gpio {
volatile u8 wu_gpioe; /* WU_GPIO + 0x00 */
volatile u8 reserved1[3]; /* WU_GPIO + 0x01 */
volatile u8 wu_ode; /* WU_GPIO + 0x04 */
volatile u8 reserved2[3]; /* WU_GPIO + 0x05 */
volatile u8 wu_ddr; /* WU_GPIO + 0x08 */
volatile u8 reserved3[3]; /* WU_GPIO + 0x09 */
volatile u8 wu_dvo; /* WU_GPIO + 0x0c */
volatile u8 reserved4[3]; /* WU_GPIO + 0x0d */
volatile u8 wu_inten; /* WU_GPIO + 0x10 */
volatile u8 reserved5[3]; /* WU_GPIO + 0x11 */
volatile u8 wu_individual; /* WU_GPIO + 0x14 */
volatile u8 reserved6[3]; /* WU_GPIO + 0x15 */
volatile u16 wu_itype; /* WU_GPIO + 0x18 */
volatile u16 reserved7; /* WU_GPIO + 0x1A */
volatile u8 gpio_control; /* WU_GPIO + 0x1C */
volatile u8 reserved8[3]; /* WU_GPIO + 0x1D */
volatile u8 wu_ival; /* WU_GPIO + 0x20 */
volatile u8 reserved9[3]; /* WU_GPIO + 0x21 */
volatile u8 wu_istat; /* WU_GPIO + 0x24 */
volatile u8 reserved10[3]; /* WU_GPIO + 0x25 */
};
struct mpc5xxx_gpt {
volatile uint32_t emsr; /* GPT + 0x00 */
volatile uint32_t cir; /* GPT + 0x04 */
volatile uint32_t pwmcr; /* GPT + 0x08 */
volatile uint32_t sr; /* GPT + 0x0c */
};
struct mpc5xxx_sdma {
volatile uint32_t taskBar; /* SDMA + 0x00 */
volatile uint32_t currentPointer; /* SDMA + 0x04 */
volatile uint32_t endPointer; /* SDMA + 0x08 */
volatile uint32_t variablePointer;/* SDMA + 0x0c */
volatile uint8_t IntVect1; /* SDMA + 0x10 */
volatile uint8_t IntVect2; /* SDMA + 0x11 */
volatile uint16_t PtdCntrl; /* SDMA + 0x12 */
volatile uint32_t IntPend; /* SDMA + 0x14 */
volatile uint32_t IntMask; /* SDMA + 0x18 */
#if 0
volatile uint16_t tcr_0; /* SDMA + 0x1c */
volatile uint16_t tcr_1; /* SDMA + 0x1e */
volatile uint16_t tcr_2; /* SDMA + 0x20 */
volatile uint16_t tcr_3; /* SDMA + 0x22 */
volatile uint16_t tcr_4; /* SDMA + 0x24 */
volatile uint16_t tcr_5; /* SDMA + 0x26 */
volatile uint16_t tcr_6; /* SDMA + 0x28 */
volatile uint16_t tcr_7; /* SDMA + 0x2a */
volatile uint16_t tcr_8; /* SDMA + 0x2c */
volatile uint16_t tcr_9; /* SDMA + 0x2e */
volatile uint16_t tcr_a; /* SDMA + 0x30 */
volatile uint16_t tcr_b; /* SDMA + 0x32 */
volatile uint16_t tcr_c; /* SDMA + 0x34 */
volatile uint16_t tcr_d; /* SDMA + 0x36 */
volatile uint16_t tcr_e; /* SDMA + 0x38 */
volatile uint16_t tcr_f; /* SDMA + 0x3a */
#else
volatile uint16_t tcr[MPC5xxx_SDMA_MAX_TASKS]; /* SDMA + 0x1c..0x3a */
#endif
#if 0
volatile uint8_t IPR0; /* SDMA + 0x3c */
volatile uint8_t IPR1; /* SDMA + 0x3d */
volatile uint8_t IPR2; /* SDMA + 0x3e */
volatile uint8_t IPR3; /* SDMA + 0x3f */
volatile uint8_t IPR4; /* SDMA + 0x40 */
volatile uint8_t IPR5; /* SDMA + 0x41 */
volatile uint8_t IPR6; /* SDMA + 0x42 */
volatile uint8_t IPR7; /* SDMA + 0x43 */
volatile uint8_t IPR8; /* SDMA + 0x44 */
volatile uint8_t IPR9; /* SDMA + 0x45 */
volatile uint8_t IPR10; /* SDMA + 0x46 */
volatile uint8_t IPR11; /* SDMA + 0x47 */
volatile uint8_t IPR12; /* SDMA + 0x48 */
volatile uint8_t IPR13; /* SDMA + 0x49 */
volatile uint8_t IPR14; /* SDMA + 0x4a */
volatile uint8_t IPR15; /* SDMA + 0x4b */
volatile uint8_t IPR16; /* SDMA + 0x4c */
volatile uint8_t IPR17; /* SDMA + 0x4d */
volatile uint8_t IPR18; /* SDMA + 0x4e */
volatile uint8_t IPR19; /* SDMA + 0x4f */
volatile uint8_t IPR20; /* SDMA + 0x50 */
volatile uint8_t IPR21; /* SDMA + 0x51 */
volatile uint8_t IPR22; /* SDMA + 0x52 */
volatile uint8_t IPR23; /* SDMA + 0x53 */
volatile uint8_t IPR24; /* SDMA + 0x54 */
volatile uint8_t IPR25; /* SDMA + 0x55 */
volatile uint8_t IPR26; /* SDMA + 0x56 */
volatile uint8_t IPR27; /* SDMA + 0x57 */
volatile uint8_t IPR28; /* SDMA + 0x58 */
volatile uint8_t IPR29; /* SDMA + 0x59 */
volatile uint8_t IPR30; /* SDMA + 0x5a */
volatile uint8_t IPR31; /* SDMA + 0x5b */
#else
volatile uint8_t IPR[MPC5xxx_SDMA_MAX_INITIATORS]; /* SDMA + 0x3c..0x5b */
#endif
volatile uint32_t res1; /* SDMA + 0x5c */
#ifdef CONFIG_MPC5100
volatile uint32_t res2; /* SDMA + 0x60 */
volatile uint32_t res3; /* SDMA + 0x64 */
#else
volatile uint32_t task_size0; /* SDMA + 0x60 */
volatile uint32_t task_size1; /* SDMA + 0x64 */
#endif
volatile uint32_t MDEDebug; /* SDMA + 0x68 */
volatile uint32_t ADSDebug; /* SDMA + 0x6c */
volatile uint32_t Value1; /* SDMA + 0x70 */
volatile uint32_t Value2; /* SDMA + 0x74 */
volatile uint32_t Control; /* SDMA + 0x78 */
volatile uint32_t Status; /* SDMA + 0x7c */
volatile uint32_t EU00; /* SDMA + 0x80 */
volatile uint32_t EU01; /* SDMA + 0x84 */
volatile uint32_t EU02; /* SDMA + 0x88 */
volatile uint32_t EU03; /* SDMA + 0x8c */
volatile uint32_t EU04; /* SDMA + 0x90 */
volatile uint32_t EU05; /* SDMA + 0x94 */
volatile uint32_t EU06; /* SDMA + 0x98 */
volatile uint32_t EU07; /* SDMA + 0x9c */
volatile uint32_t EU10; /* SDMA + 0xa0 */
volatile uint32_t EU11; /* SDMA + 0xa4 */
volatile uint32_t EU12; /* SDMA + 0xa8 */
volatile uint32_t EU13; /* SDMA + 0xac */
volatile uint32_t EU14; /* SDMA + 0xb0 */
volatile uint32_t EU15; /* SDMA + 0xb4 */
volatile uint32_t EUINT16_T; /* SDMA + 0xb8 */
volatile uint32_t EU17; /* SDMA + 0xbc */
volatile uint32_t EU20; /* SDMA + 0xc0 */
volatile uint32_t EU21; /* SDMA + 0xc4 */
volatile uint32_t EU22; /* SDMA + 0xc8 */
volatile uint32_t EU23; /* SDMA + 0xcc */
volatile uint32_t EU24; /* SDMA + 0xd0 */
volatile uint32_t EU25; /* SDMA + 0xd4 */
volatile uint32_t EU26; /* SDMA + 0xd8 */
volatile uint32_t EU27; /* SDMA + 0xdc */
volatile uint32_t EU30; /* SDMA + 0xe0 */
volatile uint32_t EU31; /* SDMA + 0xe4 */
volatile uint32_t EUINT32_T; /* SDMA + 0xe8 */
volatile uint32_t EU33; /* SDMA + 0xec */
volatile uint32_t EU34; /* SDMA + 0xf0 */
volatile uint32_t EU35; /* SDMA + 0xf4 */
volatile uint32_t EU36; /* SDMA + 0xf8 */
volatile uint32_t EU37; /* SDMA + 0xfc */
};
struct mscan_buffer {
volatile uint8_t idr[0x8]; /* 0x00 */
volatile uint8_t dsr[0x10]; /* 0x08 */
volatile uint8_t dlr; /* 0x18 */
volatile uint8_t tbpr; /* 0x19 */ /* This register is not applicable for receive buffers */
volatile uint16_t rsrv1; /* 0x1A */
volatile uint8_t tsrh; /* 0x1C */
volatile uint8_t tsrl; /* 0x1D */
volatile uint16_t rsrv2; /* 0x1E */
};
struct mpc5xxx_mscan {
volatile uint8_t canctl0; /* MSCAN + 0x00 */
volatile uint8_t canctl1; /* MSCAN + 0x01 */
volatile uint16_t rsrv1; /* MSCAN + 0x02 */
volatile uint8_t canbtr0; /* MSCAN + 0x04 */
volatile uint8_t canbtr1; /* MSCAN + 0x05 */
volatile uint16_t rsrv2; /* MSCAN + 0x06 */
volatile uint8_t canrflg; /* MSCAN + 0x08 */
volatile uint8_t canrier; /* MSCAN + 0x09 */
volatile uint16_t rsrv3; /* MSCAN + 0x0A */
volatile uint8_t cantflg; /* MSCAN + 0x0C */
volatile uint8_t cantier; /* MSCAN + 0x0D */
volatile uint16_t rsrv4; /* MSCAN + 0x0E */
volatile uint8_t cantarq; /* MSCAN + 0x10 */
volatile uint8_t cantaak; /* MSCAN + 0x11 */
volatile uint16_t rsrv5; /* MSCAN + 0x12 */
volatile uint8_t cantbsel; /* MSCAN + 0x14 */
volatile uint8_t canidac; /* MSCAN + 0x15 */
volatile uint16_t rsrv6[3]; /* MSCAN + 0x16 */
volatile uint8_t canrxerr; /* MSCAN + 0x1C */
volatile uint8_t cantxerr; /* MSCAN + 0x1D */
volatile uint16_t rsrv7; /* MSCAN + 0x1E */
volatile uint8_t canidar0; /* MSCAN + 0x20 */
volatile uint8_t canidar1; /* MSCAN + 0x21 */
volatile uint16_t rsrv8; /* MSCAN + 0x22 */
volatile uint8_t canidar2; /* MSCAN + 0x24 */
volatile uint8_t canidar3; /* MSCAN + 0x25 */
volatile uint16_t rsrv9; /* MSCAN + 0x26 */
volatile uint8_t canidmr0; /* MSCAN + 0x28 */
volatile uint8_t canidmr1; /* MSCAN + 0x29 */
volatile uint16_t rsrv10; /* MSCAN + 0x2A */
volatile uint8_t canidmr2; /* MSCAN + 0x2C */
volatile uint8_t canidmr3; /* MSCAN + 0x2D */
volatile uint16_t rsrv11; /* MSCAN + 0x2E */
volatile uint8_t canidar4; /* MSCAN + 0x30 */
volatile uint8_t canidar5; /* MSCAN + 0x31 */
volatile uint16_t rsrv12; /* MSCAN + 0x32 */
volatile uint8_t canidar6; /* MSCAN + 0x34 */
volatile uint8_t canidar7; /* MSCAN + 0x35 */
volatile uint16_t rsrv13; /* MSCAN + 0x36 */
volatile uint8_t canidmr4; /* MSCAN + 0x38 */
volatile uint8_t canidmr5; /* MSCAN + 0x39 */
volatile uint16_t rsrv14; /* MSCAN + 0x3A */
volatile uint8_t canidmr6; /* MSCAN + 0x3C */
volatile uint8_t canidmr7; /* MSCAN + 0x3D */
volatile uint16_t rsrv15; /* MSCAN + 0x3E */
struct mscan_buffer canrxfg; /* MSCAN + 0x40 */ /* Foreground receive buffer */
struct mscan_buffer cantxfg; /* MSCAN + 0x60 */ /* Foreground transmit buffer */
};
struct mpc5xxx_i2c {
volatile uint32_t madr; /* I2Cn + 0x00 */
volatile uint32_t mfdr; /* I2Cn + 0x04 */
volatile uint32_t mcr; /* I2Cn + 0x08 */
volatile uint32_t msr; /* I2Cn + 0x0C */
volatile uint32_t mdr; /* I2Cn + 0x10 */
};
struct mpc5xxx_xlb {
volatile uint8_t reserved[0x40];
volatile uint32_t config; /* XLB + 0x40 */
volatile uint32_t version; /* XLB + 0x44 */
volatile uint32_t status; /* XLB + 0x48 */
volatile uint32_t int_enable; /* XLB + 0x4c */
volatile uint32_t addr_capture; /* XLB + 0x50 */
volatile uint32_t bus_sig_capture; /* XLB + 0x54 */
volatile uint32_t addr_timeout; /* XLB + 0x58 */
volatile uint32_t data_timeout; /* XLB + 0x5c */
volatile uint32_t bus_act_timeout; /* XLB + 0x60 */
volatile uint32_t master_pri_enable; /* XLB + 0x64 */
volatile uint32_t master_priority; /* XLB + 0x68 */
volatile uint32_t base_address; /* XLB + 0x6c */
volatile uint32_t snoop_window; /* XLB + 0x70 */
};
struct mpc5xxx_cdm {
volatile uint32_t jtag_id; /* MBAR_CDM + 0x00 reg0 read only */
volatile uint32_t rstcfg; /* MBAR_CDM + 0x04 reg1 read only */
volatile uint32_t breadcrumb; /* MBAR_CDM + 0x08 reg2 */
volatile uint8_t ddr_mode; /* MBAR_CDM + 0x0c reg3 byte0 read only */
volatile uint8_t xlb_clk_sel; /* MBAR_CDM + 0x0d reg3 byte1 read only */
volatile uint8_t ipb_clk_sel; /* MBAR_CDM + 0x0e reg3 byte2 */
volatile uint8_t pci_clk_sel; /* MBAR_CDM + 0x0f reg3 byte3 */
volatile uint8_t ext_48mhz_en; /* MBAR_CDM + 0x10 reg4 byte0 */
volatile uint8_t fd_enable; /* MBAR_CDM + 0x11 reg4 byte1 */
volatile uint16_t fd_counters; /* MBAR_CDM + 0x12 reg4 byte2,3 */
volatile uint32_t clk_enables; /* MBAR_CDM + 0x14 reg5 */
volatile uint8_t osc_disable; /* MBAR_CDM + 0x18 reg6 byte0 */
volatile uint8_t reserved0[3]; /* MBAR_CDM + 0x19 reg6 byte1,2,3 */
volatile uint8_t ccs_sleep_enable; /* MBAR_CDM + 0x1c reg7 byte0 */
volatile uint8_t osc_sleep_enable; /* MBAR_CDM + 0x1d reg7 byte1 */
volatile uint8_t reserved1; /* MBAR_CDM + 0x1e reg7 byte2 */
volatile uint8_t ccs_qreq_test; /* MBAR_CDM + 0x1f reg7 byte3 */
volatile uint8_t soft_reset; /* MBAR_CDM + 0x20 uint8_t byte0 */
volatile uint8_t no_ckstp; /* MBAR_CDM + 0x21 uint8_t byte0 */
volatile uint8_t reserved2[2]; /* MBAR_CDM + 0x22 uint8_t byte1,2,3 */
volatile uint8_t pll_lock; /* MBAR_CDM + 0x24 reg9 byte0 */
volatile uint8_t pll_looselock; /* MBAR_CDM + 0x25 reg9 byte1 */
volatile uint8_t pll_sm_lockwin; /* MBAR_CDM + 0x26 reg9 byte2 */
volatile uint8_t reserved3; /* MBAR_CDM + 0x27 reg9 byte3 */
volatile uint16_t reserved4; /* MBAR_CDM + 0x28 reg10 byte0,1 */
volatile uint16_t mclken_div_psc1; /* MBAR_CDM + 0x2a reg10 byte2,3 */
volatile uint16_t reserved5; /* MBAR_CDM + 0x2c reg11 byte0,1 */
volatile uint16_t mclken_div_psc2; /* MBAR_CDM + 0x2e reg11 byte2,3 */
volatile uint16_t reserved6; /* MBAR_CDM + 0x30 reg12 byte0,1 */
volatile uint16_t mclken_div_psc3; /* MBAR_CDM + 0x32 reg12 byte2,3 */
volatile uint16_t reserved7; /* MBAR_CDM + 0x34 reg13 byte0,1 */
volatile uint16_t mclken_div_psc6; /* MBAR_CDM + 0x36 reg13 byte2,3 */
};
#define MPC5xxx_SDMA_VAR_SIZE 256
#define MPC5xxx_SDMA_VAR_ALIGN_SHIFT 8
#define MPC5xxx_SDMA_FDT_SIZE 128
#define MPC5xxx_SDMA_FDT_ALIGN_SHIFT 8
#define MPC5xxx_SDMA_CSAVE_SIZE 256
#define MPC5xxx_SDMA_CSAVE_ALIGN_SHIFT 8
#define MPC5xxx_SDMA_TASK_ENABLE 0x8000
/* Function to read the current timebase of the 603e core */
static inline uint64_t readTBx(void)
{
/* "bind" result to the registers r3 & r4 (because of 64bit int,
result will use 2 registers).
*/
register uint64_t result asm("r3");
__asm__("1: \n\t"
"mftbu %%r3 \n\t" // get TBU
"mftb %%r4 \n\t" // get TBL
"mftbu %%r5 \n\t" // get TBU once again
"cmpw %%r5, %%r3 \n\t" // see if 'old' = 'new'
"bne 1b \n\t"
: : : "r3", "r4", "r5");
/* The current value of the timebase is now stored r3 & r4 (TBU & TBL).
Because of assigning result to that registers, their value can be
returned as a one 64bit uint by just returning result.
*/
return result;
}
extern int mpc5xxx_bestcomm_init(void);
extern void mpc5xxx_get_sysclocks(uint32_t *_fsystem, uint32_t *_xlb, uint32_t *_ipb, uint32_t *_pci);
static inline uint16_t
mpc5xxx_sdma_task_status(size_t task)
{
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5xxx_SDMA;
return in_be16(sdma->tcr + task);
}
static inline void
mpc5xxx_sdma_enable_task(size_t task)
{
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5xxx_SDMA;
uint16_t val16 = in_be16(sdma->tcr + task);
val16 |= MPC5xxx_SDMA_TASK_ENABLE;
out_be16(sdma->tcr + task, val16);
}
static inline void
mpc5xxx_sdma_disable_task(size_t task)
{
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5xxx_SDMA;
uint16_t val16 = in_be16(sdma->tcr + task);
val16 &= ~MPC5xxx_SDMA_TASK_ENABLE;
out_be16(sdma->tcr + task, val16);
}
static inline void
mpc5xxx_sdma_set_initator_priority(size_t initiator, uint8_t value)
{
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5xxx_SDMA;
out_8(sdma->IPR + initiator, value);
}
void mpc5xxx_init_irq(void);
int mpc5xxx_get_irq(struct pt_regs *regs);
void mpc5xxx_pci_init_windows(uint8_t win0_ctrl, uint32_t win0_translation,
uint8_t win1_ctrl, uint32_t win1_translation,
uint8_t win2_ctrl, uint32_t win2_translation);
enum mpc5xxx_gpio_t
{
MPC5XXX_GPIO_INVALID,
MPC5XXX_GPIO_PSC2_2,
MPC5XXX_GPIO_PSC3_6,
MPC5XXX_GPIO_PSC3_7,
MPC5XXX_GPIO_TIMER5,
MPC5XXX_GPIO_TIMER7
};
extern int mpc5xxx_config_gpio(enum mpc5xxx_gpio_t port, int output, int opendrain);
extern int mpc5xxx_set_gpio(enum mpc5xxx_gpio_t port, int value);
extern int mpc5xxx_get_gpio(enum mpc5xxx_gpio_t port);
/* System Version Register Definitions */
#define MPC52XX_SVR(major,minor) ((uint32_t)(0x80110000UL | ((major)<<4) | (minor)))
#define MPC52XX_SVR_1_0 MPC52XX_SVR(1,0)
#define MPC52XX_SVR_1_1 MPC52XX_SVR(1,1)
#define MPC52XX_SVR_1_2 MPC52XX_SVR(1,2)
#define MPC52XX_SVR_2_2 MPC52XX_SVR(2,2)
extern uint32_t mpc52xx_get_system_version(void);
#if defined(CONFIG_GLACIER)
#include <platforms/glacier.h>
#elif defined(CONFIG_ICECUBE)
#include <platforms/icecube.h>
#elif defined(CONFIG_TELEMOTIVE_PPC)
#include <platforms/telemotive.h>
#elif defined(CONFIG_PM520)
#include <platforms/pm520.h>
#elif defined(CONFIG_PP01)
#include <platforms/pp01.h>
#elif defined(CONFIG_TOP5200)
#include <platforms/top5200.h>
#elif defined(CONFIG_TQM5200)
#include <platforms/tqm5200.h>
#elif defined(CONFIG_INKA4X0)
#include <platforms/inka4x0.h>
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ASM_MPC5XXX_H */
[-- Attachment #1.3: snd-psc.c --]
[-- Type: text/x-csrc, Size: 28275 bytes --]
/************************************************************************
**
** snd_psc.c
**
** Derived from i2s.c. Provides some functions to support an ALSA
** driver module providing playback and capture on an I2S PSC
** connection.
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file COPYING in the main directory of this archive for
** more details.
**
** Copyright 2005 (C) Roman Fietze (roman.fietze@telemotive.de)
**
************************************************************************/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
#include <linux/crc32.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/delay.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <mgt5200/mgt5200.h>
#include <mgt5200/sdma.h>
#ifdef CONFIG_UBOOT
#include <asm/ppcboot.h>
#endif
#include <bestcomm_api.h>
#include <dma_image.capi.h>
#include <asm/mpc5xxx.h>
#include <asm/mpc5xxx_snd.h>
#undef SND_PSC_DEBUG
// #define SND_PSC_DEBUG
#undef SND_PSC_CYCLIC_STATUS
// #define SND_PSC_CYCLIC_STATUS
#if !defined(CONFIG_BESTCOMM_IMAGE2)
#error Can only be used with BestComm Image 2!
#endif
#if defined(SND_PSC_DEBUG)
#define PRDEBUG(level, format, x... ) do {if (level <= debug) printk(KERN_INFO format, ## x );} while (0)
#else
#define PRDEBUG(level, format, x... ) do {} while(0)
#endif
static int debug = -1;
#if defined(SND_PSC_DEBUG)
static int fixed = 0;
static struct mpc5xxx_psc *status_psc = NULL;
#endif
#ifdef SND_PSC_CYCLIC_STATUS
# define SND_PSC_STATUS_TIMER_PERIOD (HZ/2)
struct timer_list status_timer;
#endif
enum snd_psc_trace_tokens
{
ST_ASSIGN
};
#if SND_PSC_TRACE
static int lognum = -1;
static const char *snd_psc_token_text[] =
{
"ASSIGN"
};
static inline void
snd_psc_add_timestamp(snd_mpc5xxx_i2s_substream_t *_s, enum snd_psc_trace_tokens t)
{
trace_add_timestamp(_s->trace_handle, t);
}
#else
static inline void
snd_psc_add_timestamp(snd_mpc5xxx_i2s_substream_t *_s, enum snd_psc_trace_tokens t)
{
}
#endif
/* SICR as found in the old I2S driver */
#define SND_PSC_I2S_SLAVE_SICR ((uint32_t)(MPC5xxx_PSC_SICR_DTS1_AFTER | \
MPC5xxx_PSC_SICR_SIM_CODEC_32 | \
MPC5xxx_PSC_SICR_CLKPOL_RISE))
#define SND_PSC_I2S_MASTER_SICR (SND_PSC_I2S_SLAVE_SICR | MPC5xxx_PSC_SICR_GENCLK_INT)
#define SND_PSC_SPI_SICR ((uint32_t)(MPC5xxx_PSC_SICR_SPI | \
MPC5xxx_PSC_SICR_GENCLK_INT | \
MPC5xxx_PSC_SICR_SHDIR_LSB | \
MPC5xxx_PSC_SICR_CPHA | \
MPC5xxx_PSC_SICR_MULTIWD | \
MPC5xxx_PSC_SICR_SIM_CODEC_16 | \
MPC5xxx_PSC_SICR_MSTR))
/* The used IRQs, PSC and DMA channel. */
#define sdma ((struct mpc5xxx_sdma *)MPC5xxx_SDMA)
typedef TaskId (*snd_psc_tx_setup_func_t)(TASK_GEN_TX_BD_api_t *taskapi, TaskSetupParamSet_t *param);
typedef TaskId (*snd_psc_rx_setup_func_t)(TASK_GEN_RX_BD_api_t *taskapi, TaskSetupParamSet_t *param);
typedef struct _snd_psc_card_setup
{
volatile uint16_t * mclken_div; /* pointer to mclk divider register */
uint32_t config_mask; /* GPIO port config mask */
uint32_t config_set; /* GPIO port config bits */
uint32_t clken; /* CDM clock enable bit mask */
int irq[2]; /* in BestComm mode both are used, w/o BestComm only the first one */
} snd_psc_card_setup_t;
#define MPC5xxx_CDM_P ((struct mpc5xxx_cdm *)MPC5xxx_CDM)
#define MPC5xxx_CDM_CER_PSC3 MPC5xxx_CDM_CER_PSC345
#define SND_PSC_MK_DIV(psc) &MPC5xxx_CDM_P->mclken_div_psc ## psc
#define SND_PSC_MK_MASK(psc) MPC5xxx_GPIO_PC_PSC ## psc ## _MASK
#define SND_PSC_MK_CODEC(psc) MPC5xxx_GPIO_PC_PSC ## psc ## _CODEC ## psc
#define SND_PSC_MK_CLKEN(psc) MPC5xxx_CDM_CER_PSC ## psc
#define SND_PSC_MK_PSC_IRQ(psc) MPC5xxx_PSC ## psc ## _IRQ
#define SND_PSC_MK_TASK_IRQNUM(psc,d) (MPC5xxx_SDMA_IRQ_BASE + TASK_GEN_## d ## X ## psc ## _BD)
#define SND_PSC_SETUP_UNDEFINED {NULL,0UL,0UL,0UL,{-1,-1}}
#define SND_PSC_SETUP(psc) {SND_PSC_MK_DIV(psc),SND_PSC_MK_MASK(psc),SND_PSC_MK_CODEC(psc),SND_PSC_MK_CLKEN(psc),\
{SND_PSC_MK_TASK_IRQNUM(psc, T),SND_PSC_MK_TASK_IRQNUM(psc, R)}}
static snd_psc_card_setup_t snd_psc_setups[8] =
{
SND_PSC_SETUP_UNDEFINED,
SND_PSC_SETUP(1),
SND_PSC_SETUP(2),
SND_PSC_SETUP(3),
SND_PSC_SETUP_UNDEFINED,
SND_PSC_SETUP_UNDEFINED,
SND_PSC_SETUP(6),
SND_PSC_SETUP_UNDEFINED
};
#define SND_PSC_NUM_BDS (4)
#define SND_PSC_TFALARM (0x100)
#define SND_PSC_TFCNTL (4)
#define SND_PSC_RFALARM (0x100)
#define SND_PSC_RFCNTL (4)
/* delay in ms */
static inline void
snd_psc_delay(const char *text, unsigned long delay, int interruptible)
{
if (delay)
{
wait_queue_head_t wait;
init_waitqueue_head(&wait);
if (interruptible)
interruptible_sleep_on_timeout(&wait, (HZ * delay) / 1000UL);
else
sleep_on_timeout(&wait, (HZ * delay) / 1000UL);
}
}
static inline void psc_tx_enable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_TX_ENABLE);
psc->command = MPC5xxx_PSC_TX_ENABLE;
}
static inline void psc_tx_disable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_TX_DISABLE);
psc->command = MPC5xxx_PSC_TX_DISABLE;
}
static inline void psc_rx_enable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RX_ENABLE);
psc->command = MPC5xxx_PSC_RX_ENABLE;
}
static inline void psc_rx_disable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RX_DISABLE);
psc->command = MPC5xxx_PSC_RX_DISABLE;
}
static inline void psc_tx_rx_enable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE);
psc->command = MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE;
}
static inline void psc_tx_rx_disable(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_DISABLE);
psc->command = MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_DISABLE;
}
static inline void psc_reset(struct mpc5xxx_psc *psc)
{
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RST_RX);
psc->command = MPC5xxx_PSC_RST_RX;
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RST_TX);
psc->command = MPC5xxx_PSC_RST_TX;
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_SEL_MODE_REG_1);
psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_RST_ERR_STAT);
psc->command = MPC5xxx_PSC_RST_ERR_STAT;
}
#ifdef SND_PSC_DEBUG
static int snd_psc_tx_rx_status_dump(int level, char *buf, char locationid)
{
int len = 0;
if (status_psc)
{
static char qbits[] = "oudrt";
static char sbits[] = "outfr";
static char tfsbits[] = "xuorfae";
static char rfsbits[] = "xuorfae";
static uint16_t lastq = 0xFFFFU;
static uint16_t lasts = 0xFFFFU;
static uint16_t lasttfs = 0xFFFFU;
static uint16_t lastrfs = 0xFFFFU;
int i;
uint16_t q = status_psc->mpc5xxx_psc_isr;
if (q != lastq)
{
char *pqbits = qbits + 4;
lastq = q;
q >>= 8;
for (i = 0; i < 5; i++)
{
if (q & 1)
*pqbits = toupper(*pqbits);
else
*pqbits = tolower(*pqbits);
q >>= 1;
pqbits--;
}
}
uint16_t s = status_psc->mpc5xxx_psc_status;
if (s != lasts)
{
char *psbits = sbits + 4;
lasts = s;
s >>= 8;
for (i = 0; i < 5; i++)
{
if (s & 1)
*psbits = toupper(*psbits);
else
*psbits = tolower(*psbits);
s >>= 1;
psbits--;
}
}
uint16_t tfs = status_psc->tfstat;
if (tfs != lasttfs)
{
char *ptfsbits = tfsbits + 6;
lasttfs = tfs;
for (i = 0; i < 7; i++)
{
if (tfs & 1)
*ptfsbits = toupper(*ptfsbits);
else
*ptfsbits = tolower(*ptfsbits);
tfs >>= 1;
ptfsbits--;
}
}
uint16_t rfs = status_psc->rfstat;
if (rfs != lastrfs)
{
char *prfsbits = rfsbits + 6;
lastrfs = rfs;
for (i = 0; i < 7; i++)
{
if (rfs & 1)
*prfsbits = toupper(*prfsbits);
else
*prfsbits = tolower(*prfsbits);
rfs >>= 1;
prfsbits--;
}
}
if (buf)
{
/* proc fs output */
len = sprintf(buf,
"ISR: %s %04x | SR: %s %04x | tx: %s %02x n=%3u w=%3u r=%3u | rx: %s %02x n=%3u w=%3u r=%3u\n",
qbits,
lastq,
sbits,
lasts,
tfsbits,
lasttfs,
status_psc->tfnum,
status_psc->tfwptr,
status_psc->tfrptr,
rfsbits,
lastrfs,
status_psc->rfnum,
status_psc->rfwptr,
status_psc->rfrptr);
}
else
{
/* printk output */
PRDEBUG(level, "PSC(%c): | ISR: %s %04x | SR: %s %04x | tx: %s %02x n=%3u w=%3u r=%3u | rx: %s %02x n=%3u w=%3u r=%3u\n",
locationid,
qbits,
lastq,
sbits,
lasts,
tfsbits,
lasttfs,
status_psc->tfnum,
status_psc->tfwptr,
status_psc->tfrptr,
rfsbits,
lastrfs,
status_psc->rfnum,
status_psc->rfwptr,
status_psc->rfrptr);
}
}
else
{
if (buf)
len = sprintf(buf, "%s: PSC not yet defined!\n", __FUNCTION__);
else
PRDEBUG(level, "%s: PSC not yet defined!\n", __FUNCTION__);
}
return (len);
}
#endif
static inline void snd_psc_tx_rx_status(int level, char locationid)
{
#ifdef SND_PSC_DEBUG
if (debug >= level)
snd_psc_tx_rx_status_dump(level, 0, locationid);
#endif
}
#if defined(SND_PSC_DEBUG)
static void snd_psc_dump_buffer(int level, char id, const void *_pc, size_t n)
{
if (debug >= level)
{
const uint8_t *pc = _pc;
size_t col = 0;
while (n--)
{
if (col == 0)
printk(KERN_INFO "%c: %p:", id, pc);
printk(" %02x", *pc);
if (col == 15)
{
col = 0;
printk("\n");
}
else
{
col++;
}
pc++;
}
if (col != 0)
printk("\n");
}
}
#else
static inline void snd_psc_dump_buffer(int level, char id, const void *pc, size_t n)
{
}
#endif
static irqreturn_t snd_psc_irq(int irq, void *dev_id, struct pt_regs *regs)
{
snd_mpc5xxx_i2s_substream_t *s = dev_id;
if (s->dma_started)
{
PRDEBUG(5, "%s(%d,%p,...) name=%s\n", __FUNCTION__, irq, dev_id, s->name);
snd_mpc5xxx_i2s_card_t *card = s->card;
size_t num = 0;
size_t tc;
static size_t maxnum = 0;
TaskBD1_t *pbd;
BDIdx bdidx;
TaskIntClear(s->task_id);
tc = s->period_size;
if (tc > SND_PSC_MAX_PERIOD_SIZE)
tc = SND_PSC_MAX_PERIOD_SIZE;
spin_lock(&card->lock);
pbd = (TaskBD1_t *)TaskGetBD(s->task_id, s->bdidx);
while (!(pbd->Status & SDMA_BD_MASK_READY))
{
s->bdidx = TaskBDRelease(s->task_id);
s->irqpos += tc;
s->irqpos %= s->buffer_size;
s->processed += tc;
num++;
PRDEBUG(5, "%s: %s: %u: bdidx=%d processed=%u dmapos=%u irqpos=%u\n",
__FUNCTION__, s->name, num, s->bdidx, s->processed, s->dmapos, s->irqpos);
#if defined(SND_PSC_DEBUG)
if (fixed && tc >= 4 * sizeof(uint16_t))
{
static const uint16_t valid[4] = {0x55AAU, 0x0C0CU, 0x55AAU, 0x0C0CU};
const uint16_t *pdata = phys_to_virt(s->dma_addr + s->dmapos);
PRDEBUG(2, "%s: pdata=%p %04x %04x %04x %04x %04x ...\n",
__FUNCTION__,
pdata,
pdata[0], pdata[1], pdata[2], pdata[3], pdata[4]);
if (memcmp(valid, pdata, sizeof(valid)))
{
PRDEBUG(1, "%s: data mismatch for fixed data WAV sample\n", __FUNCTION__);
snd_psc_dump_buffer(1, 'F', pdata, tc);
}
}
#endif
bdidx = TaskBDAssign(s->task_id, (void *)(s->dma_addr + s->dmapos), NULL, tc, 0);
if (bdidx < 0)
printk(KERN_ERR "snd-psc: %s: error %d assigning BD\n", s->name, bdidx);
s->dmapos += tc;
s->dmapos %= s->buffer_size;
pbd = (TaskBD1_t *)TaskGetBD(s->task_id, s->bdidx);
}
if (s->processed >= s->period_size)
{
s->processed %= s->period_size;
spin_unlock(&card->lock);
PRDEBUG(5, "%s: handler\n", __FUNCTION__);
s->handler(s->stream);
}
else
{
spin_unlock(&card->lock);
}
if (num > maxnum)
maxnum = num;
if (num != 1)
PRDEBUG(1, "%s: num=%u maxnum=%u\n", __FUNCTION__, num, maxnum);
}
}
size_t snd_psc_get_substream_pos(snd_mpc5xxx_i2s_substream_t *_s)
{
PRDEBUG(5, "%s(%s) return %u\n", __FUNCTION__, _s->name, _s->irqpos);
return _s->irqpos;
}
int snd_psc_substream_open(snd_mpc5xxx_i2s_substream_t *_s, void *_stream)
{
snd_mpc5xxx_i2s_card_t *card = _s->card;
unsigned long flags;
PRDEBUG(1, "%s(%s,%p)\n", __FUNCTION__, _s->name, _stream);
spin_lock_irqsave(&card->lock, flags);
_s->stream = _stream;
_s->dma_addr = 0;
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
int snd_psc_substream_params(snd_mpc5xxx_i2s_substream_t *_s,
uint32_t _rate, size_t _channels, size_t _bits,
size_t _buffer_size, size_t _period_size)
{
snd_mpc5xxx_i2s_card_t *card = _s->card;
const uint32_t bitrate = _rate * _channels * _bits;
int ret = -EINVAL;
unsigned long flags;
PRDEBUG(1, "%s(%s,%u,%u,%u,%u,%u) bitrate=%uHz\n",
__FUNCTION__,
_s->name, _rate, _channels, _bits, _buffer_size, _period_size,
bitrate);
spin_lock_irqsave(&card->lock, flags);
// In slave mode this wouldn't work:
// if (card->rate != _rate || card->channels != _channels || card->bits != _bits)
// so we always go in here until we understand why :)
if (1)
{
spin_unlock_irqrestore(&card->lock, flags);
PRDEBUG(1, "%s: changing some parameters\n", __FUNCTION__);
PRDEBUG(1, "%s: card: old: rate=%u channels=%u bits=%u\n", __FUNCTION__, card->rate, card->channels, card->bits);
struct mpc5xxx_psc *psc = PSC_ADDRESS(card->pscnum);
struct mpc5xxx_gpio * const gpio = (struct mpc5xxx_gpio *)MPC5xxx_GPIO;
const snd_psc_card_setup_t *setup = snd_psc_setups + card->pscnum;
uint32_t mclk;
uint32_t mclkdiv;
uint32_t bitclkdiv;
uint32_t testmclkdiv;
uint32_t testbitclkdiv;
uint32_t maxerr;
uint32_t currerr;
uint32_t btmp;
uint8_t ctur;
uint8_t ctlr;
uint16_t ccr;
uint32_t sicr;
uint32_t port_config;
#ifdef CONFIG_UBOOT
extern unsigned char __res[];
const bd_t * const bd = (bd_t *)__res;
uint32_t fsystem = 0;
if (MPC5xxx_CDM_P->rstcfg & ( 1 << 5))
fsystem = bd->bi_busfreq * 8;
else
fsystem = bd->bi_busfreq * 4;
PRDEBUG(3, "%s: cdm->rstcfg = 0x%08x fsystem=%uHz\n", __FUNCTION__, MPC5xxx_CDM_P->rstcfg, fsystem);
#else
return -EINVAL;
#endif
const uint32_t MCLKDIV_MAX = (1U << 9);
const uint32_t BITCLKDIV_MAX = (1U << 8);
PRDEBUG(4, " psc->command=%02x\n", MPC5xxx_PSC_TX_DISABLE | MPC5xxx_PSC_RX_DISABLE);
spin_lock_irqsave(&card->lock, flags);
psc_tx_rx_disable(psc);
psc_reset(psc);
PRDEBUG(4, " psc->mode=0\n");
psc->mode = 0;
PRDEBUG(4, "snd-psc: %s\n", __FUNCTION__);
if (!card->slave)
{
/* Calculate CDM MCLK, PSC CCR BitClkDiv from bitrate. As well
* calculate PSC CCR FrameSyncDiv from mclk and check that it
* is not too large.
*/
maxerr = UINT32_MAX;
for (testmclkdiv = 1; ret && testmclkdiv < MCLKDIV_MAX; testmclkdiv++)
{
mclk = fsystem / (testmclkdiv + 1);
PRDEBUG(5, "snd-psc: mclk=%u\n", mclk);
if (mclk > bitrate)
{
for (testbitclkdiv = 1; ret && testbitclkdiv < BITCLKDIV_MAX; testbitclkdiv++)
{
btmp = mclk / (testbitclkdiv + 1);
if (btmp != bitrate)
{
if (btmp > bitrate)
currerr = btmp - bitrate;
else
currerr = bitrate - btmp;
if (currerr < maxerr)
{
maxerr = currerr;
mclkdiv = testmclkdiv;
bitclkdiv = testbitclkdiv;
PRDEBUG(5,
"snd-psc: currerr=%u mclkdiv=%u bitclkdiv=%u\n",
currerr, testmclkdiv, testbitclkdiv);
}
}
else
{
maxerr = 0;
mclkdiv = testmclkdiv;
bitclkdiv = testbitclkdiv;
ret = 0;
}
}
}
}
if (maxerr < bitrate / 10)
ret = 0;
PRDEBUG(1,
"snd-psc: maxerr=%u mclkdiv=%u bitclkdiv=%u bitrate=%u resulting br=%u\n",
maxerr, mclkdiv, bitclkdiv, bitrate, fsystem / (mclkdiv+1) / (bitclkdiv+1));
PRDEBUG(1, "snd-psc: mclkdiv=%u, bitclkdiv=%u, ret=%d\n", mclkdiv, bitclkdiv, ret);
if (ret < 0)
{
printk(KERN_ERR
"%s: cannot find correct clock dividers for a sample rate of %u.\n",
__FUNCTION__,
_rate);
return ret;
}
}
if (card->spi)
{
const uint32_t ipb = bd->bi_ipbfreq;
const uint16_t dtl = 2;
const uint32_t ct = (dtl * ipb) / 1000000U;
ctur = MPC5xxx_PSC_CTUR_CODEC(ct >> 8); /* DTL high byte */
ctlr = MPC5xxx_PSC_CTLR_CODEC(ct); /* DTL low byte */
ccr = MPC5xxx_PSC_CCR_CODEC(0, bitclkdiv); /* DSCKL as low as possible: TBR */
sicr = SND_PSC_SPI_SICR;
}
else
{
ctur = MPC5xxx_PSC_CTUR_CODEC(8 * sizeof(uint16_t) - 1);
ctlr = 0;
ccr = MPC5xxx_PSC_CCR_CODEC(2 * 8 * sizeof(uint16_t) - 1, bitclkdiv);
sicr = card->slave ? SND_PSC_I2S_SLAVE_SICR : SND_PSC_I2S_MASTER_SICR;
}
PRDEBUG(4, " cdm->mclken_div_psc%u=%08x\n", card->pscnum,
MPC5xxx_PSC_MCLOCK_ENABLE | MPC5xxx_PSC_MCLOCK_MCLKDIV(mclkdiv));
*(setup->mclken_div) = MPC5xxx_PSC_MCLOCK_ENABLE | MPC5xxx_PSC_MCLOCK_MCLKDIV(mclkdiv);
PRDEBUG(4, " cdm->clk_enables|=%08x\n", setup->clken);
MPC5xxx_CDM_P->clk_enables |= setup->clken;
PRDEBUG(4, " psc->ctur=%02x\n", ctur);
psc->ctur = ctur;
PRDEBUG(4, " psc->ctlr=%02x\n", ctlr);
psc->ctlr = ctlr;
PRDEBUG(4, " psc->ccr=%04x\n", ccr);
psc->ccr = ccr;
port_config = gpio->port_config;
port_config = (port_config & ~setup->config_mask) | setup->config_set;
PRDEBUG(4, " gpio->port_config = %08x\n", port_config);
gpio->port_config = port_config;
PRDEBUG(4, " psc->tfstat=%04x\n", MPC5xxx_PSC_FIFO_ERR | MPC5xxx_PSC_FIFO_UF | MPC5xxx_PSC_FIFO_OF);
psc->tfstat = MPC5xxx_PSC_FIFO_ERR | MPC5xxx_PSC_FIFO_UF | MPC5xxx_PSC_FIFO_OF; // reset some status bits
PRDEBUG(4, " psc->rfstat=%04x\n", MPC5xxx_PSC_FIFO_ERR | MPC5xxx_PSC_FIFO_UF | MPC5xxx_PSC_FIFO_OF);
psc->rfstat = MPC5xxx_PSC_FIFO_ERR | MPC5xxx_PSC_FIFO_UF | MPC5xxx_PSC_FIFO_OF;
PRDEBUG(4, " psc->tfalarm=%d\n", SND_PSC_TFALARM);
psc->tfalarm = SND_PSC_TFALARM; /* alarm threshold level */
PRDEBUG(4, " psc->rfalarm=%d\n", SND_PSC_RFALARM);
psc->rfalarm = SND_PSC_RFALARM;
PRDEBUG(4, " psc->tfcntl=%d\n", SND_PSC_TFCNTL);
psc->tfcntl = SND_PSC_TFCNTL; /* granularity */
PRDEBUG(4, " psc->rfcntl=%d\n", SND_PSC_RFCNTL);
psc->rfcntl = SND_PSC_RFCNTL;
PRDEBUG(4, " psc->imr=0\n");
psc->mpc5xxx_psc_imr = 0; /* disable interrupts */
PRDEBUG(1, "%s: %s: sicr=%08x\n", __FUNCTION__, _s->name, sicr);
psc->sicr = sicr;
if (card->loopback)
{
volatile int val;
printk(KERN_INFO "snd-psc: ************** local loop back mode enabled on PSC%u\n", card->pscnum);
val = psc->mode; /* to switch from mode1 to mode2 */
val++; /* ??? short delay ??? */
psc->mode = 0x80;
}
#if defined(SND_PSC_DEBUG)
if (fixed)
snd_psc_tx_rx_status(1, 'P');
#endif
/* reset PSC again */
psc_reset(psc);
if (card->psc_started)
psc_tx_rx_enable(psc);
card->rate = _rate;
card->channels = _channels;
card->bits = _bits;
}
_s->buffer_size = _buffer_size;
_s->period_size = _period_size;
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
int snd_psc_substream_start(snd_mpc5xxx_i2s_substream_t *_s, dma_addr_t _dma_addr)
{
snd_mpc5xxx_i2s_card_t *card = _s->card;
unsigned long flags;
PRDEBUG(1, "snd-psc: %s(s=%s,dma_addr=%08x) id=%d\n", __FUNCTION__, _s->name, _dma_addr, _s->id);
spin_lock_irqsave(&card->lock, flags);
if (!_s->dma_started)
{
struct mpc5xxx_psc *psc = PSC_ADDRESS(card->pscnum);
size_t i;
size_t tc;
BDIdx bdidx;
card->streams[_s->id] = _s;
_s->processed = 0;
_s->dma_addr = _dma_addr;
_s->dmapos = _s->irqpos = 0;
if (_s->id)
{
uint32_t tmp;
/* empty RX FIFO to remove noise */
while (psc->rfnum >= sizeof(uint32_t))
tmp = psc->mpc5xxx_psc_buffer_32;
}
tc = _s->period_size;
if (tc > SND_PSC_MAX_PERIOD_SIZE)
tc = SND_PSC_MAX_PERIOD_SIZE;
bdidx = TaskBDReset(_s->task_id);
if (bdidx < 0)
printk(KERN_ERR "snd-psc: %s: error %d resetting BDs\n", _s->name, bdidx);
for (i = 0; i < SND_PSC_NUM_BDS; i++)
{
PRDEBUG(3, "%s: assign BD at dma_addr[%u] (%08x)\n",
__FUNCTION__,
_s->dmapos, _s->dma_addr + _s->dmapos);
bdidx = TaskBDAssign(_s->task_id, (void *)(_s->dma_addr + _s->dmapos), NULL, tc, 0);
if (bdidx < 0)
printk(KERN_ERR "snd-psc: %s: error %d assigning BD\n", _s->name, bdidx);
_s->dmapos += tc;
_s->dmapos %= _s->buffer_size;
}
if (!card->psc_started)
psc_tx_rx_enable(psc);
card->psc_started |= 1 << _s->id;
#if defined(SND_PSC_DEBUG)
if (fixed)
snd_psc_tx_rx_status(1, 'S');
#endif
TaskStart(_s->task_id, TASK_AUTOSTART_ENABLE, _s->task_id, TASK_INTERRUPT_ENABLE);
_s->dma_started = 1;
}
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
int snd_psc_substream_stop(snd_mpc5xxx_i2s_substream_t *_s)
{
snd_mpc5xxx_i2s_card_t *card = _s->card;
unsigned long flags;
PRDEBUG(3, "snd-psc: %s(%s)\n", __FUNCTION__, _s->name);
spin_lock_irqsave(&card->lock, flags);
if (_s->dma_started)
{
struct mpc5xxx_psc *psc = PSC_ADDRESS(card->pscnum);
_s->dma_started = 0;
card->streams[_s->id] = NULL;
/* stop the tasks */
card->psc_started &= ~(1 << _s->id);
if (!card->psc_started)
psc_tx_rx_disable(psc);
TaskStop(_s->task_id);
TaskBDReset(_s->task_id);
}
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
/* Initialize as much as possible of the BestComm init
* structures.
*/
int snd_psc_substream_create(snd_mpc5xxx_i2s_substream_t **_s,
snd_mpc5xxx_i2s_card_t *_card,
const char *_name,
int _id, /* 0..1 */
snd_psc_irq_handler_t _handler)
{
struct mpc5xxx_psc *psc = PSC_ADDRESS(_card->pscnum);
TaskSetupParamSet_t setup;
int ret;
snd_mpc5xxx_i2s_substream_t *s = kmalloc(sizeof(snd_mpc5xxx_i2s_substream_t), GFP_KERNEL);
*_s = s;
if (s == NULL)
return -ENOMEM;
/* first of all, disable all PSC interrupts */
psc->mpc5xxx_psc_imr = 0;
PRDEBUG(1, "snd-psc: %s(s=%p,card=%p,name=%s,id=%d,handler=%p) substream=%p\n",
__FUNCTION__,
_s, _card,
_name, _id, _handler,
s);
s->id = _id;
s->card = _card;
s->stream = NULL;
strncpy(s->name, _name, sizeof(s->name));
s->task_id = 0;
s->bdidx = 0;
s->irq = snd_psc_setups[_card->pscnum].irq[_id];
s->dmapos = s->irqpos = 0;
s->dma_started = 0;
s->processed = 0;
s->handler = _handler;
s->stream = NULL;
#if SND_PSC_TRACE
trace_create(&s->trace_handle, lognum, snd_psc_token_text, ARRAY_SIZE(snd_psc_token_text), SND_PSC_TRACE);
#endif
memset(&setup, 0, sizeof(setup));
/* setup.Initiator will be setup by the task setup function automatically */
setup.NumBD = SND_PSC_NUM_BDS;
setup.Size.MaxBuf = SND_PSC_MAX_PERIOD_SIZE;
setup.StartAddrSrc = setup.StartAddrDst = 0;
setup.SzSrc = setup.SzDst = sizeof(uint32_t);
PRDEBUG(4, "%s: pscnum=%u Initiator=%u\n", __FUNCTION__, _card->pscnum, setup.Initiator);
if (!_id)
{
/* task to transmit data */
setup.StartAddrDst = (uint32_t)&(psc->mpc5xxx_psc_buffer_32);
setup.IncrSrc = sizeof(uint32_t);
setup.IncrDst = 0;
PRDEBUG(3, "%s: setup TX\n", __FUNCTION__);
s->task_id = TaskSetup_TASK_GEN_TX_BD(_card->pscnum, &setup, 0);
}
else
{
/* task to receive data */
setup.StartAddrSrc = (uint32_t)&(psc->mpc5xxx_psc_buffer_32);
setup.IncrSrc = 0;
setup.IncrDst = sizeof(uint32_t);
PRDEBUG(3, "%s: setup RX\n", __FUNCTION__);
s->task_id = TaskSetup_TASK_GEN_RX_BD(_card->pscnum, &setup, 0);
}
if (s->task_id < 0)
{
printk(KERN_ERR "snd-psc: cannot setup BestComm task: err=%d\n", s->task_id);
kfree(s);
*_s = NULL;
return -EFAULT;
}
PRDEBUG(3, "%s: pscnum=%u _s->task_id=%u, request IRQ%d\n", __FUNCTION__, _card->pscnum, s->task_id, s->irq);
if ((ret = request_irq(s->irq, snd_psc_irq, SA_INTERRUPT, s->name, s)))
{
printk(KERN_ERR
"%s: PSC DMA irq (%d) allocation failed, error %d\n",
s->name,
s->irq,
-ret);
kfree(s);
*_s = NULL;
return ret;
}
return 0;
}
int snd_psc_substream_close(snd_mpc5xxx_i2s_substream_t *_s)
{
PRDEBUG(1, "%s(%s)\n", __FUNCTION__, _s->name);
return 0;
}
int snd_psc_substream_free(snd_mpc5xxx_i2s_substream_t *_s)
{
struct mpc5xxx_psc *psc = PSC_ADDRESS(_s->card->pscnum);
PRDEBUG(1, "%s(%p)\n", __FUNCTION__, _s);
/* stop the PSC */
psc_tx_disable(psc);
psc_rx_disable(psc);
psc_reset(psc);
free_irq(_s->irq, _s);
#if SND_PSC_TRACE
trace_dump(_s->trace_handle);
trace_free(_s->trace_handle);
#endif
return 0;
}
#ifdef SND_PSC_CYCLIC_STATUS
static void snd_psc_status_timer_interrupt(unsigned long arg)
{
snd_psc_tx_rx_status(1, 'T');
if (status_psc)
mod_timer(&status_timer, jiffies + SND_PSC_STATUS_TIMER_PERIOD);
}
#endif
int snd_psc_card_create(snd_mpc5xxx_i2s_card_t **_card,
uint16_t _pscnum,
int _slave, int _spi, int _loopback)
{
static const char *request_names[8] =
{
"invalid_PSC",
"snd_psc_PS1",
"snd_psc_PS2",
"snd_psc_PS3",
"invalid_PSC",
"invalid_PSC",
"snd_psc_PS6",
"invalid_PSC"
};
size_t i;
struct mpc5xxx_psc *psc = PSC_ADDRESS(_pscnum);
snd_mpc5xxx_i2s_card_t *card = kmalloc(sizeof(snd_mpc5xxx_i2s_card_t), GFP_KERNEL);
*_card = card;
if (card == NULL)
{
return -ENOMEM;
}
MOD_INC_USE_COUNT;
#if defined(SND_PSC_DEBUG)
status_psc = psc;
#else
if (debug != -1)
printk(KERN_WARNING "%s: compiled without debug support\n", __FUNCTION__);
#endif
PRDEBUG(1,
"%s(card=%p,pscnum=%u,slave=%d,spi=%d,loopback=%d) card=%p\n",
__FUNCTION__,
_card, _pscnum, _slave, _spi, _loopback, card);
/* Can't fail */
request_region((unsigned long)psc, sizeof(struct mpc5xxx_psc), request_names[_pscnum]);
snprintf(card->name, sizeof(card->name), "snd_psc_psc%u", _pscnum);
card->pscnum = _pscnum;
card->rate = 0;
card->channels = 0;
card->bits = 0;
card->slave = _slave;
card->spi = _spi;
card->loopback = _loopback;
spin_lock_init(&card->lock);
for (i = 0; i < SND_PSC_MAX_STREAMS; i++)
card->streams[i] = NULL;
card->psc_started = 0;
psc->mpc5xxx_psc_imr = 0;
#ifdef SND_PSC_CYCLIC_STATUS
/* Start timer interrupt to get transfer status every second. */
PRDEBUG(1, "snd-psc: starting cyclic status\n");
init_timer(&status_timer);
status_timer.function = snd_psc_status_timer_interrupt;
status_timer.data = 0;
add_timer(&status_timer);
#endif
return 0;
}
void snd_psc_card_free(snd_mpc5xxx_i2s_card_t *_card)
{
PRDEBUG(1, "%s(%p)\n", __FUNCTION__, _card);
if (_card)
{
struct mpc5xxx_psc *psc = PSC_ADDRESS(_card->pscnum);
release_region((unsigned long)psc, sizeof(struct mpc5xxx_psc));
}
#ifdef SND_PSC_CYCLIC_STATUS
if (status_psc)
{
PRDEBUG(1, "snd-psc: stopping cyclic status\n");
status_psc = NULL;
del_timer_sync(&status_timer);
}
#endif
MOD_DEC_USE_COUNT;
}
static int __init snd_psc_init(void)
{
PRDEBUG(1, "%s() debug=%d fixed=%d\n", __FUNCTION__, debug, fixed);
printk(KERN_INFO "MPC5200 PSC I2S Audio DMA Driver\n");
return 0;
}
static void __exit snd_psc_exit(void)
{
PRDEBUG(1, "%s\n", __FUNCTION__);
}
module_init(snd_psc_init);
module_exit(snd_psc_exit);
MODULE_DESCRIPTION("Driver for the MPC5200 PSC in CODEC SND_PSC mode.");
MODULE_AUTHOR("Roman Fietze, Telemotive AG, roman.fietze@telemotive.de");
MODULE_SUPPORTED_DEVICE("MPC5200 PSC SND_PSC Codec");
MODULE_LICENSE("GPL");
#if defined(SND_PSC_DEBUG)
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "debug level (0-6)");
MODULE_PARM(fixed, "i");
MODULE_PARM_DESC(fixed, "check fixed data stream (0-1)");
#endif
#if SND_PSC_TRACE
MODULE_PARM(lognum, "i");
MODULE_PARM_DESC(lognum, "Log file number (/var/log/tmproto-<num>) (0-99)");
#endif
EXPORT_SYMBOL(snd_psc_card_create);
EXPORT_SYMBOL(snd_psc_card_free);
EXPORT_SYMBOL(snd_psc_substream_create);
EXPORT_SYMBOL(snd_psc_substream_open);
EXPORT_SYMBOL(snd_psc_substream_params);
EXPORT_SYMBOL(snd_psc_substream_start);
EXPORT_SYMBOL(snd_psc_get_substream_pos);
EXPORT_SYMBOL(snd_psc_substream_stop);
EXPORT_SYMBOL(snd_psc_substream_close);
EXPORT_SYMBOL(snd_psc_substream_free);
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 9:39 ` Pedro Luis D. L.
2006-12-13 12:56 ` Roman Fietze
2006-12-13 12:58 ` Roman Fietze
@ 2006-12-13 13:15 ` Roman Fietze
2006-12-13 14:37 ` Pedro Luis D. L.
2 siblings, 1 reply; 13+ messages in thread
From: Roman Fietze @ 2006-12-13 13:15 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 259 bytes --]
Hello Pedro,
I just discovered one important, but missing file.
Roman
--
Roman Fietze Telemotive AG Büro Mühlhausen
Breitwiesen 73347 Mühlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
[-- Attachment #1.2: mpc5xxx_snd.h --]
[-- Type: text/x-chdr, Size: 3069 bytes --]
/*
* mpc5xxx_snd.h
*
* Definitions to use the PSC in I2S codec mode with the BestComm for
* an ALSA sound driver.
*/
#ifndef _MPC5XXX_SND_H
#define _MPC5XXX_SND_H
#include <linux/kernel.h>
#include <linux/interrupt.h>
#define SND_PSC_TRACE (0)
// #define SND_PSC_TRACE (1000)
// #undef SND_PSC_STATISTICS
#define SND_PSC_STATISTICS
/* Some needed or useful constants. */
#define SND_PSC_AUDIO_RATE_MIN (8000)
#define SND_PSC_AUDIO_RATE_DEFAULT (44100)
#define SND_PSC_AUDIO_RATE_MAX (48000)
#define SND_PSC_MAX_BUFFER_SIZE (0x40000)
#define SND_PSC_MIN_PERIOD_SIZE (1024)
#define SND_PSC_MAX_PERIOD_SIZE (4096)
#if SND_PSC_TRACE
# if defined(MODULE)
# if !defined(CONFIG_TRACE) && !defined(CONFIG_TRACE_MODULE)
# warning "Need CONFIG_TRACE or CONFIG_TRACE_MODULE, disable trace."
# undef SND_PSC_TRACE
# define SND_PSC_TRACE (0)
# endif
# elif !defined(CONFIG_TRACE)
# warning "Need CONFIG_TRACE, disable trace."
# undef SND_PSC_TRACE
# define SND_PSC_TRACE (0)
# endif
#endif
#if SND_PSC_TRACE
# include <linux/trace.h>
#endif
#define SND_PSC_MAX_STREAMS (2)
typedef void (*snd_psc_irq_handler_t)(void *_stream);
typedef struct _snd_mpc5xxx_i2s_substream
{
char name[40];
int id;
struct _snd_mpc5xxx_i2s_card *card;
int dma_started;
int8_t task_id;
int32_t bdidx; /* BestComms current BDIdx */
int irq;
dma_addr_t dma_addr;
size_t dmapos;
size_t irqpos;
size_t processed; /* processed since last call of xxx_pointer() */
size_t buffer_size;
size_t period_size;
snd_psc_irq_handler_t handler;
void *stream;
#if SND_PSC_TRACE
trace_handle_t *trace_handle;
#endif
} snd_mpc5xxx_i2s_substream_t;
typedef struct _snd_mpc5xxx_i2s_card
{
char name[20];
uint16_t pscnum; /* identical to cardid in ALSA driver */
int loopback;
uint32_t rate;
size_t channels;
size_t bits;
int slave; /* run I2S codec in clock slave mode */
int spi; /* run SPI codec instead of I2S codec */
spinlock_t lock;
int psc_started; /* bit mask for started substreams */
snd_mpc5xxx_i2s_substream_t *streams[SND_PSC_MAX_STREAMS];
} snd_mpc5xxx_i2s_card_t;
int snd_psc_card_create(snd_mpc5xxx_i2s_card_t **_card,
uint16_t _pscnum,
int _slave, int _spi, int _loopback);
void snd_psc_card_free(snd_mpc5xxx_i2s_card_t *_card);
int snd_psc_substream_create(snd_mpc5xxx_i2s_substream_t **_s,
snd_mpc5xxx_i2s_card_t *_card,
const char *_name,
int _id, /* 0..1 */
snd_psc_irq_handler_t _handler);
int snd_psc_substream_open(snd_mpc5xxx_i2s_substream_t *_s, void *_stream);
int snd_psc_substream_params(snd_mpc5xxx_i2s_substream_t *_s,
uint32_t _rate, size_t _channels, size_t _bits,
size_t _buffer_size, size_t _period_size);
int snd_psc_substream_start(snd_mpc5xxx_i2s_substream_t *_s, dma_addr_t _dma_addr);
size_t snd_psc_get_substream_pos(snd_mpc5xxx_i2s_substream_t *_s);
int snd_psc_substream_stop(snd_mpc5xxx_i2s_substream_t *_s);
int snd_psc_substream_close(snd_mpc5xxx_i2s_substream_t *_s);
int snd_psc_substream_free(snd_mpc5xxx_i2s_substream_t *_s);
#endif
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 13:15 ` Roman Fietze
@ 2006-12-13 14:37 ` Pedro Luis D. L.
0 siblings, 0 replies; 13+ messages in thread
From: Pedro Luis D. L. @ 2006-12-13 14:37 UTC (permalink / raw)
To: linuxppc-embedded
On Wed, 13 Dec 2006, Roman Fietze wrote:
>Hello Pedro,
>
>I just discovered one important, but missing file.
>
>
>Roman
>
Hello Roman,
Thank you very much for the code. I´ll see what can I do.
Pedro.
_________________________________________________________________
Dale rienda suelta a tu tiempo libre. Mil ideas para exprimir tu ocio con
MSN Entretenimiento. http://entretenimiento.msn.es/
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-12 15:47 Lite5200B I2S driver Pedro Luis D. L.
2006-12-12 19:22 ` Sylvain Munaut
2006-12-13 9:10 ` Roman Fietze
@ 2006-12-17 8:03 ` Grant Likely
2 siblings, 0 replies; 13+ messages in thread
From: Grant Likely @ 2006-12-17 8:03 UTC (permalink / raw)
To: Pedro Luis D. L.; +Cc: linuxppc-embedded
On 12/12/06, Pedro Luis D. L. <carcadiz@hotmail.com> wrote:
> Hi all,
>
> I=B4m working with a Lite5200B EVB, trying to atach an audio output to a =
PCM
> 1680 from Texas Instruments.
> At this moment I am using the patched 2.6.16.11-rt18 kernel that comes wi=
th
> Freescale BSP.
> I=B4ve tried to develop an I2S driver for the platform with no results. I=
=B4m
> afraid that my driver devolping skills are still too low.
>
> Anybody knows a working I2S driver for this board that can throw any
> audiooutput through PSCs?
I've just pushed a driver for the mpc52xx psc + AIC26 codec out to the
'lite5200' branch of my git tree on http://git.secretlab.ca. I've
just pushed it out to my tree so that those who are interested can
take a look at it. But it is *not* complete. Here's a non-exhaustive
list of known issues with it.
1. not ported to arch/powerpc
2. doesn't use the SPI infrastructure
3. I had to rip out some board specific code for manipulating SPI chip
selects (in order to release it)
4. Poor coding convention in places
It works quite well on one of my targets; but I was not able to
release that code as is; hence the broken driver. I'll be working on
this code to get it into shape for inclusion into mainline. Most of
the work will probably revolve around doing a proper SPI connection
and adapting the bestcomm code to whatever Sylvain has brewing in his
tree. The move to arch/powerpc will also have a fair impact.
Cheers,
g.
--=20
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-13 12:56 ` Roman Fietze
@ 2006-12-18 13:47 ` Stefan Strobl
2006-12-18 14:46 ` Roman Fietze
0 siblings, 1 reply; 13+ messages in thread
From: Stefan Strobl @ 2006-12-18 13:47 UTC (permalink / raw)
To: linuxppc-embedded
Hello Roman
I'm interested in your code also though I haven't had a chance to look
at it yet. I am also having a MPC5200 based board running Wolfgang's
kernel 2.4.25.
Roman Fietze wrote:
> The driver uses some modified bestcomm code, because the original
> bestcomm code from Freescale is, ahem, not very well designed, one of
> the reasons for the new design in the 2.6. The changes were done in
> the code image 2. They are a more generic approach for the PSC tasks,
> so I can more easily switch PSC's. You should easily be able to modify
> the kernel part of the driver, to use the bestcomm code from
> Wolfgang's 2.4.25 git kernel tree. If not, please contact me and I
> will send you the sources of my bestcomm/ subdirectory, or anybody
> else of course.
What I am wondering is, how many DMA tasks do you run besides Audio?
I am already using DMA for IDE and FEC so Audio would be my third DMA
task. I remember that it used to be difficult to get more than two tasks
running at the same time.
Would you send me or post your bestcomm sources since I'm not that
proficient in kernel programming.
Thanks
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-18 13:47 ` Stefan Strobl
@ 2006-12-18 14:46 ` Roman Fietze
2006-12-18 15:10 ` Stefan Strobl
0 siblings, 1 reply; 13+ messages in thread
From: Roman Fietze @ 2006-12-18 14:46 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1056 bytes --]
Hello Stefan,
On Monday 18 December 2006 14:47, Stefan Strobl wrote:
> What I am wondering is, how many DMA tasks do you run besides Audio?
> I am already using DMA for IDE and FEC so Audio would be my third
> DMA task. I remember that it used to be difficult to get more than
> two tasks running at the same time.
As of my curret knowledge it is definitely a problem to run IDE-DMA
together with any access to the LocalPlus on the old B2 mask of the
MPC5200. We did not have problems using the BestComm concurrently for
IDE, FEC and the PSC (I2S+SPI codec mode) on either mask.
> Would you send me or post your bestcomm sources since I'm not that
> proficient in kernel programming.
No problem, I will mail you the same tar fiel I sent to Wolfgang. This
includes the BestComm code and once more the drivers. It's derived
work and GPL'd.
Roman
--
Roman Fietze Telemotive AG Büro Mühlhausen
Breitwiesen 73347 Mühlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Lite5200B I2S driver
2006-12-18 14:46 ` Roman Fietze
@ 2006-12-18 15:10 ` Stefan Strobl
0 siblings, 0 replies; 13+ messages in thread
From: Stefan Strobl @ 2006-12-18 15:10 UTC (permalink / raw)
To: linuxppc-embedded
Hello Roman
Roman Fietze wrote:
> As of my curret knowledge it is definitely a problem to run IDE-DMA
> together with any access to the LocalPlus on the old B2 mask of the
> MPC5200. We did not have problems using the BestComm concurrently for
> IDE, FEC and the PSC (I2S+SPI codec mode) on either mask.
That's good news for me.
> No problem, I will mail you the same tar fiel I sent to Wolfgang. This
> includes the BestComm code and once more the drivers. It's derived
> work and GPL'd.
Thanks a lot. I'm looking forward to trying that out. I'll send you a
note once I've got it run, but it'll take some time until I have a
hardware to work on.
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2006-12-18 15:15 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-12 15:47 Lite5200B I2S driver Pedro Luis D. L.
2006-12-12 19:22 ` Sylvain Munaut
2006-12-13 9:31 ` Pedro Luis D. L.
2006-12-13 9:10 ` Roman Fietze
2006-12-13 9:39 ` Pedro Luis D. L.
2006-12-13 12:56 ` Roman Fietze
2006-12-18 13:47 ` Stefan Strobl
2006-12-18 14:46 ` Roman Fietze
2006-12-18 15:10 ` Stefan Strobl
2006-12-13 12:58 ` Roman Fietze
2006-12-13 13:15 ` Roman Fietze
2006-12-13 14:37 ` Pedro Luis D. L.
2006-12-17 8:03 ` Grant Likely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).