summaryrefslogtreecommitdiff
path: root/patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch')
-rw-r--r--patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch1390
1 files changed, 1390 insertions, 0 deletions
diff --git a/patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch b/patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch
new file mode 100644
index 00000000000..bdac1c02613
--- /dev/null
+++ b/patches.tizen/0267-iio-Add-driver-for-the-LPS331AP-barometer-sensor.patch
@@ -0,0 +1,1390 @@
+From 527ea6d2bb301d25b4fd54ce4b8d1e2c7fac9193 Mon Sep 17 00:00:00 2001
+From: Jacek Anaszewski <j.anaszewski@samsung.com>
+Date: Fri, 21 Jun 2013 10:52:31 +0200
+Subject: [PATCH 0267/1302] iio: Add driver for the LPS331AP barometer sensor
+
+Add new driver for the barometer device. The driver is
+compliant with IIO framework, and exposes two channels
+for reading the pressure and the temperature. The output
+data can be read either in 'one shot' mode or by exploiting
+IIO events.
+
+Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
+Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
+Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
+Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
+---
+ .../devicetree/bindings/iio/barometer/lps331ap.txt | 40 +
+ drivers/iio/Kconfig | 1 +
+ drivers/iio/Makefile | 1 +
+ drivers/iio/barometer/Kconfig | 12 +
+ drivers/iio/barometer/Makefile | 7 +
+ drivers/iio/barometer/lps331ap.c | 1252 ++++++++++++++++++++
+ 6 files changed, 1313 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/iio/barometer/lps331ap.txt
+ create mode 100644 drivers/iio/barometer/Kconfig
+ create mode 100644 drivers/iio/barometer/Makefile
+ create mode 100644 drivers/iio/barometer/lps331ap.c
+
+diff --git a/Documentation/devicetree/bindings/iio/barometer/lps331ap.txt b/Documentation/devicetree/bindings/iio/barometer/lps331ap.txt
+new file mode 100644
+index 0000000..f0e44bc
+--- /dev/null
++++ b/Documentation/devicetree/bindings/iio/barometer/lps331ap.txt
+@@ -0,0 +1,40 @@
++* STMicroelectronics LPS331AP barometer sensor
++
++Required properties:
++
++ - compatible : should be "st,lps331ap"
++ - reg : the I2C address of the barometer
++
++Optional properties:
++
++ - interrupt-parent : phandle to the interrupt map subnode
++ - interrupts : interrupt mapping for LPS331AP interrupt sources:
++ 2 sources: 0 - INT1, 1 - INT2
++ - irq-map : irq sub-node defining interrupt map
++ (all properties listed below are required):
++ - #interrupt-cells : should be 1
++ - #address-cells : should be 0
++ - #size-cells : should be 0
++ - interrupt-map : table of entries consisting of three child elements:
++ - unit_interrupt_specifier - 0 : INT1, 1 : INT2
++ - interrupt parent phandle
++ - parent unit interrupt specifier consisiting of two elements:
++ - index of the interrupt within the controller
++ - flags : should be 0
++
++Example:
++
++lps331ap@5d {
++ compatible = "lps331ap";
++ reg = <0x5d>;
++ interrupt-parent = <&irq_map>;
++ interrupts = <0>, <1>;
++
++ irq_map: irq-map {
++ #interrupt-cells = <1>;
++ #address-cells = <0>;
++ #size-cells = <0>;
++ interrupt-map = <0 &gpf0 5 0>,
++ <1 &gpx0 3 0>;
++ };
++};
+diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
+index b2f963b..edf69ff 100644
+--- a/drivers/iio/Kconfig
++++ b/drivers/iio/Kconfig
+@@ -63,6 +63,7 @@ config IIO_CONSUMERS_PER_TRIGGER
+ source "drivers/iio/accel/Kconfig"
+ source "drivers/iio/adc/Kconfig"
+ source "drivers/iio/amplifiers/Kconfig"
++source "drivers/iio/barometer/Kconfig"
+ source "drivers/iio/common/Kconfig"
+ source "drivers/iio/dac/Kconfig"
+ source "drivers/iio/frequency/Kconfig"
+diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
+index a0e8cdd..cfcc812 100644
+--- a/drivers/iio/Makefile
++++ b/drivers/iio/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+ obj-y += accel/
+ obj-y += adc/
+ obj-y += amplifiers/
++obj-y += barometer/
+ obj-y += common/
+ obj-y += dac/
+ obj-y += gyro/
+diff --git a/drivers/iio/barometer/Kconfig b/drivers/iio/barometer/Kconfig
+new file mode 100644
+index 0000000..927c06c
+--- /dev/null
++++ b/drivers/iio/barometer/Kconfig
+@@ -0,0 +1,12 @@
++#
++# Magnetometer sensors
++#
++menu "Barometer sensors"
++
++config SENSORS_LPS331
++ tristate "STMicro LPS331 driver"
++ depends on I2C
++ help
++ Driver for STMicro LPS331
++
++endmenu
+diff --git a/drivers/iio/barometer/Makefile b/drivers/iio/barometer/Makefile
+new file mode 100644
+index 0000000..8beba1c
+--- /dev/null
++++ b/drivers/iio/barometer/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the sensors drivers.
++#
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_SENSORS_LPS331) += lps331ap.o
+diff --git a/drivers/iio/barometer/lps331ap.c b/drivers/iio/barometer/lps331ap.c
+new file mode 100644
+index 0000000..1e7cf07
+--- /dev/null
++++ b/drivers/iio/barometer/lps331ap.c
+@@ -0,0 +1,1252 @@
++/*
++* STMicroelectronics LPS331AP Pressure / Temperature Sensor module driver
++*
++* Copyright (C) 2013 Samsung Electronics Co., Ltd.
++* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
++*
++* Copyright (C) 2010 STMicroelectronics- MSH - Motion Mems BU - Application Team
++* Authors:
++* Matteo Dameno <matteo.dameno@st.com>
++* Carmine Iascone <carmine.iascone@st.com>
++*
++* Both authors are willing to be considered the contact and update points for
++* the driver.
++*
++* The device can be controlled by IIO sysfs interface from the location
++* /sys/bus/iio/devices/iio:deviceN, where N is the variable IIO device
++* number. The LPS331AP device can be identified by reading the 'name'
++* attribute.
++* Output data from the device can be read in two ways - on demand and by
++* initiating IIO events for the device. The former mode allows for power
++* saving as it instructs the device to do a 'one shot' measurement and return
++* to the power down mode, whereas the latter enables cyclic measurements
++* with the period managed through the 'odr' attribute, where possible settings
++* are: 40ms, 80ms, 143ms and 1000ms. The value has to be given in miliseconds.
++* Every integer value is accepted - the driver will round it to the nearest
++* bottom odr setting.
++*
++* Initialization of 'one shot' measurement:
++* - read in_pressure_raw or in_temp_raw sysfs attribute
++* Managing cyclic measurements:
++* 1) enable:
++* - write 1 to the events/in_pressure_mag_either_en and/or
++* events/in_temp_mag_either_en attribute
++* 2) read:
++* - perform periodic read of events/in_pressure_mag_either_value
++* and/or events/in_temp_mag_either_value atrributes
++* 3) alter output data rate:
++* - write value of 40, 80, 143 or 1000 to the 'odr' attribute
++* 1) disable:
++* - write 0 to the events/in_pressure_mag_either_en and/or
++* events/in_temp_mag_either_en attribute
++*
++* Read pressures and temperatures output can be converted in units of
++* measurement by dividing them respectively by in_pressure_scale and
++* in_temp_scale. Temperature values must then be added by the constant float
++* in_temp_offset expressed as Celsius degrees.
++*
++* Obtained values are then expessed as
++* mbar (=0.1 kPa) and Celsius degrees.
++*
++* 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.
++*
++* This program is distributed in the hope that it will be useful, but
++* WITHOUT ANY WARRANTY; without even the implied warranty of
++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++* General Public License for more details.
++*
++* You should have received a copy of the GNU General Public License
++* along with this program; if not, write to the Free Software
++* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++* 02110-1301 USA
++*/
++
++#include <linux/module.h>
++#include <linux/ratelimit.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/gpio.h>
++#include <linux/of_gpio.h>
++#include <linux/of_irq.h>
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/sysfs.h>
++#include <linux/iio/events.h>
++#include <linux/bitops.h>
++
++#define LPS331AP_VENDOR "STM"
++#define LPS331AP_CHIP_ID "LPS331"
++
++#define PR_ABS_MAX 8388607 /* 24 bit 2'compl */
++#define PR_ABS_MIN -8388608
++
++#define WHOAMI_LPS331AP_PRS 0xBB /* Expected content for WAI */
++
++/* Control registers */
++#define REF_P_XL 0x08 /* pressure reference */
++#define REF_P_L 0x09 /* pressure reference */
++#define REF_P_H 0x0a /* pressure reference */
++#define REF_T_L 0x0b /* temperature reference */
++#define REF_T_H 0x0c /* temperature reference */
++
++#define WHO_AM_I 0x0f /* WhoAmI register */
++#define TP_RESOL 0x10 /* Pres Temp resolution set */
++#define DGAIN_L 0x18 /* Dig Gain (3 regs) */
++
++#define CTRL_REG1 0x20 /* power / ODR control reg */
++#define CTRL_REG2 0x21 /* boot reg */
++#define CTRL_REG3 0x22 /* interrupt control reg */
++#define INT_CFG_REG 0x23 /* 2nterrupt config reg */
++#define INT_SRC_REG 0x24 /* interrupt source reg */
++#define THS_P_L 0x25 /* pressure threshold */
++#define THS_P_H 0x26 /* pressure threshold */
++#define STATUS_REG 0X27 /* status reg */
++
++#define PRESS_OUT_XL 0x28 /* press output (3 regs) */
++#define TEMP_OUT_L 0x2b /* temper output (2 regs) */
++#define DELTAREG_1 0x3c /* deltaPressure reg1 */
++#define DELTAREG_2 0x3d /* deltaPressure reg2 */
++#define DELTAREG_3 0x3e /* deltaPressure reg3 */
++
++/* Register aliases */
++#define P_REF_INDATA_REG REF_P_XL
++#define T_REF_INDATA_REG REF_T_L
++#define P_THS_INDATA_REG THS_P_L
++#define P_OUTDATA_REG PRESS_OUT_XL
++#define T_OUTDATA_REG TEMP_OUT_L
++#define OUTDATA_REG PRESS_OUT_XL
++
++/* Register masks */
++#define LPS331AP_PRS_ENABLE_MASK 0x80 /* ctrl_reg1 */
++#define LPS331AP_PRS_ODR_MASK 0x70 /* ctrl_reg1 */
++#define LPS331AP_PRS_DIFF_MASK 0x08 /* ctrl_reg1 */
++#define LPS331AP_PRS_BDU_MASK 0x04 /* ctrl_reg1 */
++#define LPS331AP_PRS_DELTA_EN_MASK 0x02 /* ctrl_reg1 */
++#define LPS331AP_PRS_BOOT_MASK 0x80 /* ctrl_reg2 */
++#define LPS331AP_PRS_SWRESET_MASK 0x04 /* ctrl_reg2 */
++#define LPS331AP_PRS_AUTOZ_MASK 0x02 /* ctrl_reg2 */
++#define LPS331AP_PRS_ONE_SHOT 0x01 /* ctrl_reg2 */
++#define LPS331AP_PRS_INT1_MASK 0x07 /* ctrl_reg3 */
++#define LPS331AP_PRS_INT2_MASK 0x38 /* ctrl_reg3 */
++#define LPS331AP_PRS_PP_OD_MASK 0x40 /* ctrl_reg3 */
++
++#define LPS331AP_PRS_PM_NORMAL 0x80 /* Power Normal Mode */
++#define LPS331AP_PRS_PM_OFF 0x00 /* Power Down */
++
++#define LPS331AP_PRS_DIFF_ON 0x08 /* En Difference circuitry */
++#define LPS331AP_PRS_DIFF_OFF 0x00 /* Dis Difference circuitry */
++
++#define LPS331AP_PRS_AUTOZ_ON 0x02 /* En AutoZero Function */
++#define LPS331AP_PRS_AUTOZ_OFF 0x00 /* Dis Difference Function */
++
++#define LPS331AP_PRS_BDU_ON 0x04 /* En BDU Block Data Upd */
++#define LPS331AP_PRS_DELTA_EN_ON 0x02 /* En Delta Press registers */
++#define LPS331AP_PRS_DIFF_EN 0x08 /* En diff pressure computing */
++#define LPS331AP_PRS_RES_AVGTEMP_064 0x60
++#define LPS331AP_PRS_RES_AVGTEMP_128 0x70
++#define LPS331AP_PRS_RES_AVGPRES_512 0x0a
++#define LPS331AP_PRS_RES_AVGPRES_384 0x09
++
++#define LPS331AP_PRS_RES_MAX (LPS331AP_PRS_RES_AVGTEMP_128 | \
++ LPS331AP_PRS_RES_AVGPRES_512)
++ /* Max Resol. for 1/7/12,5Hz */
++
++#define LPS331AP_PRS_RES_25HZ (LPS331AP_PRS_RES_AVGTEMP_128 | \
++ LPS331AP_PRS_RES_AVGPRES_384)
++ /* Max Resol. for 25Hz */
++#define LPS331AP_PRS_DRDY_INT1 0x04 /* En INT1 'data ready' */
++#define LPS331AP_PRS_DRDY_INT2 0x20 /* En INT2 'data ready' */
++#define LPS331AP_PRS_P_HIGH_INT1 0x01 /* En INT1 P_high */
++#define LPS331AP_PRS_P_HIGH_INT2 0x08 /* En INT2 P_high */
++#define LPS331AP_PRS_P_LOW_INT1 0x02 /* En INT1 P_low */
++#define LPS331AP_PRS_P_LOW_INT2 0x10 /* En INT2 P_low */
++#define LPS331AP_PRS_PH_E 0x01 /* En prs high evt interrupt */
++#define LPS331AP_PRS_PL_E 0x02 /* En prs low evt interrupt */
++
++#define LPS331AP_PRS_INT_FLAG_PH 0x01 /* Diff press high int flag */
++#define LPS331AP_PRS_INT_FLAG_PL 0x02 /* Diff press low int flag */
++#define LPS331AP_PRS_INT_FLAG_IA 0x04 /* Any int flag */
++
++#define LPS331AP_PRESS_SCALE 4096
++#define LPS331AP_TEMP_SCALE 480
++#define LPS331AP_TEMP_OFFSET_INT 42
++#define LPS331AP_TEMP_OFFSET_FRACT 500000
++
++#define I2C_AUTO_INCREMENT 0x80
++
++/* Register cache indices */
++#define LPS331AP_RES_REF_P_XL 0
++#define LPS331AP_RES_REF_P_L 1
++#define LPS331AP_RES_REF_P_H 2
++#define LPS331AP_RES_REF_T_L 3
++#define LPS331AP_RES_REF_T_H 4
++#define LPS331AP_RES_TP_RESOL 5
++#define LPS331AP_RES_CTRL_REG1 6
++#define LPS331AP_RES_CTRL_REG2 7
++#define LPS331AP_RES_CTRL_REG3 8
++#define LPS331AP_RES_INT_CFG_REG 9
++#define LPS331AP_RES_THS_P_L 10
++#define LPS331AP_RES_THS_P_H 11
++#define REG_ENTRIES 12
++
++/* Poll delays */
++#define LPS331AP_ODR_DELAY_DEFAULT 200
++#define LPS331AP_ODR_DELAY_MINIMUM 40
++#define LPS331AP_DATA_READY_TIMEOUT (HZ * 2)
++#define LPS331AP_DATA_READY_POLL_TIME 10
++
++#define LPS331AP_PRS_DEV_NAME "lps331ap"
++
++/* Barometer and Termometer output data rate (ODR) */
++#define LPS331AP_PRS_ODR_ONESH 0x00 /* one shot both */
++#define LPS331AP_PRS_ODR_1_1 0x10 /* 1 Hz baro, 1 Hz term ODR */
++#define LPS331AP_PRS_ODR_7_7 0x50 /* 7 Hz baro, 7 Hz term ODR */
++#define LPS331AP_PRS_ODR_12_12 0x60 /* 12.5Hz baro, 12.5Hz term ODR */
++#define LPS331AP_PRS_ODR_25_25 0x70 /* 25 Hz baro, 25 Hz term ODR */
++
++enum {
++ LPS331AP_LPS331AP_VENDOR,
++ LPS331AP_NAME,
++ LPS331AP_ODR,
++ LPS331AP_PRESSURE_REF_LEVEL,
++};
++
++enum {
++ LPS331AP_INTERRUPT_SRC_NONE,
++ LPS331AP_INTERRUPT_SRC_INT1,
++ LPS331AP_INTERRUPT_SRC_INT2
++};
++
++enum prs_state {
++ FL_HW_ENABLED,
++ FL_HW_INITIALIZED,
++ FL_PRESS_EV_ENABLED,
++ FL_TEMP_EV_ENABLED
++};
++
++static const struct {
++ unsigned int cutoff_ms;
++ unsigned int mask;
++} lps331ap_odr_table[] = {
++ { 40, LPS331AP_PRS_ODR_25_25 },
++ { 80, LPS331AP_PRS_ODR_12_12 },
++ { 143, LPS331AP_PRS_ODR_7_7 },
++ { 1000, LPS331AP_PRS_ODR_1_1 }
++};
++
++struct outputdata {
++ unsigned int press;
++ int temperature;
++};
++
++struct lps331ap_data {
++ struct i2c_client *client;
++ struct mutex lock;
++ struct outputdata press_temp;
++
++ unsigned int output_data_rate;
++ unsigned long flags;
++ u8 reg_cache[REG_ENTRIES];
++
++ int lps_irq;
++ int lps_irq_src;
++};
++
++static int lps331ap_i2c_read(struct lps331ap_data *prs,
++ u8 *buf, int len)
++{
++ int err;
++ struct i2c_msg msgs[] = {
++ {
++ .addr = prs->client->addr,
++ .flags = prs->client->flags & I2C_M_TEN,
++ .len = 1,
++ .buf = buf,
++ },
++ {
++ .addr = prs->client->addr,
++ .flags = (prs->client->flags & I2C_M_TEN) | I2C_M_RD,
++ .len = len,
++ .buf = buf,
++ },
++ };
++
++ err = i2c_transfer(prs->client->adapter, msgs, 2);
++ if (err != 2) {
++ dev_err(&prs->client->dev, "read transfer error = %d\n", err);
++ err = -EIO;
++ }
++ return err;
++}
++
++static int lps331ap_i2c_write(struct lps331ap_data *prs,
++ u8 *buf, int len)
++{
++ int err;
++ struct i2c_msg msgs[] = {
++ {
++ .addr = prs->client->addr,
++ .flags = prs->client->flags & I2C_M_TEN,
++ .len = len + 1,
++ .buf = buf,
++ },
++ };
++
++ err = i2c_transfer(prs->client->adapter, msgs, 1);
++ if (err != 1) {
++ dev_err(&prs->client->dev, "write transfer error\n");
++ err = -EIO;
++ }
++ return err;
++}
++
++static int lps331ap_hw_init(struct lps331ap_data *prs)
++{
++ int err;
++ u8 buf[6];
++
++ dev_dbg(&prs->client->dev, "hw init start\n");
++
++ buf[0] = WHO_AM_I;
++ err = lps331ap_i2c_read(prs, buf, 1);
++ if (err < 0) {
++ dev_err(&prs->client->dev,
++ "error reading WHO_AM_I: is device available/working?\n");
++ goto err_hw_init;
++ }
++
++ if (buf[0] != WHOAMI_LPS331AP_PRS) {
++ err = -ENODEV;
++ dev_err(&prs->client->dev,
++ "device unknown. Expected: 0x%02x, Replies: 0x%02x\n",
++ WHOAMI_LPS331AP_PRS, buf[0]);
++ goto err_hw_init;
++ }
++
++ buf[0] = (I2C_AUTO_INCREMENT | P_REF_INDATA_REG);
++ buf[1] = prs->reg_cache[LPS331AP_RES_REF_P_XL];
++ buf[2] = prs->reg_cache[LPS331AP_RES_REF_P_L];
++ buf[3] = prs->reg_cache[LPS331AP_RES_REF_P_H];
++ buf[4] = prs->reg_cache[LPS331AP_RES_REF_T_L];
++ buf[5] = prs->reg_cache[LPS331AP_RES_REF_T_H];
++ err = lps331ap_i2c_write(prs, buf, 5);
++ if (err < 0)
++ goto err_hw_init;
++
++ buf[0] = TP_RESOL;
++ buf[1] = prs->reg_cache[LPS331AP_RES_TP_RESOL];
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto err_hw_init;
++
++ buf[0] = (I2C_AUTO_INCREMENT | P_THS_INDATA_REG);
++ buf[1] = prs->reg_cache[LPS331AP_RES_THS_P_L];
++ buf[2] = prs->reg_cache[LPS331AP_RES_THS_P_H];
++ err = lps331ap_i2c_write(prs, buf, 2);
++ if (err < 0)
++ goto err_hw_init;
++
++ /* clear INT_ACK flag */
++ buf[0] = INT_SRC_REG;
++ err = lps331ap_i2c_read(prs, buf, 1);
++ if (err < 0)
++ return err;
++
++ /* CTRL_REG3 register has to be initialized before powering on */
++ buf[0] = CTRL_REG3;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG3];
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto err_hw_init;
++
++ buf[0] = (I2C_AUTO_INCREMENT | CTRL_REG1);
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG1];
++ buf[2] = prs->reg_cache[LPS331AP_RES_CTRL_REG2];
++ err = lps331ap_i2c_write(prs, buf, 2);
++ if (err < 0)
++ goto err_hw_init;
++
++ set_bit(FL_HW_INITIALIZED, &prs->flags);
++ dev_dbg(&prs->client->dev, "hw init done\n");
++
++ return 0;
++
++err_hw_init:
++ clear_bit(FL_HW_INITIALIZED, &prs->flags);
++ dev_err(&prs->client->dev, "hw init error 0x%02x,0x%02x: %d\n",
++ buf[0], buf[1], err);
++ return err;
++}
++
++static int lps331ap_device_power_off(struct lps331ap_data *prs)
++{
++ int err;
++ u8 buf[2];
++
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1]
++ &= ~LPS331AP_PRS_PM_NORMAL;
++
++ buf[0] = CTRL_REG1;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG1];
++
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ return err;
++
++ return 0;
++}
++
++static int lps331ap_device_power_on(struct lps331ap_data *prs)
++{
++ u8 buf[2];
++ int err;
++
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1] |= LPS331AP_PRS_PM_NORMAL;
++
++ if (!test_bit(FL_HW_INITIALIZED, &prs->flags)) {
++ err = lps331ap_hw_init(prs);
++ lps331ap_device_power_off(prs);
++ } else {
++ buf[0] = CTRL_REG1;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG1];
++ err = lps331ap_i2c_write(prs, buf, 1);
++ }
++
++ return err;
++}
++
++static int lps331ap_update_odr(struct lps331ap_data *prs, int delay_ms)
++{
++ int err = -1;
++ int i;
++
++ u8 buf[2];
++ u8 init_val, updated_val;
++ u8 curr_val, new_val;
++ u8 mask = LPS331AP_PRS_ODR_MASK;
++ u8 resol = LPS331AP_PRS_RES_MAX;
++
++ /*
++ * Following, looks for the longest possible odr interval scrolling the
++ * odr_table vector from the end (longest period) backward (shortest
++ * period), to support the poll_interval requested by the system.
++ * It must be the longest period shorter then the set poll period.
++ */
++ for (i = ARRAY_SIZE(lps331ap_odr_table) - 1; i >= 0; i--) {
++ if ((lps331ap_odr_table[i].cutoff_ms <= delay_ms)
++ || (i == 0))
++ break;
++ }
++
++ prs->output_data_rate = lps331ap_odr_table[i].cutoff_ms;
++
++ new_val = lps331ap_odr_table[i].mask;
++ if (new_val == LPS331AP_PRS_ODR_25_25)
++ resol = LPS331AP_PRS_RES_25HZ;
++
++ if (!test_bit(FL_HW_ENABLED, &prs->flags))
++ return 0;
++
++ buf[0] = CTRL_REG1;
++ err = lps331ap_i2c_read(prs, buf, 1);
++ if (err < 0)
++ goto error;
++ /* work on all but ENABLE bits */
++ init_val = buf[0];
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1] = init_val;
++
++ /* disable */
++ curr_val = ((LPS331AP_PRS_ENABLE_MASK & LPS331AP_PRS_PM_OFF)
++ | ((~LPS331AP_PRS_ENABLE_MASK) & init_val));
++ buf[0] = CTRL_REG1;
++ buf[1] = curr_val;
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto error;
++
++ buf[0] = CTRL_REG1;
++ updated_val = ((mask & new_val) | ((~mask) & curr_val));
++
++ buf[0] = CTRL_REG1;
++ buf[1] = updated_val;
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto error;
++
++ /* enable */
++ curr_val = ((LPS331AP_PRS_ENABLE_MASK & LPS331AP_PRS_PM_NORMAL)
++ | ((~LPS331AP_PRS_ENABLE_MASK) & updated_val));
++ buf[0] = CTRL_REG1;
++ buf[1] = curr_val;
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto error;
++
++ buf[0] = TP_RESOL;
++ buf[1] = resol;
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto error;
++
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1] = curr_val;
++ prs->reg_cache[LPS331AP_RES_TP_RESOL] = resol;
++
++ return err;
++
++error:
++ dev_err(&prs->client->dev, "update odr failed 0x%02x,0x%02x: %d\n",
++ buf[0], buf[1], err);
++
++ return err;
++}
++
++static int lps331ap_set_press_reference(struct lps331ap_data *prs,
++ s32 new_reference)
++{
++ u8 buf[4], *ref;
++ __le32 new_ref;
++ int err;
++
++ new_ref = cpu_to_le32(new_reference);
++ ref = (u8 *)&new_ref;
++
++ buf[0] = (I2C_AUTO_INCREMENT | P_REF_INDATA_REG);
++ buf[1] = ref[0];
++ buf[2] = ref[1];
++ buf[3] = ref[2];
++
++ err = lps331ap_i2c_write(prs, buf, 3);
++ if (err < 0)
++ return err;
++
++ prs->reg_cache[LPS331AP_RES_REF_P_XL] = ref[0];
++ prs->reg_cache[LPS331AP_RES_REF_P_L] = ref[1];
++ prs->reg_cache[LPS331AP_RES_REF_P_H] = ref[2];
++
++ return 0;
++}
++
++static int lps331ap_get_press_reference(struct lps331ap_data *prs,
++ s32 *reference)
++{
++ u8 buf[4];
++ int err;
++
++ memset(buf, 0, sizeof(buf));
++ buf[0] = (I2C_AUTO_INCREMENT | P_REF_INDATA_REG);
++ err = lps331ap_i2c_read(prs, buf, 3);
++
++ if (err < 0)
++ return err;
++
++ *reference = le32_to_cpup((__le32 *) buf);
++
++ return 0;
++}
++
++static int lps331ap_enable(struct lps331ap_data *prs)
++{
++ int err;
++
++ if (!test_bit(FL_HW_ENABLED, &prs->flags)) {
++ err = lps331ap_device_power_on(prs);
++ if (err < 0) {
++ clear_bit(FL_HW_ENABLED, &prs->flags);
++ return err;
++ }
++ set_bit(FL_HW_ENABLED, &prs->flags);
++ }
++
++ return 0;
++}
++
++static int lps331ap_disable(struct lps331ap_data *prs)
++{
++ int err;
++
++ if (!test_bit(FL_HW_ENABLED, &prs->flags))
++ return 0;
++
++ err = lps331ap_device_power_off(prs);
++ clear_bit(FL_HW_ENABLED, &prs->flags);
++
++ return err;
++}
++
++static int lps331ap_get_presstemp_data(struct lps331ap_data *prs,
++ struct outputdata *out)
++{
++ /*
++ * Data bytes from hardware:
++ * PRESS_OUT_XL, PRESS_OUT_L, PRESS_OUT_H,
++ * TEMP_OUT_L, TEMP_OUT_H.
++ */
++ u8 prs_data[5] = { 0, };
++ int err = 0;
++
++ s32 pressure = 0;
++ s16 temperature = 0;
++
++ int reg_to_read = 5;
++
++ prs_data[0] = (I2C_AUTO_INCREMENT | OUTDATA_REG);
++ err = lps331ap_i2c_read(prs, prs_data, reg_to_read);
++ if (err < 0)
++ return err;
++
++ dev_dbg(&prs->client->dev,
++ "temp out tH = 0x%02x, tL = 0x%02x",
++ prs_data[4], prs_data[3]);
++ dev_dbg(&prs->client->dev,
++ "press_out: pH = 0x%02x, pL = 0x%02x, pXL= 0x%02x\n",
++ prs_data[2], prs_data[1], prs_data[0]);
++
++ pressure = (s32) ((((s8) prs_data[2]) << 16) |
++ (prs_data[1] << 8) | (prs_data[0]));
++ temperature = (s16) ((((s8) prs_data[4]) << 8) | (prs_data[3]));
++
++ out->press = pressure;
++ out->temperature = temperature;
++
++ return 0;
++}
++
++static ssize_t lps331ap_get_press_ref(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct iio_dev *dev_info = dev_to_iio_dev(dev);
++ struct lps331ap_data *prs = iio_priv(dev_info);
++ s32 val;
++ int err;
++
++ mutex_lock(&prs->lock);
++ err = lps331ap_get_press_reference(prs, &val);
++ mutex_unlock(&prs->lock);
++ if (err < 0)
++ return err;
++
++ return sprintf(buf, "%d\n", val);
++}
++
++static ssize_t lps331ap_set_press_ref(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct iio_dev *dev_info = dev_to_iio_dev(dev);
++ struct lps331ap_data *prs = iio_priv(dev_info);
++ long val;
++ int err;
++
++ if (kstrtol(buf, 10, &val))
++ return -EINVAL;
++
++ if (val < PR_ABS_MIN || val > PR_ABS_MAX)
++ return -EINVAL;
++
++ mutex_lock(&prs->lock);
++ err = lps331ap_set_press_reference(prs, val);
++ mutex_unlock(&prs->lock);
++
++ return err < 0 ? err : size;
++}
++static ssize_t lps331ap_get_odr(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int val;
++ struct iio_dev *dev_info = dev_to_iio_dev(dev);
++ struct lps331ap_data *prs = iio_priv(dev_info);
++
++ mutex_lock(&prs->lock);
++ val = prs->output_data_rate;
++ mutex_unlock(&prs->lock);
++
++ return sprintf(buf, "%d\n", val);
++}
++
++static ssize_t lps331ap_set_odr(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct iio_dev *dev_info = dev_to_iio_dev(dev);
++ struct lps331ap_data *prs = iio_priv(dev_info);
++ unsigned long delay_ms = 0;
++ unsigned int delay_min = LPS331AP_ODR_DELAY_MINIMUM;
++
++ if (kstrtoul(buf, 10, &delay_ms))
++ return -EINVAL;
++ if (!delay_ms)
++ return -EINVAL;
++
++ dev_dbg(&prs->client->dev, "delay_ms passed = %ld\n", delay_ms);
++ delay_ms = max_t(unsigned int, (unsigned int)delay_ms, delay_min);
++
++ mutex_lock(&prs->lock);
++ prs->output_data_rate = delay_ms;
++ lps331ap_update_odr(prs, delay_ms);
++
++ if (delay_ms == LPS331AP_ODR_DELAY_MINIMUM)
++ dev_dbg(&prs->client->dev, "delay limited to 40ms\n");
++
++ mutex_unlock(&prs->lock);
++
++ return size;
++}
++
++static ssize_t lps331_vendor_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%s\n", LPS331AP_VENDOR);
++}
++
++static ssize_t lps331_name_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%s\n", LPS331AP_CHIP_ID);
++}
++
++static int lps331ap_wait_one_shot_ready_polled(struct iio_dev *indio_dev)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ u32 timeout_ms = LPS331AP_DATA_READY_TIMEOUT;
++ u8 buf;
++ int err;
++
++ /* Wait for the conversion to complete. */
++ while (timeout_ms) {
++ msleep(LPS331AP_DATA_READY_POLL_TIME);
++ buf = CTRL_REG2;
++ err = lps331ap_i2c_read(prs, &buf, 1);
++ if (err < 0)
++ return err;
++ if (!(buf & LPS331AP_PRS_ONE_SHOT))
++ break;
++ timeout_ms -= LPS331AP_DATA_READY_POLL_TIME;
++ }
++ if (!timeout_ms) {
++ dev_err(&prs->client->dev, "Conversion timeout occurred.\n");
++ return -ETIME;
++ }
++
++ return err;
++}
++
++static u8 get_drdy_reg_mask(struct lps331ap_data *prs)
++{
++ if (prs->lps_irq_src == LPS331AP_INTERRUPT_SRC_INT1)
++ return LPS331AP_PRS_DRDY_INT1;
++ else
++ return LPS331AP_PRS_DRDY_INT2;
++}
++
++static int lps331ap_read_presstemp(struct iio_dev *indio_dev, int index,
++ int *val)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ u8 drdy_reg_mask;
++ int enabled;
++ char buf[2], curr_odr;
++ int err;
++
++ mutex_lock(&prs->lock);
++
++ drdy_reg_mask = get_drdy_reg_mask(prs);
++ /*
++ * Set 'one shot' mode if either device is in power down mode
++ * or it is powered up but 'data ready' interrupt isn't enabled.
++ * If this condition evaluates to false then it means that the recent
++ * output is being cached periodically by 'data ready' interrupt
++ * handler, so we can return the cached value.
++ */
++ enabled = test_bit(FL_HW_ENABLED, &prs->flags);
++ if (!enabled ||
++ !(prs->reg_cache[LPS331AP_RES_CTRL_REG3] & drdy_reg_mask)) {
++ /* ensure device is in power down mode */
++ lps331ap_disable(prs);
++
++ /* set ODR configuration to 'one shot' */
++ curr_odr = prs->reg_cache[LPS331AP_RES_CTRL_REG1]
++ & LPS331AP_PRS_ODR_MASK;
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1]
++ &= ~LPS331AP_PRS_ODR_MASK;
++ buf[0] = CTRL_REG1;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG1];
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto exit;
++
++ /* power on the device */
++ err = lps331ap_enable(prs);
++ if (err < 0)
++ goto exit;
++
++ /* set ONE_SHOT mode */
++ buf[0] = CTRL_REG2;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG2]
++ | LPS331AP_PRS_ONE_SHOT;
++ err = lps331ap_i2c_write(prs, buf, 1);
++
++ if (err < 0)
++ goto exit;
++
++ /* wait for the end of coversion */
++ err = lps331ap_wait_one_shot_ready_polled(indio_dev);
++ if (err < 0)
++ goto exit;
++
++ /* read output data */
++ err = lps331ap_get_presstemp_data(prs, &prs->press_temp);
++ if (err < 0)
++ goto exit;
++
++ /* bring back previous ODR settings */
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1]
++ |= curr_odr;
++ buf[0] = CTRL_REG1;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG1];
++ err = lps331ap_i2c_write(prs, buf, 1);
++
++ if (!enabled)
++ lps331ap_disable(prs);
++ }
++
++ *val = index == 0 ? prs->press_temp.press : prs->press_temp.temperature;
++
++ mutex_unlock(&prs->lock);
++
++ return IIO_VAL_INT;
++
++exit:
++ mutex_unlock(&prs->lock);
++ return -EINVAL;
++}
++
++static irqreturn_t lps331ap_irq_handler(int irq, void *data)
++{
++ struct iio_dev *indio_dev = data;
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ int err;
++
++ if (test_bit(FL_PRESS_EV_ENABLED, &prs->flags))
++ iio_push_event(indio_dev,
++ IIO_UNMOD_EVENT_CODE(IIO_PRESSURE, 0,
++ IIO_EV_TYPE_MAG,
++ IIO_EV_DIR_EITHER),
++ iio_get_time_ns());
++ if (test_bit(FL_TEMP_EV_ENABLED, &prs->flags))
++ iio_push_event(indio_dev,
++ IIO_UNMOD_EVENT_CODE(IIO_TEMP, 1,
++ IIO_EV_TYPE_MAG,
++ IIO_EV_DIR_EITHER),
++ iio_get_time_ns());
++
++ err = lps331ap_get_presstemp_data(prs, &prs->press_temp);
++ if (err < 0)
++ dev_err_ratelimited(&prs->client->dev,
++ "get_presstemp_data failed\n");
++
++ return IRQ_HANDLED;
++}
++
++static int lps331ap_setup_irq(struct iio_dev *indio_dev)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ struct i2c_client *client = prs->client;
++ int err;
++
++ err = request_threaded_irq(prs->lps_irq, NULL,
++ lps331ap_irq_handler,
++ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
++ dev_name(&client->dev), indio_dev);
++ if (err < 0) {
++ dev_err(&client->dev,
++ "irq %d request failed: %d\n",
++ prs->lps_irq, err);
++ return err;
++ }
++
++ return 0;
++}
++
++static int lps331ap_read_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int *val, int *val2, long mask)
++{
++ switch (mask) {
++ case IIO_CHAN_INFO_RAW:
++ return lps331ap_read_presstemp(indio_dev, chan->address, val);
++ case IIO_CHAN_INFO_SCALE:
++ switch (chan->type) {
++ case IIO_PRESSURE:
++ *val = LPS331AP_PRESS_SCALE;
++ return IIO_VAL_INT;
++ case IIO_TEMP:
++ *val = LPS331AP_TEMP_SCALE;
++ return IIO_VAL_INT;
++ default:
++ return -EINVAL;
++ }
++ case IIO_CHAN_INFO_OFFSET:
++ /* Only the temperature channel has an offset. */
++ *val = LPS331AP_TEMP_OFFSET_INT;
++ *val2 = LPS331AP_TEMP_OFFSET_FRACT;
++ return IIO_VAL_INT_PLUS_MICRO;
++ }
++
++ return -EINVAL;
++}
++
++static int lps331ap_read_event_val(struct iio_dev *indio_dev, u64 event_code,
++ int *val)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ int chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code);
++ int event_type = IIO_EVENT_CODE_EXTRACT_TYPE(event_code);
++ u8 drdy_reg_mask;
++
++ drdy_reg_mask = get_drdy_reg_mask(prs);
++
++ if (event_type == IIO_EV_TYPE_MAG) {
++ /*
++ * If events are enabled the output data is being
++ * cached in the interrupt handler and thus we
++ * can return it here.
++ */
++ if (prs->reg_cache[LPS331AP_RES_CTRL_REG3]
++ & drdy_reg_mask)
++ switch (chan_type) {
++ case IIO_PRESSURE:
++ *val = prs->press_temp.press;
++ break;
++ case IIO_TEMP:
++ *val = prs->press_temp.temperature;
++ break;
++ } else
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int lps331ap_write_event_config(struct iio_dev *indio_dev,
++ u64 event_code, int state)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ int event_type = IIO_EVENT_CODE_EXTRACT_TYPE(event_code);
++ int chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code);
++ u8 ctrl_reg3 = prs->reg_cache[LPS331AP_RES_CTRL_REG3];
++ u8 drdy_reg_mask;
++ char buf[2];
++ enum prs_state event_state = (chan_type == IIO_PRESSURE) ?
++ FL_PRESS_EV_ENABLED : FL_TEMP_EV_ENABLED;
++ int err = 0;
++
++ if (prs->lps_irq_src == LPS331AP_INTERRUPT_SRC_NONE) {
++ dev_err(&prs->client->dev,
++ "current platform doesn't support LPS331 interrupts\n");
++ return -EINVAL;
++ }
++
++ mutex_lock(&prs->lock);
++
++ drdy_reg_mask = get_drdy_reg_mask(prs);
++
++ if (state) {
++ /* Don't do anything if the event is already enabled. */
++ if (test_bit(event_state, &prs->flags))
++ goto done;
++ switch (event_type) {
++ case IIO_EV_TYPE_MAG:
++ ctrl_reg3 |= drdy_reg_mask;
++ set_bit(event_state, &prs->flags);
++ break;
++ default:
++ goto err_unsupported_event_type;
++ }
++ } else {
++ switch (event_type) {
++ case IIO_EV_TYPE_MAG:
++ clear_bit(event_state, &prs->flags);
++ /*
++ * Disable 'data ready' interrupt only if
++ * there is no enabled event.
++ */
++ if (!test_bit(FL_PRESS_EV_ENABLED, &prs->flags) &&
++ !test_bit(FL_TEMP_EV_ENABLED, &prs->flags))
++ ctrl_reg3 &= ~drdy_reg_mask;
++ break;
++ default:
++ goto err_unsupported_event_type;
++ }
++ }
++
++ /* Setup new interrupt configuration. */
++ prs->reg_cache[LPS331AP_RES_CTRL_REG3] = ctrl_reg3;
++
++ buf[0] = CTRL_REG3;
++ buf[1] = prs->reg_cache[LPS331AP_RES_CTRL_REG3];
++ err = lps331ap_i2c_write(prs, buf, 1);
++ if (err < 0)
++ goto err_write_event_config;
++
++ /*
++ * The device should be powered on only
++ * if at least one event is enabled.
++ */
++ if (ctrl_reg3 & drdy_reg_mask) {
++ err = lps331ap_enable(prs);
++ if (err < 0)
++ goto err_write_event_config;
++ } else {
++ err = lps331ap_disable(prs);
++ if (err < 0)
++ goto err_write_event_config;
++ }
++
++ /* clear INT_ACK flag */
++ buf[0] = INT_SRC_REG;
++ err = lps331ap_i2c_read(prs, buf, 1);
++ if (err < 0)
++ goto err_write_event_config;
++done:
++ mutex_unlock(&prs->lock);
++
++ return 0;
++
++err_unsupported_event_type:
++ err = -EINVAL;
++ dev_err(&prs->client->dev, "unsupported event type\n");
++err_write_event_config:
++ clear_bit(event_state, &prs->flags);
++ mutex_unlock(&prs->lock);
++ dev_err(&prs->client->dev, "writing event config failed\n");
++
++ return err;
++}
++
++static int lps331ap_read_event_config(struct iio_dev *indio_dev,
++ u64 event_code)
++{
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++ int event_type = IIO_EVENT_CODE_EXTRACT_TYPE(event_code);
++ int chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code);
++ enum prs_state event_state = (chan_type == IIO_PRESSURE) ?
++ FL_PRESS_EV_ENABLED : FL_TEMP_EV_ENABLED;
++ int val;
++
++ if (prs->lps_irq_src == LPS331AP_INTERRUPT_SRC_NONE)
++ return -EINVAL;
++
++ switch (event_type) {
++ case IIO_EV_TYPE_MAG:
++ val = test_bit(event_state, &prs->flags);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return val;
++}
++
++static IIO_DEVICE_ATTR(odr, 0664,
++ lps331ap_get_odr, lps331ap_set_odr, LPS331AP_ODR);
++static IIO_DEVICE_ATTR(pressure_reference_level, 0664,
++ lps331ap_get_press_ref,
++ lps331ap_set_press_ref, LPS331AP_PRESSURE_REF_LEVEL);
++static IIO_DEVICE_ATTR(vendor, 0644, lps331_vendor_show, NULL,
++ LPS331AP_LPS331AP_VENDOR);
++static IIO_DEVICE_ATTR(name, 0644, lps331_name_show, NULL, LPS331AP_NAME);
++
++static struct attribute *lps331ap_attributes[] = {
++ &iio_dev_attr_vendor.dev_attr.attr,
++ &iio_dev_attr_name.dev_attr.attr,
++ &iio_dev_attr_odr.dev_attr.attr,
++ &iio_dev_attr_pressure_reference_level.dev_attr.attr,
++ NULL
++};
++
++static struct attribute_group lps331ap_attribute_group = {
++ .attrs = lps331ap_attributes,
++};
++
++#define LPS331AP_PRESSURE_CHANNEL(index) \
++ { \
++ .channel = index, \
++ .address = index, \
++ .type = IIO_PRESSURE, \
++ .modified = 0, \
++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
++ BIT(IIO_CHAN_INFO_SCALE), \
++ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_MAG, \
++ IIO_EV_DIR_EITHER), \
++ }
++
++#define LPS331AP_TEMP_CHANNEL(index) \
++ { \
++ .channel = index, \
++ .address = index, \
++ .type = IIO_TEMP, \
++ .modified = 0, \
++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
++ BIT(IIO_CHAN_INFO_SCALE) | \
++ BIT(IIO_CHAN_INFO_OFFSET), \
++ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_MAG, \
++ IIO_EV_DIR_EITHER), \
++ }
++
++static const struct iio_chan_spec lps331ap_channels[] = {
++ LPS331AP_PRESSURE_CHANNEL(0), LPS331AP_TEMP_CHANNEL(1),
++};
++
++static const struct iio_info lps331ap_info = {
++ .attrs = &lps331ap_attribute_group,
++ .read_raw = &lps331ap_read_raw,
++ .read_event_value = &lps331ap_read_event_val,
++ .read_event_config = &lps331ap_read_event_config,
++ .write_event_config = &lps331ap_write_event_config,
++ .driver_module = THIS_MODULE,
++};
++
++static int lps331ap_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct lps331ap_data *prs;
++ struct iio_dev *indio_dev;
++ int int1_src, int2_src;
++ int err = -EINVAL;
++
++ indio_dev = iio_device_alloc(sizeof(struct lps331ap_data));
++ if (indio_dev == NULL)
++ return -ENOMEM;
++
++ prs = iio_priv(indio_dev);
++
++ if (client->dev.of_node) {
++ int1_src = irq_of_parse_and_map(client->dev.of_node, 0);
++ int2_src = irq_of_parse_and_map(client->dev.of_node, 1);
++
++ if (int1_src) {
++ prs->lps_irq = int1_src;
++ prs->lps_irq_src = LPS331AP_INTERRUPT_SRC_INT1;
++ } else if (int2_src) {
++ prs->lps_irq = int2_src;
++ prs->lps_irq_src = LPS331AP_INTERRUPT_SRC_INT2;
++ } else {
++ prs->lps_irq_src = LPS331AP_INTERRUPT_SRC_NONE;
++ }
++ } else {
++ prs->lps_irq = -EINVAL;
++ }
++
++ prs->output_data_rate = LPS331AP_ODR_DELAY_DEFAULT;
++ prs->client = client;
++ mutex_init(&prs->lock);
++ indio_dev->dev.parent = &client->dev;
++ indio_dev->channels = lps331ap_channels;
++ indio_dev->num_channels = ARRAY_SIZE(lps331ap_channels);
++ indio_dev->info = &lps331ap_info;
++ indio_dev->modes = INDIO_DIRECT_MODE;
++
++ if (prs->lps_irq) {
++ err = lps331ap_setup_irq(indio_dev);
++ if (err < 0) {
++ dev_err(&client->dev,
++ "Error setting data ready interrupt\n");
++ goto err_free_data;
++ }
++ }
++
++ i2c_set_clientdata(client, indio_dev);
++
++ memset(prs->reg_cache, 0, sizeof(prs->reg_cache));
++
++ /* Do not update output registers until MSB and LSB reading. */
++ prs->reg_cache[LPS331AP_RES_CTRL_REG1] = LPS331AP_PRS_BDU_ON;
++
++ /* Perform hw init. */
++ err = lps331ap_device_power_on(prs);
++ if (err < 0) {
++ dev_err(&client->dev, "power on failed: %d\n", err);
++ goto err_free_data;
++ }
++
++ set_bit(FL_HW_ENABLED, &prs->flags);
++
++ err = lps331ap_update_odr(prs, prs->output_data_rate);
++ if (err < 0) {
++ dev_err(&client->dev, "update_odr failed\n");
++ goto err_power_off;
++ }
++
++ lps331ap_device_power_off(prs);
++
++ clear_bit(FL_HW_ENABLED, &prs->flags);
++
++ err = iio_device_register(indio_dev);
++ if (err < 0)
++ goto err_free_data;
++
++ return 0;
++
++err_power_off:
++ lps331ap_device_power_off(prs);
++err_free_data:
++ if (prs->lps_irq)
++ free_irq(prs->lps_irq, indio_dev);
++ iio_device_free(indio_dev);
++
++ return err;
++}
++
++static int lps331ap_remove(struct i2c_client *client)
++{
++ struct iio_dev *indio_dev = i2c_get_clientdata(client);
++ struct lps331ap_data *prs = iio_priv(indio_dev);
++
++ if (prs->lps_irq)
++ free_irq(prs->lps_irq, indio_dev);
++
++ lps331ap_device_power_off(prs);
++
++ iio_device_unregister(indio_dev);
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++static const struct i2c_device_id lps331ap_id[] = {
++ { LPS331AP_PRS_DEV_NAME, 0 },
++ { },
++};
++
++MODULE_DEVICE_TABLE(i2c, lps331ap_id);
++
++#ifdef CONFIG_OF
++static const struct of_device_id lps331ap_of_match[] = {
++ { .compatible = "st,lps331ap" },
++ { .compatible = "lps331ap" },
++ { }
++};
++#endif
++
++static struct i2c_driver lps331ap_driver = {
++ .driver = {
++ .name = LPS331AP_PRS_DEV_NAME,
++ .of_match_table = of_match_ptr(lps331ap_of_match),
++ },
++ .probe = lps331ap_probe,
++ .remove = lps331ap_remove,
++ .id_table = lps331ap_id,
++};
++
++module_i2c_driver(lps331ap_driver);
++
++MODULE_DESCRIPTION("STMicrolectronics LPS331AP pressure sensor IIO driver");
++MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
++MODULE_AUTHOR("Matteo Dameno, STMicroelectronic <matteo.dameno@st.com>");
++MODULE_AUTHOR("Carmine Iascone, STMicroelectronic <carmine.iascone@st.com>");
++MODULE_LICENSE("GPL");
+--
+1.8.3.2
+