456 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver4 *5 * Copyright (c) Andreas Klinger <ak@it-klinger.de>6 *7 * Data sheet:8 * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf9 *10 */11 12#include <linux/array_size.h>13#include <linux/bitfield.h>14#include <linux/bits.h>15#include <linux/math64.h>16#include <linux/mod_devicetable.h>17#include <linux/module.h>18#include <linux/property.h>19#include <linux/units.h>20 21#include <linux/gpio/consumer.h>22 23#include <linux/iio/buffer.h>24#include <linux/iio/trigger_consumer.h>25#include <linux/iio/triggered_buffer.h>26 27#include <linux/regulator/consumer.h>28 29#include <linux/unaligned.h>30 31#include "mprls0025pa.h"32 33/* bits in status byte */34#define MPR_ST_POWER BIT(6) /* device is powered */35#define MPR_ST_BUSY BIT(5) /* device is busy */36#define MPR_ST_MEMORY BIT(2) /* integrity test passed */37#define MPR_ST_MATH BIT(0) /* internal math saturation */38 39#define MPR_ST_ERR_FLAG (MPR_ST_BUSY | MPR_ST_MEMORY | MPR_ST_MATH)40 41/*42 * support _RAW sysfs interface:43 *44 * Calculation formula from the datasheet:45 * pressure = (press_cnt - outputmin) * scale + pmin46 * with:47 * * pressure - measured pressure in Pascal48 * * press_cnt - raw value read from sensor49 * * pmin - minimum pressure range value of sensor (data->pmin)50 * * pmax - maximum pressure range value of sensor (data->pmax)51 * * outputmin - minimum numerical range raw value delivered by sensor52 * (mpr_func_spec.output_min)53 * * outputmax - maximum numerical range raw value delivered by sensor54 * (mpr_func_spec.output_max)55 * * scale - (pmax - pmin) / (outputmax - outputmin)56 *57 * formula of the userspace:58 * pressure = (raw + offset) * scale59 *60 * Values given to the userspace in sysfs interface:61 * * raw - press_cnt62 * * offset - (-1 * outputmin) - pmin / scale63 * note: With all sensors from the datasheet pmin = 064 * which reduces the offset to (-1 * outputmin)65 */66 67/*68 * transfer function A: 10% to 90% of 2^2469 * transfer function B: 2.5% to 22.5% of 2^2470 * transfer function C: 20% to 80% of 2^2471 */72struct mpr_func_spec {73 u32 output_min;74 u32 output_max;75};76 77static const struct mpr_func_spec mpr_func_spec[] = {78 [MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 },79 [MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 },80 [MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 },81};82 83enum mpr_variants {84 MPR0001BA = 0x00, MPR01_6BA = 0x01, MPR02_5BA = 0x02, MPR0060MG = 0x03,85 MPR0100MG = 0x04, MPR0160MG = 0x05, MPR0250MG = 0x06, MPR0400MG = 0x07,86 MPR0600MG = 0x08, MPR0001BG = 0x09, MPR01_6BG = 0x0a, MPR02_5BG = 0x0b,87 MPR0100KA = 0x0c, MPR0160KA = 0x0d, MPR0250KA = 0x0e, MPR0006KG = 0x0f,88 MPR0010KG = 0x10, MPR0016KG = 0x11, MPR0025KG = 0x12, MPR0040KG = 0x13,89 MPR0060KG = 0x14, MPR0100KG = 0x15, MPR0160KG = 0x16, MPR0250KG = 0x17,90 MPR0015PA = 0x18, MPR0025PA = 0x19, MPR0030PA = 0x1a, MPR0001PG = 0x1b,91 MPR0005PG = 0x1c, MPR0015PG = 0x1d, MPR0030PG = 0x1e, MPR0300YG = 0x1f,92 MPR_VARIANTS_MAX93};94 95static const char * const mpr_triplet_variants[MPR_VARIANTS_MAX] = {96 [MPR0001BA] = "0001BA", [MPR01_6BA] = "01.6BA", [MPR02_5BA] = "02.5BA",97 [MPR0060MG] = "0060MG", [MPR0100MG] = "0100MG", [MPR0160MG] = "0160MG",98 [MPR0250MG] = "0250MG", [MPR0400MG] = "0400MG", [MPR0600MG] = "0600MG",99 [MPR0001BG] = "0001BG", [MPR01_6BG] = "01.6BG", [MPR02_5BG] = "02.5BG",100 [MPR0100KA] = "0100KA", [MPR0160KA] = "0160KA", [MPR0250KA] = "0250KA",101 [MPR0006KG] = "0006KG", [MPR0010KG] = "0010KG", [MPR0016KG] = "0016KG",102 [MPR0025KG] = "0025KG", [MPR0040KG] = "0040KG", [MPR0060KG] = "0060KG",103 [MPR0100KG] = "0100KG", [MPR0160KG] = "0160KG", [MPR0250KG] = "0250KG",104 [MPR0015PA] = "0015PA", [MPR0025PA] = "0025PA", [MPR0030PA] = "0030PA",105 [MPR0001PG] = "0001PG", [MPR0005PG] = "0005PG", [MPR0015PG] = "0015PG",106 [MPR0030PG] = "0030PG", [MPR0300YG] = "0300YG"107};108 109/**110 * struct mpr_range_config - list of pressure ranges based on nomenclature111 * @pmin: lowest pressure that can be measured112 * @pmax: highest pressure that can be measured113 */114struct mpr_range_config {115 const s32 pmin;116 const s32 pmax;117};118 119/* All min max limits have been converted to pascals */120static const struct mpr_range_config mpr_range_config[MPR_VARIANTS_MAX] = {121 [MPR0001BA] = { .pmin = 0, .pmax = 100000 },122 [MPR01_6BA] = { .pmin = 0, .pmax = 160000 },123 [MPR02_5BA] = { .pmin = 0, .pmax = 250000 },124 [MPR0060MG] = { .pmin = 0, .pmax = 6000 },125 [MPR0100MG] = { .pmin = 0, .pmax = 10000 },126 [MPR0160MG] = { .pmin = 0, .pmax = 16000 },127 [MPR0250MG] = { .pmin = 0, .pmax = 25000 },128 [MPR0400MG] = { .pmin = 0, .pmax = 40000 },129 [MPR0600MG] = { .pmin = 0, .pmax = 60000 },130 [MPR0001BG] = { .pmin = 0, .pmax = 100000 },131 [MPR01_6BG] = { .pmin = 0, .pmax = 160000 },132 [MPR02_5BG] = { .pmin = 0, .pmax = 250000 },133 [MPR0100KA] = { .pmin = 0, .pmax = 100000 },134 [MPR0160KA] = { .pmin = 0, .pmax = 160000 },135 [MPR0250KA] = { .pmin = 0, .pmax = 250000 },136 [MPR0006KG] = { .pmin = 0, .pmax = 6000 },137 [MPR0010KG] = { .pmin = 0, .pmax = 10000 },138 [MPR0016KG] = { .pmin = 0, .pmax = 16000 },139 [MPR0025KG] = { .pmin = 0, .pmax = 25000 },140 [MPR0040KG] = { .pmin = 0, .pmax = 40000 },141 [MPR0060KG] = { .pmin = 0, .pmax = 60000 },142 [MPR0100KG] = { .pmin = 0, .pmax = 100000 },143 [MPR0160KG] = { .pmin = 0, .pmax = 160000 },144 [MPR0250KG] = { .pmin = 0, .pmax = 250000 },145 [MPR0015PA] = { .pmin = 0, .pmax = 103421 },146 [MPR0025PA] = { .pmin = 0, .pmax = 172369 },147 [MPR0030PA] = { .pmin = 0, .pmax = 206843 },148 [MPR0001PG] = { .pmin = 0, .pmax = 6895 },149 [MPR0005PG] = { .pmin = 0, .pmax = 34474 },150 [MPR0015PG] = { .pmin = 0, .pmax = 103421 },151 [MPR0030PG] = { .pmin = 0, .pmax = 206843 },152 [MPR0300YG] = { .pmin = 0, .pmax = 39997 }153};154 155static const struct iio_chan_spec mpr_channels[] = {156 {157 .type = IIO_PRESSURE,158 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |159 BIT(IIO_CHAN_INFO_SCALE) |160 BIT(IIO_CHAN_INFO_OFFSET),161 .scan_index = 0,162 .scan_type = {163 .sign = 's',164 .realbits = 32,165 .storagebits = 32,166 .endianness = IIO_CPU,167 },168 },169 IIO_CHAN_SOFT_TIMESTAMP(1),170};171 172static void mpr_reset(struct mpr_data *data)173{174 if (data->gpiod_reset) {175 gpiod_set_value(data->gpiod_reset, 0);176 udelay(10);177 gpiod_set_value(data->gpiod_reset, 1);178 }179}180 181/**182 * mpr_read_pressure() - Read pressure value from sensor183 * @data: Pointer to private data struct.184 * @press: Output value read from sensor.185 *186 * Reading from the sensor by sending and receiving telegrams.187 *188 * If there is an end of conversion (EOC) interrupt registered the function189 * waits for a maximum of one second for the interrupt.190 *191 * Context: The function can sleep and data->lock should be held when calling it192 * Return:193 * * 0 - OK, the pressure value could be read194 * * -ETIMEDOUT - Timeout while waiting for the EOC interrupt or busy flag is195 * still set after nloops attempts of reading196 */197static int mpr_read_pressure(struct mpr_data *data, s32 *press)198{199 struct device *dev = data->dev;200 int ret, i;201 int nloops = 10;202 203 reinit_completion(&data->completion);204 205 ret = data->ops->write(data, MPR_CMD_SYNC, MPR_PKT_SYNC_LEN);206 if (ret < 0) {207 dev_err(dev, "error while writing ret: %d\n", ret);208 return ret;209 }210 211 if (data->irq > 0) {212 ret = wait_for_completion_timeout(&data->completion, HZ);213 if (!ret) {214 dev_err(dev, "timeout while waiting for eoc irq\n");215 return -ETIMEDOUT;216 }217 } else {218 /* wait until status indicates data is ready */219 for (i = 0; i < nloops; i++) {220 /*221 * datasheet only says to wait at least 5 ms for the222 * data but leave the maximum response time open223 * --> let's try it nloops (10) times which seems to be224 * quite long225 */226 usleep_range(5000, 10000);227 ret = data->ops->read(data, MPR_CMD_NOP, 1);228 if (ret < 0) {229 dev_err(dev,230 "error while reading, status: %d\n",231 ret);232 return ret;233 }234 if (!(data->buffer[0] & MPR_ST_ERR_FLAG))235 break;236 }237 if (i == nloops) {238 dev_err(dev, "timeout while reading\n");239 return -ETIMEDOUT;240 }241 }242 243 ret = data->ops->read(data, MPR_CMD_NOP, MPR_PKT_NOP_LEN);244 if (ret < 0)245 return ret;246 247 if (data->buffer[0] & MPR_ST_ERR_FLAG) {248 dev_err(data->dev,249 "unexpected status byte %02x\n", data->buffer[0]);250 return -ETIMEDOUT;251 }252 253 *press = get_unaligned_be24(&data->buffer[1]);254 255 dev_dbg(dev, "received: %*ph cnt: %d\n", ret, data->buffer, *press);256 257 return 0;258}259 260static irqreturn_t mpr_eoc_handler(int irq, void *p)261{262 struct mpr_data *data = p;263 264 complete(&data->completion);265 266 return IRQ_HANDLED;267}268 269static irqreturn_t mpr_trigger_handler(int irq, void *p)270{271 int ret;272 struct iio_poll_func *pf = p;273 struct iio_dev *indio_dev = pf->indio_dev;274 struct mpr_data *data = iio_priv(indio_dev);275 276 mutex_lock(&data->lock);277 ret = mpr_read_pressure(data, &data->chan.pres);278 if (ret < 0)279 goto err;280 281 iio_push_to_buffers_with_timestamp(indio_dev, &data->chan,282 iio_get_time_ns(indio_dev));283 284err:285 mutex_unlock(&data->lock);286 iio_trigger_notify_done(indio_dev->trig);287 288 return IRQ_HANDLED;289}290 291static int mpr_read_raw(struct iio_dev *indio_dev,292 struct iio_chan_spec const *chan, int *val, int *val2, long mask)293{294 int ret;295 s32 pressure;296 struct mpr_data *data = iio_priv(indio_dev);297 298 if (chan->type != IIO_PRESSURE)299 return -EINVAL;300 301 switch (mask) {302 case IIO_CHAN_INFO_RAW:303 mutex_lock(&data->lock);304 ret = mpr_read_pressure(data, &pressure);305 mutex_unlock(&data->lock);306 if (ret < 0)307 return ret;308 *val = pressure;309 return IIO_VAL_INT;310 case IIO_CHAN_INFO_SCALE:311 *val = data->scale;312 *val2 = data->scale2;313 return IIO_VAL_INT_PLUS_NANO;314 case IIO_CHAN_INFO_OFFSET:315 *val = data->offset;316 *val2 = data->offset2;317 return IIO_VAL_INT_PLUS_NANO;318 default:319 return -EINVAL;320 }321}322 323static const struct iio_info mpr_info = {324 .read_raw = &mpr_read_raw,325};326 327int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq)328{329 int ret;330 struct mpr_data *data;331 struct iio_dev *indio_dev;332 const char *triplet;333 s64 scale, offset;334 u32 func;335 336 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));337 if (!indio_dev)338 return -ENOMEM;339 340 data = iio_priv(indio_dev);341 data->dev = dev;342 data->ops = ops;343 data->irq = irq;344 345 mutex_init(&data->lock);346 init_completion(&data->completion);347 348 indio_dev->name = "mprls0025pa";349 indio_dev->info = &mpr_info;350 indio_dev->channels = mpr_channels;351 indio_dev->num_channels = ARRAY_SIZE(mpr_channels);352 indio_dev->modes = INDIO_DIRECT_MODE;353 354 ret = devm_regulator_get_enable(dev, "vdd");355 if (ret)356 return dev_err_probe(dev, ret,357 "can't get and enable vdd supply\n");358 359 ret = data->ops->init(data->dev);360 if (ret)361 return ret;362 363 ret = device_property_read_u32(dev,364 "honeywell,transfer-function", &func);365 if (ret)366 return dev_err_probe(dev, ret,367 "honeywell,transfer-function could not be read\n");368 data->function = func - 1;369 if (data->function > MPR_FUNCTION_C)370 return dev_err_probe(dev, -EINVAL,371 "honeywell,transfer-function %d invalid\n",372 data->function);373 374 ret = device_property_read_string(dev, "honeywell,pressure-triplet",375 &triplet);376 if (ret) {377 ret = device_property_read_u32(dev, "honeywell,pmin-pascal",378 &data->pmin);379 if (ret)380 return dev_err_probe(dev, ret,381 "honeywell,pmin-pascal could not be read\n");382 383 ret = device_property_read_u32(dev, "honeywell,pmax-pascal",384 &data->pmax);385 if (ret)386 return dev_err_probe(dev, ret,387 "honeywell,pmax-pascal could not be read\n");388 } else {389 ret = device_property_match_property_string(dev,390 "honeywell,pressure-triplet",391 mpr_triplet_variants,392 MPR_VARIANTS_MAX);393 if (ret < 0)394 return dev_err_probe(dev, -EINVAL,395 "honeywell,pressure-triplet is invalid\n");396 397 data->pmin = mpr_range_config[ret].pmin;398 data->pmax = mpr_range_config[ret].pmax;399 }400 401 if (data->pmin >= data->pmax)402 return dev_err_probe(dev, -EINVAL,403 "pressure limits are invalid\n");404 405 data->outmin = mpr_func_spec[data->function].output_min;406 data->outmax = mpr_func_spec[data->function].output_max;407 408 /* use 64 bit calculation for preserving a reasonable precision */409 scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO,410 data->outmax - data->outmin);411 data->scale = div_s64_rem(scale, NANO, &data->scale2);412 /*413 * multiply with NANO before dividing by scale and later divide by NANO414 * again.415 */416 offset = ((-1LL) * (s64)data->outmin) * NANO -417 div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);418 data->offset = div_s64_rem(offset, NANO, &data->offset2);419 420 if (data->irq > 0) {421 ret = devm_request_irq(dev, data->irq, mpr_eoc_handler,422 IRQF_TRIGGER_RISING,423 dev_name(dev),424 data);425 if (ret)426 return dev_err_probe(dev, ret,427 "request irq %d failed\n", data->irq);428 }429 430 data->gpiod_reset = devm_gpiod_get_optional(dev, "reset",431 GPIOD_OUT_HIGH);432 if (IS_ERR(data->gpiod_reset))433 return dev_err_probe(dev, PTR_ERR(data->gpiod_reset),434 "request reset-gpio failed\n");435 436 mpr_reset(data);437 438 ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,439 mpr_trigger_handler, NULL);440 if (ret)441 return dev_err_probe(dev, ret,442 "iio triggered buffer setup failed\n");443 444 ret = devm_iio_device_register(dev, indio_dev);445 if (ret)446 return dev_err_probe(dev, ret,447 "unable to register iio device\n");448 449 return 0;450}451EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA);452 453MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");454MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver");455MODULE_LICENSE("GPL");456