Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304167
  • 博文数量: 111
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 672
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-05 23:41
文章分类

全部博文(111)

文章存档

2017年(111)

我的朋友

分类: LINUX

2017-06-19 18:14:06

/* drivers/nova/i2c1mux.c - i2c1mux compass driver
 * drivers/i2c/chips/i2c1mux.c - i2c1mux compass driver
 *
 * Copyright (C) 2007-2008 HTC Corporation.
 * Author: Hou-Kun Chen
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
//#include
//#include
//#include  


#if 1
#define mmaprintk(x...) printk(x)
#else
#define mmaprintk(x...)
#endif


#if 1
#define mmaprintkd(x...) printk(x)
#else
#define mmaprintkd(x...)
#endif


#if 1
#define mmaprintkf(x...) printk(x)
#else
#define mmaprintkf(x...)
#endif




#define I2C1MUX_DEVICE_NAME "i2c1mux"
#define I2C1MUX_SPEED 200 * 1000 // I2C SPEED
#define I2C1MUX_ADDR 0x1d


static int  i2c1mux_probe(struct i2c_client *client, const struct i2c_device_id *id);


/* Addresses to scan -- protected by sense_data_mutex */
//static char sense_data[RBUFF_SIZE + 1];
static struct i2c_client *this_client;
static struct miscdevice i2c1mux_device;






//static char devid;


struct i2c1mux_data {
struct i2c_client *client;
    struct mutex operation_mutex;
};




static int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msgs[2];
int ret;
char reg_buf = reg;
printk("client->addr=%d\n",client->addr);
// msgs[0].addr = I2C1MUX_ADDR;//client->addr;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].buf = ®_buf;
msgs[0].scl_rate = scl_rate;


// msgs[1].addr = I2C1MUX_ADDR;//client->addr;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = count;
msgs[1].buf = (char *)buf;
msgs[1].scl_rate = scl_rate;


ret = i2c_transfer(adap, msgs, 2);


return (ret == 2)? count : ret;
}








static int i2c1mux_rx_data(struct i2c_client *client, char *rxData, int length)
{
int ret = 0;
char reg = rxData[0];
ret = i2c_master_reg8_recv(client, reg, rxData, length, I2C1MUX_SPEED);
return (ret > 0)? 0 : ret;
}






/*


static int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
char *tx_buf = (char *)kzalloc(count + 1, GFP_KERNEL);
if(!tx_buf)
return -ENOMEM;
tx_buf[0] = reg;
memcpy(tx_buf+1, buf, count); 


msg.addr = client->addr;
msg.flags = client->flags;
msg.len = count + 1;
msg.buf = (char *)tx_buf;
msg.scl_rate = scl_rate;


ret = i2c_transfer(adap, &msg, 1);
kfree(tx_buf);
return (ret == 1) ? count : ret;


}




static int i2c1mux_tx_data(struct i2c_client *client, char *txData, int length)
{
int ret = 0;
char reg = txData[0];
ret = i2c_master_reg8_send(client, reg, &txData[1], length-1, I2C1MUX_SPEED);
return (ret > 0)? 0 : ret;
}


static char i2c1mux_read_reg(struct i2c_client *client,int addr)
{
char tmp;
int ret = 0;


tmp = addr;
ret = i2c1mux_rx_data(client, &tmp, 1);
return tmp;
}


static int i2c1mux_write_reg(struct i2c_client *client,int addr,int value)
{
char buffer[3];
int ret = 0;


buffer[0] = addr;
buffer[1] = value;
ret = i2c1mux_tx_data(client, &buffer[0], 2);
return ret;
}
*/




//ret = i2c1mux_write_reg(client,MMA8452_REG_CTRL_REG4,1)
//ret = i2c1mux_rx_data(client, &buffer[0], 3);


/** ?ú μ×°?2???DD, ??ì???è? g sensor êy?Y. */
//static int i2c1mux_get_data(struct i2c_client *client)
//{
//    struct i2c1mux_data* i2c1mux = i2c_get_clientdata(client);
// int ret;
//// int x,y,z;


/* enabled only if FREAD MODE */
/*
char buffer[3];
    do {
        memset(buffer, 0, 3);
        buffer[0] = MMA8452_REG_X_OUT_MSB;
        ret = i2c1mux_rx_data(client, &buffer[0], 3);
        if (ret < 0)
            return ret;
    } while (0);


x = i2c1mux_convert_to_int(buffer[0],0);
y = i2c1mux_convert_to_int(buffer[1],0);
z = i2c1mux_convert_to_int(buffer[2],0);
*/




