HP203B air pressure temperature sensor driver

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