ARM: Davinci: tlvaic32 audio oss driver support

parent 017a079d
......@@ -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_AIC33=y
CONFIG_SOUND_DAVINCI_AIC32=y
#
# DaVinci Audio Options
......
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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 !
......
/*
* 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 */
/*
* 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");
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment