⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ak470x.c

📁 ak470x的linux驱动程序.ak470x是scart控制芯片.
💻 C
📖 第 1 页 / 共 3 页
字号:
static int ak470x_audio_volume_set (struct i2c_client *client, AK470X_AUDIO_IOCTL_VOLUME_t *volume){    AK470X_AUDIO_CHANNEL_NUMBER_t   channel;    int     retValue    =   -EINVAL;    u8      data_byte   =   0;    int     gain;    // Check out channel number    channel     =   volume->audio_channel;    if (!ak470x_audio_channel_number_isvalid(channel))  return retValue;    // SET Audio Master Volume (L+R)/2 -> (Global)    gain = ((int)volume->master_left + (int)volume->master_right) / 2;    // Enforce boundaries    data_byte = (u8) ak470x_enforce_volume_boundaries (gain, AK470X_gain_min, AK470X_gain_max);    // I2C buffered I/O    retValue = ak470x_audio_write (client, AK470X_ADDR_VOLUME, &data_byte);    if (retValue) {        dprintk(1,  KERN_INFO "ak470x.c: Failed to set volume for audio channel %d (0x%X)\n", (int) channel, retValue);        return retValue;    }    // Refresh back buffer    ak470x_RegBackBuffer[AK470X_VOLUME] = data_byte;    return retValue;}//  ----------------------- AK470X Audio Function (Global init)  ---------------static int ak470x_audio_init (struct i2c_client *client){    int     retValue    =   -EINVAL;    int 	channel;        for (channel=AK470X_AUDIO_CHANNEL_NUMBER_MIN; channel<=AK470X_AUDIO_CHANNEL_NUMBER_MAX; channel++)       {    	AK470X_AUDIO_IOCTL_VOLUME_t	*pvolume, volume;    	pvolume = &ak470x_delta_volume	[ak470x_audio_channel_number_to_index(channel)];		// Preset associative buffer		pvolume->audio_channel 	= 	channel;		pvolume->master_left	=	(AK470X_AUDIO_MASTER_VOLUME_t)  ak470x_internal_gain (AK470X_AUDIO_EXTERNAL_VOLUME_MID);		pvolume->master_right	=	(AK470X_AUDIO_MASTER_VOLUME_t)  ak470x_internal_gain (AK470X_AUDIO_EXTERNAL_VOLUME_MID);		pvolume->external_left	=	AK470X_AUDIO_EXTERNAL_VOLUME_MID;		pvolume->external_right	=	AK470X_AUDIO_EXTERNAL_VOLUME_MID;    	// Default volume : AK470X_AUDIO_EXTERNAL_VOLUME_MID (-60+((34/2)x2) = -26dB std)				// Set volume     	retValue = ak470x_audio_volume_set (client, pvolume);    	if (retValue)	break;    			// Retrieve actual AK470X chip volume     	volume.audio_channel	=	channel;    	retValue = ak470x_audio_volume_get (client, &volume);    	if (retValue)	break;    	    	// Pick associated buffered external value if match	(LEFT)    	if (volume.master_left!=pvolume->master_left)    	{    		// Else resync with chipset value	(LEFT)    		pvolume->master_left	=	volume.master_left;    		pvolume->external_left  = 	ak470x_standard_volume (volume.master_left);    	}    	    	// Pick associated buffered external value if match	(RIGHT)    	if (volume.master_right!=pvolume->master_right)    	{    		// Else resync with fresh chipset value	(RIGHT)     		pvolume->master_right	=	volume.master_right;    		pvolume->external_right = 	ak470x_standard_volume (volume.master_right);    	}	    	    }    return retValue;}//  ****************************************************************************//  *                                                                          *//  *                           M O D U L E    S E C T I O N                   *//  *                                                                          *//  ****************************************************************************//  ----------------------- AK470X IOCTL switch  (Commands) ----------------static int ak470x_command ( struct inode  *inode, struct file   *file,                            unsigned int   cmd, unsigned long  arg){    dprintk(1, KERN_INFO "Got AK470X Command : 0x%X\n", cmd);    switch (cmd)    {        //----------------------------------------------------------------------        //  AV Switch IOCTLs        //----------------------------------------------------------------------        case AK470X_IOCTL_SWITCH_MODE_SET:            return ak470x_switch_set ((const AK470X_SWITCH_IOCTL_MODE_t*)arg);            break;        case AK470X_IOCTL_SWITCH_MODE_GET:            return ak470x_switch_get ((AK470X_SWITCH_IOCTL_MODE_t*)arg);            break;        //----------------------------------------------------------------------        //  Audio IOCTLs        //----------------------------------------------------------------------        case AK470X_IOCTL_AUDIO_MODE_SET:            return ak470x_set_audio_mode    (ak470x_client, (AK470X_AUDIO_IOCTL_MODE_t*)    arg);            break;        case AK470X_IOCTL_AUDIO_VOLUME_GET:            return ak470x_audio_volume_get  (ak470x_client, (AK470X_AUDIO_IOCTL_VOLUME_t*)  arg);            break;        case AK470X_IOCTL_AUDIO_VOLUME_SET:            return ak470x_audio_volume_set  (ak470x_client, (AK470X_AUDIO_IOCTL_VOLUME_t*)  arg);            break;        // Unimplemented IOCTL        default:            dprintk(1, KERN_INFO "unknown ak470x??(%d)\n",  cmd);            return -EINVAL;    }    return 0;}//  ----------------------- AK470X I2C Detection Function (Detect) ------------static int ak470x_detect_client (struct i2c_adapter *adapter, int address, int kind){    int rv;    u8 value;    dprintk(1,        KERN_INFO        "ak470x.c: detecting ak470x client on address 0x%x\n",        address << 1);    /* Check if the adapter supports the needed features */    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))    {        return 0;    }    /* Create the I2C client data structure */    ak470x_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);    if (ak470x_client == 0)    {        return -ENOMEM;    }    memset(ak470x_client, 0, sizeof(struct i2c_client));    ak470x_client->addr = address;    ak470x_client->adapter = adapter;    ak470x_client->driver = &i2c_driver_ak470x;    snprintf(I2C_NAME(ak470x_client), sizeof(I2C_NAME(ak470x_client)) - 1, "ak470x");    /* Attach the AV switch to the I2C adapter */    rv = i2c_attach_client(ak470x_client);    if (rv) {        dprintk(1,            KERN_INFO            "ak470x.c: Failed to attach to client on adapter %s (0x%x) - 0x%02X\n",            I2C_NAME(adapter), adapter->id, rv);        kfree(ak470x_client);        return rv;    }    if (ak470x_initialised)    {        return 0;    }    /* Previous way of determining variant caused a popping noise on  */    /* the output. So be a bit more explicit in the device selection. */#if defined (CONFIG_NXP_STB225)        is_ak4702 = 0;#else        is_ak4702 = 1;#endif    ak470x_initialised = 1;    dprintk(1,        KERN_INFO        "ak470x.c: found device (%s) on adapter %s (0x%x) - 0x%02X\n",        is_ak4702 ? "AK4702" : "AK4706", I2C_NAME(adapter), adapter->id, rv);    return 0;}//  ----------------------- AK470X I2C Detection Function (Attach)     --------static int ak470x_attach_adapter (struct i2c_adapter *adapter){    return i2c_probe(adapter, &addr_data, &ak470x_detect_client);}//  ----------------------- AK470X I2C Detection Function (Detach)     --------static int ak470x_detach_client (struct i2c_client *client){    int err;    err = i2c_detach_client(client);    if (err)    {        return err;    }    kfree(client);    return 0;}#ifdef CONFIG_PMstatic int ak470x_suspend(struct i2c_client *client, pm_message_t mesg){    keep_control_status = ak470x_read(ak470x_client, AK470X_ADDR_CONTROL);    ak470x_write(ak470x_client, AK470X_ADDR_CONTROL, AK470X_POWER_DOWN);    return 0;}static int ak470x_resume(struct i2c_client *client){    ak470x_write(ak470x_client, AK470X_ADDR_CONTROL, keep_control_status);    return 0;}#endif//  ----------------------- MODULE INIT     ------------------------------------static int __init ak470x_init (void){    int result;    ak470x_initialised = 0;    /* Register a misc device called "ak470x". */    result = misc_register( &ak470x_device );    if (result < 0)    {        printk("can't register misc device (minor %d)!\n", ak470x_device.minor );        return result;    }    result = i2c_add_driver(&i2c_driver_ak470x);    // Initialise the AV switch (loop through mode by default)    ak470x_switch_init (ak470x_client);    // Initialise the Audio mixer (50% volume by default)    ak470x_audio_init  (ak470x_client);    if (result == 0)    {        printk ("%s (%s-%s) - Device %s Loopthrough %s\n",                THIS_MODULE_DESCRIPTION,                __DATE__,                __TIME__,                is_ak4702 ? "AK4702" : "AK4706",                loopthrough ? "enabled" : "disabled");        ak470x_installed = 1;    }    else    {        printk ("%s (%s-%s) - Scart Switch not available - Dummy Driver only.\n",                THIS_MODULE_DESCRIPTION,                __DATE__,                __TIME__);        ak470x_installed = 0;    }    return 0;}//  ----------------------- MODULE EXIT     ------------------------------------static void __exit ak470x_exit (void){    misc_deregister(&ak470x_device);    i2c_del_driver(&i2c_driver_ak470x);    printk("Shutting down %s\n", THIS_MODULE_DESCRIPTION);}//  ****************************************************************************//  *                                                                          *//  *                       P U B L I C    O B J E C T S                       *//  *                                                                          *//  ****************************************************************************//  -----------------------------------------------------------------------------//                          Exported functions//  -----------------------------------------------------------------------------//  ----------------------- AK470X IOCTL wrapper  (Commands)    ----------------int ak470x_exec (unsigned int cmd, void *p_object){    return ak470x_command (NULL, NULL, cmd, (unsigned long) p_object);}//  ----------------------- AK470X exported function    ------------------------int ak470x_std_volume_get       (int channel, int *p_left, int *p_right){    int     retValue    =   -EINVAL;    AK470X_AUDIO_IOCTL_VOLUME_t volume;    AK470X_AUDIO_IOCTL_VOLUME_t *pvolume;        pvolume = &ak470x_delta_volume	[ak470x_audio_channel_number_to_index(channel)];    volume.audio_channel    =   channel;    volume.master_left      =   AK470X_AUDIO_INTERNAL_GAIN_MIN;    volume.master_right     =   AK470X_AUDIO_INTERNAL_GAIN_MIN;    retValue    =   ak470x_exec (AK470X_IOCTL_AUDIO_VOLUME_GET, &volume);    if (!retValue) // If ok ...    {    	// Pick associated buffered external value if match	(LEFT)    	if (volume.master_left!=pvolume->master_left)    	{    		// Else resync with chipset value	(LEFT)    		pvolume->external_left  = ak470x_standard_volume (volume.master_left);    	}    	    	// Pick associated buffered external value if match	(RIGHT)    	if (volume.master_right!=pvolume->master_right)    	{    		// Else resync with fresh chipset value	(RIGHT)    		pvolume->external_right = ak470x_standard_volume (volume.master_right);    	}    	        if (p_left  != NULL) *p_left  = pvolume->external_left;        if (p_right != NULL) *p_right = pvolume->external_right;    }    return  retValue;}//  ----------------------- AK470X exported function    ------------------------int ak470x_std_volume_set       (int channel, int left, int right){    int     retValue    =   -EINVAL;    AK470X_AUDIO_IOCTL_VOLUME_t *pvolume;        pvolume = &ak470x_delta_volume	[ak470x_audio_channel_number_to_index(channel)];	// Set channel ID    pvolume->audio_channel    =   channel;	// Store requested external scale volumes (values associated with internal ones)    pvolume->external_left    =   left;    pvolume->external_right   =   right;    	// Set internal scale volumes (values associated with external ones)    pvolume->master_left      =   (AK470X_AUDIO_MASTER_VOLUME_t)  ak470x_internal_gain (left);    pvolume->master_right     =   (AK470X_AUDIO_MASTER_VOLUME_t)  ak470x_internal_gain (right);    retValue    =   ak470x_exec (AK470X_IOCTL_AUDIO_VOLUME_SET, pvolume);    return  retValue;}//  ----------------------- AK470X exported function    ------------------------int ak470x_std_volume_range_get	(int channel, int *p_min, int *p_max){    int     retValue    =   -EINVAL;    if (ak470x_audio_channel_number_isvalid(channel)) // If channel# ok ...    {        if (p_min != NULL) *p_min = AK470X_vol_min;        if (p_max != NULL) *p_max = AK470X_vol_max;        retValue = 0;    }    return  retValue;}//  ****************************************************************************//  *                                                                          *//  *                       E X P O R T E D    S Y M B O L S                   *//  *                                                                          *//  ****************************************************************************EXPORT_SYMBOL(ak470x_exec);EXPORT_SYMBOL(ak470x_std_volume_get);EXPORT_SYMBOL(ak470x_std_volume_set);EXPORT_SYMBOL(ak470x_std_volume_range_get);EXPORT_SYMBOL(ak470x_switch_set);EXPORT_SYMBOL(ak470x_switch_get);EXPORT_SYMBOL(ak470x_switch_installed);//  ----------------------- MODULE MANAGEMENT   --------------------------------module_init(ak470x_init);module_exit(ak470x_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -