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= {
 {
0x970x970x790x790x0a0x080x9f0x0a0x000x000x000x7b0x320x00},/*idle*/
 {
0x970x970x1380x1380x140x000x00x8a0x000x010x000x7b0x320x00},/*speaker*/
 {
0x970x970x1790x1790x140x000x00x8a0x000x010x000x7b0x320x00},/*headphone*/
 {
0x1B0x1B0x1790x1790x0e0x000x00x0a0x000x000x000xff0x320x00},/*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, 
0sizeof(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

posted @ 2009-06-03 09:14  Hill.Chang  阅读(378)  评论(0编辑  收藏  举报