嵌入式Linux 下 adc芯片MCP3421系列芯片驱动实现

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>

typedef enum RESOLUTIONS{
RESOLUTION_12BIT=0,
RESOLUTION_14BIT,
RESOLUTION_16BIT,
RESOLUTION_18BIT,
}adc_res;

struct i2c_client *adc3421_client;
static dev_t adc3421_devno;
static struct class *adc3421_class;
static struct cdev *adc3421_dev;
static adc_res adc_resolution = RESOLUTION_16BIT; //默认使用16Bit分辨率
static u8 adc_channel = 1; //采集通道1-16,以最末端为准
static int adc3421_open (struct inode *inode, struct file *filep)
{
printk(“Adc_mcp3421 Open %s 0x%02X \n”, func, adc3421_client->addr);
return 0;
}
static ssize_t adc3421_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
{
u32 adc_out = 0;
u8 i = 0;
u8 recv_buf[5];
int ret;
ret = i2c_master_recv(adc3421_client, recv_buf, 5);
if(ret > 0)
{
switch (adc_resolution)
{
case RESOLUTION_12BIT:
adc_out = recv_buf[0] << 8 | recv_buf[1];
adc_out &= 0xfff;
break;
case RESOLUTION_14BIT:
adc_out = recv_buf[0] << 8 | recv_buf[1];
adc_out &= 0x3fff;
break;
case RESOLUTION_16BIT:
adc_out = recv_buf[0] << 8 | recv_buf[1];
adc_out &= 0x7fff;
break;
case RESOLUTION_18BIT:
adc_out = recv_buf[0] << 16 | recv_buf[1] << 8 | recv_buf[2];
adc_out &= 0x3ffff;
break;
default:
break;
}
}
copy_to_user(buf, &adc_out, 4);
return 1;
}
static ssize_t adc3421_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int ret;
u8 resolution;
unsigned char config_buf[2];
copy_from_user(&config_buf, buf, 2);
//config_buf[0] MCP3421的配置寄存器
//config_buf[1] 用于后期扩展通道选择
//解析分辨率-12 14 16 18 — 配置寄存器Bit[3] Bit[2]
resolution = config_buf[0] & 0x0C;
resolution = resolution >> 2;
switch(resolution){
case 0x00:
adc_resolution = RESOLUTION_12BIT;
break;
case 0x01:
adc_resolution = RESOLUTION_14BIT;
break;
case 0x02:
adc_resolution = RESOLUTION_16BIT;
break;
case 0x03:
adc_resolution = RESOLUTION_18BIT;
break;
default:
break;
}
adc_channel = config_buf[1];
//配置字写入到mcp3421中
ret = i2c_master_send(adc3421_client, config_buf, 1);
//printk(“Write Config:%x %d\n”, resolution, adc_resolution);
//printk(“write config:%d-%x-%d\n”, ret, config_buf[0], config_buf[1]);
return 1;
}
static struct file_operations adc3421_ops=
{
.open = adc3421_open,
.read = adc3421_read,
.write = adc3421_write,
};
static int __devexit adc3421_remove(struct i2c_client *client)
{
printk(“ADC_MCP3421 Remove…\n”);
device_destroy(adc3421_class, adc3421_devno);
class_destroy(adc3421_class);
cdev_del(&adc3421_dev);
unregister_chrdev_region(adc3421_devno,1);
adc3421_client = NULL;
return 0;
}
static int __devinit adc3421_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
adc3421_client = client;
printk(“Adc_mcp3421 Probe %s 0x%02X \n”, func, client->addr);
ret = alloc_chrdev_region(&adc3421_devno, 0, 1, “adc_mcp3421”);
if(ret)
{
printk(“alloc_chrdev_region for adc_mcp3421 fail…\n”);
unregister_chrdev_region(adc3421_devno,1);
return ret;
}
else
{
printk(“alloc_chrdev_region for adc_mcp3421 success!\n”);
}
cdev_init(&adc3421_dev, &adc3421_ops);
ret = cdev_add(&adc3421_dev, adc3421_devno, 1);
if(ret)
{
printk(“cdev add fail.\n”);
unregister_chrdev_region(adc3421_devno, 1);
return ret;
}
else
{
printk(“cdev add sucess!\n”);
}
adc3421_class = class_create(THIS_MODULE,“adc_mcp3421”);
if(IS_ERR(adc3421_class))
{
printk(“Create Adc3421 class fail!\n”);
unregister_chrdev_region(adc3421_devno,1);
return -1;
}
else
{
printk(“Create Adc3421 class sucess!\n”);
}
device_create(adc3421_class,NULL,adc3421_devno,0, “adc_mcp3421”);
//使用74HCD4067的话,需要在这里申请用于切换通道的IO
return 0;
}

static int adc3421_detect(struct i2c_client *client, struct i2c_board_info *info)
{
printk(“ADC_MCP3421 Detect…\n”);
int send_ret;
unsigned char config_call[5];
struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
//使用TWI2
if(2 == adapter->nr)
{
int retry = 5; //尝试5次
do
{
//尝试读取数据,成功的话再调用到probe,创建字符设备驱动节点
send_ret = i2c_master_recv(client, config_call, 5);
if(send_ret > 0)
{
strlcpy(info->type, “adc_mcp3421”, I2C_NAME_SIZE);
printk("%s 0x%02X %d OK\n", func, client->addr, send_ret);
return 0;
}
retry–;
msleep(100);
}while(retry>0);
printk("%s 0x%02X error\n", func, client->addr);
}
return -ENODEV;
}
static const struct i2c_device_id adc3421_id_table[] = {
{ “adc_mcp3421”, 0 },
{ }
};
static const unsigned short normal_i2c[] = {0x68, I2C_CLIENT_END};
static struct i2c_driver adc3421_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.owner = THIS_MODULE,
.name = “adc_mcp3421”,
},
.id_table = adc3421_id_table,
.address_list = normal_i2c,
.probe = adc3421_probe,
.remove = adc3421_remove,
.detect = adc3421_detect,
};
static int adc3421_init(void)
{
printk(“ADC_MCP3421 init…\n”);
return i2c_add_driver(&adc3421_driver);
}
static void adc3421_exit(void)
{
i2c_del_driver(&adc3421_driver);
}
MODULE_LICENSE(“GPL”);
module_init(adc3421_init);
module_exit(adc3421_exit);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值