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
...
@@ -756,6 +756,7 @@ CONFIG_I2C_DAVINCI=y
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_PCF8591 is not set
CONFIG_SENSORS_TLV320AIC23=y
CONFIG_SENSORS_TLV320AIC23=y
CONFIG_SENSORS_TLV320AIC32=y
CONFIG_SENSORS_TLV320AIC33=y
CONFIG_SENSORS_TLV320AIC33=y
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_SENSORS_TSL2550 is not set
...
@@ -940,7 +941,7 @@ CONFIG_SOUND_PRIME=y
...
@@ -940,7 +941,7 @@ CONFIG_SOUND_PRIME=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_DAVINCI=y
CONFIG_SOUND_DAVINCI=y
CONFIG_SOUND_DAVINCI_AIC3
3
=y
CONFIG_SOUND_DAVINCI_AIC3
2
=y
#
#
# DaVinci Audio Options
# DaVinci Audio Options
...
...
drivers/i2c/chips/Kconfig
View file @
6094d6e2
...
@@ -123,6 +123,11 @@ config SENSORS_TLV320AIC23
...
@@ -123,6 +123,11 @@ config SENSORS_TLV320AIC23
If you say yes here you get support for the I2C control
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC23 audio codec.
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
config SENSORS_TLV320AIC33
tristate "Texas Instruments TLV320AIC33 Codec"
tristate "Texas Instruments TLV320AIC33 Codec"
depends on I2C && I2C_DAVINCI
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)
...
@@ -107,6 +107,18 @@ int tlv320aic33_write_value(u8 reg, u16 value)
}
}
#endif
/* CONFIG_SENSORS_TLV320AIC33 */
#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
,
static
int
aic23_detect_client
(
struct
i2c_adapter
*
adapter
,
int
address
,
int
kind
)
int
kind
)
{
{
...
@@ -685,3 +697,12 @@ module_exit(aic23_exit)
...
@@ -685,3 +697,12 @@ module_exit(aic23_exit)
EXPORT_SYMBOL
(
aic23_write_value
);
EXPORT_SYMBOL
(
aic23_write_value
);
EXPORT_SYMBOL
(
aic23_power_up
);
EXPORT_SYMBOL
(
aic23_power_up
);
EXPORT_SYMBOL
(
aic23_power_down
);
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
...
@@ -661,6 +661,18 @@ config SOUND_DAVINCI
---help---
---help---
DaVinci Sound driver
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
config SOUND_DAVINCI_AIC33
tristate "AIC33 Stereo Codec"
tristate "AIC33 Stereo Codec"
depends on SOUND_DAVINCI
depends on SOUND_DAVINCI
...
@@ -668,6 +680,7 @@ config SOUND_DAVINCI_AIC33
...
@@ -668,6 +680,7 @@ config SOUND_DAVINCI_AIC33
---help---
---help---
If you say yes here you get support for the I2C control
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC33 audio codec.
interface for Texas Instruments TLV320AIC33 audio codec.
endchoice
menu "DaVinci Audio Options"
menu "DaVinci Audio Options"
depends on SOUND_DAVINCI
depends on SOUND_DAVINCI
...
...
sound/oss/Makefile
View file @
6094d6e2
...
@@ -14,6 +14,7 @@ obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o
...
@@ -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)
+=
davinci-audio-dma-intfc.o davinci-audio.o
obj-$(CONFIG_SOUND_DAVINCI_AIC33)
+=
davinci-audio-aic33.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 !
# 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);
...
@@ -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
int
audio_resume
(
struct
platform_device
*
dev
);
static
void
audio_device_release
(
struct
device
*
dev
);
/***************************** Data Structures ********************************/
/***************************** Data Structures ********************************/
/*
/*
...
@@ -160,6 +162,7 @@ static struct platform_device davinci_audio_device = {
...
@@ -160,6 +162,7 @@ static struct platform_device davinci_audio_device = {
.
name
=
DAVINCI_AUDIO_NAME
,
.
name
=
DAVINCI_AUDIO_NAME
,
.
dev
=
{
.
dev
=
{
.
driver_data
=
&
audio_state
,
.
driver_data
=
&
audio_state
,
.
release
=
&
audio_device_release
,
},
},
.
id
=
0
,
.
id
=
0
,
};
};
...
@@ -297,6 +300,18 @@ static int audio_remove(struct platform_device *dev)
...
@@ -297,6 +300,18 @@ static int audio_remove(struct platform_device *dev)
return
0
;
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
* 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