Gigabeat S: Implement i2c driver - transmit works but no testing of receiving which will get a chance later. Add some seeds for codec driver. Correct a few #defines.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17254 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
fec6af659f
commit
27fac88548
10 changed files with 572 additions and 34 deletions
|
@ -210,7 +210,9 @@ drivers/mas.c
|
|||
drivers/audio/uda1380.c
|
||||
#elif defined(HAVE_WM8751)
|
||||
drivers/audio/wm8751.c
|
||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8978)
|
||||
#elif defined(HAVE_WM8978)
|
||||
drivers/audio/wm8978.c
|
||||
#elif defined(HAVE_WM8975)
|
||||
drivers/audio/wm8975.c
|
||||
#elif defined(HAVE_WM8985)
|
||||
drivers/audio/wm8985.c
|
||||
|
|
60
firmware/drivers/audio/wm8978.c
Normal file
60
firmware/drivers/audio/wm8978.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2008 by Michael Sevakis
|
||||
*
|
||||
* Driver for WM8978 audio codec
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "audiohw.h"
|
||||
#include "wmcodec.h"
|
||||
#include "audio.h"
|
||||
|
||||
const struct sound_settings_info audiohw_settings[] = {
|
||||
[SOUND_VOLUME] = {"dB", 0, 1, -58, 6, -25},
|
||||
[SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
|
||||
[SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
|
||||
[SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
|
||||
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
|
||||
[SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
|
||||
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
|
||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
|
||||
[SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
|
||||
#if 0
|
||||
[SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
|
||||
[SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
|
||||
#endif
|
||||
};
|
||||
|
||||
void audiohw_preinit(void)
|
||||
{
|
||||
wmcodec_write(WM8978_SOFTWARE_RESET, 0);
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
sleep(HZ);
|
||||
}
|
||||
|
||||
void audiohw_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
void audiohw_mute(bool mute)
|
||||
{
|
||||
(void)mute;
|
||||
}
|
|
@ -27,7 +27,9 @@
|
|||
#include "uda1380.h"
|
||||
#elif defined(HAVE_WM8751)
|
||||
#include "wm8751.h"
|
||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8978)
|
||||
#elif defined(HAVE_WM8978)
|
||||
#include "wm8978.h"
|
||||
#elif defined(HAVE_WM8975)
|
||||
#include "wm8975.h"
|
||||
#elif defined(HAVE_WM8985)
|
||||
#include "wm8985.h"
|
||||
|
@ -109,7 +111,14 @@ extern const struct sound_settings_info audiohw_settings[];
|
|||
void audiohw_init(void);
|
||||
|
||||
/**
|
||||
* Do some stuff (codec related) after audiohw_init.
|
||||
* Do initial audio codec setup.
|
||||
*/
|
||||
void audiohw_preinit(void);
|
||||
|
||||
/**
|
||||
* Do some stuff (codec related) after audiohw_init that needs to be
|
||||
* delayed such as enabling outputs to prevent popping. This lets
|
||||
* other inits in the system complete in the meantime.
|
||||
*/
|
||||
void audiohw_postinit(void);
|
||||
|
||||
|
|
|
@ -66,10 +66,9 @@
|
|||
/* The number of bytes reserved for loadable plugins */
|
||||
#define PLUGIN_BUFFER_SIZE 0x80000
|
||||
|
||||
/* Define this if you have the WM8975 audio codec */
|
||||
/* Define this if you have the WM8978 audio codec */
|
||||
#define HAVE_WM8978
|
||||
|
||||
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \
|
||||
SAMPR_CAP_11)
|
||||
|
||||
|
@ -85,8 +84,9 @@
|
|||
/* Define this if you want to use coldfire's i2c interface */
|
||||
#define CONFIG_I2C I2C_IMX31L
|
||||
|
||||
/* Define the bitmask of serial interface modules (CSPI) used */
|
||||
/* Define the bitmask of modules used */
|
||||
#define SPI_MODULE_MASK (USE_CSPI2_MODULE)
|
||||
#define I2C_MODULE_MASK (USE_I2C1_MODULE)
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 1
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#define ETB_SLOT4_BASE_ADDR 0x43F10000
|
||||
#define ETB_SLOT5_BASE_ADDR 0x43F14000
|
||||
#define ECT_CTIO_BASE_ADDR 0x43F18000
|
||||
#define I2C_BASE_ADDR 0x43F80000
|
||||
#define I2C1_BASE_ADDR 0x43F80000
|
||||
#define I2C3_BASE_ADDR 0x43F84000
|
||||
#define OTG_BASE_ADDR 0x43F88000
|
||||
#define ATA_BASE_ADDR 0x43F8C000
|
||||
|
@ -628,6 +628,112 @@
|
|||
#define CSPI_TESTREG_SWAP (1 << 15)
|
||||
#define CSPI_TESTREG_LBC (1 << 14)
|
||||
|
||||
/* I2C */
|
||||
#define I2C_IADR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x0))
|
||||
#define I2C_IFDR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x4))
|
||||
#define I2C_I2CR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x8))
|
||||
#define I2C_I2SR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0xC))
|
||||
#define I2C_I2DR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x10))
|
||||
|
||||
#define I2C_IADR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x0))
|
||||
#define I2C_IFDR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x4))
|
||||
#define I2C_I2CR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x8))
|
||||
#define I2C_I2SR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0xC))
|
||||
#define I2C_I2DR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x10))
|
||||
|
||||
#define I2C_IADR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x0))
|
||||
#define I2C_IFDR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x4))
|
||||
#define I2C_I2CR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x8))
|
||||
#define I2C_I2SR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0xC))
|
||||
#define I2C_I2DR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x10))
|
||||
|
||||
/* IADR - [7:1] Address */
|
||||
|
||||
/* IFDR */
|
||||
#define I2C_IFDR_DIV30 0x00
|
||||
#define I2C_IFDR_DIV32 0x01
|
||||
#define I2C_IFDR_DIV36 0x02
|
||||
#define I2C_IFDR_DIV42 0x03
|
||||
#define I2C_IFDR_DIV48 0x04
|
||||
#define I2C_IFDR_DIV52 0x05
|
||||
#define I2C_IFDR_DIV60 0x06
|
||||
#define I2C_IFDR_DIV72 0x07
|
||||
#define I2C_IFDR_DIV80 0x08
|
||||
#define I2C_IFDR_DIV88 0x09
|
||||
#define I2C_IFDR_DIV104 0x0a
|
||||
#define I2C_IFDR_DIV128 0x0b
|
||||
#define I2C_IFDR_DIV144 0x0c
|
||||
#define I2C_IFDR_DIV160 0x0d
|
||||
#define I2C_IFDR_DIV192 0x0e
|
||||
#define I2C_IFDR_DIV240 0x0f
|
||||
#define I2C_IFDR_DIV288 0x10
|
||||
#define I2C_IFDR_DIV320 0x11
|
||||
#define I2C_IFDR_DIV384 0x12
|
||||
#define I2C_IFDR_DIV480 0x13
|
||||
#define I2C_IFDR_DIV576 0x14
|
||||
#define I2C_IFDR_DIV640 0x15
|
||||
#define I2C_IFDR_DIV768 0x16
|
||||
#define I2C_IFDR_DIV960 0x17
|
||||
#define I2C_IFDR_DIV1152 0x18
|
||||
#define I2C_IFDR_DIV1280 0x19
|
||||
#define I2C_IFDR_DIV1536 0x1a
|
||||
#define I2C_IFDR_DIV1920 0x1b
|
||||
#define I2C_IFDR_DIV2304 0x1c
|
||||
#define I2C_IFDR_DIV2560 0x1d
|
||||
#define I2C_IFDR_DIV3072 0x1e
|
||||
#define I2C_IFDR_DIV3840 0x1f
|
||||
#define I2C_IFDR_DIV22 0x20
|
||||
#define I2C_IFDR_DIV24 0x21
|
||||
#define I2C_IFDR_DIV26 0x22
|
||||
#define I2C_IFDR_DIV28 0x23
|
||||
#define I2C_IFDR_DIV32_2 0x24
|
||||
#define I2C_IFDR_DIV36_2 0x25
|
||||
#define I2C_IFDR_DIV40 0x26
|
||||
#define I2C_IFDR_DIV44 0x27
|
||||
#define I2C_IFDR_DIV48_2 0x28
|
||||
#define I2C_IFDR_DIV56 0x29
|
||||
#define I2C_IFDR_DIV64 0x2a
|
||||
#define I2C_IFDR_DIV72_2 0x2b
|
||||
#define I2C_IFDR_DIV80_2 0x2c
|
||||
#define I2C_IFDR_DIV96 0x2d
|
||||
#define I2C_IFDR_DIV112 0x2e
|
||||
#define I2C_IFDR_DIV128_2 0x2f
|
||||
#define I2C_IFDR_DIV160_2 0x30
|
||||
#define I2C_IFDR_DIV192_2 0x31
|
||||
#define I2C_IFDR_DIV224 0x32
|
||||
#define I2C_IFDR_DIV256 0x33
|
||||
#define I2C_IFDR_DIV320_2 0x34
|
||||
#define I2C_IFDR_DIV384_2 0x35
|
||||
#define I2C_IFDR_DIV448 0x36
|
||||
#define I2C_IFDR_DIV512 0x37
|
||||
#define I2C_IFDR_DIV640_2 0x38
|
||||
#define I2C_IFDR_DIV768_2 0x39
|
||||
#define I2C_IFDR_DIV896 0x3a
|
||||
#define I2C_IFDR_DIV1024 0x3b
|
||||
#define I2C_IFDR_DIV1280_2 0x3c
|
||||
#define I2C_IFDR_DIV1536_2 0x3d
|
||||
#define I2C_IFDR_DIV1792 0x3e
|
||||
#define I2C_IFDR_DIV2048 0x3f
|
||||
|
||||
/* I2CR */
|
||||
#define I2C_I2CR_IEN (1 << 7)
|
||||
#define I2C_I2CR_IIEN (1 << 6)
|
||||
#define I2C_I2CR_MSTA (1 << 5)
|
||||
#define I2C_I2CR_MTX (1 << 4)
|
||||
#define I2C_I2CR_TXAK (1 << 3)
|
||||
#define I2C_I2CR_RSATA (1 << 2)
|
||||
|
||||
/* I2SR */
|
||||
#define I2C_I2SR_ICF (1 << 7)
|
||||
#define I2C_I2SR_IAAS (1 << 6)
|
||||
#define I2C_I2SR_IBB (1 << 5)
|
||||
#define I2C_I2SR_IAL (1 << 4)
|
||||
#define I2C_I2SR_SRW (1 << 2)
|
||||
#define I2C_I2SR_IIF (1 << 1)
|
||||
#define I2C_I2SR_RXAK (1 << 0)
|
||||
|
||||
/* I2DR - [7:0] Data */
|
||||
|
||||
/* RTC */
|
||||
#define RTC_HOURMIN (*(REG32_PTR_T)(RTC_BASE_ADDR+0x00))
|
||||
#define RTC_SECONDS (*(REG32_PTR_T)(RTC_BASE_ADDR+0x04))
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#ifndef _WM8978_H
|
||||
#define _WM8978_H
|
||||
|
||||
#define VOLUME_MIN -570
|
||||
#define VOLUME_MAX 60
|
||||
|
||||
#define WM8978_I2C_ADDR 0x34
|
||||
|
||||
/* Registers */
|
||||
|
@ -142,7 +145,7 @@
|
|||
#define WM8978_DAC_COMP_U_LAW (2 << 3)
|
||||
#define WM8978_DAC_COMP_A_LAW (3 << 3)
|
||||
#define WM8978_ADC_COMP (3 << 1)
|
||||
#define WM8978_DAC_COMP_OFF (0 << 1)
|
||||
#define WM8978_ADC_COMP_OFF (0 << 1)
|
||||
#define WM8978_ADC_COMP_U_LAW (2 << 1)
|
||||
#define WM8978_ADC_COMP_A_LAW (3 << 1)
|
||||
#define WM8978_LOOPBACK (1 << 0)
|
||||
|
@ -159,12 +162,12 @@
|
|||
#define WM8978_MCLKDIV_8 (6 << 5)
|
||||
#define WM8978_MCLKDIV_12 (7 << 5)
|
||||
#define WM8978_BCLKDIV (7 << 2)
|
||||
#define WM8978_MCLKDIV_1 (0 << 2)
|
||||
#define WM8978_MCLKDIV_2 (1 << 2)
|
||||
#define WM8978_MCLKDIV_4 (2 << 2)
|
||||
#define WM8978_MCLKDIV_8 (3 << 2)
|
||||
#define WM8978_MCLKDIV_16 (4 << 2)
|
||||
#define WM8978_MCLKDIV_32 (5 << 2)
|
||||
#define WM8978_BCLKDIV_1 (0 << 2)
|
||||
#define WM8978_BCLKDIV_2 (1 << 2)
|
||||
#define WM8978_BCLKDIV_4 (2 << 2)
|
||||
#define WM8978_BCLKDIV_8 (3 << 2)
|
||||
#define WM8978_BCLKDIV_16 (4 << 2)
|
||||
#define WM8978_BCLKDIV_32 (5 << 2)
|
||||
#define WM8978_MS (1 << 0)
|
||||
|
||||
/* WM8978_ADDITIONAL_CTRL (0x07) */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Michael Sevakis
|
||||
* Copyright (C) 2008 by Michael Sevakis
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
|
@ -16,38 +16,321 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "i2c-imx31.h"
|
||||
|
||||
#if 0
|
||||
static int i2c_getack(void)
|
||||
/* Forward interrupt handler declarations */
|
||||
#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void);
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void);
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void);
|
||||
#endif
|
||||
|
||||
static struct i2c_module_descriptor
|
||||
{
|
||||
return 0;
|
||||
struct i2c_map *base; /* Module base address */
|
||||
enum IMX31_CG_LIST cg; /* Clock gating index */
|
||||
enum IMX31_INT_LIST ints; /* Module interrupt number */
|
||||
int enable; /* Enable count */
|
||||
void (*handler)(void); /* Module interrupt handler */
|
||||
struct mutex m; /* Node mutual-exclusion */
|
||||
struct wakeup w; /* I2C done signal */
|
||||
unsigned char *addr_data; /* Additional addressing data */
|
||||
int addr_count; /* Addressing byte count */
|
||||
unsigned char *data; /* TX/RX buffer (actual data) */
|
||||
int data_count; /* TX/RX byte count */
|
||||
unsigned char addr; /* Address + r/w bit */
|
||||
} i2c_descs[I2C_NUM_I2C] =
|
||||
{
|
||||
#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
|
||||
{
|
||||
.base = (struct i2c_map *)I2C1_BASE_ADDR,
|
||||
.cg = CG_I2C1,
|
||||
.ints = I2C1,
|
||||
.handler = I2C1_HANDLER,
|
||||
},
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
|
||||
{
|
||||
.base = (struct i2c_map *)I2C2_BASE_ADDR,
|
||||
.cg = CG_I2C2,
|
||||
.ints = I2C2,
|
||||
.handler = I2C2_HANDLER,
|
||||
},
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
|
||||
{
|
||||
.base = (struct i2c_map *)I2C3_BASE_ADDR,
|
||||
.cg = CG_I2C3,
|
||||
.ints = I2C3,
|
||||
.handler = I2C3_HANDLER,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void i2c_interrupt(enum i2c_module_number i2c)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[i2c];
|
||||
struct i2c_map * const base = desc->base;
|
||||
uint16_t i2sr = base->i2sr;
|
||||
|
||||
base->i2sr = i2sr & ~I2C_I2SR_IIF; /* Clear IIF */
|
||||
|
||||
if (desc->addr_count >= 0)
|
||||
{
|
||||
/* ADDR cycle - either done or more to send */
|
||||
if ((i2sr & I2C_I2SR_RXAK) != 0)
|
||||
{
|
||||
goto i2c_stop; /* problem */
|
||||
}
|
||||
|
||||
if (--desc->addr_count < 0)
|
||||
{
|
||||
/* Switching to data cycle */
|
||||
if (desc->addr & 0x1)
|
||||
{
|
||||
base->i2cr &= ~I2C_I2CR_MTX; /* Switch to RX mode */
|
||||
base->i2dr; /* Dummy read */
|
||||
return;
|
||||
}
|
||||
/* else remaining data is TX - handle below */
|
||||
goto i2c_transmit;
|
||||
}
|
||||
else
|
||||
{
|
||||
base->i2dr = *desc->addr_data++; /* Send next addressing byte */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (base->i2cr & I2C_I2CR_MTX)
|
||||
{
|
||||
i2c_transmit:
|
||||
/* Transmitting data */
|
||||
if ((i2sr & I2C_I2SR_RXAK) == 0 && desc->data_count > 0)
|
||||
{
|
||||
/* More bytes to send, got ACK from previous byte */
|
||||
base->i2dr = *desc->data++;
|
||||
desc->data_count--;
|
||||
return;
|
||||
}
|
||||
/* else done or no ACK received */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Receiving data */
|
||||
if (--desc->data_count > 0)
|
||||
{
|
||||
if (desc->data_count == 1)
|
||||
{
|
||||
/* 2nd to Last byte - NACK */
|
||||
base->i2cr |= I2C_I2CR_TXAK;
|
||||
}
|
||||
|
||||
*desc->data++ = base->i2dr; /* Read data from I2DR and store */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Generate STOP signal before reading data */
|
||||
base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
|
||||
*desc->data++ = base->i2dr; /* Read data from I2DR and store */
|
||||
goto i2c_done;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_stop:
|
||||
/* Generate STOP signal */
|
||||
base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
|
||||
i2c_done:
|
||||
/* Signal thread we're done */
|
||||
wakeup_signal(&desc->w);
|
||||
}
|
||||
|
||||
static int i2c_start(void)
|
||||
#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void)
|
||||
{
|
||||
return 0;
|
||||
i2c_interrupt(I2C1_NUM);
|
||||
}
|
||||
|
||||
static void i2c_stop(void)
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void)
|
||||
{
|
||||
i2c_interrupt(I2C2_NUM);
|
||||
}
|
||||
|
||||
static int i2c_outb(unsigned char byte)
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
|
||||
static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void)
|
||||
{
|
||||
(void)byte;
|
||||
return 0;
|
||||
i2c_interrupt(I2C3_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
void i2c_write(int addr, const unsigned char *buf, int count)
|
||||
static int i2c_transfer(struct i2c_node * const node,
|
||||
struct i2c_module_descriptor *const desc)
|
||||
{
|
||||
(void)addr;
|
||||
(void)buf;
|
||||
(void)count;
|
||||
struct i2c_map * const base = desc->base;
|
||||
int count = desc->data_count;
|
||||
uint16_t i2cr;
|
||||
|
||||
/* Set speed */
|
||||
base->ifdr = node->ifdr;
|
||||
|
||||
/* Enable module */
|
||||
base->i2cr = I2C_I2CR_IEN;
|
||||
|
||||
/* Enable Interrupt, Master */
|
||||
i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
|
||||
|
||||
if ((desc->addr & 0x1) && desc->data_count < 2)
|
||||
{
|
||||
/* Receiving less than two bytes - disable ACK generation */
|
||||
i2cr |= I2C_I2CR_TXAK;
|
||||
}
|
||||
|
||||
/* Set config */
|
||||
base->i2cr = i2cr;
|
||||
|
||||
/* Generate START */
|
||||
base->i2cr |= I2C_I2CR_MSTA;
|
||||
|
||||
/* Address slave (first byte sent) and begin session. */
|
||||
base->i2dr = desc->addr;
|
||||
|
||||
/* Wait for transfer to complete */
|
||||
count = (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) ?
|
||||
-1 : (count - desc->data_count);
|
||||
|
||||
/* Disable module - generate STOP if timeout */
|
||||
base->i2cr = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int i2c_read(struct i2c_node *node, int reg,
|
||||
unsigned char *data, int data_count)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
|
||||
unsigned char ad[1];
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
desc->addr = (node->addr & 0xfe) | 0x1; /* Slave address/rd */
|
||||
|
||||
if (reg >= 0)
|
||||
{
|
||||
/* Sub-address */
|
||||
desc->addr_count = 1;
|
||||
desc->addr_data = ad;
|
||||
ad[0] = reg;
|
||||
}
|
||||
/* else raw read from slave */
|
||||
|
||||
desc->data = data;
|
||||
desc->data_count = data_count;
|
||||
|
||||
data_count = i2c_transfer(node, desc);
|
||||
|
||||
desc->addr_count = 0; /* To eliminate zeroing elsewhere */
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
|
||||
return data_count;
|
||||
}
|
||||
|
||||
int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
desc->addr = node->addr & 0xfe; /* Slave address/wr */
|
||||
desc->data = (unsigned char *)data;
|
||||
desc->data_count = data_count;
|
||||
|
||||
data_count = i2c_transfer(node, desc);
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
|
||||
return data_count;
|
||||
}
|
||||
|
||||
void i2c_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Do one-time inits for each module that will be used - leave
|
||||
* module disabled and unclocked until something wants it */
|
||||
for (i = 0; i < I2C_NUM_I2C; i++)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[i];
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
|
||||
mutex_init(&desc->m);
|
||||
wakeup_init(&desc->w);
|
||||
desc->base->i2cr = 0;
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Pad config set up by OF bootloader doesn't agree with manual but
|
||||
* TX works at the moment - probably would't do this here either */
|
||||
uint32_t reg = SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT;
|
||||
reg &= ~0xfffff;
|
||||
reg |= (1 << 19) | (3 << 17) | (1 << 15) | (1 << 14) |
|
||||
(1 << 13) | (0 << 11);
|
||||
|
||||
reg |= (1 << 9) | (3 << 7) | (1 << 5) | (1 << 4) |
|
||||
(1 << 3) | (0 << 1);
|
||||
|
||||
SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT = reg;
|
||||
#endif
|
||||
}
|
||||
|
||||
void i2c_enable_node(struct i2c_node *node, bool enable)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
|
||||
|
||||
mutex_lock(&desc->m);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (++desc->enable == 1)
|
||||
{
|
||||
/* First enable */
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
|
||||
avic_enable_int(desc->ints, IRQ, 7, desc->handler);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (desc->enable > 0 && --desc->enable == 0)
|
||||
{
|
||||
/* Last enable */
|
||||
avic_disable_int(desc->ints);
|
||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&desc->m);
|
||||
}
|
||||
|
||||
void i2c_lock_node(struct i2c_node *node)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
|
||||
mutex_lock(&desc->m);
|
||||
}
|
||||
|
||||
void i2c_unlock_node(struct i2c_node *node)
|
||||
{
|
||||
struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
|
||||
mutex_unlock(&desc->m);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,61 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _I2C_IMX31_H_
|
||||
#define _I2C_IMX31_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* I2C module usage masks */
|
||||
#define USE_I2C1_MODULE (1 << 0)
|
||||
#define USE_I2C2_MODULE (1 << 1)
|
||||
#define USE_I2C3_MODULE (1 << 2)
|
||||
|
||||
enum i2c_module_number
|
||||
{
|
||||
__I2C_NUM_START = -1,
|
||||
#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
|
||||
I2C1_NUM,
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
|
||||
I2C2_NUM,
|
||||
#endif
|
||||
#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
|
||||
I2C3_NUM,
|
||||
#endif
|
||||
I2C_NUM_I2C,
|
||||
};
|
||||
|
||||
/* Module interface map structure */
|
||||
struct i2c_map
|
||||
{
|
||||
volatile uint16_t iadr; /* 0x00 */
|
||||
volatile uint16_t unused1;
|
||||
volatile uint16_t ifdr; /* 0x04 */
|
||||
volatile uint16_t unused2;
|
||||
volatile uint16_t i2cr; /* 0x08 */
|
||||
volatile uint16_t unused3;
|
||||
volatile uint16_t i2sr; /* 0x0C */
|
||||
volatile uint16_t unused4;
|
||||
volatile uint16_t i2dr; /* 0x10 */
|
||||
};
|
||||
|
||||
struct i2c_node
|
||||
{
|
||||
enum i2c_module_number num; /* Module that this node uses */
|
||||
unsigned int ifdr; /* Maximum frequency for node */
|
||||
unsigned char addr; /* Slave address on module */
|
||||
};
|
||||
|
||||
void i2c_init(void);
|
||||
void i2c_write(int addr, const unsigned char *data, int count);
|
||||
/* Enable or disable the node - modules will be switch on/off accordingly. */
|
||||
void i2c_enable_node(struct i2c_node *node, bool enable);
|
||||
/* If addr < 0, then raw read */
|
||||
int i2c_read(struct i2c_node *node, int addr, unsigned char *data, int count);
|
||||
int i2c_write(struct i2c_node *node, const unsigned char *data, int count);
|
||||
/* Gain mutually-exclusive access to the node and module to perform multiple
|
||||
* operations atomically */
|
||||
void i2c_lock_node(struct i2c_node *node);
|
||||
void i2c_unlock_node(struct i2c_node *node);
|
||||
|
||||
#endif /* _I2C_IMX31_H_ */
|
||||
|
|
|
@ -49,10 +49,12 @@ void pcm_apply_settings(void)
|
|||
|
||||
void pcm_play_dma_init(void)
|
||||
{
|
||||
audiohw_init();
|
||||
}
|
||||
|
||||
void pcm_postinit(void)
|
||||
{
|
||||
audiohw_postinit();
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Gigabeat specific code for the Wolfson codec
|
||||
* Gigabeat S specific code for the WM8978 codec
|
||||
*
|
||||
* Based on code from the ipodlinux project - http://ipodlinux.org/
|
||||
* Adapted for Rockbox in December 2005
|
||||
|
@ -28,12 +28,31 @@
|
|||
#include "sound.h"
|
||||
#include "i2c-imx31.h"
|
||||
|
||||
/* NOTE: Some port-specific bits will have to be moved away (node and GPIO
|
||||
* writes) for cleanest implementation. */
|
||||
|
||||
static struct i2c_node wm8978_i2c_node =
|
||||
{
|
||||
.num = I2C1_NUM,
|
||||
.ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */
|
||||
/* Just hard-code for now - scaling may require
|
||||
* updating */
|
||||
.addr = WM8978_I2C_ADDR,
|
||||
};
|
||||
|
||||
void audiohw_init(void)
|
||||
{
|
||||
i2c_enable_node(&wm8978_i2c_node, true);
|
||||
GPIO3_DR |= (1 << 21); /* Turn on analogue LDO */
|
||||
sleep(HZ/10); /* Wait for things to stabilize */
|
||||
audiohw_preinit();
|
||||
}
|
||||
|
||||
void wmcodec_write(int reg, int data)
|
||||
{
|
||||
(void)reg;
|
||||
(void)data;
|
||||
unsigned char d[2];
|
||||
/* |aaaaaaad|dddddddd| */
|
||||
d[0] = (reg << 1) | ((data & 0x100) >> 8);
|
||||
d[1] = data;
|
||||
i2c_write(&wm8978_i2c_node, d, 2);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue