Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci-2.6.23
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci-2.6.23
Commits
6094d6e2
Commit
6094d6e2
authored
Apr 18, 2008
by
张青山(steven.zhang)
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ARM: Davinci: tlvaic32 audio oss driver support
parent
017a079d
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1516 additions
and
1 deletion
+1516
-1
arch/arm/configs/ntosd_644xA_defconfig
arch/arm/configs/ntosd_644xA_defconfig
+2
-1
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Kconfig
+5
-0
drivers/i2c/chips/tlv320aic23.c
drivers/i2c/chips/tlv320aic23.c
+21
-0
sound/oss/Kconfig
sound/oss/Kconfig
+13
-0
sound/oss/Makefile
sound/oss/Makefile
+1
-0
sound/oss/davinci-aic32.h
sound/oss/davinci-aic32.h
+262
-0
sound/oss/davinci-audio-aic32.c
sound/oss/davinci-audio-aic32.c
+1197
-0
sound/oss/davinci-audio.c
sound/oss/davinci-audio.c
+15
-0
No files found.
arch/arm/configs/ntosd_644xA_defconfig
View file @
6094d6e2
...
...
@@ -756,6 +756,7 @@ CONFIG_I2C_DAVINCI=y
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
CONFIG_SENSORS_TLV320AIC23=y
CONFIG_SENSORS_TLV320AIC32=y
CONFIG_SENSORS_TLV320AIC33=y
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
...
...
@@ -940,7 +941,7 @@ CONFIG_SOUND_PRIME=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_DAVINCI=y
CONFIG_SOUND_DAVINCI_AIC3
3
=y
CONFIG_SOUND_DAVINCI_AIC3
2
=y
#
# DaVinci Audio Options
...
...
drivers/i2c/chips/Kconfig
View file @
6094d6e2
...
...
@@ -123,6 +123,11 @@ config SENSORS_TLV320AIC23
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC23 audio codec.
config SENSORS_TLV320AIC32
tristate "Texas Instruments TLV320AIC32 Codec"
depends on I2C && I2C_DAVINCI
select SENSORS_TLV320AIC23
config SENSORS_TLV320AIC33
tristate "Texas Instruments TLV320AIC33 Codec"
depends on I2C && I2C_DAVINCI
...
...
drivers/i2c/chips/tlv320aic23.c
View file @
6094d6e2
...
...
@@ -107,6 +107,18 @@ int tlv320aic33_write_value(u8 reg, u16 value)
}
#endif
/* CONFIG_SENSORS_TLV320AIC33 */
#ifdef CONFIG_SENSORS_TLV320AIC32
int
tlv320aic32_write_value
(
u8
reg
,
u16
value
)
{
static
struct
i2c_client
*
client
;
u8
val
=
value
&
0xff
;
client
=
new_client
;
return
i2c_smbus_write_byte_data
(
client
,
reg
,
val
);
}
#endif
/* CONFIG_SENSORS_TLV320AIC32 */
static
int
aic23_detect_client
(
struct
i2c_adapter
*
adapter
,
int
address
,
int
kind
)
{
...
...
@@ -685,3 +697,12 @@ module_exit(aic23_exit)
EXPORT_SYMBOL
(
aic23_write_value
);
EXPORT_SYMBOL
(
aic23_power_up
);
EXPORT_SYMBOL
(
aic23_power_down
);
#ifdef CONFIG_SENSORS_TLV320AIC33
EXPORT_SYMBOL
(
tlv320aic33_write_value
);
#endif
#ifdef CONFIG_SENSORS_TLV320AIC32
EXPORT_SYMBOL
(
tlv320aic32_write_value
);
#endif
sound/oss/Kconfig
View file @
6094d6e2
...
...
@@ -661,6 +661,18 @@ config SOUND_DAVINCI
---help---
DaVinci Sound driver
choice
prompt "Sound driver"
depends on SOUND_DAVINCI
config SOUND_DAVINCI_AIC32
tristate "AIC32 Stereo Codec"
depends on SOUND_DAVINCI
select SENSORS_TLV320AIC32
---help---
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC32 audio codec.
config SOUND_DAVINCI_AIC33
tristate "AIC33 Stereo Codec"
depends on SOUND_DAVINCI
...
...
@@ -668,6 +680,7 @@ config SOUND_DAVINCI_AIC33
---help---
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC33 audio codec.
endchoice
menu "DaVinci Audio Options"
depends on SOUND_DAVINCI
...
...
sound/oss/Makefile
View file @
6094d6e2
...
...
@@ -14,6 +14,7 @@ obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o
obj-$(CONFIG_SOUND_DAVINCI)
+=
davinci-audio-dma-intfc.o davinci-audio.o
obj-$(CONFIG_SOUND_DAVINCI_AIC33)
+=
davinci-audio-aic33.o
obj-$(CONFIG_SOUND_DAVINCI_AIC32)
+=
davinci-audio-aic32.o
# Please leave it as is, cause the link order is significant !
...
...
sound/oss/davinci-aic32.h
0 → 100644
View file @
6094d6e2
/*
* linux/sound/oss/davinci-aic32.h
*
* Glue driver for AIC32 for Davinci processors
*
* Copyright (C) 2008 Neuros Technology.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef __ASM_ARCH_AIC32_H
#define __ASM_ARCH_AIC32_H
/* aic32 control registers */
#define PAGE_SELECT_REG 0
#define SOFT_RESET_REG 1
#define CODEC_SAMPLERATE_SELECT_REG 2
#define PLL_A_REG 3
#define PLL_B_REG 4
#define PLL_C_REG 5
#define PLL_D_REG 6
#define CODEC_DATAPATH_SETUP_REG 7
#define SERIAL_DATA_CTRL_REG 8
#define LEFT_ADC_GAIN_CTRL_REG 15
#define RIGHT_ADC_GAIN_CTRL_REG 16
#define MIC3_TO_LEFT_ADC_CTRL_REG 17
#define MIC3_TO_RIGHT_ADC_CTRL_REG 18
#define LINE1L_TO_LEFT_ADC_CTRL_REG 19
#define LINE1R_TO_RIGHT_ADC_CTRL_REG 22
#define MCBIAS_CTRL_REG 25
#define LEFT_AGC_CTRL_A_REG 26
#define LEFT_AGC_CTRL_B_REG 27
#define LEFT_AGC_CTRL_C_REG 28
#define RIGHT_AGC_CTRL_A_REG 29
#define RIGHT_AGC_CTRL_B_REG 30
#define RIGHT_AGC_CTRL_C_REG 31
#define DAC_POWER_CTRL_REG 37
#define OUTPUT_REDUCTION_REG 42
#define LEFT_DAC_VOLUME_CTRL_REG 43
#define RIGHT_DAC_VOLUME_CTRL_REG 44
#define DACL1_HPLOUT_VOLUME_REG 47
#define DACR1_HPLOUT_VOLUME_REG 64
#define DACL1_LEFT_LOP_VOLUME_REG 82
#define DACR1_RIGHT_LOP_VOLUME_REG 92
#define LEFTLOP_OUTPUT_LEVEL_CTRL_REG 86
#define RIGHTLOP_OUTPUT_LEVEL_CTRL_REG 93
#define HPLOUT_LEVEL_CTRL_REG 51
#define HPROUT_LEVEL_CTRL_REG 65
#define LEFTLOP_LEVEL_CTRL_REG 86
#define RIGHTLOP_LEVEL_CTRL_REG 93
/* aic32 control registers value */
#define PAGE0 0x0
/* Codec Datapath setup register 7 */
#define FS_REF_44_1 0x80
#define FS_REF_DEFAULT_48 0x00
#define ADC_DUAL_RATE_MODE 0x40
#define DAC_DUAL_RATE_MODE 0x20
#define LDAC_LCHAN 0x08
#define LDAC_RCHAN 0x10
#define LDAC_MONO_MIX 0x18
#define RDAC_RCHAN 0x02
#define RDAC_LCHAN 0x04
#define RDAC_MONO_MIX 0x06
/* soft reset control register 1 */
#define SELF_CLEAR_SOFT_RESET 0x80
/* used by register 17 */
#define MIC3L_LEFT_ADC_NOT_CONNECT 0xF0
#define MIC3R_LEFT_ADC_NOT_CONNECT 0x0F
/* used by register 18 */
#define MIC3L_RIGHT_ADC_NOT_CONNECT 0xF0
#define MIC3R_RIGHT_ADC_NOT_CONNECT 0x0F
/* used by register 19 */
#define LINE1L_NOT_CONNECT 0x78
#define LEFT_ADC_POWER_UP 0x04
/* used by register 22 */
#define LINE1R_NOT_CONNECT 0x78
#define RIGHT_ADC_POWER_UP 0x04
/* MICBIAS control register 25 */
#define MICBIAS_OUTPUT_2_0V 0x40
#define MICBIAS_OUTPUT_2_5V 0x80
#define MICBIAS_OUTPUT_AVDD 0xC0
/* output reduction register 42 */
#define OUTPUT_POWERON_DELAY 0x60
#define RAMPUP_STEP_TIME 0x0C
/* HPLCOM output level register 51 */
#define HPLCOM_OUTPUT_LEVEL 0x90
#define HPLOUT_IS_MUTE 0x08
#define HPLOUT_FULL_POWER_UP 0x01
/* HPRCOM output level register 65 */
#define HPRCOM_OUTPUT_LEVEL 0x90
#define HPROUT_IS_MUTE 0x08
#define HPROUT_FULL_POWER_UP 0x01
/* LEFT_LOP output level register 86 */
#define LEFTLOP_OUTPUT_LEVEL 0x90
#define LEFTLOP_IS_MUTE 0x08
#define LEFTLOP_FULL_POWER_UP 0x01
/* RIGHT_LOP output level register 86 */
#define RIGHTLOP_OUTPUT_LEVEL 0x90
#define RIGHTLOP_IS_MUTE 0x08
#define RIGHTLOP_FULL_POWER_UP 0x01
/* output level control register 86&93 */
#define OUTPUT_LEVEL 0x90
#define LEFTLOP_NOT_MUTE 0x80
#define LEFTLOP_FULL_POWER_UP 0x01
#define RIGHTLOP_NOT_MUTE 0x80
#define RIGHTLOP_FULL_POWER_UP 0x01
/* PLL Programming registerA 3 */
#define PLL_ENABLE 0x80
/* Audio serial data interface control registerA 8 */
#define BIT_CLK_MASTER 0x80
#define WORD_CLK_MASTER 0x40
#define DOUT_TRI_STATE 0x20
#define CLK_TRANS_MASTER 0x10
#define ENABLE_3D 0x04
#define DM_ENABLE_128 0x01
#define DM_ENABLE_64 0x02
#define DM_ENABLE_32 0x03
/*Audio serial data interface control registerB 9 */
#define DSP_MODE 0x40
#define RJ_MODE 0x80
#define LJ_MODE 0xC0
#define WORD_LENGTH20 0x10
#define WORD_LENGTH24 0x20
#define WORD_LENGTH32 0x30
#define BITCLOCK_256CLK_FRAME 0x08
/*Left/Right ADC PGA gain control register 15 & 16 */
#define ADC_PGA_MUTE 0x80
#define ADC_PGA_GAIN_MAX 0x78
#define ADC_PGA_GAIN_MIN 0x00
/* MIC3L/R to left/right ADC control register 17 & 18 */
#define ADCPGA_GAIN_MAX 0x00
#define MIC3L_ADCPGA_GAIN_MIN 0x80
#define MIC3L_ADCPGA_DISCONNECT 0xF0
#define MIC3R_ADCPGA_GAIN_MIN 0x08
#define MIC3R_ADCPGA_DISCONNECT 0x0F
/*LINE1L to left ADC Control Register 19 */
#define DIFF_MODE 0x80
#define LINE_ADCPGA_GAIN_MIN 0x40
#define LINE_ADCPGA_DISCONNECT 0x78
#define ADC_CHAN_ON 0x04
#define ADCPGA_SOFT_STEP2FS 0x01
#define ADCPGA_SOFT_STEP_OFF 0x03
/*LINE2L to left ADC Control Register 20 */
#define ADC_WEAK_INPUT_BIAS 0x04
/*LEFT/RIGHT AGC Control registerA 26 & 29 */
#define AGC_ENABLE 0x80
#define AGC_TARGET_GAIN_MAX 0x00
#define AGC_TARGET_GAIN_MIN 0x70
#define AGC_ATTACK_TIME_11 0x04
#define AGC_ATTACK_TIME_16 0x08
#define AGC_ATTACK_TIME_20 0x0C
#define AGC_DECAY_TIME_200 0x01
#define AGC_DECAY_TIME_400 0x02
#define AGC_DECAY_TIME_500 0x03
/*LEFT AGC Control registerB 27 & 30 */
#define AGC_GAIN_ALLOWED_MAX 0xEE
#define AGC_GAIN_ALLOWED_MIN 0x00
/*DAC Power and output driver control register 37 */
#define LEFT_DAC_POWER_ON 0x80
#define RIGHT_DAC_POWER_ON 0x40
#define HPLCOM_INDEPENDENT 0x20
/*High Power Output Stage Control Register 40 */
#define LINE2L_BYPASS_DISABLE_DEFAULT 0x00
#define LINE2LP_BYPASS_SINGLE 0x10
#define LINE2LM_BYPASS_SINGLE 0x20
#define LINE2LPM_BYPASS_DIFFERENTIAL 0x30
#define LINE2R_BYPASS_DISABLE_DEFAULT 0x00
#define LINE2RP_BYPASS_SINGLE 0x04
#define LINE2RM_BYPASS_SINGLE 0x08
#define LINE2RPM_BYPASS_DIFFERENTIAL 0x0C
/*DAC Output Switching Control Register 41 */
#define LEFT_DAC_DEFAULT_L1 0x00
#define LEFT_DAC_L2 0x80
#define LEFT_DAC_L3 0x40
#define RIGHT_DAC_DEFAULT_R1 0x00
#define RIGHT_DAC_R2 0x08
#define RIGHT_DAC_R3 0x04
/*LEFT/RIGHT DAC Digital volume control register 43 & 44 */
#define DAC_CHAN_MUTE 0x80
#define DAC_DIG_VOL_GAIN_MAX 0x00
/* 0.0db */
#define DAC_DIG_VOL_GAIN_MIN 0x7F
/* -63.5db */
/*LINE2L to HPLOUT Volume Control Register 45 */
#define LINE2L_HPLOUT_ROUTED 0x80
/*PGA_L to HPLOUT Volume Control Register 46 */
#define PGAL_HPLOUT_ROUTED 0x80
/*any to LOP/M Volume control */
#define LOPM_ON 0x80
#define LOPM_VOL_GAIN_MAX 0x00
/*0 db */
#define LOPM_VOL_GAIN_MIN 0x76
/*-78.3 db is MUTE */
/*MONO_LOP/M output level volume control register 79 */
#define LOPM_POWER_ON 0x01
#define LOPM_MUTE_OFF 0x08
#define LOPM_OUTPUT_LEVEL_MIN 0x00
#define LOPM_OUTPUT_LEVEL_MAX 0x90
/*Module Power Status Register 94 */
#define HPROUT_DRIVER_POWER_ON 0x02
#define LIV_MAX 0x0077
#define LIV_MIN 0x0000
#define LHV_MAX 0x0077
#define LHV_MIN 0x0000
#define LIG_MAX 0x0077
#define LIG_MIN 0x0000
#define LOG_MAX 0x007f
#define LOG_MIN 0x0000
#endif
/* __ASM_ARCH_AIC32_H */
sound/oss/davinci-audio-aic32.c
0 → 100644
View file @
6094d6e2
/*
* linux/sound/oss/davinci-audio-aic32.c
*
* Glue driver for AIC32 for Davinci processors
*
* Copyright (C) 2008 Neuros Technology.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/errno.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/clk.h>
#include <sound/davincisound.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/mcbsp.h>
#include "davinci-aic32.h"
#include "davinci-audio.h"
#include "davinci-audio-dma-intfc.h"
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#define PROC_START_FILE "driver/aic32-audio-start"
#define PROC_STOP_FILE "driver/aic32-audio-stop"
#endif
/*# define DEBUG */
#ifdef DEBUG
#define DPRINTK(ARGS...) \
do { \
printk(KERN_INFO, "<%s>: ", __FUNCTION__);\
printk(KERN_INFO, ARGS); \
} while (0)
#define FN_IN printk("<%s>: start\n", __FUNCTION__)
#else
#define DPRINTK(x...)
#define FN_IN
#endif
#define CODEC_NAME "AIC32"
#define PLATFORM_NAME "DAVINCI"
/* Define to set the AIC32 as the master w.r.t McBSP */
#define AIC32_MASTER
/* codec clock frequency */
#define MCLK 27
/*
* AUDIO related MACROS
*/
#define DEFAULT_BITPERSAMPLE 16
#define AUDIO_RATE_DEFAULT 48000
#define DEFAULT_MCBSP_CLOCK 81000000
/* Select the McBSP For Audio */
#define AUDIO_MCBSP DAVINCI_MCBSP1
#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
#define MONO 1
#define STEREO 2
#define SET_VOLUME 1
#define SET_LINE 2
#define SET_MIC 3
#define SET_RECSRC 4
#define SET_IGAIN 5
#define SET_OGAIN 6
#define SET_BASS 7
#define SET_TREBLE 8
#define SET_MICBIAS 9
#define DEFAULT_OUTPUT_VOLUME 50
#define DEFAULT_INPUT_VOLUME 20
/* 0 ==> mute line in */
#define DEFAULT_INPUT_IGAIN 20
#define DEFAULT_INPUT_OGAIN 100
#define OUTPUT_VOLUME_MIN LHV_MIN
#define OUTPUT_VOLUME_MAX LHV_MAX
#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
#define INPUT_VOLUME_MIN LIV_MIN
#define INPUT_VOLUME_MAX LIV_MAX
#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
#define INPUT_GAIN_MIN LIG_MIN
#define INPUT_GAIN_MAX LIG_MAX
#define INPUT_GAIN_RANGE (INPUT_GAIN_MAX - INPUT_GAIN_MIN)
#define OUTPUT_GAIN_MIN LOG_MIN
#define OUTPUT_GAIN_MAX LOG_MAX
#define OUTPUT_GAIN_RANGE (INPUT_GAIN_MAX - INPUT_GAIN_MIN)
#define NUMBER_SAMPLE_RATES_SUPPORTED 11
#define MSB8BIT(x) ((unsigned char)((x) >> 6))
#define LSB6BIT(x) ((unsigned char)((x) << 2))
#define CLK_OUT0_FUNCTION_BIT 16
#define ASP_FUNCTION_BIT 10
#define SET_BIT(addr, bit) outl(inl(addr) | (1U << bit), addr)
#define CLEAR_BIT(addr, bit) outl(inl(addr) & ~(1U << bit), addr)
#define PINMUX1 0x01C40004
static
audio_stream_t
output_stream
=
{
.
id
=
"AIC32 out"
,
.
dma_dev
=
DAVINCI_DMA_MCBSP1_TX
,
.
input_or_output
=
FMODE_WRITE
};
static
audio_stream_t
input_stream
=
{
.
id
=
"AIC32 in"
,
.
dma_dev
=
DAVINCI_DMA_MCBSP1_RX
,
.
input_or_output
=
FMODE_READ
};
static
int
audio_dev_id
,
mixer_dev_id
;
static
struct
aic32_local_info
{
u8
volume
;
u16
volume_reg
;
u8
line
;
u8
mic
;
int
recsrc
;
int
nochan
;
u8
igain
;
u8
ogain
;
u8
micbias
;
u8
bass
;
u8
treble
;
u16
input_volume_reg
;
int
mod_cnt
;
}
aic32_local
;
struct
sample_rate_reg_info
{
u32
sample_rate
;
u32
Fsref
;
float
divider
;
u8
data
;
};
/* To Store the default sample rate */
static
long
audio_samplerate
=
AUDIO_RATE_DEFAULT
;
struct
clk
*
davinci_mcbsp_get_clock
(
void
);
/* DAC USB-mode sampling rates*/
static
const
struct
sample_rate_reg_info
reg_info
[
NUMBER_SAMPLE_RATES_SUPPORTED
]
=
{
/* {sample_rate, Fsref, divider, data}*/
{
96000
,
96000
,
1
,
0x00
},
{
88200
,
88200
,
1
,
0x00
},
{
48000
,
48000
,
1
,
0x00
},
{
44100
,
44100
,
1
,
0x00
},
{
32000
,
48000
,
1
.
5
,
0x11
},
{
24000
,
96000
,
4
,
0x66
},
{
22050
,
44100
,
2
,
0x22
},
{
16000
,
48000
,
3
,
0x44
},
{
12000
,
48000
,
4
,
0x66
},
{
11025
,
44100
,
4
,
0x66
},
{
8000
,
48000
,
6
,
0xAA
},
};
static
struct
davinci_mcbsp_reg_cfg
initial_config
=
{
.
spcr2
=
FREE
|
XINTM
(
3
),
.
spcr1
=
RINTM
(
3
),
.
rcr2
=
RWDLEN2
(
DAVINCI_MCBSP_WORD_16
)
|
RDATDLY
(
1
),
.
rcr1
=
RFRLEN1
(
1
)
|
RWDLEN1
(
DAVINCI_MCBSP_WORD_16
),
.
xcr2
=
XWDLEN2
(
DAVINCI_MCBSP_WORD_16
)
|
XDATDLY
(
1
)
|
XFIG
,
.
xcr1
=
XFRLEN1
(
1
)
|
XWDLEN1
(
DAVINCI_MCBSP_WORD_16
),
.
srgr1
=
FWID
(
DEFAULT_BITPERSAMPLE
-
1
),
.
srgr2
=
FSGM
|
FPER
(
DEFAULT_BITPERSAMPLE
*
2
-
1
),
#ifndef AIC32_MASTER
/* configure McBSP to be the I2S master */
.
pcr0
=
FSXM
|
FSRM
|
CLKXM
|
CLKRM
|
CLKXP
|
CLKRP
,
#else
/* configure McBSP to be the I2S slave */
.
pcr0
=
CLKXP
|
CLKRP
,
#endif
/* AIC32_MASTER */
};
static
void
davinci_aic32_initialize
(
void
*
dummy
);
static
void
davinci_aic32_shutdown
(
void
*
dummy
);
static
int
davinci_aic32_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
);
static
int
davinci_aic32_probe
(
void
);
#ifdef MODULE
static
void
davinci_aic32_remove
(
void
);
#endif
static
int
davinci_aic32_suspend
(
void
);
static
int
davinci_aic32_resume
(
void
);
static
inline
void
davinci_enable_mclk
(
void
);
static
inline
void
davinci_disable_mclk
(
void
);
static
inline
void
aic32_configure
(
void
);
static
int
mixer_open
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
mixer_release
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
mixer_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
);
#ifdef CONFIG_PROC_FS
static
int
codec_start
(
char
*
buf
,
char
**
start
,
off_t
offset
,
int
count
,
int
*
eof
,
void
*
data
);
static
int
codec_stop
(
char
*
buf
,
char
**
start
,
off_t
offset
,
int
count
,
int
*
eof
,
void
*
data
);
#endif
/* File Op structure for mixer */
static
struct
file_operations
davinci_mixer_fops
=
{
.
open
=
mixer_open
,
.
release
=
mixer_release
,
.
ioctl
=
mixer_ioctl
,
.
owner
=
THIS_MODULE
};
/* To store characteristic info regarding the codec for the audio driver */
static
audio_state_t
aic32_state
=
{
.
owner
=
THIS_MODULE
,
.
output_stream
=
&
output_stream
,
.
input_stream
=
&
input_stream
,
/* .need_tx_for_rx = 1, //Once the Full Duplex works */
.
need_tx_for_rx
=
0
,
.
hw_init
=
davinci_aic32_initialize
,
.
hw_shutdown
=
davinci_aic32_shutdown
,
.
client_ioctl
=
davinci_aic32_ioctl
,
.
hw_probe
=
davinci_aic32_probe
,
.
hw_remove
=
__exit_p
(
davinci_aic32_remove
),
.
hw_suspend
=
davinci_aic32_suspend
,
.
hw_resume
=
davinci_aic32_resume
,
.
sem
=
__SEMAPHORE_INIT
(
aic32_state
.
sem
,
1
),
};
/* This will be defined in the audio.h */
static
struct
file_operations
*
davinci_audio_fops
;
int
tlv320aic32_write_value
(
u8
reg
,
u16
value
);
/* TLV320AIC32 write */
static
__inline__
void
audio_aic32_write
(
u8
address
,
u16
data
)
{
if
(
tlv320aic32_write_value
(
address
,
data
)
<
0
)
printk
(
KERN_INFO
"aic32 write failed for reg = %d
\n
"
,
address
);
}
static
int
aic32_update
(
int
flag
,
int
val
)
{
u16
volume
;
u16
gain
;
/* Ignore separate left/right channel for now,
even the codec does support it. */
val
&=
0xff
;
switch
(
flag
)
{
case
SET_VOLUME
:
if
(
val
<
0
||
val
>
100
)
{
DPRINTK
(
"Trying a bad volume value(%d)!
\n
"
,
val
);
return
-
EPERM
;
}
volume
=
((
val
*
OUTPUT_VOLUME_RANGE
)
/
100
)
+
OUTPUT_VOLUME_MIN
;
aic32_local
.
volume_reg
=
OUTPUT_VOLUME_MAX
-
volume
;
audio_aic32_write
(
DACL1_HPLOUT_VOLUME_REG
,
LOPM_ON
|
aic32_local
.
volume_reg
);
audio_aic32_write
(
DACR1_HPLOUT_VOLUME_REG
,
LOPM_ON
|
aic32_local
.
volume_reg
);
audio_aic32_write
(
DACL1_LEFT_LOP_VOLUME_REG
,
LOPM_ON
|
aic32_local
.
volume_reg
);
audio_aic32_write
(
DACR1_RIGHT_LOP_VOLUME_REG
,
LOPM_ON
|
aic32_local
.
volume_reg
);
break
;
case
SET_LINE
:
case
SET_MIC
:
if
(
val
<
0
||
val
>
100
)
{
DPRINTK
(
"Trying a bad volume value(%d)!
\n
"
,
val
);
return
-
EPERM
;
}
volume
=
((
val
*
INPUT_VOLUME_RANGE
)
/
100
)
+
INPUT_VOLUME_MIN
;
aic32_local
.
input_volume_reg
=
volume
;
audio_aic32_write
(
LEFT_ADC_GAIN_CTRL_REG
,
aic32_local
.
input_volume_reg
);
audio_aic32_write
(
RIGHT_ADC_GAIN_CTRL_REG
,
aic32_local
.
input_volume_reg
);
break
;
case
SET_RECSRC
:
if
(
hweight32
(
val
)
>
1
)
val
&=
~
aic32_local
.
recsrc
;
if
(
val
==
SOUND_MASK_MIC
)
{
/* enable the mic input*/
DPRINTK
(
"Enabling mic
\n
"
);
audio_aic32_write
(
MIC3_TO_LEFT_ADC_CTRL_REG
,
0x0
);
audio_aic32_write
(
MIC3_TO_RIGHT_ADC_CTRL_REG
,
0x0
);
/* enable ADC's and disable the line input*/
audio_aic32_write
(
LINE1L_TO_LEFT_ADC_CTRL_REG
,
LINE1L_NOT_CONNECT
|
LEFT_ADC_POWER_UP
);
audio_aic32_write
(
LINE1R_TO_RIGHT_ADC_CTRL_REG
,
LINE1R_NOT_CONNECT
|
RIGHT_ADC_POWER_UP
);
}
else
if
(
val
==
SOUND_MASK_LINE
)
{
/* enable ADC's, enable line iput */
DPRINTK
(
" Enabling line in
\n
"
);
audio_aic32_write
(
LINE1L_TO_LEFT_ADC_CTRL_REG
,
LEFT_ADC_POWER_UP
);
audio_aic32_write
(
LINE1R_TO_RIGHT_ADC_CTRL_REG
,
RIGHT_ADC_POWER_UP
);
/* disable the mic input */
audio_aic32_write
(
MIC3_TO_LEFT_ADC_CTRL_REG
,
MIC3L_LEFT_ADC_NOT_CONNECT
|
MIC3R_LEFT_ADC_NOT_CONNECT
);
audio_aic32_write
(
MIC3_TO_RIGHT_ADC_CTRL_REG
,
MIC3L_RIGHT_ADC_NOT_CONNECT
|
MIC3R_RIGHT_ADC_NOT_CONNECT
);
}
aic32_local
.
recsrc
=
val
;
break
;
case
SET_IGAIN
:
if
(
val
<
0
||
val
>
100
)
{
DPRINTK
(
"Trying a bad igain value(%d)!
\n
"
,
val
);
return
-
EPERM
;
}
gain
=
((
val
*
INPUT_GAIN_RANGE
)
/
100
)
+
INPUT_GAIN_MIN
;
DPRINTK
(
"gain reg val = 0x%x"
,
gain
<<
1
);
/* Left AGC control */
audio_aic32_write
(
LEFT_AGC_CTRL_A_REG
,
AGC_ENABLE
);
audio_aic32_write
(
LEFT_AGC_CTRL_B_REG
,
gain
<<
1
);
audio_aic32_write
(
LEFT_AGC_CTRL_C_REG
,
0x0
);
/* Right AGC control */
audio_aic32_write
(
RIGHT_AGC_CTRL_A_REG
,
AGC_ENABLE
);
audio_aic32_write
(
RIGHT_AGC_CTRL_B_REG
,
gain
<<
1
);
audio_aic32_write
(
RIGHT_AGC_CTRL_C_REG
,
0x0
);
break
;
case
SET_OGAIN
:
if
(
val
<
0
||
val
>
100
)
{
DPRINTK
(
"Trying a bad igain value(%d)!
\n
"
,
val
);
return
-
EPERM
;
}
gain
=
((
val
*
OUTPUT_GAIN_RANGE
)
/
100
)
+
OUTPUT_GAIN_MIN
;
gain
=
OUTPUT_GAIN_MAX
-
gain
;
/* Left/Right DAC digital volume gain */
audio_aic32_write
(
LEFT_DAC_VOLUME_CTRL_REG
,
gain
);
audio_aic32_write
(
RIGHT_DAC_VOLUME_CTRL_REG
,
gain
);
break
;
case
SET_MICBIAS
:
if
(
val
<
0
||
val
>
3
)
{
DPRINTK
(
"Request for non supported mic bias level(%d)!
\n
"
,
val
);
return
-
EPERM
;
}
if
(
val
==
0
)
audio_aic32_write
(
MCBIAS_CTRL_REG
,
0x00
);
else
if
(
val
==
1
)
audio_aic32_write
(
MCBIAS_CTRL_REG
,
MICBIAS_OUTPUT_2_0V
);
else
if
(
val
==
2
)
audio_aic32_write
(
MCBIAS_CTRL_REG
,
MICBIAS_OUTPUT_2_5V
);
else
if
(
val
==
3
)
audio_aic32_write
(
MCBIAS_CTRL_REG
,
MICBIAS_OUTPUT_AVDD
);
break
;
case
SET_BASS
:
break
;
case
SET_TREBLE
:
break
;
}
return
0
;
}
static
int
mixer_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* Any mixer specific initialization */
return
0
;
}
static
int
mixer_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* Any mixer specific Un-initialization */
return
0
;
}
static
int
mixer_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
)
{
int
val
;
int
ret
=
0
;
int
nr
=
_IOC_NR
(
cmd
);
/*
* We only accept mixer (type 'M') ioctls.
*/
if
(
_IOC_TYPE
(
cmd
)
!=
'M'
)
return
-
EINVAL
;
DPRINTK
(
" 0x%08x
\n
"
,
cmd
);
if
(
cmd
==
SOUND_MIXER_INFO
)
{
struct
mixer_info
mi
;
strncpy
(
mi
.
id
,
"AIC32"
,
sizeof
(
mi
.
id
));
strncpy
(
mi
.
name
,
"TI AIC32"
,
sizeof
(
mi
.
name
));
mi
.
modify_counter
=
aic32_local
.
mod_cnt
;
return
copy_to_user
((
void
*
)
arg
,
&
mi
,
sizeof
(
mi
));
}
if
(
_IOC_DIR
(
cmd
)
&
_IOC_WRITE
)
{
ret
=
get_user
(
val
,
(
int
*
)
arg
);
if
(
ret
)
goto
out
;
switch
(
nr
)
{
case
SOUND_MIXER_VOLUME
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_VOLUME
,
val
);
if
(
!
ret
)
aic32_local
.
volume
=
val
;
break
;
case
SOUND_MIXER_LINE
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_LINE
,
val
);
if
(
!
ret
)
aic32_local
.
line
=
val
;
break
;
case
SOUND_MIXER_MIC
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_MIC
,
val
);
if
(
!
ret
)
aic32_local
.
mic
=
val
;
break
;
case
SOUND_MIXER_RECSRC
:
if
((
val
&
SOUND_MASK_LINE
)
||
(
val
&
SOUND_MASK_MIC
))
{
if
(
aic32_local
.
recsrc
!=
val
)
{
aic32_local
.
mod_cnt
++
;
aic32_update
(
SET_RECSRC
,
val
);
}
}
else
ret
=
-
EINVAL
;
break
;
case
SOUND_MIXER_BASS
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_BASS
,
val
);
if
(
!
ret
)
aic32_local
.
bass
=
val
;
break
;
case
SOUND_MIXER_TREBLE
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_TREBLE
,
val
);
if
(
!
ret
)
aic32_local
.
treble
=
val
;
break
;
case
SOUND_MIXER_IGAIN
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_IGAIN
,
val
);
if
(
!
ret
)
aic32_local
.
igain
=
val
;
break
;
case
SOUND_MIXER_OGAIN
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_OGAIN
,
val
);
if
(
!
ret
)
aic32_local
.
ogain
=
val
;
break
;
case
SOUND_MIXER_MICBIAS
:
aic32_local
.
mod_cnt
++
;
ret
=
aic32_update
(
SET_MICBIAS
,
val
);
if
(
!
ret
)
aic32_local
.
micbias
=
val
;
break
;
default:
ret
=
-
EINVAL
;
}
}
if
(
ret
==
0
&&
_IOC_DIR
(
cmd
)
&
_IOC_READ
)
{
ret
=
0
;
switch
(
nr
)
{
case
SOUND_MIXER_VOLUME
:
val
=
aic32_local
.
volume
;
break
;
case
SOUND_MIXER_LINE
:
val
=
aic32_local
.
line
;
break
;
case
SOUND_MIXER_MIC
:
val
=
aic32_local
.
mic
;
break
;
case
SOUND_MIXER_RECSRC
:
val
=
aic32_local
.
recsrc
;
break
;
case
SOUND_MIXER_RECMASK
:
val
=
REC_MASK
;
break
;
case
SOUND_MIXER_IGAIN
:
val
=
aic32_local
.
igain
;
break
;
case
SOUND_MIXER_OGAIN
:
val
=
aic32_local
.
ogain
;
break
;
case
SOUND_MIXER_DEVMASK
:
val
=
DEV_MASK
;
break
;
case
SOUND_MIXER_BASS
:
val
=
aic32_local
.
bass
;
break
;
case
SOUND_MIXER_TREBLE
:
val
=
aic32_local
.
treble
;
break
;
case
SOUND_MIXER_CAPS
:
val
=
0
;
break
;
case
SOUND_MIXER_STEREODEVS
:
val
=
SOUND_MASK_VOLUME
;
break
;
case
SOUND_MIXER_MICBIAS
:
val
=
aic32_local
.
micbias
;
break
;
default:
val
=
0
;
ret
=
-
EINVAL
;
break
;
}
if
(
ret
==
0
)
ret
=
put_user
(
val
,
(
int
*
)
arg
);
}
out:
return
ret
;
}
int
davinci_set_samplerate
(
long
sample_rate
)
{
u8
count
=
0
;
/* wait for any frame to complete */
udelay
(
125
);
/* Search for the right sample rate */
while
((
reg_info
[
count
].
sample_rate
!=
sample_rate
)
&&
(
count
<
NUMBER_SAMPLE_RATES_SUPPORTED
))
count
++
;
if
(
count
==
NUMBER_SAMPLE_RATES_SUPPORTED
)
{
DPRINTK
(
"Invalid Sample Rate %d requested
\n
"
,
(
int
)
sample_rate
);
return
-
EPERM
;
}
/* CODEC DATAPATH SETUP */
/* Fsref to 48kHz, dual rate mode upto 96kHz */
if
(
reg_info
[
count
].
Fsref
==
96000
)
audio_aic32_write
(
CODEC_DATAPATH_SETUP_REG
,
FS_REF_DEFAULT_48
|
ADC_DUAL_RATE_MODE
|
DAC_DUAL_RATE_MODE
|
LDAC_LCHAN
|
RDAC_RCHAN
);
/* Fsref to 44.1kHz, dual rate mode upto 88.2kHz */
else
if
(
reg_info
[
count
].
Fsref
==
88200
)
audio_aic32_write
(
CODEC_DATAPATH_SETUP_REG
,
FS_REF_44_1
|
ADC_DUAL_RATE_MODE
|
DAC_DUAL_RATE_MODE
|
LDAC_LCHAN
|
RDAC_RCHAN
);
/* Fsref to 48kHz */
else
if
(
reg_info
[
count
].
Fsref
==
48000
)
audio_aic32_write
(
CODEC_DATAPATH_SETUP_REG
,
FS_REF_DEFAULT_48
|
LDAC_LCHAN
|
RDAC_RCHAN
);
/* Fsref to 44.1kHz */
else
if
(
reg_info
[
count
].
Fsref
==
44100
)
audio_aic32_write
(
CODEC_DATAPATH_SETUP_REG
,
FS_REF_44_1
|
LDAC_LCHAN
|
RDAC_RCHAN
);
/* Codec sample rate select */
audio_aic32_write
(
CODEC_SAMPLERATE_SELECT_REG
,
reg_info
[
count
].
data
);
/* If PLL is to be used for generation of Fsref
Generate the Fsref using the PLL */
#if (MCLK == 33)
if
((
reg_info
[
count
].
Fsref
==
96000
)
|
(
reg_info
[
count
].
Fsref
==
48000
))
{
/* For MCLK = 33.8688 MHz and to get Fsref = 48kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 2, R= 1, K = 5.8049,
which results in J = 5, D = 8049 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x10
|
0x02
);
audio_aic32_write
(
PLL_B_REG
,
0x14
);
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
8049
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
8049
));
/* D-value 6-LSB's */
}
else
if
((
reg_info
[
count
].
Fsref
==
88200
)
|
(
reg_info
[
count
].
Fsref
==
44100
))
{
/* MCLK = 33.8688 MHz and to get Fsref = 44.1kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 2, R =1, K = 5.3333,
which results in J = 5, D = 3333 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x10
|
0x02
);
audio_aic32_write
(
PLL_B_REG
,
(
5
<<
2
));
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
3333
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
3333
));
/* D-value 6-LSB's */
}
#elif(MCLK == 22)
if
((
reg_info
[
count
].
Fsref
==
96000
)
|
(
reg_info
[
count
].
Fsref
==
48000
))
{
/* For MCLK = 22.5792 MHz and to get Fsref = 48kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 2, R= 1, K = 8.7075,
which results in J = 8, D = 7075 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x10
|
0x02
);
audio_aic32_write
(
PLL_B_REG
,
(
8
<<
2
));
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
7075
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
7075
));
/* D-value 6-LSB's */
}
else
if
((
reg_info
[
count
].
Fsref
==
88200
)
|
(
reg_info
[
count
].
Fsref
==
44100
))
{
/* MCLK = 22.5792 MHz and to get Fsref = 44.1kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 2, R =1, K = 8.0000,
which results in J = 8, D = 0000 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x10
|
0x02
);
audio_aic32_write
(
PLL_B_REG
,
(
8
<<
2
));
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
0x00
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
0x00
));
/* D-value 6-LSB's */
}
#elif(MCLK == 27)
if
((
reg_info
[
count
].
Fsref
==
96000
)
|
(
reg_info
[
count
].
Fsref
==
48000
))
{
/* For MCLK = 27 MHz and to get Fsref = 48kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 1, R= 1, K = 7.2817,
which results in J = 3, D = 6408 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x01
);
audio_aic32_write
(
PLL_B_REG
,
(
3
<<
2
));
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
6408
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
6408
));
/* D-value 6-LSB's */
}
else
if
((
reg_info
[
count
].
Fsref
==
88200
)
|
(
reg_info
[
count
].
Fsref
==
44100
))
{
/* MCLK = 27 MHz and to get Fsref = 44.1kHz
Fsref = (MCLK * k * R)/(2048 * p);
Select P = 1, R =1, K = 3.3450,
which results in J = 3, D = 3450 */
/*Enable the PLL | Q-value | P-value */
audio_aic32_write
(
PLL_A_REG
,
PLL_ENABLE
|
0x01
);
audio_aic32_write
(
PLL_B_REG
,
(
3
<<
2
));
/* J-value */
audio_aic32_write
(
PLL_C_REG
,
MSB8BIT
(
3450
));
/* D-value 8-MSB's */
audio_aic32_write
(
PLL_D_REG
,
LSB6BIT
(
3450
));
/* D-value 6-LSB's */
}
#else
#error "unknown audio codec frequency"
#endif
audio_samplerate
=
sample_rate
;
#ifndef AIC32_MASTER
{
int
clkgdv
=
0
;
unsigned
long
clkval
=
0
;
struct
clk
*
mbspclk
;
/*
Set Sample Rate at McBSP
Formula :
Codec System Clock = Input clock to McBSP;
clkgdv = ((Codec System Clock /
(SampleRate * BitsPerSample * 2)) - 1);
FWID = BitsPerSample - 1;
FPER = (BitsPerSample * 2) - 1;
*/
mbspclk
=
davinci_mcbsp_get_clock
();
if
(
mbspclk
==
NULL
)
{
DPRINTK
(
" Failed to get internal clock to MCBSP"
);
return
-
EPERM
;
}
clkval
=
clk_get_rate
(
mbspclk
);
DPRINTK
(
"mcbsp_clk = %ld
\n
"
,
clkval
);
if
(
clkval
)
clkgdv
=
(
clkval
/
(
sample_rate
*
DEFAULT_BITPERSAMPLE
*
2
))
-
1
;
else
{
DPRINTK
(
" Failed to get the MCBSP clock
\n
"
);
return
-
EPERM
;
}
DPRINTK
(
"clkgdv = %d
\n
"
,
clkgdv
);
if
(
clkgdv
>
255
||
clkgdv
<
0
)
{
/* For requested sampling rate, the input clock to MCBSP
cant be devided down to get the in range clock
devider value for 16 bits sample */
DPRINTK
(
"Invalid Sample Rate %d requested
\n
"
,
(
int
)
sample_rate
);
return
-
EPERM
;
}
initial_config
.
srgr1
=
(
FWID
(
DEFAULT_BITPERSAMPLE
-
1
)
|
CLKGDV
(
clkgdv
));
initial_config
.
srgr2
=
(
CLKSM
|
FSGM
|
FPER
(
DEFAULT_BITPERSAMPLE
*
2
-
1
));
davinci_mcbsp_stop
(
AUDIO_MCBSP
);
davinci_mcbsp_config
(
AUDIO_MCBSP
,
&
initial_config
);
}
#endif
/* AIC32_MASTER */
return
0
;
}
static
inline
void
davinci_enable_mclk
(
void
)
{
/* Enable CLK_OUT0 function on default GPIO[48] pin */
SET_BIT
(
IO_ADDRESS
(
PINMUX1
),
CLK_OUT0_FUNCTION_BIT
);
/* Enable ASP function on default GPIO[29:34] pins */
SET_BIT
(
IO_ADDRESS
(
PINMUX1
),
ASP_FUNCTION_BIT
);
}
static
inline
void
davinci_disable_mclk
(
void
)
{
/* Disbale ASP function on default GPIO[29:34] pins */
CLEAR_BIT
(
IO_ADDRESS
(
PINMUX1
),
ASP_FUNCTION_BIT
);
/* Disbale CLK_OUT0 function on default GPIO[48] pin */
CLEAR_BIT
(
IO_ADDRESS
(
PINMUX1
),
CLK_OUT0_FUNCTION_BIT
);
}
static
void
davinci_aic32_shutdown
(
void
*
dummy
)
{
/*
Turn off codec after it is done.
Can't do it immediately, since it may still have
buffered data.
Wait 20ms (arbitrary value) and then turn it off.
*/
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
2
);
davinci_mcbsp_stop
(
AUDIO_MCBSP
);
davinci_mcbsp_free
(
AUDIO_MCBSP
);
/* Self clearing aic32 software reset */
audio_aic32_write
(
SOFT_RESET_REG
,
SELF_CLEAR_SOFT_RESET
);
davinci_disable_mclk
();
}
static
void
davinci_set_mono_stereo
(
int
mode
)
{
if
(
mode
==
MONO
)
{
/* Driver power ON pop control */
audio_aic32_write
(
OUTPUT_REDUCTION_REG
,
OUTPUT_POWERON_DELAY
|
RAMPUP_STEP_TIME
);
/* LEFT_LOP/M, RIGHT_LOP/M output level control */
audio_aic32_write
(
LEFTLOP_OUTPUT_LEVEL_CTRL_REG
,
OUTPUT_LEVEL
|
LEFTLOP_NOT_MUTE
|
LEFTLOP_FULL_POWER_UP
);
audio_aic32_write
(
RIGHTLOP_OUTPUT_LEVEL_CTRL_REG
,
OUTPUT_LEVEL
|
RIGHTLOP_NOT_MUTE
|
RIGHTLOP_FULL_POWER_UP
);
/* Left DAC power up, Right DAC power down */
audio_aic32_write
(
DAC_POWER_CTRL_REG
,
LEFT_DAC_POWER_ON
|
HPLCOM_INDEPENDENT
);
}
else
if
(
mode
==
STEREO
)
{
/* Driver power ON pop control */
audio_aic32_write
(
OUTPUT_REDUCTION_REG
,
OUTPUT_POWERON_DELAY
|
RAMPUP_STEP_TIME
);
/* HPLOUT/HPROUT output level control */
audio_aic32_write
(
HPLOUT_LEVEL_CTRL_REG
,
HPLCOM_OUTPUT_LEVEL
|
HPLOUT_IS_MUTE
|
HPLOUT_FULL_POWER_UP
);
audio_aic32_write
(
HPROUT_LEVEL_CTRL_REG
,
HPRCOM_OUTPUT_LEVEL
|
HPROUT_IS_MUTE
|
HPROUT_FULL_POWER_UP
);
/* LEFT_LOP/M, RIGHT_LOP/M output level control */
audio_aic32_write
(
LEFTLOP_LEVEL_CTRL_REG
,
LEFTLOP_OUTPUT_LEVEL
|
LEFTLOP_IS_MUTE
|
LEFTLOP_FULL_POWER_UP
);
audio_aic32_write
(
RIGHTLOP_LEVEL_CTRL_REG
,
RIGHTLOP_OUTPUT_LEVEL
|
RIGHTLOP_IS_MUTE
|
RIGHTLOP_FULL_POWER_UP
);
/* Left/Right DAC power up */
audio_aic32_write
(
DAC_POWER_CTRL_REG
,
LEFT_DAC_POWER_ON
|
RIGHT_DAC_POWER_ON
|
HPLCOM_INDEPENDENT
);
}
else
DPRINTK
(
" REQUEST FOR INVALID MODE
\n
"
);
}
static
inline
void
aic32_configure
()
{
FN_IN
;
/* Page select register */
audio_aic32_write
(
PAGE_SELECT_REG
,
PAGE0
);
davinci_set_mono_stereo
(
aic32_local
.
nochan
);
#ifdef AIC32_MASTER
/* Enable bit and word clock as Master mode, 3-d disabled */
audio_aic32_write
(
SERIAL_DATA_CTRL_REG
,
BIT_CLK_MASTER
|
WORD_CLK_MASTER
);
#endif
aic32_update
(
SET_LINE
,
aic32_local
.
line
);
aic32_update
(
SET_VOLUME
,
aic32_local
.
volume
);
aic32_update
(
SET_RECSRC
,
aic32_local
.
recsrc
);
aic32_update
(
SET_IGAIN
,
aic32_local
.
igain
);
aic32_update
(
SET_OGAIN
,
aic32_local
.
ogain
);
aic32_update
(
SET_MICBIAS
,
aic32_local
.
micbias
);
}
static
void
davinci_aic32_initialize
(
void
*
dummy
)
{
FN_IN
;
/* initialize with default sample rate */
audio_samplerate
=
AUDIO_RATE_DEFAULT
;
if
(
davinci_mcbsp_request
(
AUDIO_MCBSP
)
<
0
)
{
DPRINTK
(
"MCBSP request failed
\n
"
);
return
;
}
/* if configured, then stop mcbsp */
davinci_mcbsp_stop
(
AUDIO_MCBSP
);
/* set initial (default) sample rate */
davinci_set_samplerate
(
audio_samplerate
);
davinci_mcbsp_config
(
AUDIO_MCBSP
,
&
initial_config
);
/* enable davinci MCLK */
davinci_enable_mclk
();
}
static
int
davinci_aic32_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
uint
cmd
,
ulong
arg
)
{
long
val
;
int
ret
=
0
;
DPRINTK
(
" 0x%08x
\n
"
,
cmd
);
/*
* These are platform dependent ioctls which are not handled by the
* generic davinci-audio module.
*/
switch
(
cmd
)
{
case
SNDCTL_DSP_STEREO
:
ret
=
get_user
(
val
,
(
int
*
)
arg
);
if
(
ret
)
return
ret
;
/* the Davinci supports AIC32 as stereo, mono on stereo jack */
ret
=
(
val
==
0
)
?
-
EINVAL
:
1
;
return
put_user
(
ret
,
(
int
*
)
arg
);
case
SNDCTL_DSP_CHANNELS
:
ret
=
get_user
(
val
,
(
long
*
)
arg
);
if
(
ret
)
{
DPRINTK
(
"get_user failed
\n
"
);
break
;
}
if
(
val
==
STEREO
)
{
DPRINTK
(
"Driver support for AIC32 as stereo
\n
"
);
aic32_local
.
nochan
=
STEREO
;
davinci_set_mono_stereo
(
aic32_local
.
nochan
);
}
else
if
(
val
==
MONO
)
{
DPRINTK
(
"Driver support for AIC32 as mono
\n
"
);
aic32_local
.
nochan
=
MONO
;
davinci_set_mono_stereo
(
aic32_local
.
nochan
);
}
else
{
DPRINTK
(
"Driver support for AIC32 as stereo/mono mode
\n
"
);
return
-
EPERM
;
}
case
SOUND_PCM_READ_CHANNELS
:
/* the Davinci supports AIC32 as stereo, mono on stereo jack */
if
(
aic32_local
.
nochan
==
MONO
)
return
put_user
(
MONO
,
(
long
*
)
arg
);
else
return
put_user
(
STEREO
,
(
long
*
)
arg
);
case
SNDCTL_DSP_SPEED
:
ret
=
get_user
(
val
,
(
long
*
)
arg
);
if
(
ret
)
{
DPRINTK
(
"get_user failed
\n
"
);
break
;
}
ret
=
davinci_set_samplerate
(
val
);
if
(
ret
)
{
DPRINTK
(
"davinci_set_samplerate failed
\n
"
);
break
;
}
/* fall through */
case
SOUND_PCM_READ_RATE
:
return
put_user
(
audio_samplerate
,
(
long
*
)
arg
);
case
SNDCTL_DSP_SETFMT
:
/* set Format */
ret
=
get_user
(
val
,
(
long
*
)
arg
);
if
(
ret
)
{
DPRINTK
(
"get_user failed
\n
"
);
break
;
}
if
(
val
!=
AFMT_S16_LE
)
{
DPRINTK
(
"Driver supports only AFMT_S16_LE audio format
\n
"
);
return
-
EPERM
;
}
case
SOUND_PCM_READ_BITS
:
case
SNDCTL_DSP_GETFMTS
:
/* we can do 16-bit only */
return
put_user
(
AFMT_S16_LE
,
(
long
*
)
arg
);
default:
/* Maybe this is meant for the mixer (As per OSS Docs) */
return
mixer_ioctl
(
inode
,
file
,
cmd
,
arg
);
}
return
ret
;
}
static
int
davinci_aic32_probe
(
void
)
{
/* Get the fops from audio oss driver */
davinci_audio_fops
=
audio_get_fops
();
if
(
!
davinci_audio_fops
)
{
DPRINTK
(
"Unable to get the file operations forAIC32 OSS driver
\n
"
);
audio_unregister_codec
(
&
aic32_state
);
return
-
EPERM
;
}
aic32_local
.
volume
=
DEFAULT_OUTPUT_VOLUME
;
aic32_local
.
line
=
DEFAULT_INPUT_VOLUME
;
/* either of SOUND_MASK_LINE/SOUND_MASK_MIC */
aic32_local
.
recsrc
=
SOUND_MASK_LINE
;
aic32_local
.
igain
=
DEFAULT_INPUT_IGAIN
;
aic32_local
.
ogain
=
DEFAULT_INPUT_OGAIN
;
aic32_local
.
nochan
=
STEREO
;
aic32_local
.
micbias
=
1
;
aic32_local
.
mod_cnt
=
0
;
/* register devices */
audio_dev_id
=
register_sound_dsp
(
davinci_audio_fops
,
-
1
);
mixer_dev_id
=
register_sound_mixer
(
&
davinci_mixer_fops
,
-
1
);
#ifdef CONFIG_PROC_FS
create_proc_read_entry
(
PROC_START_FILE
,
0
/* default mode */
,
NULL
/* parent dir */
,
codec_start
,
NULL
/* client data */
);
create_proc_read_entry
(
PROC_STOP_FILE
,
0
/* default mode */
,
NULL
/* parent dir */
,
codec_stop
,
NULL
/* client data */
);
#endif
/* Announcement Time */
DPRINTK
(
PLATFORM_NAME
" "
CODEC_NAME
" audio support initialized
\n
"
);
return
0
;
}
#ifdef MODULE
static
void
__exit
davinci_aic32_remove
(
void
)
{
/* Un-Register the codec with the audio driver */
unregister_sound_dsp
(
audio_dev_id
);
unregister_sound_mixer
(
mixer_dev_id
);
#ifdef CONFIG_PROC_FS
remove_proc_entry
(
PROC_START_FILE
,
NULL
);
remove_proc_entry
(
PROC_STOP_FILE
,
NULL
);
#endif
}
#endif
/* MODULE */
static
int
davinci_aic32_suspend
(
void
)
{
/* Empty for the moment */
return
0
;
}
static
int
davinci_aic32_resume
(
void
)
{
/* Empty for the moment */
return
0
;
}
static
int
__init
audio_aic32_init
(
void
)
{
int
err
=
0
;
/* register the codec with the audio driver */
err
=
audio_register_codec
(
&
aic32_state
);
if
(
err
)
{
DPRINTK
(
"Failed to register AIC32 driver with Audio OSS Driver
\n
"
);
}
else
{
DPRINTK
(
"codec driver register success
\n
"
);
}
/* configure aic32 with default params */
aic32_configure
();
return
err
;
}
static
void
__exit
audio_aic32_exit
(
void
)
{
davinci_aic32_shutdown
(
NULL
);
(
void
)
audio_unregister_codec
(
&
aic32_state
);
return
;
}
#ifdef CONFIG_PROC_FS
static
int
codec_start
(
char
*
buf
,
char
**
start
,
off_t
offset
,
int
count
,
int
*
eof
,
void
*
data
)
{
davinci_aic32_initialize
(
NULL
);
DPRINTK
(
"AIC32 codec initialization done.
\n
"
);
return
0
;
}
static
int
codec_stop
(
char
*
buf
,
char
**
start
,
off_t
offset
,
int
count
,
int
*
eof
,
void
*
data
)
{
davinci_aic32_shutdown
(
NULL
);
DPRINTK
(
"AIC32 codec shutdown.
\n
"
);
return
0
;
}
#endif
/* CONFIG_PROC_FS */
module_init
(
audio_aic32_init
);
module_exit
(
audio_aic32_exit
);
MODULE_AUTHOR
(
"Neuros Technology"
);
MODULE_DESCRIPTION
(
"Glue audio driver for the TI AIC32 codec."
);
MODULE_LICENSE
(
"GPL"
);
sound/oss/davinci-audio.c
View file @
6094d6e2
...
...
@@ -120,6 +120,8 @@ static int audio_suspend(struct platform_device *dev, pm_message_t state);
static
int
audio_resume
(
struct
platform_device
*
dev
);
static
void
audio_device_release
(
struct
device
*
dev
);
/***************************** Data Structures ********************************/
/*
...
...
@@ -160,6 +162,7 @@ static struct platform_device davinci_audio_device = {
.
name
=
DAVINCI_AUDIO_NAME
,
.
dev
=
{
.
driver_data
=
&
audio_state
,
.
release
=
&
audio_device_release
,
},
.
id
=
0
,
};
...
...
@@ -297,6 +300,18 @@ static int audio_remove(struct platform_device *dev)
return
0
;
}
/*******************************************************************************
*
* audio_device_release Fucntion to handle release operations
*
*****************************************************************************/
static
void
audio_device_release
(
struct
device
*
dev
)
{
FN_IN
;
/* do nothing */
FN_OUT
(
0
);
}
/*******************************************************************************
*
* audio_shutdown(): Function to handle shutdown operations
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment