2009-10-09 16:55:41 +04:00
/*
* ALSA SoC Texas Instruments TPA6130A2 headset stereo amplifier driver
*
* Copyright ( C ) Nokia Corporation
*
* Author : Peter Ujfalusi < peter . ujfalusi @ nokia . com >
*
* This program 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 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 . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*/
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/device.h>
# include <linux/i2c.h>
# include <linux/gpio.h>
2009-12-09 13:05:50 +03:00
# include <linux/regulator/consumer.h>
2009-10-09 16:55:41 +04:00
# include <sound/tpa6130a2-plat.h>
# include <sound/soc.h>
# include <sound/soc-dapm.h>
# include <sound/tlv.h>
# include "tpa6130a2.h"
2009-10-09 22:13:47 +04:00
static struct i2c_client * tpa6130a2_client ;
2009-10-09 16:55:41 +04:00
2009-12-09 13:05:50 +03:00
# define TPA6130A2_NUM_SUPPLIES 2
static const char * tpa6130a2_supply_names [ TPA6130A2_NUM_SUPPLIES ] = {
" CPVSS " ,
" Vdd " ,
} ;
2010-01-08 18:48:31 +03:00
static const char * tpa6140a2_supply_names [ TPA6130A2_NUM_SUPPLIES ] = {
" HPVdd " ,
" AVdd " ,
} ;
2009-10-09 16:55:41 +04:00
/* This struct is used to save the context */
struct tpa6130a2_data {
struct mutex mutex ;
unsigned char regs [ TPA6130A2_CACHEREGNUM ] ;
2009-12-09 13:05:50 +03:00
struct regulator_bulk_data supplies [ TPA6130A2_NUM_SUPPLIES ] ;
2009-10-09 16:55:41 +04:00
int power_gpio ;
unsigned char power_state ;
2010-05-04 12:08:18 +04:00
enum tpa_model id ;
2009-10-09 16:55:41 +04:00
} ;
static int tpa6130a2_i2c_read ( int reg )
{
struct tpa6130a2_data * data ;
int val ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
/* If powered off, return the cached value */
if ( data - > power_state ) {
val = i2c_smbus_read_byte_data ( tpa6130a2_client , reg ) ;
if ( val < 0 )
dev_err ( & tpa6130a2_client - > dev , " Read failed \n " ) ;
else
data - > regs [ reg ] = val ;
} else {
val = data - > regs [ reg ] ;
}
return val ;
}
static int tpa6130a2_i2c_write ( int reg , u8 value )
{
struct tpa6130a2_data * data ;
int val = 0 ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
if ( data - > power_state ) {
val = i2c_smbus_write_byte_data ( tpa6130a2_client , reg , value ) ;
if ( val < 0 )
dev_err ( & tpa6130a2_client - > dev , " Write failed \n " ) ;
}
/* Either powered on or off, we save the context */
data - > regs [ reg ] = value ;
return val ;
}
static u8 tpa6130a2_read ( int reg )
{
struct tpa6130a2_data * data ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
return data - > regs [ reg ] ;
}
static void tpa6130a2_initialize ( void )
{
struct tpa6130a2_data * data ;
int i ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
for ( i = 1 ; i < TPA6130A2_REG_VERSION ; i + + )
tpa6130a2_i2c_write ( i , data - > regs [ i ] ) ;
}
2009-12-09 13:05:50 +03:00
static int tpa6130a2_power ( int power )
2009-10-09 16:55:41 +04:00
{
struct tpa6130a2_data * data ;
u8 val ;
2009-12-09 13:05:50 +03:00
int ret ;
2009-10-09 16:55:41 +04:00
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
mutex_lock ( & data - > mutex ) ;
if ( power ) {
/* Power on */
2009-12-09 13:05:50 +03:00
if ( data - > power_gpio > = 0 )
2009-10-09 16:55:41 +04:00
gpio_set_value ( data - > power_gpio , 1 ) ;
2009-12-09 13:05:50 +03:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( data - > supplies ) ,
data - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( & tpa6130a2_client - > dev ,
" Failed to enable supplies: %d \n " , ret ) ;
goto exit ;
2009-10-09 16:55:41 +04:00
}
2009-12-09 13:05:50 +03:00
data - > power_state = 1 ;
tpa6130a2_initialize ( ) ;
2009-10-09 16:55:41 +04:00
/* Clear SWS */
val = tpa6130a2_read ( TPA6130A2_REG_CONTROL ) ;
val & = ~ TPA6130A2_SWS ;
tpa6130a2_i2c_write ( TPA6130A2_REG_CONTROL , val ) ;
} else {
/* set SWS */
val = tpa6130a2_read ( TPA6130A2_REG_CONTROL ) ;
val | = TPA6130A2_SWS ;
tpa6130a2_i2c_write ( TPA6130A2_REG_CONTROL , val ) ;
2009-12-09 13:05:50 +03:00
2009-10-09 16:55:41 +04:00
/* Power off */
2009-12-09 13:05:50 +03:00
if ( data - > power_gpio > = 0 )
2009-10-09 16:55:41 +04:00
gpio_set_value ( data - > power_gpio , 0 ) ;
2009-12-09 13:05:50 +03:00
ret = regulator_bulk_disable ( ARRAY_SIZE ( data - > supplies ) ,
data - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( & tpa6130a2_client - > dev ,
" Failed to disable supplies: %d \n " , ret ) ;
goto exit ;
2009-10-09 16:55:41 +04:00
}
2009-12-09 13:05:50 +03:00
data - > power_state = 0 ;
2009-10-09 16:55:41 +04:00
}
2009-12-09 13:05:50 +03:00
exit :
2009-10-09 16:55:41 +04:00
mutex_unlock ( & data - > mutex ) ;
2009-12-09 13:05:50 +03:00
return ret ;
2009-10-09 16:55:41 +04:00
}
2010-05-07 15:24:11 +04:00
static int tpa6130a2_get_volsw ( struct snd_kcontrol * kcontrol ,
2009-10-09 16:55:41 +04:00
struct snd_ctl_elem_value * ucontrol )
{
struct soc_mixer_control * mc =
( struct soc_mixer_control * ) kcontrol - > private_value ;
struct tpa6130a2_data * data ;
unsigned int reg = mc - > reg ;
unsigned int shift = mc - > shift ;
2010-05-07 15:24:11 +04:00
int max = mc - > max ;
unsigned int mask = ( 1 < < fls ( max ) ) - 1 ;
2009-10-09 16:55:41 +04:00
unsigned int invert = mc - > invert ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
mutex_lock ( & data - > mutex ) ;
ucontrol - > value . integer . value [ 0 ] =
( tpa6130a2_read ( reg ) > > shift ) & mask ;
if ( invert )
ucontrol - > value . integer . value [ 0 ] =
2010-05-07 15:24:11 +04:00
max - ucontrol - > value . integer . value [ 0 ] ;
2009-10-09 16:55:41 +04:00
mutex_unlock ( & data - > mutex ) ;
return 0 ;
}
2010-05-07 15:24:11 +04:00
static int tpa6130a2_put_volsw ( struct snd_kcontrol * kcontrol ,
2009-10-09 16:55:41 +04:00
struct snd_ctl_elem_value * ucontrol )
{
struct soc_mixer_control * mc =
( struct soc_mixer_control * ) kcontrol - > private_value ;
struct tpa6130a2_data * data ;
unsigned int reg = mc - > reg ;
unsigned int shift = mc - > shift ;
2010-05-07 15:24:11 +04:00
int max = mc - > max ;
unsigned int mask = ( 1 < < fls ( max ) ) - 1 ;
2009-10-09 16:55:41 +04:00
unsigned int invert = mc - > invert ;
unsigned int val = ( ucontrol - > value . integer . value [ 0 ] & mask ) ;
unsigned int val_reg ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
if ( invert )
2010-05-07 15:24:11 +04:00
val = max - val ;
2009-10-09 16:55:41 +04:00
mutex_lock ( & data - > mutex ) ;
val_reg = tpa6130a2_read ( reg ) ;
if ( ( ( val_reg > > shift ) & mask ) = = val ) {
mutex_unlock ( & data - > mutex ) ;
return 0 ;
}
val_reg & = ~ ( mask < < shift ) ;
val_reg | = val < < shift ;
tpa6130a2_i2c_write ( reg , val_reg ) ;
mutex_unlock ( & data - > mutex ) ;
return 1 ;
}
/*
* TPA6130 volume . From - 59.5 to 4 dB with increasing step size when going
* down in gain .
*/
static const unsigned int tpa6130_tlv [ ] = {
TLV_DB_RANGE_HEAD ( 10 ) ,
0 , 1 , TLV_DB_SCALE_ITEM ( - 5950 , 600 , 0 ) ,
2 , 3 , TLV_DB_SCALE_ITEM ( - 5000 , 250 , 0 ) ,
4 , 5 , TLV_DB_SCALE_ITEM ( - 4550 , 160 , 0 ) ,
6 , 7 , TLV_DB_SCALE_ITEM ( - 4140 , 190 , 0 ) ,
8 , 9 , TLV_DB_SCALE_ITEM ( - 3650 , 120 , 0 ) ,
10 , 11 , TLV_DB_SCALE_ITEM ( - 3330 , 160 , 0 ) ,
12 , 13 , TLV_DB_SCALE_ITEM ( - 3040 , 180 , 0 ) ,
14 , 20 , TLV_DB_SCALE_ITEM ( - 2710 , 110 , 0 ) ,
21 , 37 , TLV_DB_SCALE_ITEM ( - 1960 , 74 , 0 ) ,
38 , 63 , TLV_DB_SCALE_ITEM ( - 720 , 45 , 0 ) ,
} ;
static const struct snd_kcontrol_new tpa6130a2_controls [ ] = {
2010-05-07 15:24:10 +04:00
SOC_SINGLE_EXT_TLV ( " TPA6130A2 Headphone Playback Volume " ,
TPA6130A2_REG_VOL_MUTE , 0 , 0x3f , 0 ,
2010-05-07 15:24:11 +04:00
tpa6130a2_get_volsw , tpa6130a2_put_volsw ,
2010-05-07 15:24:10 +04:00
tpa6130_tlv ) ,
2009-10-09 16:55:41 +04:00
} ;
2010-05-04 12:08:18 +04:00
static const unsigned int tpa6140_tlv [ ] = {
TLV_DB_RANGE_HEAD ( 3 ) ,
0 , 8 , TLV_DB_SCALE_ITEM ( - 5900 , 400 , 0 ) ,
9 , 16 , TLV_DB_SCALE_ITEM ( - 2500 , 200 , 0 ) ,
17 , 31 , TLV_DB_SCALE_ITEM ( - 1000 , 100 , 0 ) ,
} ;
static const struct snd_kcontrol_new tpa6140a2_controls [ ] = {
2010-05-07 15:24:10 +04:00
SOC_SINGLE_EXT_TLV ( " TPA6140A2 Headphone Playback Volume " ,
TPA6130A2_REG_VOL_MUTE , 1 , 0x1f , 0 ,
2010-05-07 15:24:11 +04:00
tpa6130a2_get_volsw , tpa6130a2_put_volsw ,
2010-05-07 15:24:10 +04:00
tpa6140_tlv ) ,
2010-05-04 12:08:18 +04:00
} ;
2009-10-09 16:55:41 +04:00
/*
* Enable or disable channel ( left or right )
* The bit number for mute and amplifier are the same per channel :
* bit 6 : Right channel
* bit 7 : Left channel
* in both registers .
*/
static void tpa6130a2_channel_enable ( u8 channel , int enable )
{
u8 val ;
if ( enable ) {
/* Enable channel */
/* Enable amplifier */
val = tpa6130a2_read ( TPA6130A2_REG_CONTROL ) ;
val | = channel ;
tpa6130a2_i2c_write ( TPA6130A2_REG_CONTROL , val ) ;
/* Unmute channel */
val = tpa6130a2_read ( TPA6130A2_REG_VOL_MUTE ) ;
val & = ~ channel ;
tpa6130a2_i2c_write ( TPA6130A2_REG_VOL_MUTE , val ) ;
} else {
/* Disable channel */
/* Mute channel */
val = tpa6130a2_read ( TPA6130A2_REG_VOL_MUTE ) ;
val | = channel ;
tpa6130a2_i2c_write ( TPA6130A2_REG_VOL_MUTE , val ) ;
/* Disable amplifier */
val = tpa6130a2_read ( TPA6130A2_REG_CONTROL ) ;
val & = ~ channel ;
tpa6130a2_i2c_write ( TPA6130A2_REG_CONTROL , val ) ;
}
}
static int tpa6130a2_left_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
tpa6130a2_channel_enable ( TPA6130A2_HP_EN_L , 1 ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
tpa6130a2_channel_enable ( TPA6130A2_HP_EN_L , 0 ) ;
break ;
}
return 0 ;
}
static int tpa6130a2_right_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
tpa6130a2_channel_enable ( TPA6130A2_HP_EN_R , 1 ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
tpa6130a2_channel_enable ( TPA6130A2_HP_EN_R , 0 ) ;
break ;
}
return 0 ;
}
static int tpa6130a2_supply_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
2009-12-09 13:05:50 +03:00
int ret = 0 ;
2009-10-09 16:55:41 +04:00
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
2009-12-09 13:05:50 +03:00
ret = tpa6130a2_power ( 1 ) ;
2009-10-09 16:55:41 +04:00
break ;
case SND_SOC_DAPM_POST_PMD :
2009-12-09 13:05:50 +03:00
ret = tpa6130a2_power ( 0 ) ;
2009-10-09 16:55:41 +04:00
break ;
}
2009-12-09 13:05:50 +03:00
return ret ;
2009-10-09 16:55:41 +04:00
}
static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets [ ] = {
SND_SOC_DAPM_PGA_E ( " TPA6130A2 Left " , SND_SOC_NOPM ,
0 , 0 , NULL , 0 , tpa6130a2_left_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD ) ,
SND_SOC_DAPM_PGA_E ( " TPA6130A2 Right " , SND_SOC_NOPM ,
0 , 0 , NULL , 0 , tpa6130a2_right_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD ) ,
SND_SOC_DAPM_SUPPLY ( " TPA6130A2 Enable " , SND_SOC_NOPM ,
0 , 0 , tpa6130a2_supply_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD ) ,
/* Outputs */
SND_SOC_DAPM_HP ( " TPA6130A2 Headphone Left " , NULL ) ,
SND_SOC_DAPM_HP ( " TPA6130A2 Headphone Right " , NULL ) ,
} ;
static const struct snd_soc_dapm_route audio_map [ ] = {
{ " TPA6130A2 Headphone Left " , NULL , " TPA6130A2 Left " } ,
{ " TPA6130A2 Headphone Right " , NULL , " TPA6130A2 Right " } ,
{ " TPA6130A2 Headphone Left " , NULL , " TPA6130A2 Enable " } ,
{ " TPA6130A2 Headphone Right " , NULL , " TPA6130A2 Enable " } ,
} ;
int tpa6130a2_add_controls ( struct snd_soc_codec * codec )
{
2010-05-04 12:08:18 +04:00
struct tpa6130a2_data * data ;
BUG_ON ( tpa6130a2_client = = NULL ) ;
data = i2c_get_clientdata ( tpa6130a2_client ) ;
2009-10-09 16:55:41 +04:00
snd_soc_dapm_new_controls ( codec , tpa6130a2_dapm_widgets ,
ARRAY_SIZE ( tpa6130a2_dapm_widgets ) ) ;
snd_soc_dapm_add_routes ( codec , audio_map , ARRAY_SIZE ( audio_map ) ) ;
2010-05-04 12:08:18 +04:00
if ( data - > id = = TPA6140A2 )
return snd_soc_add_controls ( codec , tpa6140a2_controls ,
ARRAY_SIZE ( tpa6140a2_controls ) ) ;
else
return snd_soc_add_controls ( codec , tpa6130a2_controls ,
ARRAY_SIZE ( tpa6130a2_controls ) ) ;
2009-10-09 16:55:41 +04:00
}
EXPORT_SYMBOL_GPL ( tpa6130a2_add_controls ) ;
2010-01-12 17:13:00 +03:00
static int __devinit tpa6130a2_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2009-10-09 16:55:41 +04:00
{
struct device * dev ;
struct tpa6130a2_data * data ;
struct tpa6130a2_platform_data * pdata ;
2009-12-09 13:05:50 +03:00
int i , ret ;
2009-10-09 16:55:41 +04:00
dev = & client - > dev ;
if ( client - > dev . platform_data = = NULL ) {
dev_err ( dev , " Platform data not set \n " ) ;
dump_stack ( ) ;
return - ENODEV ;
}
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( data = = NULL ) {
dev_err ( dev , " Can not allocate memory \n " ) ;
return - ENOMEM ;
}
tpa6130a2_client = client ;
i2c_set_clientdata ( tpa6130a2_client , data ) ;
2009-10-09 22:13:47 +04:00
pdata = client - > dev . platform_data ;
2009-10-09 16:55:41 +04:00
data - > power_gpio = pdata - > power_gpio ;
2010-05-04 12:08:18 +04:00
data - > id = pdata - > id ;
2009-10-09 16:55:41 +04:00
mutex_init ( & data - > mutex ) ;
/* Set default register values */
data - > regs [ TPA6130A2_REG_CONTROL ] = TPA6130A2_SWS ;
data - > regs [ TPA6130A2_REG_VOL_MUTE ] = TPA6130A2_MUTE_R |
TPA6130A2_MUTE_L ;
if ( data - > power_gpio > = 0 ) {
ret = gpio_request ( data - > power_gpio , " tpa6130a2 enable " ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to request power GPIO (%d) \n " ,
data - > power_gpio ) ;
2009-12-09 13:05:50 +03:00
goto err_gpio ;
2009-10-09 16:55:41 +04:00
}
gpio_direction_output ( data - > power_gpio , 0 ) ;
}
2010-05-04 12:08:18 +04:00
switch ( data - > id ) {
2010-01-08 18:48:31 +03:00
case TPA6130A2 :
for ( i = 0 ; i < ARRAY_SIZE ( data - > supplies ) ; i + + )
data - > supplies [ i ] . supply = tpa6130a2_supply_names [ i ] ;
break ;
case TPA6140A2 :
for ( i = 0 ; i < ARRAY_SIZE ( data - > supplies ) ; i + + )
data - > supplies [ i ] . supply = tpa6140a2_supply_names [ i ] ; ;
break ;
default :
dev_warn ( dev , " Unknown TPA model (%d). Assuming 6130A2 \n " ,
pdata - > id ) ;
for ( i = 0 ; i < ARRAY_SIZE ( data - > supplies ) ; i + + )
data - > supplies [ i ] . supply = tpa6130a2_supply_names [ i ] ;
}
2009-12-09 13:05:50 +03:00
ret = regulator_bulk_get ( dev , ARRAY_SIZE ( data - > supplies ) ,
data - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to request supplies: %d \n " , ret ) ;
goto err_regulator ;
}
ret = tpa6130a2_power ( 1 ) ;
if ( ret ! = 0 )
goto err_power ;
2009-10-09 16:55:41 +04:00
/* Read version */
ret = tpa6130a2_i2c_read ( TPA6130A2_REG_VERSION ) &
TPA6130A2_VERSION_MASK ;
if ( ( ret ! = 1 ) & & ( ret ! = 2 ) )
dev_warn ( dev , " UNTESTED version detected (%d) \n " , ret ) ;
/* Disable the chip */
2009-12-09 13:05:50 +03:00
ret = tpa6130a2_power ( 0 ) ;
if ( ret ! = 0 )
goto err_power ;
2009-10-09 16:55:41 +04:00
return 0 ;
2009-12-09 13:05:50 +03:00
err_power :
regulator_bulk_free ( ARRAY_SIZE ( data - > supplies ) , data - > supplies ) ;
err_regulator :
if ( data - > power_gpio > = 0 )
gpio_free ( data - > power_gpio ) ;
err_gpio :
2009-10-09 16:55:41 +04:00
kfree ( data ) ;
i2c_set_clientdata ( tpa6130a2_client , NULL ) ;
2009-10-09 22:13:47 +04:00
tpa6130a2_client = NULL ;
2009-10-09 16:55:41 +04:00
return ret ;
}
2010-01-12 17:13:00 +03:00
static int __devexit tpa6130a2_remove ( struct i2c_client * client )
2009-10-09 16:55:41 +04:00
{
struct tpa6130a2_data * data = i2c_get_clientdata ( client ) ;
tpa6130a2_power ( 0 ) ;
if ( data - > power_gpio > = 0 )
gpio_free ( data - > power_gpio ) ;
2009-12-09 13:05:50 +03:00
regulator_bulk_free ( ARRAY_SIZE ( data - > supplies ) , data - > supplies ) ;
2009-10-09 16:55:41 +04:00
kfree ( data ) ;
2009-10-09 22:13:47 +04:00
tpa6130a2_client = NULL ;
2009-10-09 16:55:41 +04:00
return 0 ;
}
static const struct i2c_device_id tpa6130a2_id [ ] = {
{ " tpa6130a2 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tpa6130a2_id ) ;
static struct i2c_driver tpa6130a2_i2c_driver = {
. driver = {
. name = " tpa6130a2 " ,
. owner = THIS_MODULE ,
} ,
. probe = tpa6130a2_probe ,
. remove = __devexit_p ( tpa6130a2_remove ) ,
. id_table = tpa6130a2_id ,
} ;
static int __init tpa6130a2_init ( void )
{
return i2c_add_driver ( & tpa6130a2_i2c_driver ) ;
}
static void __exit tpa6130a2_exit ( void )
{
i2c_del_driver ( & tpa6130a2_i2c_driver ) ;
}
MODULE_AUTHOR ( " Peter Ujfalusi " ) ;
MODULE_DESCRIPTION ( " TPA6130A2 Headphone amplifier driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( tpa6130a2_init ) ;
module_exit ( tpa6130a2_exit ) ;