下面是驱动程序:
/*
* 这是一个注册 I2C 字符设备
* I2C 设备的 read/write 函数不实用,这里先写一下初始化与显示的函数
* ioctl LIST_REGS GET_REG INIT_REG SETMODE
*/
#include < linux / module.h >
#include < linux / init.h >
#include < linux / slab.h >
#include < linux / i2c.h >
#include < linux / string .h >
#include < linux / rtc.h > /* get the user-level API */
#include < linux / bcd.h >
#include < linux / list.h >
#include < linux / types.h >
// #include "i2c-dev.h"
#define SSM2602_SETMODE 0x1
#define SSM2602_LISTREGS 0x2
#define SSM2602_MAJOR 250
#define SSM2602_ADDRESS 0x1a
/*
struct i2c_msg
{
__u16 addr;
__u16 flags;
__u16 len;
__u8 *buf;
};
*/
static unsigned short normal_i2c[] = { SSM2602_ADDRESS, I2C_CLIENT_END };
// static unsigned short normal_i2c[] = { SSM2602_ADDRESS>>1, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
struct i2c_client * ssm2602_datap;
static int ssm2602_major = SSM2602_MAJOR;
static int ssm2602_attach_adapter( struct i2c_adapter * adapter);
static int ssm2602_command( struct i2c_client * client, unsigned int cmd, void * arg);
static int ssm2602_detect( struct i2c_adapter * adapter, int address, int kind);
static int ssm2602_detach_client( struct i2c_client * client);
const unsigned short Codec_I2C_Setting[ 4 ][ 14 ] = {
{ 0x97 , 0x97 , 0x79 , 0x79 , 0x0a , 0x08 , 0x9f , 0x0a , 0x00 , 0x00 , 0x00 , 0x7b , 0x32 , 0x00 }, /* idle */
{ 0x97 , 0x97 , 0x138 , 0x138 , 0x14 , 0x00 , 0x0 , 0x8a , 0x00 , 0x01 , 0x00 , 0x7b , 0x32 , 0x00 }, /* speaker */
{ 0x97 , 0x97 , 0x179 , 0x179 , 0x14 , 0x00 , 0x0 , 0x8a , 0x00 , 0x01 , 0x00 , 0x7b , 0x32 , 0x00 }, /* headphone */
{ 0x1B , 0x1B , 0x179 , 0x179 , 0x0e , 0x00 , 0x0 , 0x0a , 0x00 , 0x00 , 0x00 , 0xff , 0x32 , 0x00 }, /* bypass */
};
#define NORMAL_CONFIG_REG_LENGTH 0x0a
#define CODEC_REG_LIV 0X00 // Left-Channel ADC Input Volume
#define CODEC_REG_RIV 0X01 // Right-Channel ADC Input Volume
#define CODEC_REG_LOV 0X02 // Left-Channel DAC Volume
#define CODEC_REG_ROV 0X03 // Right-Channel DAC Volume
#define CODEC_REG_AAP 0X04 // Analog Audio Path
#define CODEC_REG_DAP 0X05 // Digital Audio Path
#define CODEC_REG_PM 0X06 // Power Management
#define CODEC_REG_DIF 0X07 // Digital Audio I/F
#define CODEC_REG_SR 0X08 // Sampling Rate
#define CODEC_REG_ACT 0X09 // Active
#define CODEC_REG_RST 0X0f // Software Reset
#define CODEC_REG_ALC1 0X10 // ALC Control 1
#define CODEC_REG_ALC2 0X11 // ALC Control 2
#define CODEC_REG_NG 0X12 // Noise Gate
const unsigned char Codec_RegAddress[] =
{
CODEC_REG_LIV ,
CODEC_REG_RIV ,
CODEC_REG_LOV ,
CODEC_REG_ROV ,
CODEC_REG_AAP ,
CODEC_REG_DAP ,
CODEC_REG_PM ,
CODEC_REG_DIF ,
CODEC_REG_SR ,
CODEC_REG_ACT ,
CODEC_REG_RST ,
CODEC_REG_ALC1,
CODEC_REG_ALC2,
CODEC_REG_NG ,
};
// ***********************************************************************
u8 ssm2602_write ( struct i2c_client * client,
u8 reg,
u8 value)
{
unsigned char buf[ 3 ] = { 0 };
struct i2c_msg msg[ 1 ];
buf[ 0 ] = (reg << 1 ) | ((value >> 8 ) & 0x0001 );
buf[ 1 ] = value & 0x00ff ;
msg[ 0 ].flags = 0 ; // 0 write
msg[ 0 ].addr = client -> addr;
msg[ 0 ].buf = buf;
msg[ 0 ].len = 2 ;
i2c_transfer(client -> adapter, msg, 1 );
return 0 ;
}
u8 ssm2602_read ( struct i2c_client * client,
u8 reg,
u8 * buf)
{
unsigned char regs[ 1 ] = { 0 };
struct i2c_msg msg[ 2 ];
regs[ 0 ] = reg << 1 & 0x00fe ;
msg[ 0 ].flags = 0 ; // 0 write
msg[ 0 ].addr = client -> addr;
msg[ 0 ].buf = regs;
msg[ 0 ].len = 1 ;
msg[ 1 ].flags = 1 ; // 1 read
msg[ 1 ].addr = client -> addr;
msg[ 1 ].buf = buf;
msg[ 1 ].len = 2 ;
i2c_transfer(client -> adapter, msg, 2 );
return 0 ;
}
// ***********************************************************************
void ssm2602_list_regs( struct i2c_client * client)
{
u8 buf[ 2 ],i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_read(client,Codec_RegAddress[i],buf);
printk(KERN_INFO " Address:0x%02x Value:0x%02x\n " ,Codec_RegAddress[i],(buf[ 1 ] << 8 ) | buf[ 0 ]);
}
}
void ssm2602_set_mode( struct i2c_client * client,u8 mode)
{
u8 i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_write(client,Codec_RegAddress[i],Codec_I2C_Setting[mode][i]);
}
}
// ***********************************************************************
int ssm2602_open( struct inode * inode, struct file * filep)
{
filep -> private_data = ssm2602_datap;
return 0 ;
}
int ssm2602_release( struct inode * inode, struct file * filp)
{
return 0 ;
}
static int ssm2602_ioctl( struct inode * inodep, struct file * filep, unsigned
int cmd, unsigned long arg)
{
struct i2c_client * client = ( struct i2c_client * )filep -> private_data;
switch (cmd)
{
case SSM2602_SETMODE:
printk(KERN_INFO " set mode command\n " );
ssm2602_set_mode(client,(u8)arg);
break ;
case SSM2602_LISTREGS:
printk(KERN_INFO " list regs command\n " );
ssm2602_list_regs(client);
break ;
default :
return - EINVAL;
}
return 0 ;
}
// ***********************************************************************
static const struct file_operations ssm2602_i2c_fops =
{
.owner = THIS_MODULE,
// .llseek = ssm2602_llseek,
// .read = ssm2602_read,
// .write = ssm2602_write,
.ioctl = ssm2602_ioctl,
.open = ssm2602_open,
.release = ssm2602_release,
};
static struct i2c_driver ssm2602_driver = {
.driver = {
.name = " SSM2602 " ,
},
.attach_adapter = ssm2602_attach_adapter,
.detach_client = ssm2602_detach_client,
.command = ssm2602_command,
};
static int ssm2602_command( struct i2c_client * client, unsigned int cmd, void * arg)
{
return 0 ;
}
void ssm2602_init_client( struct i2c_client * new_client)
{
u8 i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_write(new_client,Codec_RegAddress[i],Codec_I2C_Setting[ 1 ][i]);
}
}
static int ssm2602_detect( struct i2c_adapter * adapter, int address, int kind)
{
struct i2c_client * new_client;
int err = 0 ;
if ( ! i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_I2C))
goto exit;
if ( ! (ssm2602_datap = kzalloc( sizeof ( struct i2c_client), GFP_KERNEL))) {
err = - ENOMEM;
goto exit;
}
memset(ssm2602_datap, 0 , sizeof ( struct i2c_client));
new_client = ssm2602_datap;
new_client -> addr = address;
new_client -> adapter = adapter;
new_client -> driver = & ssm2602_driver;
new_client -> flags = 0 ;
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the DS1337 chip */
ssm2602_init_client(new_client);
return 0 ;
exit_free:
kfree(ssm2602_datap);
exit:
return err;
}
static int ssm2602_attach_adapter( struct i2c_adapter * adapter)
{
return i2c_probe(adapter, & addr_data, ssm2602_detect);
}
static int ssm2602_detach_client( struct i2c_client * client)
{
int err;
if ((err = i2c_detach_client(client)))
return err;
return 0 ;
}
/*
* Driver data (common to all clients)
*/
static int __init ssm2602_init( void )
{
int res;
res = register_chrdev(ssm2602_major, " ssm2602_iic " , & ssm2602_i2c_fops);
if (res)
goto out ;
res = i2c_add_driver( & ssm2602_driver);
if (res)
goto out_unreg_chrdev;
return 0 ;
out_unreg_chrdev: unregister_chrdev(ssm2602_major, " ssm2602_iic " );
out : printk(KERN_ERR " %s: Driver Initialisation failed \n " , __FILE__);
return res;
}
static void __exit ssm2602_exit( void )
{
i2c_del_driver( & ssm2602_driver);
unregister_chrdev(ssm2602_major, " ssm2602_iic " );
}
MODULE_AUTHOR( " Hill@Ensky.tech " );
MODULE_DESCRIPTION( " SSM2602 IIC driver " );
MODULE_LICENSE( " Dual BSD/GPL " );
module_init(ssm2602_init);
module_exit(ssm2602_exit);
* 这是一个注册 I2C 字符设备
* I2C 设备的 read/write 函数不实用,这里先写一下初始化与显示的函数
* ioctl LIST_REGS GET_REG INIT_REG SETMODE
*/
#include < linux / module.h >
#include < linux / init.h >
#include < linux / slab.h >
#include < linux / i2c.h >
#include < linux / string .h >
#include < linux / rtc.h > /* get the user-level API */
#include < linux / bcd.h >
#include < linux / list.h >
#include < linux / types.h >
// #include "i2c-dev.h"
#define SSM2602_SETMODE 0x1
#define SSM2602_LISTREGS 0x2
#define SSM2602_MAJOR 250
#define SSM2602_ADDRESS 0x1a
/*
struct i2c_msg
{
__u16 addr;
__u16 flags;
__u16 len;
__u8 *buf;
};
*/
static unsigned short normal_i2c[] = { SSM2602_ADDRESS, I2C_CLIENT_END };
// static unsigned short normal_i2c[] = { SSM2602_ADDRESS>>1, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
struct i2c_client * ssm2602_datap;
static int ssm2602_major = SSM2602_MAJOR;
static int ssm2602_attach_adapter( struct i2c_adapter * adapter);
static int ssm2602_command( struct i2c_client * client, unsigned int cmd, void * arg);
static int ssm2602_detect( struct i2c_adapter * adapter, int address, int kind);
static int ssm2602_detach_client( struct i2c_client * client);
const unsigned short Codec_I2C_Setting[ 4 ][ 14 ] = {
{ 0x97 , 0x97 , 0x79 , 0x79 , 0x0a , 0x08 , 0x9f , 0x0a , 0x00 , 0x00 , 0x00 , 0x7b , 0x32 , 0x00 }, /* idle */
{ 0x97 , 0x97 , 0x138 , 0x138 , 0x14 , 0x00 , 0x0 , 0x8a , 0x00 , 0x01 , 0x00 , 0x7b , 0x32 , 0x00 }, /* speaker */
{ 0x97 , 0x97 , 0x179 , 0x179 , 0x14 , 0x00 , 0x0 , 0x8a , 0x00 , 0x01 , 0x00 , 0x7b , 0x32 , 0x00 }, /* headphone */
{ 0x1B , 0x1B , 0x179 , 0x179 , 0x0e , 0x00 , 0x0 , 0x0a , 0x00 , 0x00 , 0x00 , 0xff , 0x32 , 0x00 }, /* bypass */
};
#define NORMAL_CONFIG_REG_LENGTH 0x0a
#define CODEC_REG_LIV 0X00 // Left-Channel ADC Input Volume
#define CODEC_REG_RIV 0X01 // Right-Channel ADC Input Volume
#define CODEC_REG_LOV 0X02 // Left-Channel DAC Volume
#define CODEC_REG_ROV 0X03 // Right-Channel DAC Volume
#define CODEC_REG_AAP 0X04 // Analog Audio Path
#define CODEC_REG_DAP 0X05 // Digital Audio Path
#define CODEC_REG_PM 0X06 // Power Management
#define CODEC_REG_DIF 0X07 // Digital Audio I/F
#define CODEC_REG_SR 0X08 // Sampling Rate
#define CODEC_REG_ACT 0X09 // Active
#define CODEC_REG_RST 0X0f // Software Reset
#define CODEC_REG_ALC1 0X10 // ALC Control 1
#define CODEC_REG_ALC2 0X11 // ALC Control 2
#define CODEC_REG_NG 0X12 // Noise Gate
const unsigned char Codec_RegAddress[] =
{
CODEC_REG_LIV ,
CODEC_REG_RIV ,
CODEC_REG_LOV ,
CODEC_REG_ROV ,
CODEC_REG_AAP ,
CODEC_REG_DAP ,
CODEC_REG_PM ,
CODEC_REG_DIF ,
CODEC_REG_SR ,
CODEC_REG_ACT ,
CODEC_REG_RST ,
CODEC_REG_ALC1,
CODEC_REG_ALC2,
CODEC_REG_NG ,
};
// ***********************************************************************
u8 ssm2602_write ( struct i2c_client * client,
u8 reg,
u8 value)
{
unsigned char buf[ 3 ] = { 0 };
struct i2c_msg msg[ 1 ];
buf[ 0 ] = (reg << 1 ) | ((value >> 8 ) & 0x0001 );
buf[ 1 ] = value & 0x00ff ;
msg[ 0 ].flags = 0 ; // 0 write
msg[ 0 ].addr = client -> addr;
msg[ 0 ].buf = buf;
msg[ 0 ].len = 2 ;
i2c_transfer(client -> adapter, msg, 1 );
return 0 ;
}
u8 ssm2602_read ( struct i2c_client * client,
u8 reg,
u8 * buf)
{
unsigned char regs[ 1 ] = { 0 };
struct i2c_msg msg[ 2 ];
regs[ 0 ] = reg << 1 & 0x00fe ;
msg[ 0 ].flags = 0 ; // 0 write
msg[ 0 ].addr = client -> addr;
msg[ 0 ].buf = regs;
msg[ 0 ].len = 1 ;
msg[ 1 ].flags = 1 ; // 1 read
msg[ 1 ].addr = client -> addr;
msg[ 1 ].buf = buf;
msg[ 1 ].len = 2 ;
i2c_transfer(client -> adapter, msg, 2 );
return 0 ;
}
// ***********************************************************************
void ssm2602_list_regs( struct i2c_client * client)
{
u8 buf[ 2 ],i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_read(client,Codec_RegAddress[i],buf);
printk(KERN_INFO " Address:0x%02x Value:0x%02x\n " ,Codec_RegAddress[i],(buf[ 1 ] << 8 ) | buf[ 0 ]);
}
}
void ssm2602_set_mode( struct i2c_client * client,u8 mode)
{
u8 i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_write(client,Codec_RegAddress[i],Codec_I2C_Setting[mode][i]);
}
}
// ***********************************************************************
int ssm2602_open( struct inode * inode, struct file * filep)
{
filep -> private_data = ssm2602_datap;
return 0 ;
}
int ssm2602_release( struct inode * inode, struct file * filp)
{
return 0 ;
}
static int ssm2602_ioctl( struct inode * inodep, struct file * filep, unsigned
int cmd, unsigned long arg)
{
struct i2c_client * client = ( struct i2c_client * )filep -> private_data;
switch (cmd)
{
case SSM2602_SETMODE:
printk(KERN_INFO " set mode command\n " );
ssm2602_set_mode(client,(u8)arg);
break ;
case SSM2602_LISTREGS:
printk(KERN_INFO " list regs command\n " );
ssm2602_list_regs(client);
break ;
default :
return - EINVAL;
}
return 0 ;
}
// ***********************************************************************
static const struct file_operations ssm2602_i2c_fops =
{
.owner = THIS_MODULE,
// .llseek = ssm2602_llseek,
// .read = ssm2602_read,
// .write = ssm2602_write,
.ioctl = ssm2602_ioctl,
.open = ssm2602_open,
.release = ssm2602_release,
};
static struct i2c_driver ssm2602_driver = {
.driver = {
.name = " SSM2602 " ,
},
.attach_adapter = ssm2602_attach_adapter,
.detach_client = ssm2602_detach_client,
.command = ssm2602_command,
};
static int ssm2602_command( struct i2c_client * client, unsigned int cmd, void * arg)
{
return 0 ;
}
void ssm2602_init_client( struct i2c_client * new_client)
{
u8 i;
for (i = 0 ;i < NORMAL_CONFIG_REG_LENGTH;i ++ )
{
ssm2602_write(new_client,Codec_RegAddress[i],Codec_I2C_Setting[ 1 ][i]);
}
}
static int ssm2602_detect( struct i2c_adapter * adapter, int address, int kind)
{
struct i2c_client * new_client;
int err = 0 ;
if ( ! i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_I2C))
goto exit;
if ( ! (ssm2602_datap = kzalloc( sizeof ( struct i2c_client), GFP_KERNEL))) {
err = - ENOMEM;
goto exit;
}
memset(ssm2602_datap, 0 , sizeof ( struct i2c_client));
new_client = ssm2602_datap;
new_client -> addr = address;
new_client -> adapter = adapter;
new_client -> driver = & ssm2602_driver;
new_client -> flags = 0 ;
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the DS1337 chip */
ssm2602_init_client(new_client);
return 0 ;
exit_free:
kfree(ssm2602_datap);
exit:
return err;
}
static int ssm2602_attach_adapter( struct i2c_adapter * adapter)
{
return i2c_probe(adapter, & addr_data, ssm2602_detect);
}
static int ssm2602_detach_client( struct i2c_client * client)
{
int err;
if ((err = i2c_detach_client(client)))
return err;
return 0 ;
}
/*
* Driver data (common to all clients)
*/
static int __init ssm2602_init( void )
{
int res;
res = register_chrdev(ssm2602_major, " ssm2602_iic " , & ssm2602_i2c_fops);
if (res)
goto out ;
res = i2c_add_driver( & ssm2602_driver);
if (res)
goto out_unreg_chrdev;
return 0 ;
out_unreg_chrdev: unregister_chrdev(ssm2602_major, " ssm2602_iic " );
out : printk(KERN_ERR " %s: Driver Initialisation failed \n " , __FILE__);
return res;
}
static void __exit ssm2602_exit( void )
{
i2c_del_driver( & ssm2602_driver);
unregister_chrdev(ssm2602_major, " ssm2602_iic " );
}
MODULE_AUTHOR( " Hill@Ensky.tech " );
MODULE_DESCRIPTION( " SSM2602 IIC driver " );
MODULE_LICENSE( " Dual BSD/GPL " );
module_init(ssm2602_init);
module_exit(ssm2602_exit);
下面是测试程序:
#include
<
fcntl.h
>
#include < sys / types.h >
#include < sys / time.h >
#include < sys / stat.h >
#include < unistd.h >
#include < stdio.h >
#include < string .h >
#include < sys / ioctl.h >
#define SSM2602_LISTREGS 0x2
#define SSM2602_SETMODE 0x1
#define Byte unsigned char
#define UINT16 unsigned short
int main( int argc, char * argv[])
{
int fd;
int count=0;
if(argc<2)
{
printf("usage: %s command [counts]\n",argv[0]);
return -1;
}
fd=open("/tmp/ssm_i2c",O_RDWR);
/**//* ioctl(fd,MMCLEAR,(void *)0); */
if(strcmp(argv[1],"list_regs")==0)
ioctl(fd,SSM2602_LISTREGS,(void *)0);
else if(strcmp(argv[1], "set_mode")==0)
ioctl(fd,SSM2602_SETMODE, (void *)(unsigned long)atol(argv[2]));
close(fd);
return 0;
}
#include < sys / types.h >
#include < sys / time.h >
#include < sys / stat.h >
#include < unistd.h >
#include < stdio.h >
#include < string .h >
#include < sys / ioctl.h >
#define SSM2602_LISTREGS 0x2
#define SSM2602_SETMODE 0x1
#define Byte unsigned char
#define UINT16 unsigned short
int main( int argc, char * argv[])
{
int fd;
int count=0;
if(argc<2)
{
printf("usage: %s command [counts]\n",argv[0]);
return -1;
}
fd=open("/tmp/ssm_i2c",O_RDWR);
/**//* ioctl(fd,MMCLEAR,(void *)0); */
if(strcmp(argv[1],"list_regs")==0)
ioctl(fd,SSM2602_LISTREGS,(void *)0);
else if(strcmp(argv[1], "set_mode")==0)
ioctl(fd,SSM2602_SETMODE, (void *)(unsigned long)atol(argv[2]));
close(fd);
return 0;
}