/* 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;
}
原作者:niuyimail