// return 0;
//}




static int i2c1mux_open(struct inode *inode, struct file *file)
{
return 0;//nonseekable_open(inode, file);
}


static int i2c1mux_release(struct inode *inode, struct file *file)
{
return 0;
}


static long i2c1mux_ioctl( struct file *file, unsigned int cmd,unsigned long arg)
{
long ret;
char tmp;
struct i2c_client *client = container_of(i2c1mux_device.parent, struct i2c_client, dev);


printk("NY::%s-0x%x,%d,%ld\n",__func__,(unsigned int)file,cmd,arg);




switch(cmd){
case 0x1d:
tmp = (char)arg;
printk(KERN_INFO "reg[0x%x]",tmp);
ret = i2c1mux_rx_data(client, &tmp, 1);
arg = (long)tmp;
printk(KERN_INFO "=0x%x\n",tmp);
return arg;
break;


default:
printk("NY::cmd error,%s-0x%x,%ud,%ld\n",__func__,(unsigned int)file,cmd,arg);
break;
}




#if 0
void __user *argp = (void __user *)arg;
// char msg[RBUFF_SIZE + 1];
    int ret = -1;
char rate;
struct i2c_client *client = container_of(i2c1mux_device.parent, struct i2c_client, dev);
    struct i2c1mux_data* this = (struct i2c1mux_data *)i2c_get_clientdata(client);  


switch (cmd) {
case MMA_IOCTL_APP_SET_RATE:
if (copy_from_user(&rate, argp, sizeof(rate)))
return -EFAULT;
break;
default:
break;
}


switch (cmd) {
case MMA_IOCTL_START:
//        mutex_lock(&(this->operation_mutex) );


//        mutex_unlock(&(this->operation_mutex) );
        mmaprintkd("finish 'MMA_IOCTL_START', ret = %d.", ret);
        return 0;


case MMA_IOCTL_CLOSE:
//        mutex_lock(&(this->operation_mutex) );
        mmaprintkd("to perform 'MMA_IOCTL_CLOSE', former 'start_count' is %d, PID : %d", this->start_count, get_current()->pid);
//        mutex_unlock(&(this->operation_mutex) );
        return 0;


case MMA_IOCTL_APP_SET_RATE:
ret = i2c1mux_reset_rate(client, rate);
if (ret < 0)
return ret;
break;
case MMA_IOCTL_GETDATA:
// ret = i2c1mux_trans_buff(msg, RBUFF_SIZE);
break;
default:
return -ENOTTY;
}


switch (cmd) {
case MMA_IOCTL_GETDATA:
        /*
if (copy_to_user(argp, &msg, sizeof(msg)))
return -EFAULT;
        */
        if ( copy_to_user(argp, &sense_data, sizeof(sense_data) ) ) {
            printk("failed to copy sense data to user space.");
return -EFAULT;
        }
break;
default:
break;
}
#endif
return 0;
}


static struct file_operations i2c1mux_fops = {
.owner = THIS_MODULE,
.open = i2c1mux_open,
.release = i2c1mux_release,
.unlocked_ioctl = i2c1mux_ioctl,
};


static struct miscdevice i2c1mux_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = I2C1MUX_DEVICE_NAME,//"i2c1mux_daemon",
.fops = &i2c1mux_fops,
};
/*
static int i2c1mux_remove(struct i2c_client *client)
{
struct i2c1mux_data *i2c1mux = i2c_get_clientdata(client);

    misc_deregister(&i2c1mux_device);
    kfree(i2c1mux); 
    this_client = NULL;
return 0;
}




//#if defined(MODULE) || defined(CONFIG_HOTPLUG)
//#define __devexit_p(x) x
//#else
//#define __devexit_p(x) NULL
//#endif
*/


static const struct i2c_device_id i2c1mux_id[] = {
{"i2c1mux", 0},
{ }
};


static struct i2c_driver i2c1mux_driver = {
.driver = {
.name = "i2c1mux",
   },
.id_table = i2c1mux_id,
.probe = i2c1mux_probe,           
// .remove = __devexit_p(i2c1mux_remove),
};




static int  i2c1mux_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct i2c1mux_data *i2c1mux;
int err;
// int ret;
// char tmp;


printk(KERN_INFO "i2c1mux_probe\n");

