Without further ado, let’s get straight to the code.
The device tree code is as follows. It should be noted that the I2C device address described in the device is 7 bits, not 8 bits. Otherwise, the I2C subsystem will prompt that the device cannot be found when initializing.
i2c3: i2c@50008c00 { compatible = "xxx-i2c3"; reg = <0x50008c00 0x800>; #address-cells = <1>; #size-cells = <0>; interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; i2c_speed = <100000>; hb203b@77{ compatible = "hp203b"; reg = w; }; \t };
driver:
#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/device.h> #include <linux/jiffies.h> #include <linux/delay.h> #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( & amp;dev->lock) #define HP203B_IOCTL_UP(dev) mutex_unlock( & amp;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\\ "); 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\\ "); 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\\ "); 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\\ "); return -1; } data = ((rxbuf[0] << 16) | (rxbuf[1] << 8) | rxbuf[2]) & amp; 0xfffff; if(data & 0x80000) data |= 0xfff00000; //complement processing 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 & amp; 0x07) << 3) | (channel & amp; 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; \t 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\\ ", 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\\ ", 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\\ ", 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 = & amp;client->dev; struct device *hwmon_dev; struct hp203b *hp203b; printk(KERN_EMERG"hp203b_probe\\ "); hp203b = devm_kzalloc(dev, sizeof(*hp203b), GFP_KERNEL); if (!hp203b) return -ENOMEM; hp203b->client = client; mutex_init( & amp;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); #defineVERSION_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");
The test results are as follows. Note that the result must be divided by 100 to get the final true value.
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