iio: pressure: add support for MS5611 pressure and temperature sensor
PATCH v3 1/1 iio: pressure: add support for MS5611 pressure and temperature sensor
Add support for Measurement Specialities MS5611 pressure and temperature sensor.
---
Changes in v3:
- Fix coding style
- Use spi_write_then_read instead of spi_write to ensure that data send to device is in it's own cacheline
Changes in v2:
- Fix coding style
- Document i2c slave addresses
- Simplify device registration/removal using devm_iio_device_register()
- Return temperature in mC and pressure in kPa
drivers/iio/pressure/Kconfig | 27 +++++ drivers/iio/pressure/Makefile | 3 + drivers/iio/pressure/ms5611.h | 44 ++++++++ drivers/iio/pressure/ms5611_core.c | 215 +++++++++++++++++++++++++++++++++++++ drivers/iio/pressure/ms5611_i2c.c | 128 ++++++++++++++++++++++ drivers/iio/pressure/ms5611_spi.c | 127 ++++++++++++++++++++++ 6 files changed, 544 insertions(+) create mode 100644 drivers/iio/pressure/ms5611.h create mode 100644 drivers/iio/pressure/ms5611_core.c create mode 100644 drivers/iio/pressure/ms5611_i2c.c create mode 100644 drivers/iio/pressure/ms5611_spi.c
drivers/iio/pressure/Kconfig +27 -0
@@ -52,6 +52,33 @@ config MPL3115 To compile this driver as a module, choose M here: the module will be called mpl3115. +config MS5611 + tristate "Measurement Specialities MS5611 pressure sensor driver" + help + Say Y here to build support for the Measurement Specialities + MS5611 pressure and temperature sensor. + + To compile this driver as a module, choose M here: the module will + be called ms5611_core. + +config MS5611_I2C + tristate "support I2C bus connection" + depends on I2C && MS5611 + help + Say Y here to build I2C bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_i2c. + +config MS5611_SPI + tristate "support SPI bus connection" + depends on SPI_MASTER && MS5611 + help + Say Y here to build SPI bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_spi. + config IIO_ST_PRESS tristate "STMicroelectronics pressure sensor Driver" depends on (I2C || SPI_MASTER) && SYSFS
drivers/iio/pressure/Makefile +3 -0
@@ -7,6 +7,9 @@ obj-$(CONFIG_BMP280) += bmp280.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL3115) += mpl3115.o +obj-$(CONFIG_MS5611) += ms5611_core.o +obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o +obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
drivers/iio/pressure/ms5611.h new file +44 -0
44 lines not on this page · raw message
drivers/iio/pressure/ms5611_core.c new file +215 -0
215 lines not on this page · raw message
drivers/iio/pressure/ms5611_i2c.c new file +128 -0
128 lines not on this page · raw message
drivers/iio/pressure/ms5611_spi.c new file +127 -0
127 lines not on this page · raw message
--
2.3.2
Quoted 4 lines · Tomasz Duszynski
Add support for Measurement Specialities MS5611 pressure and temperature sensor.
Signed-off-by Tomasz Duszynski <[email protected]>
Applied to the togreg branch of iio.git.
Initially pushed out as testing for the autobuilders to play with it.
Thanks,
Jonathan
Quoted 623 lines
---
Changes in v3:
- Fix coding style
- Usespi_write_then_readinstead ofspi_writeto ensure that data send to device is in it's own cachelineChanges in v2:
- Fix coding style
- Document i2c slave addresses
- Simplify device registration/removal usingdevm_iio_device_register()
- Return temperature in mC and pressure in kPadrivers/iio/pressure/Kconfig | 27 +++++ drivers/iio/pressure/Makefile | 3 + drivers/iio/pressure/ms5611.h | 44 ++++++++ drivers/iio/pressure/ms5611_core.c | 215 +++++++++++++++++++++++++++++++++++++ drivers/iio/pressure/ms5611_i2c.c | 128 ++++++++++++++++++++++ drivers/iio/pressure/ms5611_spi.c | 127 ++++++++++++++++++++++ 6 files changed, 544 insertions(+) create mode 100644 drivers/iio/pressure/ms5611.h create mode 100644 drivers/iio/pressure/ms5611_core.c create mode 100644 drivers/iio/pressure/ms5611_i2c.c create mode 100644 drivers/iio/pressure/ms5611_spi.cdrivers/iio/pressure/Kconfig +27
-0@@ -52,6 +52,33 @@ config MPL3115 To compile this driver as a module, choose M here: the module will be called mpl3115. +config MS5611 + tristate "Measurement Specialities MS5611 pressure sensor driver" + help + Say Y here to build support for the Measurement Specialities + MS5611 pressure and temperature sensor. + + To compile this driver as a module, choose M here: the module will + be called ms5611_core. + +config MS5611_I2C + tristate "support I2C bus connection" + depends on I2C && MS5611 + help + Say Y here to build I2C bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_i2c. + +config MS5611_SPI + tristate "support SPI bus connection" + depends on SPI_MASTER && MS5611 + help + Say Y here to build SPI bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_spi. + config IIO_ST_PRESS tristate "STMicroelectronics pressure sensor Driver" depends on (I2C || SPI_MASTER) && SYSFSdrivers/iio/pressure/Makefile +3
-0@@ -7,6 +7,9 @@ obj-$(CONFIG_BMP280) += bmp280.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL3115) += mpl3115.o +obj-$(CONFIG_MS5611) += ms5611_core.o +obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o +obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.odrivers/iio/pressure/ms5611.h new file +44
-0@@ -0,0 +1,44 @@ +/* +* MS5611 pressure and temperature sensor driver +* +* Copyright (c) Tomasz Duszynski <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ + +#ifndef _MS5611_H +#define _MS5611_H + +#include <linux/device.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> + +#define MS5611_RESET 0x1e +#define MS5611_READ_ADC 0x00 +#define MS5611_READ_PROM_WORD 0xA0 +#define MS5611_START_TEMP_CONV 0x58 +#define MS5611_START_PRESSURE_CONV 0x48 + +#define MS5611_CONV_TIME_MIN 9040 +#define MS5611_CONV_TIME_MAX 10000 + +#define MS5611_PROM_WORDS_NB 8 + +struct ms5611_state { +void *client; +struct mutex lock; + +int (*reset)(struct device *dev); +int (*read_prom_word)(struct device *dev,int index,u16 *word); +int (*read_adc_temp_and_pressure)(struct device *dev, +s32 *temp,s32 *pressure); + +u16 prom[MS5611_PROM_WORDS_NB ]; +}; + +int ms5611_probe (struct iio_dev *indio_dev,struct device *dev); + +#endif /* _MS5611_H */ drivers/iio/pressure/ms5611_core.c new file +215
-0@@ -0,0 +1,215 @@ +/* +* MS5611 pressure and temperature sensor driver +* +* Copyright (c) Tomasz Duszynski <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* Data sheet: +* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf +* +*/ + +#include <linux/module.h> +#include <linux/iio/iio.h> +#include <linux/delay.h> + +#include "ms5611.h" + +static bool ms5611_prom_is_valid (u16 *prom,size_t len) +{ +int i, j; +uint16_t crc =0 , crc_orig = prom[7 ] &0x000F ; + + prom[7 ] &=0xFF00 ; + +for (i =0 ; i < len *2 ; i++) { +if (i %2 ==1 ) + crc ^= prom[i >>1 ] &0x00FF ; +else + crc ^= prom[i >>1 ] >>8 ; + +for (j =0 ; j <8 ; j++) { +if (crc &0x8000 ) + crc = (crc <<1 ) ^0x3000 ; +else + crc <<=1 ; + } + } + + crc = (crc >>12 ) &0x000F ; + +return crc_orig !=0x0000 && crc == crc_orig; +} + +static int ms5611_read_prom (struct iio_dev *indio_dev) +{ +int ret, i; +struct ms5611_state *st =iio_priv (indio_dev); + +for (i =0 ; i <MS5611_PROM_WORDS_NB ; i++) { + ret = st->read_prom_word (&indio_dev->dev, i, &st->prom[i]); +if (ret <0 ) { +dev_err (&indio_dev->dev, +"failed to read prom at %d\n" , i); +return ret; + } + } + +if (!ms5611_prom_is_valid (st->prom,MS5611_PROM_WORDS_NB )) { +dev_err (&indio_dev->dev,"PROM integrity check failed\n" ); +return -ENODEV ; + } + +return 0 ; +} + +static int ms5611_read_temp_and_pressure (struct iio_dev *indio_dev, +s32 *temp,s32 *pressure) +{ +int ret; +s32 t, p; +s64 off, sens, dt; +struct ms5611_state *st =iio_priv (indio_dev); + + ret = st->read_adc_temp_and_pressure (&indio_dev->dev, &t, &p); +if (ret <0 ) { +dev_err (&indio_dev->dev, +"failed to read temperature and pressure\n" ); +return ret; + } + + dt = t - (st->prom[5 ] <<8 ); + off = ((s64 )st->prom[2 ] <<16 ) + ((st->prom[4 ] * dt) >>7 ); + sens = ((s64 )st->prom[1 ] <<15 ) + ((st->prom[3 ] * dt) >>8 ); + + t =2000 + ((st->prom[6 ] * dt) >>23 ); +if (t <2000 ) { +s64 off2, sens2, t2; + + t2 = (dt * dt) >>31 ; + off2 = (5 * (t -2000 ) * (t -2000 )) >>1 ; + sens2 = off2 >>1 ; + +if (t <-1500 ) { +s64 tmp = (t +1500 ) * (t +1500 ); + + off2 +=7 * tmp; + sens2 += (11 * tmp) >>1 ; + } + + t -= t2; + off -= off2; + sens -= sens2; + } + + *temp = t; + *pressure = (((p * sens) >>21 ) - off) >>15 ; + +return 0 ; +} + +static int ms5611_reset (struct iio_dev *indio_dev) +{ +int ret; +struct ms5611_state *st =iio_priv (indio_dev); + + ret = st->reset (&indio_dev->dev); +if (ret <0 ) { +dev_err (&indio_dev->dev,"failed to reset device\n" ); +return ret; + } + +usleep_range (3000 ,4000 ); + +return 0 ; +} + +static int ms5611_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int *val,int *val2,long mask) +{ +int ret; +s32 temp, pressure; +struct ms5611_state *st =iio_priv (indio_dev); + +switch (mask) { +case IIO_CHAN_INFO_PROCESSED : +mutex_lock (&st->lock); + ret =ms5611_read_temp_and_pressure (indio_dev, + &temp, &pressure); +mutex_unlock (&st->lock); +if (ret <0 ) +return ret; + +switch (chan->type) { +case IIO_TEMP : + *val = temp *10 ; +return IIO_VAL_INT ; +case IIO_PRESSURE : + *val = pressure /1000 ; + *val2 = (pressure %1000 ) *1000 ; +return IIO_VAL_INT_PLUS_MICRO ; +default : +return -EINVAL ; + } + } + +return -EINVAL ; +} + +static const struct iio_chan_spec ms5611_channels[] = { + { + .type =IIO_PRESSURE , + .info_mask_separate =BIT (IIO_CHAN_INFO_PROCESSED ) | +BIT (IIO_CHAN_INFO_SCALE ) + }, + { + .type =IIO_TEMP , + .info_mask_separate =BIT (IIO_CHAN_INFO_PROCESSED ) | +BIT (IIO_CHAN_INFO_SCALE ) + } +}; + +static const struct iio_info ms5611_info = { + .read_raw = &ms5611_read_raw, + .driver_module =THIS_MODULE , +}; + +static int ms5611_init (struct iio_dev *indio_dev) +{ +int ret; + + ret =ms5611_reset (indio_dev); +if (ret <0 ) +return ret; + +return ms5611_read_prom (indio_dev); +} + +int ms5611_probe (struct iio_dev *indio_dev,struct device *dev) +{ +int ret; +struct ms5611_state *st =iio_priv (indio_dev); + +mutex_init (&st->lock); + indio_dev->dev.parent = dev; + indio_dev->name = dev->driver->name; + indio_dev->info = &ms5611_info; + indio_dev->channels = ms5611_channels; + indio_dev->num_channels =ARRAY_SIZE (ms5611_channels); + indio_dev->modes =INDIO_DIRECT_MODE ; + + ret =ms5611_init (indio_dev); +if (ret <0 ) +return ret; + +return devm_iio_device_register (dev, indio_dev); +} +EXPORT_SYMBOL (ms5611_probe); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("MS5611 core driver" ); +MODULE_LICENSE ("GPL v2" );drivers/iio/pressure/ms5611_i2c.c new file +128
-0@@ -0,0 +1,128 @@ +/* +* MS5611 pressure and temperature sensor driver (I2C bus) +* +* Copyright (c) Tomasz Duszynski <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* 7-bit I2C slave addresses: +* +* 0x77 (CSB pin low) +* 0x76 (CSB pin high) +* +*/ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> + +#include "ms5611.h" + +static int ms5611_i2c_reset (struct device *dev) +{ +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + +return i2c_smbus_write_byte (st->client,MS5611_RESET ); +} + +static int ms5611_i2c_read_prom_word (struct device *dev,int index,u16 *word) +{ +int ret; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + + ret =i2c_smbus_read_word_swapped (st->client, +MS5611_READ_PROM_WORD + (index <<1 )); +if (ret <0 ) +return ret; + + *word = ret; + +return 0 ; +} + +static int ms5611_i2c_read_adc (struct ms5611_state *st,s32 *val) +{ +int ret; +u8 buf[3 ]; + + ret =i2c_smbus_read_i2c_block_data (st->client,MS5611_READ_ADC , +3 , buf); +if (ret <0 ) +return ret; + + *val = (buf[0 ] <<16 ) | (buf[1 ] <<8 ) | buf[2 ]; + +return 0 ; +} + +static int ms5611_i2c_read_adc_temp_and_pressure (struct device *dev, +s32 *temp,s32 *pressure) +{ +int ret; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + + ret =i2c_smbus_write_byte (st->client,MS5611_START_TEMP_CONV ); +if (ret <0 ) +return ret; + +usleep_range (MS5611_CONV_TIME_MIN ,MS5611_CONV_TIME_MAX ); + + ret =ms5611_i2c_read_adc (st, temp); +if (ret <0 ) +return ret; + + ret =i2c_smbus_write_byte (st->client,MS5611_START_PRESSURE_CONV ); +if (ret <0 ) +return ret; + +usleep_range (MS5611_CONV_TIME_MIN ,MS5611_CONV_TIME_MAX ); + +return ms5611_i2c_read_adc (st, pressure); +} + +static int ms5611_i2c_probe (struct i2c_client *client, +const struct i2c_device_id *id) +{ +struct ms5611_state *st; +struct iio_dev *indio_dev; + +if (!i2c_check_functionality (client->adapter, +I2C_FUNC_SMBUS_WRITE_BYTE | +I2C_FUNC_SMBUS_READ_WORD_DATA | +I2C_FUNC_SMBUS_READ_I2C_BLOCK )) +return -ENODEV ; + + indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*st)); +if (!indio_dev) +return -ENOMEM ; + + st =iio_priv (indio_dev); + st->reset = ms5611_i2c_reset; + st->read_prom_word = ms5611_i2c_read_prom_word; + st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure; + st->client = client; + +return ms5611_probe (indio_dev, &client->dev); +} + +static const struct i2c_device_id ms5611_id[] = { + {"ms5611" ,0 }, + { } +}; +MODULE_DEVICE_TABLE (i2c, ms5611_id); + +static struct i2c_driver ms5611_driver = { + .driver = { + .name ="ms5611" , + .owner =THIS_MODULE , + }, + .id_table = ms5611_id, + .probe = ms5611_i2c_probe, +}; +module_i2c_driver (ms5611_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("MS5611 i2c driver" ); +MODULE_LICENSE ("GPL v2" );drivers/iio/pressure/ms5611_spi.c new file +127
-1@@ -0,0 +1,127 @@ +/* +* MS5611 pressure and temperature sensor driver (SPI bus) +* +* Copyright (c) Tomasz Duszynski <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include "ms5611.h" + +static int ms5611_spi_reset (struct device *dev) +{ +u8 cmd =MS5611_RESET ; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + +return spi_write_then_read (st->client, &cmd,1 ,NULL ,0 ); +} + +static int ms5611_spi_read_prom_word (struct device *dev,int index,u16 *word) +{ +int ret; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + + ret =spi_w8r16be (st->client,MS5611_READ_PROM_WORD + (index <<1 )); +if (ret <0 ) +return ret; + + *word = ret; + +return 0 ; +} + +static int ms5611_spi_read_adc (struct device *dev,s32 *val) +{ +int ret; +u8 buf[3 ] = {MS5611_READ_ADC }; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + + ret =spi_write_then_read (st->client, buf,1 , buf,3 ); +if (ret <0 ) +return ret; + + *val = (buf[0 ] <<16 ) | (buf[1 ] <<8 ) | buf[2 ]; + +return 0 ; +} + +static int ms5611_spi_read_adc_temp_and_pressure (struct device *dev, +s32 *temp,s32 *pressure) +{ +u8 cmd; +int ret; +struct ms5611_state *st =iio_priv (dev_to_iio_dev (dev)); + + cmd =MS5611_START_TEMP_CONV ; + ret =spi_write_then_read (st->client, &cmd,1 ,NULL ,0 ); +if (ret <0 ) +return ret; + +usleep_range (MS5611_CONV_TIME_MIN ,MS5611_CONV_TIME_MAX ); + + ret =ms5611_spi_read_adc (dev, temp); +if (ret <0 ) +return ret; + + cmd =MS5611_START_PRESSURE_CONV ; + ret =spi_write_then_read (st->client, &cmd,1 ,NULL ,0 ); +if (ret <0 ) +return ret; + +usleep_range (MS5611_CONV_TIME_MIN ,MS5611_CONV_TIME_MAX ); + +return ms5611_spi_read_adc (dev, pressure); +} + +static int ms5611_spi_probe (struct spi_device *spi) +{ +int ret; +struct ms5611_state *st; +struct iio_dev *indio_dev; + + indio_dev =devm_iio_device_alloc (&spi->dev,sizeof (*st)); +if (!indio_dev) +return -ENOMEM ; + + spi->mode =SPI_MODE_0 ; + spi->max_speed_hz =20000000 ; + spi->bits_per_word =8 ; + ret =spi_setup (spi); +if (ret <0 ) +return ret; + + st =iio_priv (indio_dev); + st->reset = ms5611_spi_reset; + st->read_prom_word = ms5611_spi_read_prom_word; + st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure; + st->client = spi; + +return ms5611_probe (indio_dev, &spi->dev); +} + +static const struct spi_device_id ms5611_id[] = { + {"ms5611" ,0 }, + { } +}; +MODULE_DEVICE_TABLE (spi, ms5611_id); + +static struct spi_driver ms5611_driver = { + .driver = { + .name ="ms5611" , + .owner =THIS_MODULE , + }, + .id_table = ms5611_id, + .probe = ms5611_spi_probe, +}; +module_spi_driver (ms5611_driver); + +MODULE_AUTHOR ("Tomasz Duszynski <[email protected]>" ); +MODULE_DESCRIPTION ("MS5611 spi driver" ); +MODULE_LICENSE ("GPL v2" ); --2.3.2
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html