// ret = i2c1mux_rx_data(client, &tmp, 1);
// printk(KERN_INFO "read byte:%d\n",tmp);


mmaprintkf("%s enter\n",__FUNCTION__);


i2c1mux = kzalloc(sizeof(struct i2c1mux_data), GFP_KERNEL);
if (!i2c1mux) {
mmaprintk("[i2c1mux]:alloc data failed.\n");
err = -ENOMEM;
goto exit_alloc_data_failed;
}
    
// mutex_init(&(i2c1mux->operation_mutex) );


i2c1mux->client = client;
i2c_set_clientdata(client, i2c1mux);


this_client = client;


// devid = i2c1mux_get_devid(this_client);
// if ((MMA8452_DEVID != devid) 
// && (MMA8451_DEVID != devid)
// && (MMA8453_DEVID != devid)) {
// pr_info("i2c1mux: invalid devid\n");
// goto exit_invalid_devid;
// }


    i2c1mux_device.parent = &client->dev;
err = misc_register(&i2c1mux_device);
if (err < 0) {
mmaprintk(KERN_ERR
      "i2c1mux_probe: mmad_device register failed\n");
goto exit_misc_device_register_i2c1mux_device_failed;
}


printk(KERN_INFO "i2c1mux probe ok\n");


return 0;


//    misc_deregister(&i2c1mux_device);
exit_misc_device_register_i2c1mux_device_failed:
//exit_request_gpio_irq_failed:
//exit_invalid_devid:
kfree(i2c1mux);
exit_alloc_data_failed:
mmaprintk("%s error\n",__FUNCTION__);
return -1;
}




static int __init i2c1mux_i2c_init(void)
{
printk(KERN_INFO "i2c1mux_i2c_init\n");




return i2c_add_driver(&i2c1mux_driver);
}


static void __exit i2c1mux_i2c_exit(void)
{
printk(KERN_INFO "i2c1mux_i2c_exit\n");
i2c_del_driver(&i2c1mux_driver);
}


MODULE_AUTHOR("niuyi nova_niuyi@126.com");
MODULE_DESCRIPTION("i2c1mux i2c driver");
MODULE_LICENSE("GPL");


module_init(i2c1mux_i2c_init);
module_exit(i2c1mux_i2c_exit);






给驱动节点更改权限:
在android目录文件里system/core/rootdir/ueventd.rc 
添加
# niuyi
/dev/i2c1mux                0666   root       root






在arch/arm/boot/dts/x3288.dts里添加
&i2c1 {
/* ... */
/* niuyi */
i2c1mux@1d {
compatible = "i2c1mux";
reg = <0x1d>;
};
};


arch/arm/configs/x3288_defconfig
CONFIG_I2C1MUX=y


drivers/Makefile
obj-$(CONFIG_NOVA) += nova/ 


drivers/Kconfig
source "drivers/nova/Kconfig"


drivers/nova/Makefile
obj-$(CONFIG_I2C1MUX) += i2c1mux.o


drivers/nova/Kconfig
config I2C1MUX
    tristate "read/write device i2c Driver"
    default y
    help
    This is the i2c driver for all hw ic






测试应用:
源码路径:
hardware/nova/misctest/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := misctest
LOCAL_SRC_FILES := misctest.c
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE) 


hardware/nova/misctest/misctest.c


目标路径:
./out/target/product/rk3288/obj/EXECUTABLES/misctest_intermediates/misctest
./out/target/product/rk3288/symbol/system/bin/misctest


#include
#include
#include
#include
#include
#include
#include
#include
#include


#define I2C1MUX_DEVICE_NODE_NAME "/dev/i2c1mux"


int main (int argc, char *argv[])
{
char devname[128];
char buff[1024];
unsigned char *pbuf=buff;
size_t flen;
int i,fd;
char reg=0;
long value;


printf("0\n");


if(argc != 2)
return 0;


strcpy(devname,argv[1]);
//printf("open dev : %s\n",devname);


//if(0 == strcmp(devname,I2C1MUX_DEVICE_NODE_NAME))
{
fd = open(devname,O_RDWR);
if(fd<0){
printf("%s,open dev faile %d\n",devname,fd);
return 0;
}
for(i=0;i<15;i++){
value = ioctl(fd,0x1d,reg);
printf("reg 0x%x : 0x%x\n",reg,value);
reg++;
}
i = ioctl(fd,3,34);


close(fd);
}


return 0;
}








阅读(4355) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~