1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for Sensirion sdp500 and sdp510 pressure sensors
5 * Datasheet: https://sensirion.com/resource/datasheet/sdp600
9 #include <linux/crc8.h>
10 #include <linux/iio/iio.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/regulator/consumer.h>
13 #include <linux/unaligned.h>
15 #define SDP500_CRC8_POLYNOMIAL 0x31 /* x8+x5+x4+1 (normalized to 0x31) */
16 #define SDP500_READ_SIZE 3
18 #define SDP500_I2C_START_MEAS 0xF1
24 DECLARE_CRC8_TABLE(sdp500_crc8_table
);
26 static int sdp500_start_measurement(struct sdp500_data
*data
)
28 struct i2c_client
*client
= to_i2c_client(data
->dev
);
30 return i2c_smbus_write_byte(client
, SDP500_I2C_START_MEAS
);
33 static const struct iio_chan_spec sdp500_channels
[] = {
36 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
37 BIT(IIO_CHAN_INFO_SCALE
),
41 static int sdp500_read_raw(struct iio_dev
*indio_dev
,
42 struct iio_chan_spec
const *chan
,
43 int *val
, int *val2
, long mask
)
46 u8 rxbuf
[SDP500_READ_SIZE
];
47 u8 received_crc
, calculated_crc
;
48 struct sdp500_data
*data
= iio_priv(indio_dev
);
49 struct i2c_client
*client
= to_i2c_client(data
->dev
);
52 case IIO_CHAN_INFO_RAW
:
53 ret
= i2c_master_recv(client
, rxbuf
, SDP500_READ_SIZE
);
55 dev_err(data
->dev
, "Failed to receive data");
58 if (ret
!= SDP500_READ_SIZE
) {
59 dev_err(data
->dev
, "Data is received wrongly");
63 received_crc
= rxbuf
[2];
64 calculated_crc
= crc8(sdp500_crc8_table
, rxbuf
,
65 sizeof(rxbuf
) - 1, 0x00);
66 if (received_crc
!= calculated_crc
) {
68 "calculated crc = 0x%.2X, received 0x%.2X",
69 calculated_crc
, received_crc
);
73 *val
= get_unaligned_be16(rxbuf
);
75 case IIO_CHAN_INFO_SCALE
:
79 return IIO_VAL_FRACTIONAL
;
85 static const struct iio_info sdp500_info
= {
86 .read_raw
= &sdp500_read_raw
,
89 static int sdp500_probe(struct i2c_client
*client
)
91 struct iio_dev
*indio_dev
;
92 struct sdp500_data
*data
;
93 struct device
*dev
= &client
->dev
;
95 u8 rxbuf
[SDP500_READ_SIZE
];
97 ret
= devm_regulator_get_enable(dev
, "vdd");
99 return dev_err_probe(dev
, ret
,
100 "Failed to get and enable regulator\n");
102 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*data
));
106 /* has to be done before the first i2c communication */
107 crc8_populate_msb(sdp500_crc8_table
, SDP500_CRC8_POLYNOMIAL
);
109 data
= iio_priv(indio_dev
);
112 indio_dev
->name
= "sdp500";
113 indio_dev
->channels
= sdp500_channels
;
114 indio_dev
->info
= &sdp500_info
;
115 indio_dev
->modes
= INDIO_DIRECT_MODE
;
116 indio_dev
->num_channels
= ARRAY_SIZE(sdp500_channels
);
118 ret
= sdp500_start_measurement(data
);
120 return dev_err_probe(dev
, ret
, "Failed to start measurement");
122 /* First measurement is not correct, read it out to get rid of it */
123 i2c_master_recv(client
, rxbuf
, SDP500_READ_SIZE
);
125 ret
= devm_iio_device_register(dev
, indio_dev
);
127 return dev_err_probe(dev
, ret
, "Failed to register indio_dev");
132 static const struct i2c_device_id sdp500_id
[] = {
136 MODULE_DEVICE_TABLE(i2c
, sdp500_id
);
138 static const struct of_device_id sdp500_of_match
[] = {
139 { .compatible
= "sensirion,sdp500" },
142 MODULE_DEVICE_TABLE(of
, sdp500_of_match
);
144 static struct i2c_driver sdp500_driver
= {
146 .name
= "sensirion,sdp500",
147 .of_match_table
= sdp500_of_match
,
149 .probe
= sdp500_probe
,
150 .id_table
= sdp500_id
,
152 module_i2c_driver(sdp500_driver
);
154 MODULE_AUTHOR("Thomas Sioutas <thomas.sioutas@prodrive-technologies.com>");
155 MODULE_DESCRIPTION("Driver for Sensirion SDP500 differential pressure sensor");
156 MODULE_LICENSE("GPL");