Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/allwinner/a10_codec.c
Context not available. | |||||
struct a10codec_info { | struct a10codec_info { | ||||
device_t dev; | device_t dev; | ||||
struct resource *res[3]; | struct resource *res[2]; | ||||
struct mtx *lock; | struct mtx *lock; | ||||
bus_dma_tag_t dmat; | bus_dma_tag_t dmat; | ||||
unsigned dmasize; | unsigned dmasize; | ||||
Context not available. | |||||
static struct resource_spec a10codec_spec[] = { | static struct resource_spec a10codec_spec[] = { | ||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, | { SYS_RES_MEMORY, 0, RF_ACTIVE }, | ||||
{ SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL }, | |||||
{ SYS_RES_IRQ, 0, RF_ACTIVE }, | |||||
{ -1, 0 } | { -1, 0 } | ||||
}; | }; | ||||
#define CODEC_ANALOG_READ(sc, reg) bus_read_4((sc)->res[1], (reg)) | |||||
#define CODEC_ANALOG_WRITE(sc, reg, val) bus_write_4((sc)->res[1], (reg), (val)) | |||||
#define CODEC_READ(sc, reg) bus_read_4((sc)->res[0], (reg)) | #define CODEC_READ(sc, reg) bus_read_4((sc)->res[0], (reg)) | ||||
#define CODEC_WRITE(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) | #define CODEC_WRITE(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) | ||||
Context not available. | |||||
#define A10_PA_EN (1U << 4) | #define A10_PA_EN (1U << 4) | ||||
#define A10_DDE (1U << 3) | #define A10_DDE (1U << 3) | ||||
static void | |||||
a10codec_stop(struct a10codec_chinfo *ch); | |||||
static int | static int | ||||
a10_mixer_init(struct snd_mixer *m) | a10_mixer_init(struct snd_mixer *m) | ||||
{ | { | ||||
Context not available. | |||||
*/ | */ | ||||
#define H3_PR_CFG 0x00 | #define H3_PR_CFG 0x00 | ||||
#define H3_AC_PR_RST (1 << 18) | #define H3_AC_PR_RST (1 << 28) | ||||
#define H3_AC_PR_RW (1 << 24) | #define H3_AC_PR_RW (1 << 24) | ||||
#define H3_AC_PR_ADDR_SHIFT 16 | #define H3_AC_PR_ADDR_SHIFT 16 | ||||
#define H3_AC_PR_ADDR_MASK (0x1f << H3_AC_PR_ADDR_SHIFT) | #define H3_AC_PR_ADDR_MASK (0x1f << H3_AC_PR_ADDR_SHIFT) | ||||
Context not available. | |||||
uint32_t val; | uint32_t val; | ||||
/* Read current value */ | /* Read current value */ | ||||
val = bus_read_4(sc->res[1], H3_PR_CFG); | val = CODEC_ANALOG_READ(sc, H3_PR_CFG); | ||||
/* De-assert reset */ | /* De-assert reset */ | ||||
val |= H3_AC_PR_RST; | val |= H3_AC_PR_RST; | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Read mode */ | /* Read mode */ | ||||
val &= ~H3_AC_PR_RW; | val &= ~H3_AC_PR_RW; | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Set address */ | /* Set address */ | ||||
val &= ~H3_AC_PR_ADDR_MASK; | val &= ~H3_AC_PR_ADDR_MASK; | ||||
val |= (addr << H3_AC_PR_ADDR_SHIFT); | val |= (addr << H3_AC_PR_ADDR_SHIFT); | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Read data */ | /* Read data */ | ||||
return (bus_read_4(sc->res[1], H3_PR_CFG) & H3_ACDA_PR_RDAT_MASK); | return (CODEC_ANALOG_READ(sc , H3_PR_CFG) & H3_ACDA_PR_RDAT_MASK); | ||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
uint32_t val; | uint32_t val; | ||||
/* Read current value */ | /* Read current value */ | ||||
val = bus_read_4(sc->res[1], H3_PR_CFG); | val = CODEC_ANALOG_READ(sc, H3_PR_CFG); | ||||
/* De-assert reset */ | /* De-assert reset */ | ||||
val |= H3_AC_PR_RST; | val |= H3_AC_PR_RST; | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Set address */ | /* Set address */ | ||||
val &= ~H3_AC_PR_ADDR_MASK; | val &= ~H3_AC_PR_ADDR_MASK; | ||||
val |= (addr << H3_AC_PR_ADDR_SHIFT); | val |= (addr << H3_AC_PR_ADDR_SHIFT); | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Write data */ | /* Write data */ | ||||
val &= ~H3_ACDA_PR_WDAT_MASK; | val &= ~H3_ACDA_PR_WDAT_MASK; | ||||
val |= (data << H3_ACDA_PR_WDAT_SHIFT); | val |= (data << H3_ACDA_PR_WDAT_SHIFT); | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
/* Write mode */ | /* Write mode */ | ||||
val |= H3_AC_PR_RW; | val |= H3_AC_PR_RW; | ||||
bus_write_4(sc->res[1], H3_PR_CFG, val); | CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val); | ||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
static int | static int | ||||
h3_mixer_init(struct snd_mixer *m) | h3_mixer_init(struct snd_mixer *m) | ||||
{ | { | ||||
int rid=1; | |||||
pcell_t reg[2]; | |||||
phandle_t analogref; | |||||
struct a10codec_info *sc = mix_getdevinfo(m); | struct a10codec_info *sc = mix_getdevinfo(m); | ||||
if (OF_getencprop(ofw_bus_get_node(sc->dev), "allwinner,codec-analog-controls", | |||||
&analogref, sizeof(analogref)) <= 0) { | |||||
return (ENXIO); | |||||
} | |||||
if (OF_getencprop(OF_node_from_xref(analogref), "reg", | |||||
reg, sizeof(reg)) <= 0) { | |||||
return (ENXIO); | |||||
} | |||||
sc->res[1] = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, &rid, reg[0], | |||||
reg[0]+reg[1], reg[1], RF_ACTIVE ); | |||||
manu: Using reg[0] + reg[1] should work for the end parameter. | |||||
if (sc->res[1] == NULL) { | |||||
return (ENXIO); | |||||
} | |||||
mix_setdevs(m, SOUND_MASK_PCM | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV | | mix_setdevs(m, SOUND_MASK_PCM | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV | | ||||
SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1); | SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1); | ||||
mix_setrecdevs(m, SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1 | | mix_setrecdevs(m, SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1 | | ||||
Context not available. | |||||
ch->pos = 0; | ch->pos = 0; | ||||
a10codec_stop(ch); | |||||
Not Done Inline ActionsWhat's the reason for this stop here ? manu: What's the reason for this stop here ? | |||||
Not Done Inline ActionsSometimes during testing the sound did not start the first time after a cold start/reboot. When i started the player once again, the sound was played correctly. I just wanted to set the peripheral to a known state before starting over. With this stop placed here, i could not reproduce the error during playing a sound the first time after reboot. freebsdnewbie_freenet.de: Sometimes during testing the sound did not start the first time after a cold start/reboot. When… | |||||
if (ch->dir == PCMDIR_PLAY) { | if (ch->dir == PCMDIR_PLAY) { | ||||
/* Flush DAC FIFO */ | /* Flush DAC FIFO */ | ||||
CODEC_WRITE(sc, AC_DAC_FIFOC(sc), DAC_FIFOC_FIFO_FLUSH); | CODEC_WRITE(sc, AC_DAC_FIFOC(sc), DAC_FIFOC_FIFO_FLUSH); | ||||
Context not available. | |||||
} | } | ||||
/* De-assert hwreset */ | /* De-assert hwreset */ | ||||
if (hwreset_get_by_ofw_name(dev, 0, "apb", &rst) == 0 || | if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) { | ||||
hwreset_get_by_ofw_name(dev, 0, "ahb", &rst) == 0) { | |||||
error = hwreset_deassert(rst); | error = hwreset_deassert(rst); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "cannot de-assert reset\n"); | device_printf(dev, "cannot de-assert reset\n"); | ||||
Context not available. | |||||
val |= DAC_DPC_EN_DA; | val |= DAC_DPC_EN_DA; | ||||
CODEC_WRITE(sc, AC_DAC_DPC(sc), val); | CODEC_WRITE(sc, AC_DAC_DPC(sc), val); | ||||
#ifdef notdef | |||||
error = snd_setup_intr(dev, sc->irq, INTR_MPSAFE, a10codec_intr, sc, | |||||
&sc->ih); | |||||
if (error != 0) { | |||||
device_printf(dev, "could not setup interrupt handler\n"); | |||||
goto fail; | |||||
} | |||||
#endif | |||||
if (mixer_init(dev, sc->cfg->mixer_class, sc)) { | if (mixer_init(dev, sc->cfg->mixer_class, sc)) { | ||||
device_printf(dev, "mixer_init failed\n"); | device_printf(dev, "mixer_init failed\n"); | ||||
goto fail; | goto fail; | ||||
Context not available. |
Using reg[0] + reg[1] should work for the end parameter.