ssm2602 I2C Linux 驱动

mac2022-06-30  24

下面是驱动程序:

 

/* *   这是一个注册 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
最新回复(0)