2006-05-20 16:04:31 -03:00
/*
* tlv320aic23b - driver version 0.0 .1
*
* Copyright ( C ) 2006 Scott Alfter < salfter @ ssai . us >
*
* Based on wm8775 driver
*
* Copyright ( C ) 2004 Ulf Eklund < ivtv at eklund . to >
* Copyright ( C ) 2005 Hans Verkuil < hverkuil @ xs4all . nl >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/ioctl.h>
# include <asm/uaccess.h>
# include <linux/i2c.h>
# include <linux/i2c-id.h>
2008-07-25 05:32:50 -03:00
# include <linux/videodev2.h>
2008-12-18 12:43:56 -03:00
# include <media/v4l2-device.h>
2009-03-07 13:10:43 -03:00
# include <media/v4l2-i2c-drv.h>
2006-05-20 16:04:31 -03:00
MODULE_DESCRIPTION ( " tlv320aic23b driver " ) ;
MODULE_AUTHOR ( " Scott Alfter, Ulf Eklund, Hans Verkuil " ) ;
MODULE_LICENSE ( " GPL " ) ;
/* ----------------------------------------------------------------------- */
struct tlv320aic23b_state {
2008-12-18 12:43:56 -03:00
struct v4l2_subdev sd ;
2006-05-20 16:04:31 -03:00
u8 muted ;
} ;
2008-12-18 12:43:56 -03:00
static inline struct tlv320aic23b_state * to_state ( struct v4l2_subdev * sd )
2006-05-20 16:04:31 -03:00
{
2008-12-18 12:43:56 -03:00
return container_of ( sd , struct tlv320aic23b_state , sd ) ;
}
static int tlv320aic23b_write ( struct v4l2_subdev * sd , int reg , u16 val )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2006-05-20 16:04:31 -03:00
int i ;
if ( ( reg < 0 | | reg > 9 ) & & ( reg ! = 15 ) ) {
2008-12-18 12:43:56 -03:00
v4l2_err ( sd , " Invalid register R%d \n " , reg ) ;
2006-05-20 16:04:31 -03:00
return - 1 ;
}
2007-11-01 07:58:17 -03:00
for ( i = 0 ; i < 3 ; i + + )
if ( i2c_smbus_write_byte_data ( client ,
( reg < < 1 ) | ( val > > 8 ) , val & 0xff ) = = 0 )
2006-05-20 16:04:31 -03:00
return 0 ;
2008-12-18 12:43:56 -03:00
v4l2_err ( sd , " I2C: cannot write %03x to register R%d \n " , val , reg ) ;
2006-05-20 16:04:31 -03:00
return - 1 ;
}
2008-12-18 12:43:56 -03:00
static int tlv320aic23b_s_clock_freq ( struct v4l2_subdev * sd , u32 freq )
2006-05-20 16:04:31 -03:00
{
2008-12-18 12:43:56 -03:00
switch ( freq ) {
case 32000 : /* set sample rate to 32 kHz */
tlv320aic23b_write ( sd , 8 , 0x018 ) ;
2006-05-20 16:04:31 -03:00
break ;
2008-12-18 12:43:56 -03:00
case 44100 : /* set sample rate to 44.1 kHz */
tlv320aic23b_write ( sd , 8 , 0x022 ) ;
2006-05-20 16:04:31 -03:00
break ;
2008-12-18 12:43:56 -03:00
case 48000 : /* set sample rate to 48 kHz */
tlv320aic23b_write ( sd , 8 , 0x000 ) ;
2006-05-20 16:04:31 -03:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2008-12-18 12:43:56 -03:00
static int tlv320aic23b_g_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
{
struct tlv320aic23b_state * state = to_state ( sd ) ;
if ( ctrl - > id ! = V4L2_CID_AUDIO_MUTE )
return - EINVAL ;
ctrl - > value = state - > muted ;
return 0 ;
}
static int tlv320aic23b_s_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
{
struct tlv320aic23b_state * state = to_state ( sd ) ;
if ( ctrl - > id ! = V4L2_CID_AUDIO_MUTE )
return - EINVAL ;
state - > muted = ctrl - > value ;
tlv320aic23b_write ( sd , 0 , 0x180 ) ; /* mute both channels */
/* set gain on both channels to +3.0 dB */
if ( ! state - > muted )
tlv320aic23b_write ( sd , 0 , 0x119 ) ;
return 0 ;
}
static int tlv320aic23b_log_status ( struct v4l2_subdev * sd )
{
struct tlv320aic23b_state * state = to_state ( sd ) ;
v4l2_info ( sd , " Input: %s \n " , state - > muted ? " muted " : " active " ) ;
return 0 ;
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
. log_status = tlv320aic23b_log_status ,
. g_ctrl = tlv320aic23b_g_ctrl ,
. s_ctrl = tlv320aic23b_s_ctrl ,
} ;
static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
. s_clock_freq = tlv320aic23b_s_clock_freq ,
} ;
static const struct v4l2_subdev_ops tlv320aic23b_ops = {
. core = & tlv320aic23b_core_ops ,
. audio = & tlv320aic23b_audio_ops ,
} ;
2006-05-20 16:04:31 -03:00
/* ----------------------------------------------------------------------- */
/* i2c implementation */
/*
* Generic i2c probe
* concerning the addresses : i2c wants 7 bit ( without the r / w bit ) , so ' > > 1 '
*/
2008-04-29 23:11:39 +02:00
static int tlv320aic23b_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2006-05-20 16:04:31 -03:00
{
struct tlv320aic23b_state * state ;
2008-12-18 12:43:56 -03:00
struct v4l2_subdev * sd ;
2006-05-20 16:04:31 -03:00
/* Check if the adapter supports the needed features */
2007-09-14 05:03:17 -03:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
2007-09-16 10:47:15 -03:00
return - EIO ;
2006-05-20 16:04:31 -03:00
2007-11-01 07:58:17 -03:00
v4l_info ( client , " chip found @ 0x%x (%s) \n " ,
client - > addr < < 1 , client - > adapter - > name ) ;
2006-05-20 16:04:31 -03:00
2008-12-18 12:43:56 -03:00
state = kzalloc ( sizeof ( struct tlv320aic23b_state ) , GFP_KERNEL ) ;
2007-11-01 07:58:17 -03:00
if ( state = = NULL )
2006-05-20 16:04:31 -03:00
return - ENOMEM ;
2008-12-18 12:43:56 -03:00
sd = & state - > sd ;
v4l2_i2c_subdev_init ( sd , client , & tlv320aic23b_ops ) ;
2006-05-20 16:04:31 -03:00
state - > muted = 0 ;
2007-11-01 07:58:17 -03:00
/* Initialize tlv320aic23b */
/* RESET */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 15 , 0x000 ) ;
2007-11-01 07:58:17 -03:00
/* turn off DAC & mic input */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 6 , 0x00A ) ;
2007-11-01 07:58:17 -03:00
/* left-justified, 24-bit, master mode */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 7 , 0x049 ) ;
2007-11-01 07:58:17 -03:00
/* set gain on both channels to +3.0 dB */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 0 , 0x119 ) ;
2007-11-01 07:58:17 -03:00
/* set sample rate to 48 kHz */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 8 , 0x000 ) ;
2007-11-01 07:58:17 -03:00
/* activate digital interface */
2008-12-18 12:43:56 -03:00
tlv320aic23b_write ( sd , 9 , 0x001 ) ;
2006-05-20 16:04:31 -03:00
return 0 ;
}
2007-09-14 05:03:17 -03:00
static int tlv320aic23b_remove ( struct i2c_client * client )
2006-05-20 16:04:31 -03:00
{
2008-12-18 12:43:56 -03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
v4l2_device_unregister_subdev ( sd ) ;
kfree ( to_state ( sd ) ) ;
2006-05-20 16:04:31 -03:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
2008-05-11 20:37:06 +02:00
static const struct i2c_device_id tlv320aic23b_id [ ] = {
{ " tlv320aic23b " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tlv320aic23b_id ) ;
2006-05-20 16:04:31 -03:00
2007-09-14 05:03:17 -03:00
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
. name = " tlv320aic23b " ,
. probe = tlv320aic23b_probe ,
. remove = tlv320aic23b_remove ,
2008-05-11 20:37:06 +02:00
. id_table = tlv320aic23b_id ,
2007-09-14 05:03:17 -03:00
} ;