1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2016 Marek Vasut <marex@denx.de>
5 * Driver for Hope RF HP03 digital temperature and pressure sensor.
8 #define pr_fmt(fmt) "hp03: " fmt
10 #include <linux/module.h>
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/i2c.h>
14 #include <linux/regmap.h>
15 #include <linux/iio/iio.h>
16 #include <linux/iio/sysfs.h>
19 * The HP03 sensor occupies two fixed I2C addresses:
20 * 0x50 ... read-only EEPROM with calibration data
21 * 0x77 ... read-write ADC for pressure and temperature
23 #define HP03_EEPROM_ADDR 0x50
24 #define HP03_ADC_ADDR 0x77
26 #define HP03_EEPROM_CX_OFFSET 0x10
27 #define HP03_EEPROM_AB_OFFSET 0x1e
28 #define HP03_EEPROM_CD_OFFSET 0x20
30 #define HP03_ADC_WRITE_REG 0xff
31 #define HP03_ADC_READ_REG 0xfd
32 #define HP03_ADC_READ_PRESSURE 0xf0 /* D1 in datasheet */
33 #define HP03_ADC_READ_TEMP 0xe8 /* D2 in datasheet */
36 struct i2c_client
*client
;
38 struct gpio_desc
*xclr_gpio
;
40 struct i2c_client
*eeprom_client
;
41 struct regmap
*eeprom_regmap
;
43 s32 pressure
; /* kPa */
44 s32 temp
; /* Deg. C */
47 static const struct iio_chan_spec hp03_channels
[] = {
50 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
51 .info_mask_shared_by_type
= BIT(IIO_CHAN_INFO_SCALE
),
55 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
56 .info_mask_shared_by_type
= BIT(IIO_CHAN_INFO_SCALE
),
60 static bool hp03_is_writeable_reg(struct device
*dev
, unsigned int reg
)
65 static bool hp03_is_volatile_reg(struct device
*dev
, unsigned int reg
)
70 static const struct regmap_config hp03_regmap_config
= {
74 .max_register
= HP03_EEPROM_CD_OFFSET
+ 1,
75 .cache_type
= REGCACHE_RBTREE
,
77 .writeable_reg
= hp03_is_writeable_reg
,
78 .volatile_reg
= hp03_is_volatile_reg
,
81 static int hp03_get_temp_pressure(struct hp03_priv
*priv
, const u8 reg
)
85 ret
= i2c_smbus_write_byte_data(priv
->client
, HP03_ADC_WRITE_REG
, reg
);
89 msleep(50); /* Wait for conversion to finish */
91 return i2c_smbus_read_word_data(priv
->client
, HP03_ADC_READ_REG
);
94 static int hp03_update_temp_pressure(struct hp03_priv
*priv
)
96 struct device
*dev
= &priv
->client
->dev
;
99 int ab_val
, d1_val
, d2_val
, diff_val
, dut
, off
, sens
, x
;
102 /* Sample coefficients from EEPROM */
103 ret
= regmap_bulk_read(priv
->eeprom_regmap
, HP03_EEPROM_CX_OFFSET
,
104 coefs
, sizeof(coefs
));
106 dev_err(dev
, "Failed to read EEPROM (reg=%02x)\n",
107 HP03_EEPROM_CX_OFFSET
);
111 /* Sample Temperature and Pressure */
112 gpiod_set_value_cansleep(priv
->xclr_gpio
, 1);
114 ret
= hp03_get_temp_pressure(priv
, HP03_ADC_READ_PRESSURE
);
116 dev_err(dev
, "Failed to read pressure\n");
121 ret
= hp03_get_temp_pressure(priv
, HP03_ADC_READ_TEMP
);
123 dev_err(dev
, "Failed to read temperature\n");
128 gpiod_set_value_cansleep(priv
->xclr_gpio
, 0);
130 /* The Cx coefficients and Temp/Pressure values are MSB first. */
131 for (i
= 0; i
< 7; i
++)
132 cx_val
[i
] = (coefs
[2 * i
] << 8) | (coefs
[(2 * i
) + 1] << 0);
133 d1_val
= ((d1_val
>> 8) & 0xff) | ((d1_val
& 0xff) << 8);
134 d2_val
= ((d2_val
>> 8) & 0xff) | ((d2_val
& 0xff) << 8);
136 /* Coefficient voodoo from the HP03 datasheet. */
137 if (d2_val
>= cx_val
[4])
138 ab_val
= coefs
[14]; /* A-value */
140 ab_val
= coefs
[15]; /* B-value */
142 diff_val
= d2_val
- cx_val
[4];
143 dut
= (ab_val
* (diff_val
>> 7) * (diff_val
>> 7)) >> coefs
[16];
144 dut
= diff_val
- dut
;
146 off
= (cx_val
[1] + (((cx_val
[3] - 1024) * dut
) >> 14)) * 4;
147 sens
= cx_val
[0] + ((cx_val
[2] * dut
) >> 10);
148 x
= ((sens
* (d1_val
- 7168)) >> 14) - off
;
150 priv
->pressure
= ((x
* 100) >> 5) + (cx_val
[6] * 10);
151 priv
->temp
= 250 + ((dut
* cx_val
[5]) >> 16) - (dut
>> coefs
[17]);
156 gpiod_set_value_cansleep(priv
->xclr_gpio
, 0);
160 static int hp03_read_raw(struct iio_dev
*indio_dev
,
161 struct iio_chan_spec
const *chan
,
162 int *val
, int *val2
, long mask
)
164 struct hp03_priv
*priv
= iio_priv(indio_dev
);
167 mutex_lock(&priv
->lock
);
168 ret
= hp03_update_temp_pressure(priv
);
169 mutex_unlock(&priv
->lock
);
175 case IIO_CHAN_INFO_RAW
:
176 switch (chan
->type
) {
178 *val
= priv
->pressure
;
187 case IIO_CHAN_INFO_SCALE
:
188 switch (chan
->type
) {
192 return IIO_VAL_INT_PLUS_MICRO
;
207 static const struct iio_info hp03_info
= {
208 .read_raw
= &hp03_read_raw
,
211 static int hp03_probe(struct i2c_client
*client
,
212 const struct i2c_device_id
*id
)
214 struct device
*dev
= &client
->dev
;
215 struct iio_dev
*indio_dev
;
216 struct hp03_priv
*priv
;
219 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*priv
));
223 priv
= iio_priv(indio_dev
);
224 priv
->client
= client
;
225 mutex_init(&priv
->lock
);
227 indio_dev
->name
= id
->name
;
228 indio_dev
->channels
= hp03_channels
;
229 indio_dev
->num_channels
= ARRAY_SIZE(hp03_channels
);
230 indio_dev
->info
= &hp03_info
;
231 indio_dev
->modes
= INDIO_DIRECT_MODE
;
233 priv
->xclr_gpio
= devm_gpiod_get_index(dev
, "xclr", 0, GPIOD_OUT_HIGH
);
234 if (IS_ERR(priv
->xclr_gpio
)) {
235 dev_err(dev
, "Failed to claim XCLR GPIO\n");
236 ret
= PTR_ERR(priv
->xclr_gpio
);
241 * Allocate another device for the on-sensor EEPROM,
242 * which has it's dedicated I2C address and contains
243 * the calibration constants for the sensor.
245 priv
->eeprom_client
= i2c_new_dummy_device(client
->adapter
, HP03_EEPROM_ADDR
);
246 if (IS_ERR(priv
->eeprom_client
)) {
247 dev_err(dev
, "New EEPROM I2C device failed\n");
248 return PTR_ERR(priv
->eeprom_client
);
251 priv
->eeprom_regmap
= regmap_init_i2c(priv
->eeprom_client
,
252 &hp03_regmap_config
);
253 if (IS_ERR(priv
->eeprom_regmap
)) {
254 dev_err(dev
, "Failed to allocate EEPROM regmap\n");
255 ret
= PTR_ERR(priv
->eeprom_regmap
);
256 goto err_cleanup_eeprom_client
;
259 ret
= iio_device_register(indio_dev
);
261 dev_err(dev
, "Failed to register IIO device\n");
262 goto err_cleanup_eeprom_regmap
;
265 i2c_set_clientdata(client
, indio_dev
);
269 err_cleanup_eeprom_regmap
:
270 regmap_exit(priv
->eeprom_regmap
);
272 err_cleanup_eeprom_client
:
273 i2c_unregister_device(priv
->eeprom_client
);
277 static int hp03_remove(struct i2c_client
*client
)
279 struct iio_dev
*indio_dev
= i2c_get_clientdata(client
);
280 struct hp03_priv
*priv
= iio_priv(indio_dev
);
282 iio_device_unregister(indio_dev
);
283 regmap_exit(priv
->eeprom_regmap
);
284 i2c_unregister_device(priv
->eeprom_client
);
289 static const struct i2c_device_id hp03_id
[] = {
293 MODULE_DEVICE_TABLE(i2c
, hp03_id
);
295 static const struct of_device_id hp03_of_match
[] = {
296 { .compatible
= "hoperf,hp03" },
299 MODULE_DEVICE_TABLE(of
, hp03_of_match
);
301 static struct i2c_driver hp03_driver
= {
304 .of_match_table
= hp03_of_match
,
307 .remove
= hp03_remove
,
310 module_i2c_driver(hp03_driver
);
312 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
313 MODULE_DESCRIPTION("Driver for Hope RF HP03 pressure and temperature sensor");
314 MODULE_LICENSE("GPL v2");