2 * Copyright (c) 2016 Marek Vasut <marex@denx.de>
4 * Driver for Hope RF HP03 digital temperature and pressure sensor.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #define pr_fmt(fmt) "hp03: " fmt
13 #include <linux/module.h>
14 #include <linux/delay.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/i2c.h>
17 #include <linux/regmap.h>
18 #include <linux/iio/iio.h>
19 #include <linux/iio/sysfs.h>
22 * The HP03 sensor occupies two fixed I2C addresses:
23 * 0x50 ... read-only EEPROM with calibration data
24 * 0x77 ... read-write ADC for pressure and temperature
26 #define HP03_EEPROM_ADDR 0x50
27 #define HP03_ADC_ADDR 0x77
29 #define HP03_EEPROM_CX_OFFSET 0x10
30 #define HP03_EEPROM_AB_OFFSET 0x1e
31 #define HP03_EEPROM_CD_OFFSET 0x20
33 #define HP03_ADC_WRITE_REG 0xff
34 #define HP03_ADC_READ_REG 0xfd
35 #define HP03_ADC_READ_PRESSURE 0xf0 /* D1 in datasheet */
36 #define HP03_ADC_READ_TEMP 0xe8 /* D2 in datasheet */
39 struct i2c_client
*client
;
41 struct gpio_desc
*xclr_gpio
;
43 struct i2c_client
*eeprom_client
;
44 struct regmap
*eeprom_regmap
;
46 s32 pressure
; /* kPa */
47 s32 temp
; /* Deg. C */
50 static const struct iio_chan_spec hp03_channels
[] = {
53 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
54 .info_mask_shared_by_type
= BIT(IIO_CHAN_INFO_SCALE
),
58 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
59 .info_mask_shared_by_type
= BIT(IIO_CHAN_INFO_SCALE
),
63 static bool hp03_is_writeable_reg(struct device
*dev
, unsigned int reg
)
68 static bool hp03_is_volatile_reg(struct device
*dev
, unsigned int reg
)
73 static const struct regmap_config hp03_regmap_config
= {
77 .max_register
= HP03_EEPROM_CD_OFFSET
+ 1,
78 .cache_type
= REGCACHE_RBTREE
,
80 .writeable_reg
= hp03_is_writeable_reg
,
81 .volatile_reg
= hp03_is_volatile_reg
,
84 static int hp03_get_temp_pressure(struct hp03_priv
*priv
, const u8 reg
)
88 ret
= i2c_smbus_write_byte_data(priv
->client
, HP03_ADC_WRITE_REG
, reg
);
92 msleep(50); /* Wait for conversion to finish */
94 return i2c_smbus_read_word_data(priv
->client
, HP03_ADC_READ_REG
);
97 static int hp03_update_temp_pressure(struct hp03_priv
*priv
)
99 struct device
*dev
= &priv
->client
->dev
;
102 int ab_val
, d1_val
, d2_val
, diff_val
, dut
, off
, sens
, x
;
105 /* Sample coefficients from EEPROM */
106 ret
= regmap_bulk_read(priv
->eeprom_regmap
, HP03_EEPROM_CX_OFFSET
,
107 coefs
, sizeof(coefs
));
109 dev_err(dev
, "Failed to read EEPROM (reg=%02x)\n",
110 HP03_EEPROM_CX_OFFSET
);
114 /* Sample Temperature and Pressure */
115 gpiod_set_value_cansleep(priv
->xclr_gpio
, 1);
117 ret
= hp03_get_temp_pressure(priv
, HP03_ADC_READ_PRESSURE
);
119 dev_err(dev
, "Failed to read pressure\n");
124 ret
= hp03_get_temp_pressure(priv
, HP03_ADC_READ_TEMP
);
126 dev_err(dev
, "Failed to read temperature\n");
131 gpiod_set_value_cansleep(priv
->xclr_gpio
, 0);
133 /* The Cx coefficients and Temp/Pressure values are MSB first. */
134 for (i
= 0; i
< 7; i
++)
135 cx_val
[i
] = (coefs
[2 * i
] << 8) | (coefs
[(2 * i
) + 1] << 0);
136 d1_val
= ((d1_val
>> 8) & 0xff) | ((d1_val
& 0xff) << 8);
137 d2_val
= ((d2_val
>> 8) & 0xff) | ((d2_val
& 0xff) << 8);
139 /* Coefficient voodoo from the HP03 datasheet. */
140 if (d2_val
>= cx_val
[4])
141 ab_val
= coefs
[14]; /* A-value */
143 ab_val
= coefs
[15]; /* B-value */
145 diff_val
= d2_val
- cx_val
[4];
146 dut
= (ab_val
* (diff_val
>> 7) * (diff_val
>> 7)) >> coefs
[16];
147 dut
= diff_val
- dut
;
149 off
= (cx_val
[1] + (((cx_val
[3] - 1024) * dut
) >> 14)) * 4;
150 sens
= cx_val
[0] + ((cx_val
[2] * dut
) >> 10);
151 x
= ((sens
* (d1_val
- 7168)) >> 14) - off
;
153 priv
->pressure
= ((x
* 100) >> 5) + (cx_val
[6] * 10);
154 priv
->temp
= 250 + ((dut
* cx_val
[5]) >> 16) - (dut
>> coefs
[17]);
159 gpiod_set_value_cansleep(priv
->xclr_gpio
, 0);
163 static int hp03_read_raw(struct iio_dev
*indio_dev
,
164 struct iio_chan_spec
const *chan
,
165 int *val
, int *val2
, long mask
)
167 struct hp03_priv
*priv
= iio_priv(indio_dev
);
170 mutex_lock(&priv
->lock
);
171 ret
= hp03_update_temp_pressure(priv
);
172 mutex_unlock(&priv
->lock
);
178 case IIO_CHAN_INFO_RAW
:
179 switch (chan
->type
) {
181 *val
= priv
->pressure
;
190 case IIO_CHAN_INFO_SCALE
:
191 switch (chan
->type
) {
195 return IIO_VAL_INT_PLUS_MICRO
;
210 static const struct iio_info hp03_info
= {
211 .read_raw
= &hp03_read_raw
,
214 static int hp03_probe(struct i2c_client
*client
,
215 const struct i2c_device_id
*id
)
217 struct device
*dev
= &client
->dev
;
218 struct iio_dev
*indio_dev
;
219 struct hp03_priv
*priv
;
222 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*priv
));
226 priv
= iio_priv(indio_dev
);
227 priv
->client
= client
;
228 mutex_init(&priv
->lock
);
230 indio_dev
->dev
.parent
= dev
;
231 indio_dev
->name
= id
->name
;
232 indio_dev
->channels
= hp03_channels
;
233 indio_dev
->num_channels
= ARRAY_SIZE(hp03_channels
);
234 indio_dev
->info
= &hp03_info
;
235 indio_dev
->modes
= INDIO_DIRECT_MODE
;
237 priv
->xclr_gpio
= devm_gpiod_get_index(dev
, "xclr", 0, GPIOD_OUT_HIGH
);
238 if (IS_ERR(priv
->xclr_gpio
)) {
239 dev_err(dev
, "Failed to claim XCLR GPIO\n");
240 ret
= PTR_ERR(priv
->xclr_gpio
);
245 * Allocate another device for the on-sensor EEPROM,
246 * which has it's dedicated I2C address and contains
247 * the calibration constants for the sensor.
249 priv
->eeprom_client
= i2c_new_dummy(client
->adapter
, HP03_EEPROM_ADDR
);
250 if (!priv
->eeprom_client
) {
251 dev_err(dev
, "New EEPROM I2C device failed\n");
255 priv
->eeprom_regmap
= regmap_init_i2c(priv
->eeprom_client
,
256 &hp03_regmap_config
);
257 if (IS_ERR(priv
->eeprom_regmap
)) {
258 dev_err(dev
, "Failed to allocate EEPROM regmap\n");
259 ret
= PTR_ERR(priv
->eeprom_regmap
);
260 goto err_cleanup_eeprom_client
;
263 ret
= iio_device_register(indio_dev
);
265 dev_err(dev
, "Failed to register IIO device\n");
266 goto err_cleanup_eeprom_regmap
;
269 i2c_set_clientdata(client
, indio_dev
);
273 err_cleanup_eeprom_regmap
:
274 regmap_exit(priv
->eeprom_regmap
);
276 err_cleanup_eeprom_client
:
277 i2c_unregister_device(priv
->eeprom_client
);
281 static int hp03_remove(struct i2c_client
*client
)
283 struct iio_dev
*indio_dev
= i2c_get_clientdata(client
);
284 struct hp03_priv
*priv
= iio_priv(indio_dev
);
286 iio_device_unregister(indio_dev
);
287 regmap_exit(priv
->eeprom_regmap
);
288 i2c_unregister_device(priv
->eeprom_client
);
293 static const struct i2c_device_id hp03_id
[] = {
297 MODULE_DEVICE_TABLE(i2c
, hp03_id
);
299 static const struct of_device_id hp03_of_match
[] = {
300 { .compatible
= "hoperf,hp03" },
303 MODULE_DEVICE_TABLE(of
, hp03_of_match
);
305 static struct i2c_driver hp03_driver
= {
308 .of_match_table
= hp03_of_match
,
311 .remove
= hp03_remove
,
314 module_i2c_driver(hp03_driver
);
316 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
317 MODULE_DESCRIPTION("Driver for Hope RF HP03 pressure and temperature sensor");
318 MODULE_LICENSE("GPL v2");