Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: pressure: add Honeywell ABP2 driver

Adds driver for digital Honeywell ABP2 series of board mount
pressure and temperature sensors.

This driver covers 113 different pressure ranges and units on
both i2c and SPI buses.

The communication protocol involves sending two simple commands
to the sensor and there is no register access or a memory map.
For this reason the regmap API was not used.

The i2c address is hardcoded and depends on the part number.

Optional end of conversion interrupt control is present on the
i2c variants of the chips.
The EOC can also be defined for the SPI variants if a non-ABP2
but compatible chip is to be driven.

Tested on two sensors (ABP2MRRT001PDSA3 and ABP2DANT001BA2A3).

ocuments/sps-siot-abp2-series-datasheet-32350268-en.pdf

Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/basic-abp2-series/d
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Petre Rodan and committed by
Jonathan Cameron
47d323ce b2192756

+807
+1
MAINTAINERS
··· 11510 11510 L: linux-iio@vger.kernel.org 11511 11511 S: Maintained 11512 11512 F: Documentation/devicetree/bindings/iio/pressure/honeywell,abp2030pa.yaml 11513 + F: drivers/iio/pressure/abp2030pa* 11513 11514 11514 11515 HONEYWELL HSC030PA PRESSURE SENSOR SERIES IIO DRIVER 11515 11516 M: Petre Rodan <petre.rodan@subdimension.ro>
+29
drivers/iio/pressure/Kconfig
··· 16 16 To compile this driver as a module, choose M here: the module 17 17 will be called abp060mg. 18 18 19 + config ABP2030PA 20 + tristate 21 + select IIO_BUFFER 22 + select IIO_TRIGGERED_BUFFER 23 + 24 + config ABP2030PA_I2C 25 + tristate "Honeywell ABP2 pressure sensor series I2C driver" 26 + depends on I2C 27 + select ABP2030PA 28 + help 29 + Say Y here to build I2C bus support for the Honeywell ABP2 30 + series pressure and temperature digital sensor. 31 + 32 + To compile this driver as a module, choose M here: the module 33 + will be called abp2030pa_i2c and you will also get abp2030pa 34 + for the core module. 35 + 36 + config ABP2030PA_SPI 37 + tristate "Honeywell ABP2 pressure sensor series SPI driver" 38 + depends on SPI_MASTER 39 + select ABP2030PA 40 + help 41 + Say Y here to build I2C bus support for the Honeywell ABP2 42 + series pressure and temperature digital sensor. 43 + 44 + To compile this driver as a module, choose M here: the module 45 + will be called abp2030pa_spi and you will also get abp2030pa 46 + for the core module. 47 + 19 48 config ROHM_BM1390 20 49 tristate "ROHM BM1390GLV-Z pressure sensor driver" 21 50 depends on I2C
+3
drivers/iio/pressure/Makefile
··· 5 5 6 6 # When adding new entries keep the list in alphabetical order 7 7 obj-$(CONFIG_ABP060MG) += abp060mg.o 8 + obj-$(CONFIG_ABP2030PA) += abp2030pa.o 9 + obj-$(CONFIG_ABP2030PA_I2C) += abp2030pa_i2c.o 10 + obj-$(CONFIG_ABP2030PA_SPI) += abp2030pa_spi.o 8 11 obj-$(CONFIG_ADP810) += adp810.o 9 12 obj-$(CONFIG_ROHM_BM1390) += rohm-bm1390.o 10 13 obj-$(CONFIG_BMP280) += bmp280.o
+544
drivers/iio/pressure/abp2030pa.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Honeywell ABP2 series pressure sensor driver 4 + * 5 + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> 6 + * 7 + * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/basic-abp2-series/documents/sps-siot-abp2-series-datasheet-32350268-en.pdf 8 + */ 9 + 10 + #include <linux/array_size.h> 11 + #include <linux/bits.h> 12 + #include <linux/completion.h> 13 + #include <linux/delay.h> 14 + #include <linux/dev_printk.h> 15 + #include <linux/device.h> 16 + #include <linux/errno.h> 17 + #include <linux/export.h> 18 + #include <linux/gpio/consumer.h> 19 + #include <linux/interrupt.h> 20 + #include <linux/jiffies.h> 21 + #include <linux/math64.h> 22 + #include <linux/module.h> 23 + #include <linux/property.h> 24 + #include <linux/regulator/consumer.h> 25 + #include <linux/string.h> 26 + #include <linux/time.h> 27 + #include <linux/types.h> 28 + #include <linux/unaligned.h> 29 + #include <linux/units.h> 30 + 31 + #include <linux/iio/buffer.h> 32 + #include <linux/iio/iio.h> 33 + #include <linux/iio/trigger_consumer.h> 34 + #include <linux/iio/triggered_buffer.h> 35 + 36 + #include "abp2030pa.h" 37 + 38 + /* Status byte flags */ 39 + #define ABP2_ST_POWER BIT(6) /* 1 if device is powered */ 40 + #define ABP2_ST_BUSY BIT(5) /* 1 if device is busy */ 41 + 42 + #define ABP2_CMD_NOP 0xf0 43 + #define ABP2_CMD_SYNC 0xaa 44 + #define ABP2_PKT_SYNC_LEN 3 45 + #define ABP2_PKT_NOP_LEN ABP2_MEASUREMENT_RD_SIZE 46 + 47 + struct abp2_func_spec { 48 + u32 output_min; 49 + u32 output_max; 50 + }; 51 + 52 + /* transfer function A: 10% to 90% of 2^24 */ 53 + static const struct abp2_func_spec abp2_func_spec[] = { 54 + [ABP2_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 }, 55 + }; 56 + 57 + enum abp2_variants { 58 + ABP2001BA, ABP21_6BA, ABP22_5BA, ABP2004BA, ABP2006BA, ABP2008BA, 59 + ABP2010BA, ABP2012BA, ABP2001BD, ABP21_6BD, ABP22_5BD, ABP2004BD, 60 + ABP2001BG, ABP21_6BG, ABP22_5BG, ABP2004BG, ABP2006BG, ABP2008BG, 61 + ABP2010BG, ABP2012BG, ABP2001GG, ABP21_2GG, ABP2100KA, ABP2160KA, 62 + ABP2250KA, ABP2001KD, ABP21_6KD, ABP22_5KD, ABP2004KD, ABP2006KD, 63 + ABP2010KD, ABP2016KD, ABP2025KD, ABP2040KD, ABP2060KD, ABP2100KD, 64 + ABP2160KD, ABP2250KD, ABP2400KD, ABP2001KG, ABP21_6KG, ABP22_5KG, 65 + ABP2004KG, ABP2006KG, ABP2010KG, ABP2016KG, ABP2025KG, ABP2040KG, 66 + ABP2060KG, ABP2100KG, ABP2160KG, ABP2250KG, ABP2400KG, ABP2600KG, 67 + ABP2800KG, ABP2250LD, ABP2600LD, ABP2600LG, ABP22_5MD, ABP2006MD, 68 + ABP2010MD, ABP2016MD, ABP2025MD, ABP2040MD, ABP2060MD, ABP2100MD, 69 + ABP2160MD, ABP2250MD, ABP2400MD, ABP2600MD, ABP2006MG, ABP2010MG, 70 + ABP2016MG, ABP2025MG, ABP2040MG, ABP2060MG, ABP2100MG, ABP2160MG, 71 + ABP2250MG, ABP2400MG, ABP2600MG, ABP2001ND, ABP2002ND, ABP2004ND, 72 + ABP2005ND, ABP2010ND, ABP2020ND, ABP2030ND, ABP2002NG, ABP2004NG, 73 + ABP2005NG, ABP2010NG, ABP2020NG, ABP2030NG, ABP2015PA, ABP2030PA, 74 + ABP2060PA, ABP2100PA, ABP2150PA, ABP2175PA, ABP2001PD, ABP2005PD, 75 + ABP2015PD, ABP2030PD, ABP2060PD, ABP2001PG, ABP2005PG, ABP2015PG, 76 + ABP2030PG, ABP2060PG, ABP2100PG, ABP2150PG, ABP2175PG, 77 + }; 78 + 79 + static const char * const abp2_triplet_variants[] = { 80 + [ABP2001BA] = "001BA", [ABP21_6BA] = "1.6BA", [ABP22_5BA] = "2.5BA", 81 + [ABP2004BA] = "004BA", [ABP2006BA] = "006BA", [ABP2008BA] = "008BA", 82 + [ABP2010BA] = "010BA", [ABP2012BA] = "012BA", [ABP2001BD] = "001BD", 83 + [ABP21_6BD] = "1.6BD", [ABP22_5BD] = "2.5BD", [ABP2004BD] = "004BD", 84 + [ABP2001BG] = "001BG", [ABP21_6BG] = "1.6BG", [ABP22_5BG] = "2.5BG", 85 + [ABP2004BG] = "004BG", [ABP2006BG] = "006BG", [ABP2008BG] = "008BG", 86 + [ABP2010BG] = "010BG", [ABP2012BG] = "012BG", [ABP2001GG] = "001GG", 87 + [ABP21_2GG] = "1.2GG", [ABP2100KA] = "100KA", [ABP2160KA] = "160KA", 88 + [ABP2250KA] = "250KA", [ABP2001KD] = "001KD", [ABP21_6KD] = "1.6KD", 89 + [ABP22_5KD] = "2.5KD", [ABP2004KD] = "004KD", [ABP2006KD] = "006KD", 90 + [ABP2010KD] = "010KD", [ABP2016KD] = "016KD", [ABP2025KD] = "025KD", 91 + [ABP2040KD] = "040KD", [ABP2060KD] = "060KD", [ABP2100KD] = "100KD", 92 + [ABP2160KD] = "160KD", [ABP2250KD] = "250KD", [ABP2400KD] = "400KD", 93 + [ABP2001KG] = "001KG", [ABP21_6KG] = "1.6KG", [ABP22_5KG] = "2.5KG", 94 + [ABP2004KG] = "004KG", [ABP2006KG] = "006KG", [ABP2010KG] = "010KG", 95 + [ABP2016KG] = "016KG", [ABP2025KG] = "025KG", [ABP2040KG] = "040KG", 96 + [ABP2060KG] = "060KG", [ABP2100KG] = "100KG", [ABP2160KG] = "160KG", 97 + [ABP2250KG] = "250KG", [ABP2400KG] = "400KG", [ABP2600KG] = "600KG", 98 + [ABP2800KG] = "800KG", [ABP2250LD] = "250LD", [ABP2600LD] = "600LD", 99 + [ABP2600LG] = "600LG", [ABP22_5MD] = "2.5MD", [ABP2006MD] = "006MD", 100 + [ABP2010MD] = "010MD", [ABP2016MD] = "016MD", [ABP2025MD] = "025MD", 101 + [ABP2040MD] = "040MD", [ABP2060MD] = "060MD", [ABP2100MD] = "100MD", 102 + [ABP2160MD] = "160MD", [ABP2250MD] = "250MD", [ABP2400MD] = "400MD", 103 + [ABP2600MD] = "600MD", [ABP2006MG] = "006MG", [ABP2010MG] = "010MG", 104 + [ABP2016MG] = "016MG", [ABP2025MG] = "025MG", [ABP2040MG] = "040MG", 105 + [ABP2060MG] = "060MG", [ABP2100MG] = "100MG", [ABP2160MG] = "160MG", 106 + [ABP2250MG] = "250MG", [ABP2400MG] = "400MG", [ABP2600MG] = "600MG", 107 + [ABP2001ND] = "001ND", [ABP2002ND] = "002ND", [ABP2004ND] = "004ND", 108 + [ABP2005ND] = "005ND", [ABP2010ND] = "010ND", [ABP2020ND] = "020ND", 109 + [ABP2030ND] = "030ND", [ABP2002NG] = "002NG", [ABP2004NG] = "004NG", 110 + [ABP2005NG] = "005NG", [ABP2010NG] = "010NG", [ABP2020NG] = "020NG", 111 + [ABP2030NG] = "030NG", [ABP2015PA] = "015PA", [ABP2030PA] = "030PA", 112 + [ABP2060PA] = "060PA", [ABP2100PA] = "100PA", [ABP2150PA] = "150PA", 113 + [ABP2175PA] = "175PA", [ABP2001PD] = "001PD", [ABP2005PD] = "005PD", 114 + [ABP2015PD] = "015PD", [ABP2030PD] = "030PD", [ABP2060PD] = "060PD", 115 + [ABP2001PG] = "001PG", [ABP2005PG] = "005PG", [ABP2015PG] = "015PG", 116 + [ABP2030PG] = "030PG", [ABP2060PG] = "060PG", [ABP2100PG] = "100PG", 117 + [ABP2150PG] = "150PG", [ABP2175PG] = "175PG", 118 + }; 119 + 120 + /** 121 + * struct abp2_range_config - list of pressure ranges based on nomenclature 122 + * @pmin: lowest pressure that can be measured 123 + * @pmax: highest pressure that can be measured 124 + */ 125 + struct abp2_range_config { 126 + s32 pmin; 127 + s32 pmax; 128 + }; 129 + 130 + /* All min max limits have been converted to pascals */ 131 + static const struct abp2_range_config abp2_range_config[] = { 132 + [ABP2001BA] = { .pmin = 0, .pmax = 100000 }, 133 + [ABP21_6BA] = { .pmin = 0, .pmax = 160000 }, 134 + [ABP22_5BA] = { .pmin = 0, .pmax = 250000 }, 135 + [ABP2004BA] = { .pmin = 0, .pmax = 400000 }, 136 + [ABP2006BA] = { .pmin = 0, .pmax = 600000 }, 137 + [ABP2008BA] = { .pmin = 0, .pmax = 800000 }, 138 + [ABP2010BA] = { .pmin = 0, .pmax = 1000000 }, 139 + [ABP2012BA] = { .pmin = 0, .pmax = 1200000 }, 140 + [ABP2001BD] = { .pmin = -100000, .pmax = 100000 }, 141 + [ABP21_6BD] = { .pmin = -160000, .pmax = 160000 }, 142 + [ABP22_5BD] = { .pmin = -250000, .pmax = 250000 }, 143 + [ABP2004BD] = { .pmin = -400000, .pmax = 400000 }, 144 + [ABP2001BG] = { .pmin = 0, .pmax = 100000 }, 145 + [ABP21_6BG] = { .pmin = 0, .pmax = 160000 }, 146 + [ABP22_5BG] = { .pmin = 0, .pmax = 250000 }, 147 + [ABP2004BG] = { .pmin = 0, .pmax = 400000 }, 148 + [ABP2006BG] = { .pmin = 0, .pmax = 600000 }, 149 + [ABP2008BG] = { .pmin = 0, .pmax = 800000 }, 150 + [ABP2010BG] = { .pmin = 0, .pmax = 1000000 }, 151 + [ABP2012BG] = { .pmin = 0, .pmax = 1200000 }, 152 + [ABP2001GG] = { .pmin = 0, .pmax = 1000000 }, 153 + [ABP21_2GG] = { .pmin = 0, .pmax = 1200000 }, 154 + [ABP2100KA] = { .pmin = 0, .pmax = 100000 }, 155 + [ABP2160KA] = { .pmin = 0, .pmax = 160000 }, 156 + [ABP2250KA] = { .pmin = 0, .pmax = 250000 }, 157 + [ABP2001KD] = { .pmin = -1000, .pmax = 1000 }, 158 + [ABP21_6KD] = { .pmin = -1600, .pmax = 1600 }, 159 + [ABP22_5KD] = { .pmin = -2500, .pmax = 2500 }, 160 + [ABP2004KD] = { .pmin = -4000, .pmax = 4000 }, 161 + [ABP2006KD] = { .pmin = -6000, .pmax = 6000 }, 162 + [ABP2010KD] = { .pmin = -10000, .pmax = 10000 }, 163 + [ABP2016KD] = { .pmin = -16000, .pmax = 16000 }, 164 + [ABP2025KD] = { .pmin = -25000, .pmax = 25000 }, 165 + [ABP2040KD] = { .pmin = -40000, .pmax = 40000 }, 166 + [ABP2060KD] = { .pmin = -60000, .pmax = 60000 }, 167 + [ABP2100KD] = { .pmin = -100000, .pmax = 100000 }, 168 + [ABP2160KD] = { .pmin = -160000, .pmax = 160000 }, 169 + [ABP2250KD] = { .pmin = -250000, .pmax = 250000 }, 170 + [ABP2400KD] = { .pmin = -400000, .pmax = 400000 }, 171 + [ABP2001KG] = { .pmin = 0, .pmax = 1000 }, 172 + [ABP21_6KG] = { .pmin = 0, .pmax = 1600 }, 173 + [ABP22_5KG] = { .pmin = 0, .pmax = 2500 }, 174 + [ABP2004KG] = { .pmin = 0, .pmax = 4000 }, 175 + [ABP2006KG] = { .pmin = 0, .pmax = 6000 }, 176 + [ABP2010KG] = { .pmin = 0, .pmax = 10000 }, 177 + [ABP2016KG] = { .pmin = 0, .pmax = 16000 }, 178 + [ABP2025KG] = { .pmin = 0, .pmax = 25000 }, 179 + [ABP2040KG] = { .pmin = 0, .pmax = 40000 }, 180 + [ABP2060KG] = { .pmin = 0, .pmax = 60000 }, 181 + [ABP2100KG] = { .pmin = 0, .pmax = 100000 }, 182 + [ABP2160KG] = { .pmin = 0, .pmax = 160000 }, 183 + [ABP2250KG] = { .pmin = 0, .pmax = 250000 }, 184 + [ABP2400KG] = { .pmin = 0, .pmax = 400000 }, 185 + [ABP2600KG] = { .pmin = 0, .pmax = 600000 }, 186 + [ABP2800KG] = { .pmin = 0, .pmax = 800000 }, 187 + [ABP2250LD] = { .pmin = -250, .pmax = 250 }, 188 + [ABP2600LD] = { .pmin = -600, .pmax = 600 }, 189 + [ABP2600LG] = { .pmin = 0, .pmax = 600 }, 190 + [ABP22_5MD] = { .pmin = -250, .pmax = 250 }, 191 + [ABP2006MD] = { .pmin = -600, .pmax = 600 }, 192 + [ABP2010MD] = { .pmin = -1000, .pmax = 1000 }, 193 + [ABP2016MD] = { .pmin = -1600, .pmax = 1600 }, 194 + [ABP2025MD] = { .pmin = -2500, .pmax = 2500 }, 195 + [ABP2040MD] = { .pmin = -4000, .pmax = 4000 }, 196 + [ABP2060MD] = { .pmin = -6000, .pmax = 6000 }, 197 + [ABP2100MD] = { .pmin = -10000, .pmax = 10000 }, 198 + [ABP2160MD] = { .pmin = -16000, .pmax = 16000 }, 199 + [ABP2250MD] = { .pmin = -25000, .pmax = 25000 }, 200 + [ABP2400MD] = { .pmin = -40000, .pmax = 40000 }, 201 + [ABP2600MD] = { .pmin = -60000, .pmax = 60000 }, 202 + [ABP2006MG] = { .pmin = 0, .pmax = 600 }, 203 + [ABP2010MG] = { .pmin = 0, .pmax = 1000 }, 204 + [ABP2016MG] = { .pmin = 0, .pmax = 1600 }, 205 + [ABP2025MG] = { .pmin = 0, .pmax = 2500 }, 206 + [ABP2040MG] = { .pmin = 0, .pmax = 4000 }, 207 + [ABP2060MG] = { .pmin = 0, .pmax = 6000 }, 208 + [ABP2100MG] = { .pmin = 0, .pmax = 10000 }, 209 + [ABP2160MG] = { .pmin = 0, .pmax = 16000 }, 210 + [ABP2250MG] = { .pmin = 0, .pmax = 25000 }, 211 + [ABP2400MG] = { .pmin = 0, .pmax = 40000 }, 212 + [ABP2600MG] = { .pmin = 0, .pmax = 60000 }, 213 + [ABP2001ND] = { .pmin = -249, .pmax = 249 }, 214 + [ABP2002ND] = { .pmin = -498, .pmax = 498 }, 215 + [ABP2004ND] = { .pmin = -996, .pmax = 996 }, 216 + [ABP2005ND] = { .pmin = -1245, .pmax = 1245 }, 217 + [ABP2010ND] = { .pmin = -2491, .pmax = 2491 }, 218 + [ABP2020ND] = { .pmin = -4982, .pmax = 4982 }, 219 + [ABP2030ND] = { .pmin = -7473, .pmax = 7473 }, 220 + [ABP2002NG] = { .pmin = 0, .pmax = 498 }, 221 + [ABP2004NG] = { .pmin = 0, .pmax = 996 }, 222 + [ABP2005NG] = { .pmin = 0, .pmax = 1245 }, 223 + [ABP2010NG] = { .pmin = 0, .pmax = 2491 }, 224 + [ABP2020NG] = { .pmin = 0, .pmax = 4982 }, 225 + [ABP2030NG] = { .pmin = 0, .pmax = 7473 }, 226 + [ABP2015PA] = { .pmin = 0, .pmax = 103421 }, 227 + [ABP2030PA] = { .pmin = 0, .pmax = 206843 }, 228 + [ABP2060PA] = { .pmin = 0, .pmax = 413685 }, 229 + [ABP2100PA] = { .pmin = 0, .pmax = 689476 }, 230 + [ABP2150PA] = { .pmin = 0, .pmax = 1034214 }, 231 + [ABP2175PA] = { .pmin = 0, .pmax = 1206583 }, 232 + [ABP2001PD] = { .pmin = -6895, .pmax = 6895 }, 233 + [ABP2005PD] = { .pmin = -34474, .pmax = 34474 }, 234 + [ABP2015PD] = { .pmin = -103421, .pmax = 103421 }, 235 + [ABP2030PD] = { .pmin = -206843, .pmax = 206843 }, 236 + [ABP2060PD] = { .pmin = -413685, .pmax = 413685 }, 237 + [ABP2001PG] = { .pmin = 0, .pmax = 6895 }, 238 + [ABP2005PG] = { .pmin = 0, .pmax = 34474 }, 239 + [ABP2015PG] = { .pmin = 0, .pmax = 103421 }, 240 + [ABP2030PG] = { .pmin = 0, .pmax = 206843 }, 241 + [ABP2060PG] = { .pmin = 0, .pmax = 413685 }, 242 + [ABP2100PG] = { .pmin = 0, .pmax = 689476 }, 243 + [ABP2150PG] = { .pmin = 0, .pmax = 1034214 }, 244 + [ABP2175PG] = { .pmin = 0, .pmax = 1206583 }, 245 + }; 246 + 247 + static_assert(ARRAY_SIZE(abp2_triplet_variants) == ARRAY_SIZE(abp2_range_config)); 248 + 249 + static int abp2_get_measurement(struct abp2_data *data) 250 + { 251 + struct device *dev = data->dev; 252 + int ret; 253 + 254 + reinit_completion(&data->completion); 255 + 256 + ret = data->ops->write(data, ABP2_CMD_SYNC, ABP2_PKT_SYNC_LEN); 257 + if (ret < 0) 258 + return ret; 259 + 260 + if (data->irq > 0) { 261 + ret = wait_for_completion_timeout(&data->completion, HZ); 262 + if (!ret) { 263 + dev_err(dev, "timeout waiting for EOC interrupt\n"); 264 + return -ETIMEDOUT; 265 + } 266 + } else { 267 + fsleep(5 * USEC_PER_MSEC); 268 + } 269 + 270 + memset(data->rx_buf, 0, sizeof(data->rx_buf)); 271 + ret = data->ops->read(data, ABP2_CMD_NOP, ABP2_PKT_NOP_LEN); 272 + if (ret < 0) 273 + return ret; 274 + 275 + /* 276 + * Status byte flags 277 + * bit7 SANITY_CHK - must always be 0 278 + * bit6 ABP2_ST_POWER - 1 if device is powered 279 + * bit5 ABP2_ST_BUSY - 1 if device has no new conversion ready 280 + * bit4 SANITY_CHK - must always be 0 281 + * bit3 SANITY_CHK - must always be 0 282 + * bit2 MEMORY_ERR - 1 if integrity test has failed 283 + * bit1 SANITY_CHK - must always be 0 284 + * bit0 MATH_ERR - 1 during internal math saturation error 285 + */ 286 + 287 + if (data->rx_buf[0] == (ABP2_ST_POWER | ABP2_ST_BUSY)) 288 + return -EBUSY; 289 + 290 + /* 291 + * The ABP2 sensor series seem to have a noticeable latch-up sensitivity. 292 + * A partial latch-up condition manifests as either 293 + * - output of invalid status bytes 294 + * - zeroed out conversions (despite a normal status byte) 295 + * - the MOSI line being pulled low randomly in sync with the SCLK 296 + * signal (visible during the ABP2_CMD_NOP command). 297 + * https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1588325/am3358-spi-tx-data-corruption 298 + */ 299 + 300 + if (data->rx_buf[0] != ABP2_ST_POWER) { 301 + dev_err(data->dev, 302 + "unexpected status byte 0x%02x\n", data->rx_buf[0]); 303 + return -EIO; 304 + } 305 + 306 + return 0; 307 + } 308 + 309 + static irqreturn_t abp2_eoc_handler(int irq, void *private) 310 + { 311 + struct abp2_data *data = private; 312 + 313 + complete(&data->completion); 314 + 315 + return IRQ_HANDLED; 316 + } 317 + 318 + static irqreturn_t abp2_trigger_handler(int irq, void *private) 319 + { 320 + int ret; 321 + struct iio_poll_func *pf = private; 322 + struct iio_dev *indio_dev = pf->indio_dev; 323 + struct abp2_data *data = iio_priv(indio_dev); 324 + 325 + ret = abp2_get_measurement(data); 326 + if (ret < 0) 327 + goto out_notify_done; 328 + 329 + data->scan.chan[0] = get_unaligned_be24(&data->rx_buf[1]); 330 + data->scan.chan[1] = get_unaligned_be24(&data->rx_buf[4]); 331 + 332 + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), 333 + iio_get_time_ns(indio_dev)); 334 + 335 + out_notify_done: 336 + iio_trigger_notify_done(indio_dev->trig); 337 + 338 + return IRQ_HANDLED; 339 + } 340 + 341 + /* 342 + * IIO ABI expects 343 + * value = (conv + offset) * scale 344 + * 345 + * temp[C] = conv * a + b 346 + * where a = 200/16777215; b = -50 347 + * 348 + * temp[C] = (conv + (b/a)) * a * (1000) 349 + * => 350 + * scale = a * 1000 = .0000119209296 * 1000 = .01192092966562 351 + * offset = b/a = -50 * 16777215 / 200 = -4194303.75 352 + * 353 + * pressure = (conv - Omin) * Q + Pmin = 354 + * ((conv - Omin) + Pmin/Q) * Q 355 + * => 356 + * scale = Q = (Pmax - Pmin) / (Omax - Omin) 357 + * offset = Pmin/Q - Omin = Pmin * (Omax - Omin) / (Pmax - Pmin) - Omin 358 + */ 359 + static int abp2_read_raw(struct iio_dev *indio_dev, 360 + struct iio_chan_spec const *channel, int *val, 361 + int *val2, long mask) 362 + { 363 + struct abp2_data *data = iio_priv(indio_dev); 364 + int ret; 365 + 366 + switch (mask) { 367 + case IIO_CHAN_INFO_RAW: 368 + ret = abp2_get_measurement(data); 369 + if (ret < 0) 370 + return ret; 371 + 372 + switch (channel->type) { 373 + case IIO_PRESSURE: 374 + *val = get_unaligned_be24(&data->rx_buf[1]); 375 + return IIO_VAL_INT; 376 + case IIO_TEMP: 377 + *val = get_unaligned_be24(&data->rx_buf[4]); 378 + return IIO_VAL_INT; 379 + default: 380 + return -EINVAL; 381 + } 382 + return IIO_VAL_INT; 383 + 384 + case IIO_CHAN_INFO_SCALE: 385 + switch (channel->type) { 386 + case IIO_TEMP: 387 + *val = 0; 388 + *val2 = 11920929; 389 + return IIO_VAL_INT_PLUS_NANO; 390 + case IIO_PRESSURE: 391 + *val = data->p_scale; 392 + *val2 = data->p_scale_dec; 393 + return IIO_VAL_INT_PLUS_NANO; 394 + default: 395 + return -EINVAL; 396 + } 397 + 398 + case IIO_CHAN_INFO_OFFSET: 399 + switch (channel->type) { 400 + case IIO_TEMP: 401 + *val = -4194304; 402 + return IIO_VAL_INT; 403 + case IIO_PRESSURE: 404 + *val = data->p_offset; 405 + return IIO_VAL_INT; 406 + default: 407 + return -EINVAL; 408 + } 409 + 410 + default: 411 + return -EINVAL; 412 + } 413 + } 414 + 415 + static const struct iio_info abp2_info = { 416 + .read_raw = &abp2_read_raw, 417 + }; 418 + 419 + static const unsigned long abp2_scan_masks[] = {0x3, 0}; 420 + 421 + static const struct iio_chan_spec abp2_channels[] = { 422 + { 423 + .type = IIO_PRESSURE, 424 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 425 + BIT(IIO_CHAN_INFO_SCALE) | 426 + BIT(IIO_CHAN_INFO_OFFSET), 427 + .scan_index = 0, 428 + .scan_type = { 429 + .sign = 'u', 430 + .realbits = 24, 431 + .storagebits = 32, 432 + .endianness = IIO_CPU, 433 + }, 434 + }, 435 + { 436 + .type = IIO_TEMP, 437 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 438 + BIT(IIO_CHAN_INFO_SCALE) | 439 + BIT(IIO_CHAN_INFO_OFFSET), 440 + .scan_index = 1, 441 + .scan_type = { 442 + .sign = 'u', 443 + .realbits = 24, 444 + .storagebits = 32, 445 + .endianness = IIO_CPU, 446 + }, 447 + }, 448 + IIO_CHAN_SOFT_TIMESTAMP(2), 449 + }; 450 + 451 + int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq) 452 + { 453 + int ret; 454 + struct abp2_data *data; 455 + struct iio_dev *indio_dev; 456 + const char *triplet; 457 + s32 tmp; 458 + s64 odelta, pdelta; 459 + 460 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 461 + if (!indio_dev) 462 + return -ENOMEM; 463 + 464 + data = iio_priv(indio_dev); 465 + data->dev = dev; 466 + data->ops = ops; 467 + data->irq = irq; 468 + 469 + init_completion(&data->completion); 470 + 471 + indio_dev->name = "abp2030pa"; 472 + indio_dev->info = &abp2_info; 473 + indio_dev->channels = abp2_channels; 474 + indio_dev->num_channels = ARRAY_SIZE(abp2_channels); 475 + indio_dev->modes = INDIO_DIRECT_MODE; 476 + indio_dev->available_scan_masks = abp2_scan_masks; 477 + 478 + ret = devm_regulator_get_enable(dev, "vdd"); 479 + if (ret) 480 + return dev_err_probe(dev, ret, "can't get and enable vdd supply\n"); 481 + 482 + ret = device_property_read_string(dev, "honeywell,pressure-triplet", 483 + &triplet); 484 + if (ret) { 485 + ret = device_property_read_u32(dev, "honeywell,pmin-pascal", 486 + &data->pmin); 487 + if (ret) 488 + return dev_err_probe(dev, ret, 489 + "honeywell,pmin-pascal could not be read\n"); 490 + 491 + ret = device_property_read_u32(dev, "honeywell,pmax-pascal", 492 + &data->pmax); 493 + if (ret) 494 + return dev_err_probe(dev, ret, 495 + "honeywell,pmax-pascal could not be read\n"); 496 + } else { 497 + ret = device_property_match_property_string(dev, 498 + "honeywell,pressure-triplet", 499 + abp2_triplet_variants, 500 + ARRAY_SIZE(abp2_triplet_variants)); 501 + if (ret < 0) 502 + return dev_err_probe(dev, -EINVAL, "honeywell,pressure-triplet is invalid\n"); 503 + 504 + data->pmin = abp2_range_config[ret].pmin; 505 + data->pmax = abp2_range_config[ret].pmax; 506 + } 507 + 508 + if (data->pmin >= data->pmax) 509 + return dev_err_probe(dev, -EINVAL, "pressure limits are invalid\n"); 510 + 511 + data->outmin = abp2_func_spec[data->function].output_min; 512 + data->outmax = abp2_func_spec[data->function].output_max; 513 + 514 + odelta = data->outmax - data->outmin; 515 + pdelta = data->pmax - data->pmin; 516 + 517 + data->p_scale = div_s64_rem(div_s64(pdelta * NANO, odelta), NANO, &tmp); 518 + data->p_scale_dec = tmp; 519 + 520 + data->p_offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; 521 + 522 + if (data->irq > 0) { 523 + ret = devm_request_irq(dev, irq, abp2_eoc_handler, IRQF_ONESHOT, 524 + dev_name(dev), data); 525 + if (ret) 526 + return dev_err_probe(dev, ret, "request irq %d failed\n", data->irq); 527 + } 528 + 529 + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, 530 + abp2_trigger_handler, NULL); 531 + if (ret) 532 + return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); 533 + 534 + ret = devm_iio_device_register(dev, indio_dev); 535 + if (ret) 536 + return dev_err_probe(dev, ret, "unable to register iio device\n"); 537 + 538 + return 0; 539 + } 540 + EXPORT_SYMBOL_NS_GPL(abp2_common_probe, "IIO_HONEYWELL_ABP2030PA"); 541 + 542 + MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); 543 + MODULE_DESCRIPTION("Honeywell ABP2 pressure sensor core driver"); 544 + MODULE_LICENSE("GPL");
+73
drivers/iio/pressure/abp2030pa.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Honeywell ABP2 series pressure sensor driver 4 + * 5 + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> 6 + */ 7 + 8 + #ifndef _ABP2030PA_H 9 + #define _ABP2030PA_H 10 + 11 + #include <linux/completion.h> 12 + #include <linux/types.h> 13 + 14 + #include <linux/iio/iio.h> 15 + 16 + #define ABP2_MEASUREMENT_RD_SIZE 7 17 + 18 + struct device; 19 + 20 + struct abp2_data; 21 + struct abp2_ops; 22 + 23 + enum abp2_func_id { 24 + ABP2_FUNCTION_A, 25 + }; 26 + 27 + /** 28 + * struct abp2_data 29 + * @dev: current device structure 30 + * @ops: pointers for bus specific read and write functions 31 + * @pmin: minimal pressure in pascal 32 + * @pmax: maximal pressure in pascal 33 + * @outmin: minimum raw pressure in counts (based on transfer function) 34 + * @outmax: maximum raw pressure in counts (based on transfer function) 35 + * @function: transfer function 36 + * @p_scale: pressure scale 37 + * @p_scale_dec: pressure scale, decimal number 38 + * @p_offset: pressure offset 39 + * @irq: end of conversion - applies only to the i2c sensor 40 + * @completion: handshake from irq to read 41 + * @scan: channel values for buffered mode 42 + * @tx_buf: transmit buffer used during the SPI communication 43 + * @rx_buf: raw data provided by sensor 44 + */ 45 + struct abp2_data { 46 + struct device *dev; 47 + const struct abp2_ops *ops; 48 + s32 pmin; 49 + s32 pmax; 50 + u32 outmin; 51 + u32 outmax; 52 + enum abp2_func_id function; 53 + int p_scale; 54 + int p_scale_dec; 55 + int p_offset; 56 + int irq; 57 + struct completion completion; 58 + struct { 59 + u32 chan[2]; 60 + aligned_s64 timestamp; 61 + } scan; 62 + u8 rx_buf[ABP2_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); 63 + u8 tx_buf[ABP2_MEASUREMENT_RD_SIZE]; 64 + }; 65 + 66 + struct abp2_ops { 67 + int (*read)(struct abp2_data *data, u8 cmd, u8 nbytes); 68 + int (*write)(struct abp2_data *data, u8 cmd, u8 nbytes); 69 + }; 70 + 71 + int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq); 72 + 73 + #endif
+90
drivers/iio/pressure/abp2030pa_i2c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Honeywell ABP2 series pressure sensor driver 4 + * 5 + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/errno.h> 10 + #include <linux/i2c.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/types.h> 14 + 15 + #include "abp2030pa.h" 16 + 17 + static int abp2_i2c_read(struct abp2_data *data, u8 unused, u8 nbytes) 18 + { 19 + struct i2c_client *client = to_i2c_client(data->dev); 20 + int ret; 21 + 22 + if (nbytes > ABP2_MEASUREMENT_RD_SIZE) 23 + return -EOVERFLOW; 24 + 25 + ret = i2c_master_recv(client, data->rx_buf, nbytes); 26 + if (ret < 0) 27 + return ret; 28 + if (ret != nbytes) 29 + return -EIO; 30 + 31 + return 0; 32 + } 33 + 34 + static int abp2_i2c_write(struct abp2_data *data, u8 cmd, u8 nbytes) 35 + { 36 + struct i2c_client *client = to_i2c_client(data->dev); 37 + int ret; 38 + 39 + if (nbytes > ABP2_MEASUREMENT_RD_SIZE) 40 + return -EOVERFLOW; 41 + 42 + data->tx_buf[0] = cmd; 43 + ret = i2c_master_send(client, data->tx_buf, nbytes); 44 + if (ret < 0) 45 + return ret; 46 + if (ret != nbytes) 47 + return -EIO; 48 + 49 + return 0; 50 + } 51 + 52 + static const struct abp2_ops abp2_i2c_ops = { 53 + .read = abp2_i2c_read, 54 + .write = abp2_i2c_write, 55 + }; 56 + 57 + static int abp2_i2c_probe(struct i2c_client *client) 58 + { 59 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 60 + return -EOPNOTSUPP; 61 + 62 + return abp2_common_probe(&client->dev, &abp2_i2c_ops, client->irq); 63 + } 64 + 65 + static const struct of_device_id abp2_i2c_match[] = { 66 + { .compatible = "honeywell,abp2030pa" }, 67 + { } 68 + }; 69 + MODULE_DEVICE_TABLE(of, abp2_i2c_match); 70 + 71 + static const struct i2c_device_id abp2_i2c_id[] = { 72 + { "abp2030pa" }, 73 + { } 74 + }; 75 + MODULE_DEVICE_TABLE(i2c, abp2_i2c_id); 76 + 77 + static struct i2c_driver abp2_i2c_driver = { 78 + .driver = { 79 + .name = "abp2030pa", 80 + .of_match_table = abp2_i2c_match, 81 + }, 82 + .probe = abp2_i2c_probe, 83 + .id_table = abp2_i2c_id, 84 + }; 85 + module_i2c_driver(abp2_i2c_driver); 86 + 87 + MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); 88 + MODULE_DESCRIPTION("Honeywell ABP2 pressure sensor i2c driver"); 89 + MODULE_LICENSE("GPL"); 90 + MODULE_IMPORT_NS("IIO_HONEYWELL_ABP2030PA");
+67
drivers/iio/pressure/abp2030pa_spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Honeywell ABP2 series pressure sensor driver 4 + * 5 + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> 6 + */ 7 + 8 + #include <linux/errno.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/module.h> 11 + #include <linux/spi/spi.h> 12 + #include <linux/types.h> 13 + 14 + #include "abp2030pa.h" 15 + 16 + static int abp2_spi_xfer(struct abp2_data *data, u8 cmd, u8 nbytes) 17 + { 18 + struct spi_device *spi = to_spi_device(data->dev); 19 + struct spi_transfer xfer = { }; 20 + 21 + if (nbytes > ABP2_MEASUREMENT_RD_SIZE) 22 + return -EOVERFLOW; 23 + 24 + data->tx_buf[0] = cmd; 25 + xfer.tx_buf = data->tx_buf; 26 + xfer.rx_buf = data->rx_buf; 27 + xfer.len = nbytes; 28 + 29 + return spi_sync_transfer(spi, &xfer, 1); 30 + } 31 + 32 + static const struct abp2_ops abp2_spi_ops = { 33 + .read = abp2_spi_xfer, 34 + .write = abp2_spi_xfer, 35 + }; 36 + 37 + static int abp2_spi_probe(struct spi_device *spi) 38 + { 39 + return abp2_common_probe(&spi->dev, &abp2_spi_ops, spi->irq); 40 + } 41 + 42 + static const struct of_device_id abp2_spi_match[] = { 43 + { .compatible = "honeywell,abp2030pa" }, 44 + { } 45 + }; 46 + MODULE_DEVICE_TABLE(of, abp2_spi_match); 47 + 48 + static const struct spi_device_id abp2_spi_id[] = { 49 + { "abp2030pa" }, 50 + { } 51 + }; 52 + MODULE_DEVICE_TABLE(spi, abp2_spi_id); 53 + 54 + static struct spi_driver abp2_spi_driver = { 55 + .driver = { 56 + .name = "abp2030pa", 57 + .of_match_table = abp2_spi_match, 58 + }, 59 + .probe = abp2_spi_probe, 60 + .id_table = abp2_spi_id, 61 + }; 62 + module_spi_driver(abp2_spi_driver); 63 + 64 + MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); 65 + MODULE_DESCRIPTION("Honeywell ABP2 pressure sensor spi driver"); 66 + MODULE_LICENSE("GPL"); 67 + MODULE_IMPORT_NS("IIO_HONEYWELL_ABP2030PA");