2005-07-29 18:13:36 +04:00
/*
* Linux driver model AC97 bus interface
*
* Author : Nicolas Pitre
* Created : Jan 14 , 2005
* Copyright : ( C ) MontaVista Software Inc .
*
* 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 .
*/
2005-08-22 14:19:14 +04:00
# include <linux/module.h>
2005-07-29 18:13:36 +04:00
# include <linux/init.h>
# include <linux/device.h>
# include <linux/string.h>
2008-12-02 18:15:50 +03:00
# include <sound/ac97_codec.h>
2005-07-29 18:13:36 +04:00
2015-07-21 22:53:00 +03:00
/*
* snd_ac97_check_id ( ) - Reads and checks the vendor ID of the device
* @ ac97 : The AC97 device to check
* @ id : The ID to compare to
* @ id_mask : Mask that is applied to the device ID before comparing to @ id
*
* If @ id is 0 this function returns true if the read device vendor ID is
* a valid ID . If @ id is non 0 this functions returns true if @ id
* matches the read vendor ID . Otherwise the function returns false .
*/
static bool snd_ac97_check_id ( struct snd_ac97 * ac97 , unsigned int id ,
unsigned int id_mask )
{
ac97 - > id = ac97 - > bus - > ops - > read ( ac97 , AC97_VENDOR_ID1 ) < < 16 ;
ac97 - > id | = ac97 - > bus - > ops - > read ( ac97 , AC97_VENDOR_ID2 ) ;
if ( ac97 - > id = = 0x0 | | ac97 - > id = = 0xffffffff )
return false ;
if ( id ! = 0 & & id ! = ( ac97 - > id & id_mask ) )
return false ;
return true ;
}
/**
* snd_ac97_reset ( ) - Reset AC ' 97 device
* @ ac97 : The AC ' 97 device to reset
* @ try_warm : Try a warm reset first
* @ id : Expected device vendor ID
* @ id_mask : Mask that is applied to the device ID before comparing to @ id
*
* This function resets the AC ' 97 device . If @ try_warm is true the function
* first performs a warm reset . If the warm reset is successful the function
* returns 1. Otherwise or if @ try_warm is false the function issues cold reset
* followed by a warm reset . If this is successful the function returns 0 ,
* otherwise a negative error code . If @ id is 0 any valid device ID will be
* accepted , otherwise only the ID that matches @ id and @ id_mask is accepted .
*/
int snd_ac97_reset ( struct snd_ac97 * ac97 , bool try_warm , unsigned int id ,
unsigned int id_mask )
{
struct snd_ac97_bus_ops * ops = ac97 - > bus - > ops ;
if ( try_warm & & ops - > warm_reset ) {
ops - > warm_reset ( ac97 ) ;
if ( snd_ac97_check_id ( ac97 , id , id_mask ) )
return 1 ;
}
if ( ops - > reset )
ops - > reset ( ac97 ) ;
if ( ops - > warm_reset )
ops - > warm_reset ( ac97 ) ;
if ( snd_ac97_check_id ( ac97 , id , id_mask ) )
return 0 ;
return - ENODEV ;
}
EXPORT_SYMBOL_GPL ( snd_ac97_reset ) ;
2005-07-29 18:13:36 +04:00
/*
2005-09-16 20:46:36 +04:00
* Let drivers decide whether they want to support given codec from their
2010-12-06 16:57:53 +03:00
* probe method . Drivers have direct access to the struct snd_ac97
* structure and may decide based on the id field amongst other things .
2005-07-29 18:13:36 +04:00
*/
static int ac97_bus_match ( struct device * dev , struct device_driver * drv )
{
2005-09-16 20:46:36 +04:00
return 1 ;
2005-07-29 18:13:36 +04:00
}
2007-02-05 15:02:35 +03:00
# ifdef CONFIG_PM
2005-07-29 18:13:36 +04:00
static int ac97_bus_suspend ( struct device * dev , pm_message_t state )
{
int ret = 0 ;
2005-09-16 20:50:53 +04:00
if ( dev - > driver & & dev - > driver - > suspend )
2005-10-28 20:52:56 +04:00
ret = dev - > driver - > suspend ( dev , state ) ;
2005-07-29 18:13:36 +04:00
return ret ;
}
static int ac97_bus_resume ( struct device * dev )
{
int ret = 0 ;
2005-09-16 20:50:53 +04:00
if ( dev - > driver & & dev - > driver - > resume )
2005-10-28 20:52:56 +04:00
ret = dev - > driver - > resume ( dev ) ;
2005-07-29 18:13:36 +04:00
return ret ;
}
2007-02-05 15:02:35 +03:00
# endif /* CONFIG_PM */
2005-07-29 18:13:36 +04:00
struct bus_type ac97_bus_type = {
. name = " ac97 " ,
. match = ac97_bus_match ,
2007-02-05 15:02:35 +03:00
# ifdef CONFIG_PM
2005-07-29 18:13:36 +04:00
. suspend = ac97_bus_suspend ,
. resume = ac97_bus_resume ,
2007-02-05 15:02:35 +03:00
# endif /* CONFIG_PM */
2005-07-29 18:13:36 +04:00
} ;
static int __init ac97_bus_init ( void )
{
return bus_register ( & ac97_bus_type ) ;
}
subsys_initcall ( ac97_bus_init ) ;
static void __exit ac97_bus_exit ( void )
{
bus_unregister ( & ac97_bus_type ) ;
}
module_exit ( ac97_bus_exit ) ;
EXPORT_SYMBOL ( ac97_bus_type ) ;
MODULE_LICENSE ( " GPL " ) ;