下面是驱动程序:
/* * 这是一个注册 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:0xx Value:0xx\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;}下载源代码: /Files/xtrgm623/ssm2602_i2c_driver_src.rar
转载于:https://www.cnblogs.com/xtrgm623/archive/2009/06/03/1495054.html
相关资源:linux-3.18.20