废话不多说,直接上代码。
设备树代码如下,需要注意的是在设备中描述的I2C器件地址是7位的,不是8位的,否则I2C子系统初始化时会提示找不到设备。
i2c3: i2c@50008c00 {
compatible = "xxx-i2c3";
reg = <0x50008c00 0x800>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = ;
i2c_speed = <100000>;
hb203b@77{
compatible = "hp203b";
reg = <0x77>;
};
};
驱动程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define HP20X_READ_P 0x30 //read_p command
#define HP20X_READ_A 0x31 //read_a command
#define HP20X_READ_T 0x32 //read_t command
#define HP20X_READ_PT 0x10 //read_pt command
#define HP20X_READ_AT 0x11 //read_at command
#define HP20X_READ_CAL 0X28 //RE-CAL ANALOG
struct hp203b
{
struct device *device;
int init;
struct mutex lock;
struct i2c_client *client;
} ;
#define HP203B_IOCTL_DOWN(dev) mutex_lock(&dev->lock)
#define HP203B_IOCTL_UP(dev) mutex_unlock(&dev->lock)
#define HP203B_CHECK_INIT(dev) \
do{ \
if(!dev->init) { \
HP203B_IOCTL_DOWN(dev); \
hp203b_reset(dev->client); \
HP203B_IOCTL_UP(dev); \
msleep(3); \
dev->init = 1; \
} \
}while(0)
static unsigned char hp203b_write_cmd(struct i2c_client *client,const unsigned char cmd)
{
unsigned char txbuf[1] = {cmd};
struct i2c_msg msg[1] = {
[0] = {
.addr = client->addr,
.flags= 0,
.len = sizeof(txbuf),
.buf = txbuf,
},
};
if(i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) < 0)
{
printk(KERN_EMERG"hp203b_write_cmd fail\n");
return 0xFF;
}
return 0;
}
/*
static unsigned char hp203b_write_reg(struct i2c_client *client,const unsigned char reg,const unsigned char val)
{
unsigned char txbuf[2] = {reg | 0x80, val};
struct i2c_msg msg[1] = {
[0] = {
.addr = client->addr,
.flags= 0,
.len = sizeof(txbuf),
.buf = txbuf,
},
};
if(i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) < 0)
{
printk(KERN_EMERG"hp203b_write_reg fail\n");
return 0xFF;
}
return 0;
}
static unsigned char hp203b_read_reg(struct i2c_client *client, const unsigned char reg)
{
unsigned char txbuf[1] = {reg | 0x80};
unsigned char rxbuf[1] = {0};
struct i2c_msg msg[2] = {
[0] = {
.addr = client->addr,
.flags = 0,
.len = sizeof(txbuf),
.buf = txbuf,
},
[1] = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(rxbuf),
.buf = rxbuf,
},
};
if(i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) < 0)
{
printk(KERN_EMERG"hp203b_read_reg fail\n");
return 0;
}
return rxbuf[0];
}
*/
static int hp203b_read_3byte_data(struct i2c_client *client, unsigned char cmd)
{
unsigned char txbuf[1] = {cmd};
unsigned char rxbuf[3] = {0};
int data;
struct i2c_msg msg[2] = {
[0] = {
.addr = client->addr,
.flags = 0,
.len = sizeof(txbuf),
.buf = txbuf,
},
[1] = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(rxbuf),
.buf = rxbuf,
},
};
if(i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) < 0)
{
printk(KERN_EMERG"hp203b_read_3byte_data fail\n");
return -1;
}
data = ((rxbuf[0] << 16) | (rxbuf[1] << 8) | rxbuf[2]) & 0xfffff;
if(data & 0x80000)
data |= 0xfff00000; //补码处理
return data;
// return data / 100;
}
static unsigned char hp203b_reset(struct i2c_client *client)
{
return hp203b_write_cmd(client, 0x06);
}
static unsigned char hp203b_set_osr_channel(struct i2c_client *client, unsigned char osr, unsigned channel)
{
unsigned char cmd = 0;
cmd = 0x40 | ((osr & 0x07) << 3) | (channel & 0x03);
return hp203b_write_cmd(client, cmd);
}
static int hp203b_read_pressure(struct i2c_client *client)
{
return hp203b_read_3byte_data(client, HP20X_READ_P);
}
static int hp203b_read_altitude(struct i2c_client *client)
{
return hp203b_read_3byte_data(client, HP20X_READ_A);
}
static int hp203b_read_temperature(struct i2c_client *client)
{
return hp203b_read_3byte_data(client, HP20X_READ_T);
}
static ssize_t hp203b_pressure_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hp203b *hp203b = dev_get_drvdata(dev);
int data = 0;
HP203B_CHECK_INIT(hp203b);
HP203B_IOCTL_DOWN(hp203b);
hp203b_set_osr_channel(hp203b->client, 0, 0);
msleep(135);
data = hp203b_read_pressure(hp203b->client);
HP203B_IOCTL_UP(hp203b);
return sprintf(buf, "%d\n", data);
}
static ssize_t hp203b_altitude_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hp203b *hp203b = dev_get_drvdata(dev);
int data = 0;
HP203B_CHECK_INIT(hp203b);
HP203B_IOCTL_DOWN(hp203b);
hp203b_set_osr_channel(hp203b->client, 0, 0);
msleep(135);
data = hp203b_read_altitude(hp203b->client);
HP203B_IOCTL_UP(hp203b);
return sprintf(buf, "%d\n", data);
}
static ssize_t hp203b_temperature_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hp203b *hp203b = dev_get_drvdata(dev);
int data = 0;
HP203B_CHECK_INIT(hp203b);
HP203B_IOCTL_DOWN(hp203b);
hp203b_set_osr_channel(hp203b->client, 0, 0);
msleep(135);
data = hp203b_read_temperature(hp203b->client);
HP203B_IOCTL_UP(hp203b);
return sprintf(buf, "%d\n", data);
}
/* sysfs attributes */
static SENSOR_DEVICE_ATTR_RO(pressure, hp203b_pressure, 0);
static SENSOR_DEVICE_ATTR_RO(altitude, hp203b_altitude, 0);
static SENSOR_DEVICE_ATTR_RO(temperature, hp203b_temperature, 0);
static struct attribute *hp203b_attrs[] = {
&sensor_dev_attr_pressure.dev_attr.attr,
&sensor_dev_attr_altitude.dev_attr.attr,
&sensor_dev_attr_temperature.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(hp203b);
static int hp203b_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct hp203b *hp203b;
printk(KERN_EMERG"hp203b_probe\n");
hp203b = devm_kzalloc(dev, sizeof(*hp203b), GFP_KERNEL);
if (!hp203b)
return -ENOMEM;
hp203b->client = client;
mutex_init(&hp203b->lock);
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
hp203b, hp203b_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id hp203b_id[] = {
{ "hp203b", 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, hp203b_id);
static struct i2c_driver hp203b_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "hp203b",
},
.probe_new = hp203b_probe,
.id_table = hp203b_id,
};
module_i2c_driver(hp203b_driver);
#define VERSION_LEN 16
static char ver[VERSION_LEN];
module_param_string(version, ver, VERSION_LEN, S_IRUGO);
MODULE_PARM_DESC(version,"1.5.5");
MODULE_VERSION("1.5.5");
MODULE_AUTHOR("Dokin");
MODULE_DESCRIPTION("hp203b driver");
MODULE_LICENSE("GPL");
测试结果如下,注意结果要除以100才是最后真实的值。
cat /sys/devices/platform/50007800.i2c/i2c-1/1-0077/hwmon/hwmon3/temperature
3049
cat /sys/devices/platform/50007800.i2c/i2c-1/1-0077/hwmon/hwmon3/pressure
102830
cat /sys/devices/platform/50007800.i2c/i2c-1/1-0077/hwmon/hwmon3/altitude
-12475