ssm2602 I2C Linux 驱动

下面是驱动程序:

 

/*
*   这是一个注册 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[])
ExpandedBlockStart.gifContractedBlock.gif
{
  
int fd;
  
int count=0;

  
if(argc<2)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
{    
     printf(
"usage:   %s command [counts]\n",argv[0]);
     
return -1;
  }



  fd
=open("/tmp/ssm_i2c",O_RDWR);  

ExpandedSubBlockStart.gifContractedSubBlock.gif 
/**//* 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值