* STMicroelectronics series of patches to support pressure sensors
@ 2013-06-03 14:58 Denis CIOCCA
2013-06-03 14:58 ` [PATCH 1/3] iio:common: ST_SENSORS_LSM_CHANNELS macro changed Denis CIOCCA
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Denis CIOCCA @ 2013-06-03 14:58 UTC (permalink / raw)
To: jic23; +Cc: linux-iio, frederic.pillon, lee.jones
Hi Jonathan,
I modified the series of patches to avoid the VLAs issues replacing them with kmalloc statements. It's correctly?
Thanks,
Denis
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 1/3] iio:common: ST_SENSORS_LSM_CHANNELS macro changed 2013-06-03 14:58 STMicroelectronics series of patches to support pressure sensors Denis CIOCCA @ 2013-06-03 14:58 ` Denis CIOCCA 2013-06-03 14:58 ` [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel Denis CIOCCA 2013-06-03 14:58 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2 siblings, 0 replies; 15+ messages in thread From: Denis CIOCCA @ 2013-06-03 14:58 UTC (permalink / raw) To: jic23; +Cc: linux-iio, frederic.pillon, lee.jones, Denis Ciocca Signed-off-by: Denis Ciocca <denis.ciocca@st.com> --- drivers/iio/accel/st_accel_core.c | 36 ++++++++++++++++++++----------- drivers/iio/gyro/st_gyro_core.c | 21 ++++++++++-------- drivers/iio/magnetometer/st_magn_core.c | 36 ++++++++++++++++++++----------- include/linux/iio/common/st_sensors.h | 20 ++++++++--------- 4 files changed, 69 insertions(+), 44 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index e0f5a3c..40236d5 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -125,22 +125,34 @@ #define ST_ACCEL_3_MULTIREAD_BIT false static const struct iio_chan_spec st_accel_12bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE, - ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE, - ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE, - ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16, + ST_ACCEL_DEFAULT_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16, + ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16, + ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_accel_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_ACCEL_DEFAULT_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), IIO_CHAN_SOFT_TIMESTAMP(3) }; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index fa9b242..9bae46b 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -86,15 +86,18 @@ #define ST_GYRO_2_MULTIREAD_BIT true static const struct iio_chan_spec st_gyro_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_X, - IIO_MOD_X, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS, - ST_GYRO_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Y, - IIO_MOD_Y, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS, - ST_GYRO_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Z, - IIO_MOD_Z, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS, - ST_GYRO_DEFAULT_OUT_Z_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_GYRO_DEFAULT_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_GYRO_DEFAULT_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_GYRO_DEFAULT_OUT_Z_L_ADDR), IIO_CHAN_SOFT_TIMESTAMP(3) }; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 16f0d6d..715d616 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -113,22 +113,34 @@ #define ST_MAGN_2_OUT_Z_L_ADDR 0x2c static const struct iio_chan_spec st_magn_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Z_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_DEFAULT_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_DEFAULT_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_DEFAULT_OUT_Z_L_ADDR), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_magn_2_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE, - ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Z_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_2_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_2_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_2_OUT_Z_L_ADDR), IIO_CHAN_SOFT_TIMESTAMP(3) }; diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 172c5b2..5ffd763 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -30,8 +30,6 @@ #define ST_SENSORS_SCAN_X 0 #define ST_SENSORS_SCAN_Y 1 #define ST_SENSORS_SCAN_Z 2 -#define ST_SENSORS_DEFAULT_12_REALBITS 12 -#define ST_SENSORS_DEFAULT_16_REALBITS 16 #define ST_SENSORS_DEFAULT_POWER_ON_VALUE 0x01 #define ST_SENSORS_DEFAULT_POWER_OFF_VALUE 0x00 #define ST_SENSORS_DEFAULT_WAI_ADDRESS 0x0f @@ -42,20 +40,20 @@ #define ST_SENSORS_MAX_NAME 17 #define ST_SENSORS_MAX_4WAI 7 -#define ST_SENSORS_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \ +#define ST_SENSORS_LSM_CHANNELS(device_type, mask, index, mod, \ + ch2, s, endian, rbits, sbits, addr) \ { \ .type = device_type, \ - .modified = 1, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ + .modified = mod, \ + .info_mask_separate = mask, \ .scan_index = index, \ - .channel2 = mod, \ + .channel2 = ch2, \ .address = addr, \ .scan_type = { \ - .sign = 's', \ - .realbits = bits, \ - .shift = 16 - bits, \ - .storagebits = 16, \ + .sign = s, \ + .realbits = rbits, \ + .shift = sbits - rbits, \ + .storagebits = sbits, \ .endianness = endian, \ }, \ } -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel 2013-06-03 14:58 STMicroelectronics series of patches to support pressure sensors Denis CIOCCA 2013-06-03 14:58 ` [PATCH 1/3] iio:common: ST_SENSORS_LSM_CHANNELS macro changed Denis CIOCCA @ 2013-06-03 14:58 ` Denis CIOCCA 2013-06-04 18:03 ` Jonathan Cameron 2013-06-03 14:58 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2 siblings, 1 reply; 15+ messages in thread From: Denis CIOCCA @ 2013-06-03 14:58 UTC (permalink / raw) To: jic23; +Cc: linux-iio, frederic.pillon, lee.jones, Denis Ciocca This patch introduce num_data_channels variable on st_sensors struct to manage different type of channels (size or number) in st_sensors_get_buffer_element function. Removed ST_SENSORS_NUMBER_DATA_CHANNELS and ST_SENSORS_BYTE_FOR_CHANNEL and used struct iio_chan_spec const *ch to catch data. Added 3 byte channel data support on one-shot reads. Signed-off-by: Denis Ciocca <denis.ciocca@st.com> --- drivers/iio/accel/st_accel_core.c | 3 ++ drivers/iio/common/st_sensors/st_sensors_buffer.c | 49 ++++++++++++--------- drivers/iio/common/st_sensors/st_sensors_core.c | 34 ++++++++++---- drivers/iio/gyro/st_gyro_core.c | 3 ++ drivers/iio/magnetometer/st_magn_core.c | 3 ++ include/linux/iio/common/st_sensors.h | 4 +- 6 files changed, 64 insertions(+), 32 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 40236d5..4aec121 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -26,6 +26,8 @@ #include <linux/iio/common/st_sensors.h> #include "st_accel.h" +#define ST_ACCEL_NUMBER_DATA_CHANNELS 3 + /* DEFAULT VALUE FOR SENSORS */ #define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28 #define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a @@ -454,6 +456,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_accel_common_probe_error; + adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; adata->multiread_bit = adata->sensor->multi_read_bit; indio_dev->channels = adata->sensor->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 09b236d..7a76db3 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -24,11 +24,20 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { + u8 *addr; int i, n = 0, len; - u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS]; struct st_sensor_data *sdata = iio_priv(indio_dev); + unsigned int num_data_channels = sdata->num_data_channels; + unsigned int byte_for_channel = + indio_dev->channels[0].scan_type.storagebits >> 3; - for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) { + addr = kmalloc(num_data_channels, GFP_KERNEL); + if (!addr) { + len = -ENOMEM; + goto st_sensors_get_buffer_element_error; + } + + for (i = 0; i < num_data_channels; i++) { if (test_bit(i, indio_dev->active_scan_mask)) { addr[n] = indio_dev->channels[i].address; n++; @@ -37,52 +46,48 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) switch (n) { case 1: len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf, - sdata->multiread_bit); + addr[0], byte_for_channel, buf, sdata->multiread_bit); break; case 2: - if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) { + if ((addr[1] - addr[0]) == byte_for_channel) { len = sdata->tf->read_multiple_byte(&sdata->tb, - sdata->dev, addr[0], - ST_SENSORS_BYTE_FOR_CHANNEL*n, - buf, sdata->multiread_bit); + sdata->dev, addr[0], byte_for_channel * n, + buf, sdata->multiread_bit); } else { - u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL* - ST_SENSORS_NUMBER_DATA_CHANNELS]; + u8 rx_array[byte_for_channel * num_data_channels]; len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, addr[0], - ST_SENSORS_BYTE_FOR_CHANNEL* - ST_SENSORS_NUMBER_DATA_CHANNELS, + byte_for_channel * num_data_channels, rx_array, sdata->multiread_bit); if (len < 0) - goto read_data_channels_error; + goto st_sensors_free_memory; - for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS; - i++) { + for (i = 0; i < n * num_data_channels; i++) { if (i < n) buf[i] = rx_array[i]; else buf[i] = rx_array[n + i]; } - len = ST_SENSORS_BYTE_FOR_CHANNEL*n; + len = byte_for_channel * n; } break; case 3: len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - addr[0], ST_SENSORS_BYTE_FOR_CHANNEL* - ST_SENSORS_NUMBER_DATA_CHANNELS, + addr[0], byte_for_channel * num_data_channels, buf, sdata->multiread_bit); break; default: len = -EINVAL; - goto read_data_channels_error; + goto st_sensors_free_memory; } - if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) { + if (len != byte_for_channel * n) { len = -EIO; - goto read_data_channels_error; + goto st_sensors_free_memory; } -read_data_channels_error: +st_sensors_free_memory: + kfree(addr); +st_sensors_get_buffer_element_error: return len; } EXPORT_SYMBOL(st_sensors_get_buffer_element); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index ed9bc8a..865b178 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -20,6 +20,11 @@ #define ST_SENSORS_WAI_ADDRESS 0x0f +static inline u32 st_sensors_get_unaligned_le24(const u8 *p) +{ + return ((s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8); +} + static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, u8 reg_addr, u8 mask, u8 data) { @@ -112,7 +117,8 @@ st_sensors_match_odr_error: return ret; } -static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) +static int st_sensors_set_fullscale(struct iio_dev *indio_dev, + unsigned int fs) { int err, i = 0; struct st_sensor_data *sdata = iio_priv(indio_dev); @@ -273,21 +279,33 @@ st_sensors_match_scale_error: EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); static int st_sensors_read_axis_data(struct iio_dev *indio_dev, - u8 ch_addr, int *data) + struct iio_chan_spec const *ch, int *data) { int err; - u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL]; + u8 *outdata; struct st_sensor_data *sdata = iio_priv(indio_dev); + unsigned int byte_for_channel = ch->scan_type.storagebits >> 3; + + outdata = kmalloc(byte_for_channel, GFP_KERNEL); + if (!outdata) { + err = -EINVAL; + goto st_sensors_read_axis_data_error; + } err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL, + ch->address, byte_for_channel, outdata, sdata->multiread_bit); if (err < 0) - goto read_error; + goto st_sensors_free_memory; - *data = (s16)get_unaligned_le16(outdata); + if (byte_for_channel == 2) + *data = (s16)get_unaligned_le16(outdata); + else if (byte_for_channel == 3) + *data = (s32)st_sensors_get_unaligned_le24(outdata); -read_error: +st_sensors_free_memory: + kfree(outdata); +st_sensors_read_axis_data_error: return err; } @@ -307,7 +325,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, goto read_error; msleep((sdata->sensor->bootime * 1000) / sdata->odr); - err = st_sensors_read_axis_data(indio_dev, ch->address, val); + err = st_sensors_read_axis_data(indio_dev, ch, val); if (err < 0) goto read_error; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 9bae46b..f9ed348 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -27,6 +27,8 @@ #include <linux/iio/common/st_sensors.h> #include "st_gyro.h" +#define ST_GYRO_NUMBER_DATA_CHANNELS 3 + /* DEFAULT VALUE FOR SENSORS */ #define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28 #define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a @@ -313,6 +315,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_gyro_common_probe_error; + gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; gdata->multiread_bit = gdata->sensor->multi_read_bit; indio_dev->channels = gdata->sensor->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 715d616..ebfe8f1 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -26,6 +26,8 @@ #include <linux/iio/common/st_sensors.h> #include "st_magn.h" +#define ST_MAGN_NUMBER_DATA_CHANNELS 3 + /* DEFAULT VALUE FOR SENSORS */ #define ST_MAGN_DEFAULT_OUT_X_L_ADDR 0X04 #define ST_MAGN_DEFAULT_OUT_Y_L_ADDR 0X08 @@ -356,6 +358,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_magn_common_probe_error; + mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; mdata->multiread_bit = mdata->sensor->multi_read_bit; indio_dev->channels = mdata->sensor->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 5ffd763..72b2694 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -24,9 +24,7 @@ #define ST_SENSORS_FULLSCALE_AVL_MAX 10 #define ST_SENSORS_NUMBER_ALL_CHANNELS 4 -#define ST_SENSORS_NUMBER_DATA_CHANNELS 3 #define ST_SENSORS_ENABLE_ALL_AXIS 0x07 -#define ST_SENSORS_BYTE_FOR_CHANNEL 2 #define ST_SENSORS_SCAN_X 0 #define ST_SENSORS_SCAN_Y 1 #define ST_SENSORS_SCAN_Z 2 @@ -202,6 +200,7 @@ struct st_sensors { * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread. * @buffer_data: Data used by buffer part. * @odr: Output data rate of the sensor [Hz]. + * num_data_channels: Number of data channels used in buffer. * @get_irq_data_ready: Function to get the IRQ used for data ready signal. * @tf: Transfer function structure used by I/O operations. * @tb: Transfer buffers and mutex used by I/O operations. @@ -218,6 +217,7 @@ struct st_sensor_data { char *buffer_data; unsigned int odr; + unsigned int num_data_channels; unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel 2013-06-03 14:58 ` [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel Denis CIOCCA @ 2013-06-04 18:03 ` Jonathan Cameron 0 siblings, 0 replies; 15+ messages in thread From: Jonathan Cameron @ 2013-06-04 18:03 UTC (permalink / raw) To: Denis CIOCCA; +Cc: linux-iio, frederic.pillon, lee.jones On 06/03/2013 03:58 PM, Denis CIOCCA wrote: > This patch introduce num_data_channels variable on st_sensors struct > to manage different type of channels (size or number) in > st_sensors_get_buffer_element function. > Removed ST_SENSORS_NUMBER_DATA_CHANNELS and ST_SENSORS_BYTE_FOR_CHANNEL > and used struct iio_chan_spec const *ch to catch data. > Added 3 byte channel data support on one-shot reads. You missed one VLA. I've fixed up as you did for the others an applied. If you could take a quick look at the togreg branch of iio.git that would be great. I'll probably not send a pull request until you have confirmed I haven't done anything silly. > > Signed-off-by: Denis Ciocca <denis.ciocca@st.com> > --- > drivers/iio/accel/st_accel_core.c | 3 ++ > drivers/iio/common/st_sensors/st_sensors_buffer.c | 49 ++++++++++++--------- > drivers/iio/common/st_sensors/st_sensors_core.c | 34 ++++++++++---- > drivers/iio/gyro/st_gyro_core.c | 3 ++ > drivers/iio/magnetometer/st_magn_core.c | 3 ++ > include/linux/iio/common/st_sensors.h | 4 +- > 6 files changed, 64 insertions(+), 32 deletions(-) > > diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c > index 40236d5..4aec121 100644 > --- a/drivers/iio/accel/st_accel_core.c > +++ b/drivers/iio/accel/st_accel_core.c > @@ -26,6 +26,8 @@ > #include <linux/iio/common/st_sensors.h> > #include "st_accel.h" > > +#define ST_ACCEL_NUMBER_DATA_CHANNELS 3 > + > /* DEFAULT VALUE FOR SENSORS */ > #define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28 > #define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a > @@ -454,6 +456,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) > if (err < 0) > goto st_accel_common_probe_error; > > + adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; > adata->multiread_bit = adata->sensor->multi_read_bit; > indio_dev->channels = adata->sensor->ch; > indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; > diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c > index 09b236d..7a76db3 100644 > --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c > +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c > @@ -24,11 +24,20 @@ > > int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) > { > + u8 *addr; > int i, n = 0, len; > - u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS]; > struct st_sensor_data *sdata = iio_priv(indio_dev); > + unsigned int num_data_channels = sdata->num_data_channels; > + unsigned int byte_for_channel = > + indio_dev->channels[0].scan_type.storagebits >> 3; > > - for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) { > + addr = kmalloc(num_data_channels, GFP_KERNEL); > + if (!addr) { > + len = -ENOMEM; > + goto st_sensors_get_buffer_element_error; > + } > + > + for (i = 0; i < num_data_channels; i++) { > if (test_bit(i, indio_dev->active_scan_mask)) { > addr[n] = indio_dev->channels[i].address; > n++; > @@ -37,52 +46,48 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) > switch (n) { > case 1: > len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, > - addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf, > - sdata->multiread_bit); > + addr[0], byte_for_channel, buf, sdata->multiread_bit); > break; > case 2: > - if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) { > + if ((addr[1] - addr[0]) == byte_for_channel) { > len = sdata->tf->read_multiple_byte(&sdata->tb, > - sdata->dev, addr[0], > - ST_SENSORS_BYTE_FOR_CHANNEL*n, > - buf, sdata->multiread_bit); > + sdata->dev, addr[0], byte_for_channel * n, > + buf, sdata->multiread_bit); > } else { > - u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL* > - ST_SENSORS_NUMBER_DATA_CHANNELS]; > + u8 rx_array[byte_for_channel * num_data_channels]; You missed this one. > len = sdata->tf->read_multiple_byte(&sdata->tb, > sdata->dev, addr[0], > - ST_SENSORS_BYTE_FOR_CHANNEL* > - ST_SENSORS_NUMBER_DATA_CHANNELS, > + byte_for_channel * num_data_channels, > rx_array, sdata->multiread_bit); > if (len < 0) > - goto read_data_channels_error; > + goto st_sensors_free_memory; > > - for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS; > - i++) { > + for (i = 0; i < n * num_data_channels; i++) { > if (i < n) > buf[i] = rx_array[i]; > else > buf[i] = rx_array[n + i]; > } > - len = ST_SENSORS_BYTE_FOR_CHANNEL*n; > + len = byte_for_channel * n; > } > break; > case 3: > len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, > - addr[0], ST_SENSORS_BYTE_FOR_CHANNEL* > - ST_SENSORS_NUMBER_DATA_CHANNELS, > + addr[0], byte_for_channel * num_data_channels, > buf, sdata->multiread_bit); > break; > default: > len = -EINVAL; > - goto read_data_channels_error; > + goto st_sensors_free_memory; > } > - if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) { > + if (len != byte_for_channel * n) { > len = -EIO; > - goto read_data_channels_error; > + goto st_sensors_free_memory; > } > > -read_data_channels_error: > +st_sensors_free_memory: > + kfree(addr); > +st_sensors_get_buffer_element_error: > return len; > } > EXPORT_SYMBOL(st_sensors_get_buffer_element); > diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c > index ed9bc8a..865b178 100644 > --- a/drivers/iio/common/st_sensors/st_sensors_core.c > +++ b/drivers/iio/common/st_sensors/st_sensors_core.c > @@ -20,6 +20,11 @@ > > #define ST_SENSORS_WAI_ADDRESS 0x0f > > +static inline u32 st_sensors_get_unaligned_le24(const u8 *p) > +{ > + return ((s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8); > +} > + > static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, > u8 reg_addr, u8 mask, u8 data) > { > @@ -112,7 +117,8 @@ st_sensors_match_odr_error: > return ret; > } > > -static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) > +static int st_sensors_set_fullscale(struct iio_dev *indio_dev, > + unsigned int fs) > { > int err, i = 0; > struct st_sensor_data *sdata = iio_priv(indio_dev); > @@ -273,21 +279,33 @@ st_sensors_match_scale_error: > EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); > > static int st_sensors_read_axis_data(struct iio_dev *indio_dev, > - u8 ch_addr, int *data) > + struct iio_chan_spec const *ch, int *data) > { > int err; > - u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL]; > + u8 *outdata; > struct st_sensor_data *sdata = iio_priv(indio_dev); > + unsigned int byte_for_channel = ch->scan_type.storagebits >> 3; > + > + outdata = kmalloc(byte_for_channel, GFP_KERNEL); > + if (!outdata) { > + err = -EINVAL; > + goto st_sensors_read_axis_data_error; > + } > > err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, > - ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL, > + ch->address, byte_for_channel, > outdata, sdata->multiread_bit); > if (err < 0) > - goto read_error; > + goto st_sensors_free_memory; > > - *data = (s16)get_unaligned_le16(outdata); > + if (byte_for_channel == 2) > + *data = (s16)get_unaligned_le16(outdata); > + else if (byte_for_channel == 3) > + *data = (s32)st_sensors_get_unaligned_le24(outdata); > > -read_error: > +st_sensors_free_memory: > + kfree(outdata); > +st_sensors_read_axis_data_error: > return err; > } > > @@ -307,7 +325,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, > goto read_error; > > msleep((sdata->sensor->bootime * 1000) / sdata->odr); > - err = st_sensors_read_axis_data(indio_dev, ch->address, val); > + err = st_sensors_read_axis_data(indio_dev, ch, val); > if (err < 0) > goto read_error; > > diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c > index 9bae46b..f9ed348 100644 > --- a/drivers/iio/gyro/st_gyro_core.c > +++ b/drivers/iio/gyro/st_gyro_core.c > @@ -27,6 +27,8 @@ > #include <linux/iio/common/st_sensors.h> > #include "st_gyro.h" > > +#define ST_GYRO_NUMBER_DATA_CHANNELS 3 > + > /* DEFAULT VALUE FOR SENSORS */ > #define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28 > #define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a > @@ -313,6 +315,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) > if (err < 0) > goto st_gyro_common_probe_error; > > + gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; > gdata->multiread_bit = gdata->sensor->multi_read_bit; > indio_dev->channels = gdata->sensor->ch; > indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; > diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c > index 715d616..ebfe8f1 100644 > --- a/drivers/iio/magnetometer/st_magn_core.c > +++ b/drivers/iio/magnetometer/st_magn_core.c > @@ -26,6 +26,8 @@ > #include <linux/iio/common/st_sensors.h> > #include "st_magn.h" > > +#define ST_MAGN_NUMBER_DATA_CHANNELS 3 > + > /* DEFAULT VALUE FOR SENSORS */ > #define ST_MAGN_DEFAULT_OUT_X_L_ADDR 0X04 > #define ST_MAGN_DEFAULT_OUT_Y_L_ADDR 0X08 > @@ -356,6 +358,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) > if (err < 0) > goto st_magn_common_probe_error; > > + mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; > mdata->multiread_bit = mdata->sensor->multi_read_bit; > indio_dev->channels = mdata->sensor->ch; > indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; > diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h > index 5ffd763..72b2694 100644 > --- a/include/linux/iio/common/st_sensors.h > +++ b/include/linux/iio/common/st_sensors.h > @@ -24,9 +24,7 @@ > #define ST_SENSORS_FULLSCALE_AVL_MAX 10 > > #define ST_SENSORS_NUMBER_ALL_CHANNELS 4 > -#define ST_SENSORS_NUMBER_DATA_CHANNELS 3 > #define ST_SENSORS_ENABLE_ALL_AXIS 0x07 > -#define ST_SENSORS_BYTE_FOR_CHANNEL 2 > #define ST_SENSORS_SCAN_X 0 > #define ST_SENSORS_SCAN_Y 1 > #define ST_SENSORS_SCAN_Z 2 > @@ -202,6 +200,7 @@ struct st_sensors { > * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread. > * @buffer_data: Data used by buffer part. > * @odr: Output data rate of the sensor [Hz]. > + * num_data_channels: Number of data channels used in buffer. > * @get_irq_data_ready: Function to get the IRQ used for data ready signal. > * @tf: Transfer function structure used by I/O operations. > * @tb: Transfer buffers and mutex used by I/O operations. > @@ -218,6 +217,7 @@ struct st_sensor_data { > char *buffer_data; > > unsigned int odr; > + unsigned int num_data_channels; > > unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev); > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-06-03 14:58 STMicroelectronics series of patches to support pressure sensors Denis CIOCCA 2013-06-03 14:58 ` [PATCH 1/3] iio:common: ST_SENSORS_LSM_CHANNELS macro changed Denis CIOCCA 2013-06-03 14:58 ` [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel Denis CIOCCA @ 2013-06-03 14:58 ` Denis CIOCCA 2013-06-04 18:03 ` Jonathan Cameron 2 siblings, 1 reply; 15+ messages in thread From: Denis CIOCCA @ 2013-06-03 14:58 UTC (permalink / raw) To: jic23; +Cc: linux-iio, frederic.pillon, lee.jones, Denis Ciocca This patch adds a generic pressure driver for STMicroelectronics pressure sensors, currently it supports: LPS331AP. Signed-off-by: Denis Ciocca <denis.ciocca@st.com> --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/pressure/Kconfig | 35 ++++ drivers/iio/pressure/Makefile | 10 ++ drivers/iio/pressure/st_pressure.h | 39 +++++ drivers/iio/pressure/st_pressure_buffer.c | 105 +++++++++++ drivers/iio/pressure/st_pressure_core.c | 272 +++++++++++++++++++++++++++++ drivers/iio/pressure/st_pressure_i2c.c | 77 ++++++++ drivers/iio/pressure/st_pressure_spi.c | 76 ++++++++ 9 files changed, 616 insertions(+) create mode 100644 drivers/iio/pressure/Kconfig create mode 100644 drivers/iio/pressure/Makefile create mode 100644 drivers/iio/pressure/st_pressure.h create mode 100644 drivers/iio/pressure/st_pressure_buffer.c create mode 100644 drivers/iio/pressure/st_pressure_core.c create mode 100644 drivers/iio/pressure/st_pressure_i2c.c create mode 100644 drivers/iio/pressure/st_pressure_spi.c diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index daa3ddd..9af763a 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -73,5 +73,6 @@ source "drivers/iio/magnetometer/Kconfig" if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER +source "drivers/iio/pressure/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index a349a96..7a3866c 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -22,3 +22,4 @@ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += trigger/ +obj-y += pressure/ diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig new file mode 100644 index 0000000..9427f01 --- /dev/null +++ b/drivers/iio/pressure/Kconfig @@ -0,0 +1,35 @@ +# +# Pressure drivers +# +menu "Pressure Sensors" + +config IIO_ST_PRESS + tristate "STMicroelectronics pressures Driver" + depends on (I2C || SPI_MASTER) && SYSFS + select IIO_ST_SENSORS_CORE + select IIO_ST_PRESS_I2C if (I2C) + select IIO_ST_PRESS_SPI if (SPI_MASTER) + select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) + help + Say yes here to build support for STMicroelectronics pressures: + LPS331AP. + + This driver can also be built as a module. If so, will be created + these modules: + - st_pressure (core functions for the driver [it is mandatory]); + - st_pressure_i2c (necessary for the I2C devices [optional*]); + - st_pressure_spi (necessary for the SPI devices [optional*]); + + (*) one of these is necessary to do something. + +config IIO_ST_PRESS_I2C + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_I2C + +config IIO_ST_PRESS_SPI + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_SPI + +endmenu diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile new file mode 100644 index 0000000..d4bb33e --- /dev/null +++ b/drivers/iio/pressure/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for industrial I/O pressure drivers +# + +obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o +st_pressure-y := st_pressure_core.o +st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o + +obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o +obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h new file mode 100644 index 0000000..414e45a --- /dev/null +++ b/drivers/iio/pressure/st_pressure.h @@ -0,0 +1,39 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * v. 1.0.0 + * Licensed under the GPL-2. + */ + +#ifndef ST_PRESS_H +#define ST_PRESS_H + +#include <linux/types.h> +#include <linux/iio/common/st_sensors.h> + +#define LPS331AP_PRESS_DEV_NAME "lps331ap" + +int st_press_common_probe(struct iio_dev *indio_dev); +void st_press_common_remove(struct iio_dev *indio_dev); + +#ifdef CONFIG_IIO_BUFFER +int st_press_allocate_ring(struct iio_dev *indio_dev); +void st_press_deallocate_ring(struct iio_dev *indio_dev); +int st_press_trig_set_state(struct iio_trigger *trig, bool state); +#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) +#else /* CONFIG_IIO_BUFFER */ +static inline int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ +} +#define ST_PRESS_TRIGGER_SET_STATE NULL +#endif /* CONFIG_IIO_BUFFER */ + +#endif /* ST_PRESS_H */ diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c new file mode 100644 index 0000000..f877ef8 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -0,0 +1,105 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +int st_press_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + +static int st_press_buffer_preenable(struct iio_dev *indio_dev) +{ + int err; + + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_press_set_enable_error; + + err = iio_sw_buffer_preenable(indio_dev); + +st_press_set_enable_error: + return err; +} + +static int st_press_buffer_postenable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (pdata->buffer_data == NULL) { + err = -ENOMEM; + goto allocate_memory_error; + } + + err = iio_triggered_buffer_postenable(indio_dev); + if (err < 0) + goto st_press_buffer_postenable_error; + + return err; + +st_press_buffer_postenable_error: + kfree(pdata->buffer_data); +allocate_memory_error: + return err; +} + +static int st_press_buffer_predisable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + err = iio_triggered_buffer_predisable(indio_dev); + if (err < 0) + goto st_press_buffer_predisable_error; + + err = st_sensors_set_enable(indio_dev, false); + +st_press_buffer_predisable_error: + kfree(pdata->buffer_data); + return err; +} + +static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { + .preenable = &st_press_buffer_preenable, + .postenable = &st_press_buffer_postenable, + .predisable = &st_press_buffer_predisable, +}; + +int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &st_sensors_trigger_handler, &st_press_buffer_setup_ops); +} + +void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ + iio_triggered_buffer_cleanup(indio_dev); +} + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c new file mode 100644 index 0000000..9c343b4 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_core.c @@ -0,0 +1,272 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/buffer.h> +#include <asm/unaligned.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +#define ST_PRESS_MBAR_TO_KPASCAL(x) (x * 10) +#define ST_PRESS_NUMBER_DATA_CHANNELS 1 + +/* DEFAULT VALUE FOR SENSORS */ +#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 +#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b + +/* FULLSCALE */ +#define ST_PRESS_FS_AVL_1260MB 1260 + +/* CUSTOM VALUES FOR SENSOR 1 */ +#define ST_PRESS_1_WAI_EXP 0xbb +#define ST_PRESS_1_ODR_ADDR 0x20 +#define ST_PRESS_1_ODR_MASK 0x70 +#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 +#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 +#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 +#define ST_PRESS_1_PW_ADDR 0x20 +#define ST_PRESS_1_PW_MASK 0x80 +#define ST_PRESS_1_FS_ADDR 0x23 +#define ST_PRESS_1_FS_MASK 0x30 +#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_MBAR_TO_KPASCAL(244141) +#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000 +#define ST_PRESS_1_BDU_ADDR 0x20 +#define ST_PRESS_1_BDU_MASK 0x04 +#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 +#define ST_PRESS_1_DRDY_IRQ_MASK 0x04 +#define ST_PRESS_1_MULTIREAD_BIT true +#define ST_PRESS_1_TEMP_OFFSET 42500 + +static const struct iio_chan_spec st_press_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, + ST_PRESS_DEFAULT_OUT_XL_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_TEMP, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, + ST_TEMP_DEFAULT_OUT_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + +static const struct st_sensors st_press_sensors[] = { + { + .wai = ST_PRESS_1_WAI_EXP, + .sensors_supported = { + [0] = LPS331AP_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_channels, + .odr = { + .addr = ST_PRESS_1_ODR_ADDR, + .mask = ST_PRESS_1_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_1_PW_ADDR, + .mask = ST_PRESS_1_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = ST_PRESS_1_FS_ADDR, + .mask = ST_PRESS_1_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .value = ST_PRESS_1_FS_AVL_1260_VAL, + .gain = ST_PRESS_1_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_PRESS_1_BDU_ADDR, + .mask = ST_PRESS_1_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_1_DRDY_IRQ_ADDR, + .mask = ST_PRESS_1_DRDY_IRQ_MASK, + }, + .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, + .bootime = 2, + }, +}; + +static int st_press_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, int *val, + int *val2, long mask) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = st_sensors_read_info_raw(indio_dev, ch, val); + if (err < 0) + goto read_error; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + + switch (ch->type) { + case IIO_PRESSURE: + *val2 = pdata->current_fullscale->gain; + break; + case IIO_TEMP: + *val2 = pdata->current_fullscale->gain2; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + switch (ch->type) { + case IIO_TEMP: + *val = 425; + *val2 = 10; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + +read_error: + return err; +} + +static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); +static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); + +static struct attribute *st_press_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_press_attribute_group = { + .attrs = st_press_attributes, +}; + +static const struct iio_info press_info = { + .driver_module = THIS_MODULE, + .attrs = &st_press_attribute_group, + .read_raw = &st_press_read_raw, +}; + +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_press_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, +}; +#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) +#else +#define ST_PRESS_TRIGGER_OPS NULL +#endif + +int st_press_common_probe(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &press_info; + + err = st_sensors_check_device_support(indio_dev, + ARRAY_SIZE(st_press_sensors), st_press_sensors); + if (err < 0) + goto st_press_common_probe_error; + + pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; + pdata->multiread_bit = pdata->sensor->multi_read_bit; + indio_dev->channels = pdata->sensor->ch; + indio_dev->num_channels = ARRAY_SIZE(st_press_channels); + + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) + &pdata->sensor->fs.fs_avl[0]; + pdata->odr = pdata->sensor->odr.odr_avl[0].hz; + + err = st_sensors_init_sensor(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + if (pdata->get_irq_data_ready(indio_dev) > 0) { + err = st_press_allocate_ring(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + err = st_sensors_allocate_trigger(indio_dev, + ST_PRESS_TRIGGER_OPS); + if (err < 0) + goto st_press_probe_trigger_error; + } + + err = iio_device_register(indio_dev); + if (err) + goto st_press_device_register_error; + + return err; + +st_press_device_register_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_sensors_deallocate_trigger(indio_dev); +st_press_probe_trigger_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_press_deallocate_ring(indio_dev); +st_press_common_probe_error: + return err; +} +EXPORT_SYMBOL(st_press_common_probe); + +void st_press_common_remove(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (pdata->get_irq_data_ready(indio_dev) > 0) { + st_sensors_deallocate_trigger(indio_dev); + st_press_deallocate_ring(indio_dev); + } + iio_device_free(indio_dev); +} +EXPORT_SYMBOL(st_press_common_remove); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c new file mode 100644 index 0000000..7cebcc7 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -0,0 +1,77 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_i2c.h> +#include "st_pressure.h" + +static int st_press_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &client->dev; + + st_sensors_i2c_configure(indio_dev, client, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_i2c_remove(struct i2c_client *client) +{ + st_press_common_remove(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, st_press_id_table); + +static struct i2c_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-i2c", + }, + .probe = st_press_i2c_probe, + .remove = st_press_i2c_remove, + .id_table = st_press_id_table, +}; +module_i2c_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c new file mode 100644 index 0000000..17a1490 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -0,0 +1,76 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_spi.h> +#include "st_pressure.h" + +static int st_press_spi_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &spi->dev; + + st_sensors_spi_configure(indio_dev, spi, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_spi_remove(struct spi_device *spi) +{ + st_press_common_remove(spi_get_drvdata(spi)); + + return 0; +} + +static const struct spi_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, st_press_id_table); + +static struct spi_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-spi", + }, + .probe = st_press_spi_probe, + .remove = st_press_spi_remove, + .id_table = st_press_id_table, +}; +module_spi_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); +MODULE_LICENSE("GPL v2"); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-06-03 14:58 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA @ 2013-06-04 18:03 ` Jonathan Cameron 0 siblings, 0 replies; 15+ messages in thread From: Jonathan Cameron @ 2013-06-04 18:03 UTC (permalink / raw) To: Denis CIOCCA; +Cc: linux-iio, frederic.pillon, lee.jones On 06/03/2013 03:58 PM, Denis CIOCCA wrote: > This patch adds a generic pressure driver for STMicroelectronics > pressure sensors, currently it supports: LPS331AP. > > Signed-off-by: Denis Ciocca <denis.ciocca@st.com> Applied to the togreg branch of iio.git. Thanks, > --- > drivers/iio/Kconfig | 1 + > drivers/iio/Makefile | 1 + > drivers/iio/pressure/Kconfig | 35 ++++ > drivers/iio/pressure/Makefile | 10 ++ > drivers/iio/pressure/st_pressure.h | 39 +++++ > drivers/iio/pressure/st_pressure_buffer.c | 105 +++++++++++ > drivers/iio/pressure/st_pressure_core.c | 272 +++++++++++++++++++++++++++++ > drivers/iio/pressure/st_pressure_i2c.c | 77 ++++++++ > drivers/iio/pressure/st_pressure_spi.c | 76 ++++++++ > 9 files changed, 616 insertions(+) > create mode 100644 drivers/iio/pressure/Kconfig > create mode 100644 drivers/iio/pressure/Makefile > create mode 100644 drivers/iio/pressure/st_pressure.h > create mode 100644 drivers/iio/pressure/st_pressure_buffer.c > create mode 100644 drivers/iio/pressure/st_pressure_core.c > create mode 100644 drivers/iio/pressure/st_pressure_i2c.c > create mode 100644 drivers/iio/pressure/st_pressure_spi.c > > diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig > index daa3ddd..9af763a 100644 > --- a/drivers/iio/Kconfig > +++ b/drivers/iio/Kconfig > @@ -73,5 +73,6 @@ source "drivers/iio/magnetometer/Kconfig" > if IIO_TRIGGER > source "drivers/iio/trigger/Kconfig" > endif #IIO_TRIGGER > +source "drivers/iio/pressure/Kconfig" > > endif # IIO > diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile > index a349a96..7a3866c 100644 > --- a/drivers/iio/Makefile > +++ b/drivers/iio/Makefile > @@ -22,3 +22,4 @@ obj-y += imu/ > obj-y += light/ > obj-y += magnetometer/ > obj-y += trigger/ > +obj-y += pressure/ > diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig > new file mode 100644 > index 0000000..9427f01 > --- /dev/null > +++ b/drivers/iio/pressure/Kconfig > @@ -0,0 +1,35 @@ > +# > +# Pressure drivers > +# > +menu "Pressure Sensors" > + > +config IIO_ST_PRESS > + tristate "STMicroelectronics pressures Driver" > + depends on (I2C || SPI_MASTER) && SYSFS > + select IIO_ST_SENSORS_CORE > + select IIO_ST_PRESS_I2C if (I2C) > + select IIO_ST_PRESS_SPI if (SPI_MASTER) > + select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) > + help > + Say yes here to build support for STMicroelectronics pressures: > + LPS331AP. > + > + This driver can also be built as a module. If so, will be created > + these modules: > + - st_pressure (core functions for the driver [it is mandatory]); > + - st_pressure_i2c (necessary for the I2C devices [optional*]); > + - st_pressure_spi (necessary for the SPI devices [optional*]); > + > + (*) one of these is necessary to do something. > + > +config IIO_ST_PRESS_I2C > + tristate > + depends on IIO_ST_PRESS > + depends on IIO_ST_SENSORS_I2C > + > +config IIO_ST_PRESS_SPI > + tristate > + depends on IIO_ST_PRESS > + depends on IIO_ST_SENSORS_SPI > + > +endmenu > diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile > new file mode 100644 > index 0000000..d4bb33e > --- /dev/null > +++ b/drivers/iio/pressure/Makefile > @@ -0,0 +1,10 @@ > +# > +# Makefile for industrial I/O pressure drivers > +# > + > +obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o > +st_pressure-y := st_pressure_core.o > +st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o > + > +obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o > +obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o > diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h > new file mode 100644 > index 0000000..414e45a > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure.h > @@ -0,0 +1,39 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * v. 1.0.0 > + * Licensed under the GPL-2. > + */ > + > +#ifndef ST_PRESS_H > +#define ST_PRESS_H > + > +#include <linux/types.h> > +#include <linux/iio/common/st_sensors.h> > + > +#define LPS331AP_PRESS_DEV_NAME "lps331ap" > + > +int st_press_common_probe(struct iio_dev *indio_dev); > +void st_press_common_remove(struct iio_dev *indio_dev); > + > +#ifdef CONFIG_IIO_BUFFER > +int st_press_allocate_ring(struct iio_dev *indio_dev); > +void st_press_deallocate_ring(struct iio_dev *indio_dev); > +int st_press_trig_set_state(struct iio_trigger *trig, bool state); > +#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) > +#else /* CONFIG_IIO_BUFFER */ > +static inline int st_press_allocate_ring(struct iio_dev *indio_dev) > +{ > + return 0; > +} > + > +static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) > +{ > +} > +#define ST_PRESS_TRIGGER_SET_STATE NULL > +#endif /* CONFIG_IIO_BUFFER */ > + > +#endif /* ST_PRESS_H */ > diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c > new file mode 100644 > index 0000000..f877ef8 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_buffer.c > @@ -0,0 +1,105 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/stat.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <linux/delay.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/buffer.h> > +#include <linux/iio/trigger_consumer.h> > +#include <linux/iio/triggered_buffer.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include "st_pressure.h" > + > +int st_press_trig_set_state(struct iio_trigger *trig, bool state) > +{ > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > + > + return st_sensors_set_dataready_irq(indio_dev, state); > +} > + > +static int st_press_buffer_preenable(struct iio_dev *indio_dev) > +{ > + int err; > + > + err = st_sensors_set_enable(indio_dev, true); > + if (err < 0) > + goto st_press_set_enable_error; > + > + err = iio_sw_buffer_preenable(indio_dev); > + > +st_press_set_enable_error: > + return err; > +} > + > +static int st_press_buffer_postenable(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); > + if (pdata->buffer_data == NULL) { > + err = -ENOMEM; > + goto allocate_memory_error; > + } > + > + err = iio_triggered_buffer_postenable(indio_dev); > + if (err < 0) > + goto st_press_buffer_postenable_error; > + > + return err; > + > +st_press_buffer_postenable_error: > + kfree(pdata->buffer_data); > +allocate_memory_error: > + return err; > +} > + > +static int st_press_buffer_predisable(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + err = iio_triggered_buffer_predisable(indio_dev); > + if (err < 0) > + goto st_press_buffer_predisable_error; > + > + err = st_sensors_set_enable(indio_dev, false); > + > +st_press_buffer_predisable_error: > + kfree(pdata->buffer_data); > + return err; > +} > + > +static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { > + .preenable = &st_press_buffer_preenable, > + .postenable = &st_press_buffer_postenable, > + .predisable = &st_press_buffer_predisable, > +}; > + > +int st_press_allocate_ring(struct iio_dev *indio_dev) > +{ > + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, > + &st_sensors_trigger_handler, &st_press_buffer_setup_ops); > +} > + > +void st_press_deallocate_ring(struct iio_dev *indio_dev) > +{ > + iio_triggered_buffer_cleanup(indio_dev); > +} > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c > new file mode 100644 > index 0000000..9c343b4 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_core.c > @@ -0,0 +1,272 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/errno.h> > +#include <linux/types.h> > +#include <linux/mutex.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <linux/gpio.h> > +#include <linux/irq.h> > +#include <linux/delay.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/sysfs.h> > +#include <linux/iio/trigger.h> > +#include <linux/iio/buffer.h> > +#include <asm/unaligned.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include "st_pressure.h" > + > +#define ST_PRESS_MBAR_TO_KPASCAL(x) (x * 10) > +#define ST_PRESS_NUMBER_DATA_CHANNELS 1 > + > +/* DEFAULT VALUE FOR SENSORS */ > +#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 > +#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b > + > +/* FULLSCALE */ > +#define ST_PRESS_FS_AVL_1260MB 1260 > + > +/* CUSTOM VALUES FOR SENSOR 1 */ > +#define ST_PRESS_1_WAI_EXP 0xbb > +#define ST_PRESS_1_ODR_ADDR 0x20 > +#define ST_PRESS_1_ODR_MASK 0x70 > +#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 > +#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 > +#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 > +#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 > +#define ST_PRESS_1_PW_ADDR 0x20 > +#define ST_PRESS_1_PW_MASK 0x80 > +#define ST_PRESS_1_FS_ADDR 0x23 > +#define ST_PRESS_1_FS_MASK 0x30 > +#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 > +#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_MBAR_TO_KPASCAL(244141) > +#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000 > +#define ST_PRESS_1_BDU_ADDR 0x20 > +#define ST_PRESS_1_BDU_MASK 0x04 > +#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 > +#define ST_PRESS_1_DRDY_IRQ_MASK 0x04 > +#define ST_PRESS_1_MULTIREAD_BIT true > +#define ST_PRESS_1_TEMP_OFFSET 42500 > + > +static const struct iio_chan_spec st_press_channels[] = { > + ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, > + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), > + ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, > + ST_PRESS_DEFAULT_OUT_XL_ADDR), > + ST_SENSORS_LSM_CHANNELS(IIO_TEMP, > + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | > + BIT(IIO_CHAN_INFO_OFFSET), > + -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, > + ST_TEMP_DEFAULT_OUT_L_ADDR), > + IIO_CHAN_SOFT_TIMESTAMP(1) > +}; > + > +static const struct st_sensors st_press_sensors[] = { > + { > + .wai = ST_PRESS_1_WAI_EXP, > + .sensors_supported = { > + [0] = LPS331AP_PRESS_DEV_NAME, > + }, > + .ch = (struct iio_chan_spec *)st_press_channels, > + .odr = { > + .addr = ST_PRESS_1_ODR_ADDR, > + .mask = ST_PRESS_1_ODR_MASK, > + .odr_avl = { > + { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, > + { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, > + { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, > + { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, > + }, > + }, > + .pw = { > + .addr = ST_PRESS_1_PW_ADDR, > + .mask = ST_PRESS_1_PW_MASK, > + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, > + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, > + }, > + .fs = { > + .addr = ST_PRESS_1_FS_ADDR, > + .mask = ST_PRESS_1_FS_MASK, > + .fs_avl = { > + [0] = { > + .num = ST_PRESS_FS_AVL_1260MB, > + .value = ST_PRESS_1_FS_AVL_1260_VAL, > + .gain = ST_PRESS_1_FS_AVL_1260_GAIN, > + .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, > + }, > + }, > + }, > + .bdu = { > + .addr = ST_PRESS_1_BDU_ADDR, > + .mask = ST_PRESS_1_BDU_MASK, > + }, > + .drdy_irq = { > + .addr = ST_PRESS_1_DRDY_IRQ_ADDR, > + .mask = ST_PRESS_1_DRDY_IRQ_MASK, > + }, > + .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, > + .bootime = 2, > + }, > +}; > + > +static int st_press_read_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *ch, int *val, > + int *val2, long mask) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + switch (mask) { > + case IIO_CHAN_INFO_RAW: > + err = st_sensors_read_info_raw(indio_dev, ch, val); > + if (err < 0) > + goto read_error; > + > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_SCALE: > + *val = 0; > + > + switch (ch->type) { > + case IIO_PRESSURE: > + *val2 = pdata->current_fullscale->gain; > + break; > + case IIO_TEMP: > + *val2 = pdata->current_fullscale->gain2; > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > + return IIO_VAL_INT_PLUS_NANO; > + case IIO_CHAN_INFO_OFFSET: > + switch (ch->type) { > + case IIO_TEMP: > + *val = 425; > + *val2 = 10; > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > + return IIO_VAL_FRACTIONAL; > + default: > + return -EINVAL; > + } > + > +read_error: > + return err; > +} > + > +static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); > +static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); > + > +static struct attribute *st_press_attributes[] = { > + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, > + &iio_dev_attr_sampling_frequency.dev_attr.attr, > + NULL, > +}; > + > +static const struct attribute_group st_press_attribute_group = { > + .attrs = st_press_attributes, > +}; > + > +static const struct iio_info press_info = { > + .driver_module = THIS_MODULE, > + .attrs = &st_press_attribute_group, > + .read_raw = &st_press_read_raw, > +}; > + > +#ifdef CONFIG_IIO_TRIGGER > +static const struct iio_trigger_ops st_press_trigger_ops = { > + .owner = THIS_MODULE, > + .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, > +}; > +#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) > +#else > +#define ST_PRESS_TRIGGER_OPS NULL > +#endif > + > +int st_press_common_probe(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->info = &press_info; > + > + err = st_sensors_check_device_support(indio_dev, > + ARRAY_SIZE(st_press_sensors), st_press_sensors); > + if (err < 0) > + goto st_press_common_probe_error; > + > + pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; > + pdata->multiread_bit = pdata->sensor->multi_read_bit; > + indio_dev->channels = pdata->sensor->ch; > + indio_dev->num_channels = ARRAY_SIZE(st_press_channels); > + > + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) > + &pdata->sensor->fs.fs_avl[0]; > + pdata->odr = pdata->sensor->odr.odr_avl[0].hz; > + > + err = st_sensors_init_sensor(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + if (pdata->get_irq_data_ready(indio_dev) > 0) { > + err = st_press_allocate_ring(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + err = st_sensors_allocate_trigger(indio_dev, > + ST_PRESS_TRIGGER_OPS); > + if (err < 0) > + goto st_press_probe_trigger_error; > + } > + > + err = iio_device_register(indio_dev); > + if (err) > + goto st_press_device_register_error; > + > + return err; > + > +st_press_device_register_error: > + if (pdata->get_irq_data_ready(indio_dev) > 0) > + st_sensors_deallocate_trigger(indio_dev); > +st_press_probe_trigger_error: > + if (pdata->get_irq_data_ready(indio_dev) > 0) > + st_press_deallocate_ring(indio_dev); > +st_press_common_probe_error: > + return err; > +} > +EXPORT_SYMBOL(st_press_common_probe); > + > +void st_press_common_remove(struct iio_dev *indio_dev) > +{ > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + iio_device_unregister(indio_dev); > + if (pdata->get_irq_data_ready(indio_dev) > 0) { > + st_sensors_deallocate_trigger(indio_dev); > + st_press_deallocate_ring(indio_dev); > + } > + iio_device_free(indio_dev); > +} > +EXPORT_SYMBOL(st_press_common_remove); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c > new file mode 100644 > index 0000000..7cebcc7 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_i2c.c > @@ -0,0 +1,77 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/i2c.h> > +#include <linux/iio/iio.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include <linux/iio/common/st_sensors_i2c.h> > +#include "st_pressure.h" > + > +static int st_press_i2c_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct iio_dev *indio_dev; > + struct st_sensor_data *pdata; > + int err; > + > + indio_dev = iio_device_alloc(sizeof(*pdata)); > + if (indio_dev == NULL) { > + err = -ENOMEM; > + goto iio_device_alloc_error; > + } > + > + pdata = iio_priv(indio_dev); > + pdata->dev = &client->dev; > + > + st_sensors_i2c_configure(indio_dev, client, pdata); > + > + err = st_press_common_probe(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + return 0; > + > +st_press_common_probe_error: > + iio_device_free(indio_dev); > +iio_device_alloc_error: > + return err; > +} > + > +static int st_press_i2c_remove(struct i2c_client *client) > +{ > + st_press_common_remove(i2c_get_clientdata(client)); > + > + return 0; > +} > + > +static const struct i2c_device_id st_press_id_table[] = { > + { LPS331AP_PRESS_DEV_NAME }, > + {}, > +}; > +MODULE_DEVICE_TABLE(i2c, st_press_id_table); > + > +static struct i2c_driver st_press_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "st-press-i2c", > + }, > + .probe = st_press_i2c_probe, > + .remove = st_press_i2c_remove, > + .id_table = st_press_id_table, > +}; > +module_i2c_driver(st_press_driver); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c > new file mode 100644 > index 0000000..17a1490 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_spi.c > @@ -0,0 +1,76 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/spi/spi.h> > +#include <linux/iio/iio.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include <linux/iio/common/st_sensors_spi.h> > +#include "st_pressure.h" > + > +static int st_press_spi_probe(struct spi_device *spi) > +{ > + struct iio_dev *indio_dev; > + struct st_sensor_data *pdata; > + int err; > + > + indio_dev = iio_device_alloc(sizeof(*pdata)); > + if (indio_dev == NULL) { > + err = -ENOMEM; > + goto iio_device_alloc_error; > + } > + > + pdata = iio_priv(indio_dev); > + pdata->dev = &spi->dev; > + > + st_sensors_spi_configure(indio_dev, spi, pdata); > + > + err = st_press_common_probe(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + return 0; > + > +st_press_common_probe_error: > + iio_device_free(indio_dev); > +iio_device_alloc_error: > + return err; > +} > + > +static int st_press_spi_remove(struct spi_device *spi) > +{ > + st_press_common_remove(spi_get_drvdata(spi)); > + > + return 0; > +} > + > +static const struct spi_device_id st_press_id_table[] = { > + { LPS331AP_PRESS_DEV_NAME }, > + {}, > +}; > +MODULE_DEVICE_TABLE(spi, st_press_id_table); > + > +static struct spi_driver st_press_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "st-press-spi", > + }, > + .probe = st_press_spi_probe, > + .remove = st_press_spi_remove, > + .id_table = st_press_id_table, > +}; > +module_spi_driver(st_press_driver); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); > +MODULE_LICENSE("GPL v2"); > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Support pressure sensors @ 2013-05-24 14:25 Denis CIOCCA 2013-05-24 14:25 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 0 siblings, 1 reply; 15+ messages in thread From: Denis CIOCCA @ 2013-05-24 14:25 UTC (permalink / raw) To: jic23; +Cc: lars, linux-iio, j.anaszewski, lee.jones Hi Jonathan, all, I have modified the previous series of patch to support the pressure sensors. The major modifications are: - removed stuff macros; - added support on st-sensor-library for 3 channel data; - removed one-shot reading function on pressure driver (integrated on st-sensor-library); - removed specific function for buffer in pressure driver (integrated on st-sensor-library), as Jonathan suggest me; Thanks, Denis ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-24 14:25 Support pressure sensors Denis CIOCCA @ 2013-05-24 14:25 ` Denis CIOCCA 0 siblings, 0 replies; 15+ messages in thread From: Denis CIOCCA @ 2013-05-24 14:25 UTC (permalink / raw) To: jic23; +Cc: lars, linux-iio, j.anaszewski, lee.jones, Denis Ciocca This patch adds a generic pressure driver for STMicroelectronics pressure sensors, currently it supports: LPS331AP. Signed-off-by: Denis Ciocca <denis.ciocca@st.com> --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/pressure/Kconfig | 35 ++++ drivers/iio/pressure/Makefile | 10 ++ drivers/iio/pressure/st_pressure.h | 39 +++++ drivers/iio/pressure/st_pressure_buffer.c | 105 +++++++++++ drivers/iio/pressure/st_pressure_core.c | 272 +++++++++++++++++++++++++++++ drivers/iio/pressure/st_pressure_i2c.c | 77 ++++++++ drivers/iio/pressure/st_pressure_spi.c | 76 ++++++++ 9 files changed, 616 insertions(+) create mode 100644 drivers/iio/pressure/Kconfig create mode 100644 drivers/iio/pressure/Makefile create mode 100644 drivers/iio/pressure/st_pressure.h create mode 100644 drivers/iio/pressure/st_pressure_buffer.c create mode 100644 drivers/iio/pressure/st_pressure_core.c create mode 100644 drivers/iio/pressure/st_pressure_i2c.c create mode 100644 drivers/iio/pressure/st_pressure_spi.c diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index daa3ddd..9af763a 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -73,5 +73,6 @@ source "drivers/iio/magnetometer/Kconfig" if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER +source "drivers/iio/pressure/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index a349a96..7a3866c 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -22,3 +22,4 @@ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += trigger/ +obj-y += pressure/ diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig new file mode 100644 index 0000000..9427f01 --- /dev/null +++ b/drivers/iio/pressure/Kconfig @@ -0,0 +1,35 @@ +# +# Pressure drivers +# +menu "Pressure Sensors" + +config IIO_ST_PRESS + tristate "STMicroelectronics pressures Driver" + depends on (I2C || SPI_MASTER) && SYSFS + select IIO_ST_SENSORS_CORE + select IIO_ST_PRESS_I2C if (I2C) + select IIO_ST_PRESS_SPI if (SPI_MASTER) + select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) + help + Say yes here to build support for STMicroelectronics pressures: + LPS331AP. + + This driver can also be built as a module. If so, will be created + these modules: + - st_pressure (core functions for the driver [it is mandatory]); + - st_pressure_i2c (necessary for the I2C devices [optional*]); + - st_pressure_spi (necessary for the SPI devices [optional*]); + + (*) one of these is necessary to do something. + +config IIO_ST_PRESS_I2C + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_I2C + +config IIO_ST_PRESS_SPI + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_SPI + +endmenu diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile new file mode 100644 index 0000000..d4bb33e --- /dev/null +++ b/drivers/iio/pressure/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for industrial I/O pressure drivers +# + +obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o +st_pressure-y := st_pressure_core.o +st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o + +obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o +obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h new file mode 100644 index 0000000..414e45a --- /dev/null +++ b/drivers/iio/pressure/st_pressure.h @@ -0,0 +1,39 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * v. 1.0.0 + * Licensed under the GPL-2. + */ + +#ifndef ST_PRESS_H +#define ST_PRESS_H + +#include <linux/types.h> +#include <linux/iio/common/st_sensors.h> + +#define LPS331AP_PRESS_DEV_NAME "lps331ap" + +int st_press_common_probe(struct iio_dev *indio_dev); +void st_press_common_remove(struct iio_dev *indio_dev); + +#ifdef CONFIG_IIO_BUFFER +int st_press_allocate_ring(struct iio_dev *indio_dev); +void st_press_deallocate_ring(struct iio_dev *indio_dev); +int st_press_trig_set_state(struct iio_trigger *trig, bool state); +#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) +#else /* CONFIG_IIO_BUFFER */ +static inline int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ +} +#define ST_PRESS_TRIGGER_SET_STATE NULL +#endif /* CONFIG_IIO_BUFFER */ + +#endif /* ST_PRESS_H */ diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c new file mode 100644 index 0000000..f877ef8 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -0,0 +1,105 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +int st_press_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + +static int st_press_buffer_preenable(struct iio_dev *indio_dev) +{ + int err; + + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_press_set_enable_error; + + err = iio_sw_buffer_preenable(indio_dev); + +st_press_set_enable_error: + return err; +} + +static int st_press_buffer_postenable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (pdata->buffer_data == NULL) { + err = -ENOMEM; + goto allocate_memory_error; + } + + err = iio_triggered_buffer_postenable(indio_dev); + if (err < 0) + goto st_press_buffer_postenable_error; + + return err; + +st_press_buffer_postenable_error: + kfree(pdata->buffer_data); +allocate_memory_error: + return err; +} + +static int st_press_buffer_predisable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + err = iio_triggered_buffer_predisable(indio_dev); + if (err < 0) + goto st_press_buffer_predisable_error; + + err = st_sensors_set_enable(indio_dev, false); + +st_press_buffer_predisable_error: + kfree(pdata->buffer_data); + return err; +} + +static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { + .preenable = &st_press_buffer_preenable, + .postenable = &st_press_buffer_postenable, + .predisable = &st_press_buffer_predisable, +}; + +int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &st_sensors_trigger_handler, &st_press_buffer_setup_ops); +} + +void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ + iio_triggered_buffer_cleanup(indio_dev); +} + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c new file mode 100644 index 0000000..9c343b4 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_core.c @@ -0,0 +1,272 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/buffer.h> +#include <asm/unaligned.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +#define ST_PRESS_MBAR_TO_KPASCAL(x) (x * 10) +#define ST_PRESS_NUMBER_DATA_CHANNELS 1 + +/* DEFAULT VALUE FOR SENSORS */ +#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 +#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b + +/* FULLSCALE */ +#define ST_PRESS_FS_AVL_1260MB 1260 + +/* CUSTOM VALUES FOR SENSOR 1 */ +#define ST_PRESS_1_WAI_EXP 0xbb +#define ST_PRESS_1_ODR_ADDR 0x20 +#define ST_PRESS_1_ODR_MASK 0x70 +#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 +#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 +#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 +#define ST_PRESS_1_PW_ADDR 0x20 +#define ST_PRESS_1_PW_MASK 0x80 +#define ST_PRESS_1_FS_ADDR 0x23 +#define ST_PRESS_1_FS_MASK 0x30 +#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_MBAR_TO_KPASCAL(244141) +#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000 +#define ST_PRESS_1_BDU_ADDR 0x20 +#define ST_PRESS_1_BDU_MASK 0x04 +#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 +#define ST_PRESS_1_DRDY_IRQ_MASK 0x04 +#define ST_PRESS_1_MULTIREAD_BIT true +#define ST_PRESS_1_TEMP_OFFSET 42500 + +static const struct iio_chan_spec st_press_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, + ST_PRESS_DEFAULT_OUT_XL_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_TEMP, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, + ST_TEMP_DEFAULT_OUT_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + +static const struct st_sensors st_press_sensors[] = { + { + .wai = ST_PRESS_1_WAI_EXP, + .sensors_supported = { + [0] = LPS331AP_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_channels, + .odr = { + .addr = ST_PRESS_1_ODR_ADDR, + .mask = ST_PRESS_1_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_1_PW_ADDR, + .mask = ST_PRESS_1_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = ST_PRESS_1_FS_ADDR, + .mask = ST_PRESS_1_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .value = ST_PRESS_1_FS_AVL_1260_VAL, + .gain = ST_PRESS_1_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_PRESS_1_BDU_ADDR, + .mask = ST_PRESS_1_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_1_DRDY_IRQ_ADDR, + .mask = ST_PRESS_1_DRDY_IRQ_MASK, + }, + .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, + .bootime = 2, + }, +}; + +static int st_press_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, int *val, + int *val2, long mask) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = st_sensors_read_info_raw(indio_dev, ch, val); + if (err < 0) + goto read_error; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + + switch (ch->type) { + case IIO_PRESSURE: + *val2 = pdata->current_fullscale->gain; + break; + case IIO_TEMP: + *val2 = pdata->current_fullscale->gain2; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + switch (ch->type) { + case IIO_TEMP: + *val = 425; + *val2 = 10; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + +read_error: + return err; +} + +static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); +static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); + +static struct attribute *st_press_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_press_attribute_group = { + .attrs = st_press_attributes, +}; + +static const struct iio_info press_info = { + .driver_module = THIS_MODULE, + .attrs = &st_press_attribute_group, + .read_raw = &st_press_read_raw, +}; + +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_press_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, +}; +#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) +#else +#define ST_PRESS_TRIGGER_OPS NULL +#endif + +int st_press_common_probe(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &press_info; + + err = st_sensors_check_device_support(indio_dev, + ARRAY_SIZE(st_press_sensors), st_press_sensors); + if (err < 0) + goto st_press_common_probe_error; + + pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; + pdata->multiread_bit = pdata->sensor->multi_read_bit; + indio_dev->channels = pdata->sensor->ch; + indio_dev->num_channels = ARRAY_SIZE(st_press_channels); + + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) + &pdata->sensor->fs.fs_avl[0]; + pdata->odr = pdata->sensor->odr.odr_avl[0].hz; + + err = st_sensors_init_sensor(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + if (pdata->get_irq_data_ready(indio_dev) > 0) { + err = st_press_allocate_ring(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + err = st_sensors_allocate_trigger(indio_dev, + ST_PRESS_TRIGGER_OPS); + if (err < 0) + goto st_press_probe_trigger_error; + } + + err = iio_device_register(indio_dev); + if (err) + goto st_press_device_register_error; + + return err; + +st_press_device_register_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_sensors_deallocate_trigger(indio_dev); +st_press_probe_trigger_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_press_deallocate_ring(indio_dev); +st_press_common_probe_error: + return err; +} +EXPORT_SYMBOL(st_press_common_probe); + +void st_press_common_remove(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (pdata->get_irq_data_ready(indio_dev) > 0) { + st_sensors_deallocate_trigger(indio_dev); + st_press_deallocate_ring(indio_dev); + } + iio_device_free(indio_dev); +} +EXPORT_SYMBOL(st_press_common_remove); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c new file mode 100644 index 0000000..7cebcc7 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -0,0 +1,77 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_i2c.h> +#include "st_pressure.h" + +static int st_press_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &client->dev; + + st_sensors_i2c_configure(indio_dev, client, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_i2c_remove(struct i2c_client *client) +{ + st_press_common_remove(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, st_press_id_table); + +static struct i2c_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-i2c", + }, + .probe = st_press_i2c_probe, + .remove = st_press_i2c_remove, + .id_table = st_press_id_table, +}; +module_i2c_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c new file mode 100644 index 0000000..17a1490 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -0,0 +1,76 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_spi.h> +#include "st_pressure.h" + +static int st_press_spi_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &spi->dev; + + st_sensors_spi_configure(indio_dev, spi, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_spi_remove(struct spi_device *spi) +{ + st_press_common_remove(spi_get_drvdata(spi)); + + return 0; +} + +static const struct spi_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, st_press_id_table); + +static struct spi_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-spi", + }, + .probe = st_press_spi_probe, + .remove = st_press_spi_remove, + .id_table = st_press_id_table, +}; +module_spi_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); +MODULE_LICENSE("GPL v2"); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* STMicroelectronics pressure sensors driver @ 2013-05-15 8:44 Denis CIOCCA 2013-05-15 8:44 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 0 siblings, 1 reply; 15+ messages in thread From: Denis CIOCCA @ 2013-05-15 8:44 UTC (permalink / raw) To: jic23, linux-iio, lars, j.anaszewski Hi all, As Lars said me, I have updated the users of the macro in the same patch. Thanks Denis ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-15 8:44 STMicroelectronics pressure sensors driver Denis CIOCCA @ 2013-05-15 8:44 ` Denis CIOCCA 2013-05-17 15:00 ` Jacek Anaszewski 2013-05-18 21:06 ` Jonathan Cameron 0 siblings, 2 replies; 15+ messages in thread From: Denis CIOCCA @ 2013-05-15 8:44 UTC (permalink / raw) To: jic23, linux-iio, lars, j.anaszewski; +Cc: Denis Ciocca This patch adds a generic pressure driver for STMicroelectronics pressures, currently it supports: LPS331AP. Signed-off-by: Denis Ciocca <denis.ciocca@st.com> --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/pressure/Kconfig | 35 +++ drivers/iio/pressure/Makefile | 10 + drivers/iio/pressure/st_pressure.h | 47 ++++ drivers/iio/pressure/st_pressure_buffer.c | 115 ++++++++++ drivers/iio/pressure/st_pressure_core.c | 349 +++++++++++++++++++++++++++++ drivers/iio/pressure/st_pressure_i2c.c | 77 +++++++ drivers/iio/pressure/st_pressure_spi.c | 76 +++++++ 9 files changed, 711 insertions(+) create mode 100644 drivers/iio/pressure/Kconfig create mode 100644 drivers/iio/pressure/Makefile create mode 100644 drivers/iio/pressure/st_pressure.h create mode 100644 drivers/iio/pressure/st_pressure_buffer.c create mode 100644 drivers/iio/pressure/st_pressure_core.c create mode 100644 drivers/iio/pressure/st_pressure_i2c.c create mode 100644 drivers/iio/pressure/st_pressure_spi.c diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index b2f963b..b45b070 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -70,5 +70,6 @@ source "drivers/iio/gyro/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" +source "drivers/iio/pressure/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index a0e8cdd..5ee89f3 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -21,3 +21,4 @@ obj-y += frequency/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += pressure/ diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig new file mode 100644 index 0000000..9427f01 --- /dev/null +++ b/drivers/iio/pressure/Kconfig @@ -0,0 +1,35 @@ +# +# Pressure drivers +# +menu "Pressure Sensors" + +config IIO_ST_PRESS + tristate "STMicroelectronics pressures Driver" + depends on (I2C || SPI_MASTER) && SYSFS + select IIO_ST_SENSORS_CORE + select IIO_ST_PRESS_I2C if (I2C) + select IIO_ST_PRESS_SPI if (SPI_MASTER) + select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) + help + Say yes here to build support for STMicroelectronics pressures: + LPS331AP. + + This driver can also be built as a module. If so, will be created + these modules: + - st_pressure (core functions for the driver [it is mandatory]); + - st_pressure_i2c (necessary for the I2C devices [optional*]); + - st_pressure_spi (necessary for the SPI devices [optional*]); + + (*) one of these is necessary to do something. + +config IIO_ST_PRESS_I2C + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_I2C + +config IIO_ST_PRESS_SPI + tristate + depends on IIO_ST_PRESS + depends on IIO_ST_SENSORS_SPI + +endmenu diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile new file mode 100644 index 0000000..d4bb33e --- /dev/null +++ b/drivers/iio/pressure/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for industrial I/O pressure drivers +# + +obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o +st_pressure-y := st_pressure_core.o +st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o + +obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o +obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h new file mode 100644 index 0000000..d817387 --- /dev/null +++ b/drivers/iio/pressure/st_pressure.h @@ -0,0 +1,47 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * v. 1.0.0 + * Licensed under the GPL-2. + */ + +#ifndef ST_PRESS_H +#define ST_PRESS_H + +#include <linux/types.h> +#include <linux/iio/common/st_sensors.h> + +#define LPS331AP_PRESS_DEV_NAME "lps331ap" + +#define ST_PRESS_BYTE_FOR_CHANNEL 3 +#define ST_TEMP_BYTE_FOR_CHANNEL 2 + +int st_press_common_probe(struct iio_dev *indio_dev); +void st_press_common_remove(struct iio_dev *indio_dev); + +#ifdef CONFIG_IIO_BUFFER +int st_press_allocate_ring(struct iio_dev *indio_dev); +void st_press_deallocate_ring(struct iio_dev *indio_dev); +int st_press_trig_set_state(struct iio_trigger *trig, bool state); +int st_press_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); +#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) +#else /* CONFIG_IIO_BUFFER */ +static inline int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return 0; +} +static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ +} +static int st_press_get_buffer_element(struct iio_dev *indio_dev, + u8 *buf) +{ + return 0; +} +#define ST_PRESS_TRIGGER_SET_STATE NULL +#endif /* CONFIG_IIO_BUFFER */ + +#endif /* ST_PRESS_H */ diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c new file mode 100644 index 0000000..db9753d --- /dev/null +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -0,0 +1,115 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +int st_press_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + return pdata->tf->read_multiple_byte(&pdata->tb, pdata->dev, + indio_dev->channels[ST_SENSORS_SCAN_X].address, + ST_PRESS_BYTE_FOR_CHANNEL, buf, pdata->multiread_bit); +} +EXPORT_SYMBOL(st_press_get_buffer_element); + +int st_press_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + +static int st_press_buffer_preenable(struct iio_dev *indio_dev) +{ + int err; + + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_press_set_enable_error; + + err = iio_sw_buffer_preenable(indio_dev); + +st_press_set_enable_error: + return err; +} + +static int st_press_buffer_postenable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (pdata->buffer_data == NULL) { + err = -ENOMEM; + goto allocate_memory_error; + } + + err = iio_triggered_buffer_postenable(indio_dev); + if (err < 0) + goto st_press_buffer_postenable_error; + + return err; + +st_press_buffer_postenable_error: + kfree(pdata->buffer_data); +allocate_memory_error: + return err; +} + +static int st_press_buffer_predisable(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + err = iio_triggered_buffer_predisable(indio_dev); + if (err < 0) + goto st_press_buffer_predisable_error; + + err = st_sensors_set_enable(indio_dev, false); + +st_press_buffer_predisable_error: + kfree(pdata->buffer_data); + return err; +} + +static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { + .preenable = &st_press_buffer_preenable, + .postenable = &st_press_buffer_postenable, + .predisable = &st_press_buffer_predisable, +}; + +int st_press_allocate_ring(struct iio_dev *indio_dev) +{ + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &st_sensors_trigger_handler, &st_press_buffer_setup_ops); +} + +void st_press_deallocate_ring(struct iio_dev *indio_dev) +{ + iio_triggered_buffer_cleanup(indio_dev); +} + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c new file mode 100644 index 0000000..ae5703f --- /dev/null +++ b/drivers/iio/pressure/st_pressure_core.c @@ -0,0 +1,349 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/buffer.h> +#include <asm/unaligned.h> + +#include <linux/iio/common/st_sensors.h> +#include "st_pressure.h" + +#define ST_PRESS_MBAR_TO_KPASCAL(x) (x * 10) +#define ST_PRESS_NUMBER_ALL_CHANNELS 3 + +/* DEFAULT VALUE FOR SENSORS */ +#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 +#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b + +/* FULLSCALE */ +#define ST_PRESS_FS_AVL_1260MB 1260 + +/* CUSTOM VALUES FOR SENSOR 1 */ +#define ST_PRESS_1_WAI_EXP 0xbb +#define ST_PRESS_1_ODR_ADDR 0x20 +#define ST_PRESS_1_ODR_MASK 0x70 +#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 +#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 +#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 +#define ST_PRESS_1_PW_ADDR 0x20 +#define ST_PRESS_1_PW_MASK 0x80 +#define ST_PRESS_1_FS_ADDR 0x23 +#define ST_PRESS_1_FS_MASK 0x30 +#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_MBAR_TO_KPASCAL(244141) +#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000 +#define ST_PRESS_1_BDU_ADDR 0x20 +#define ST_PRESS_1_BDU_MASK 0x04 +#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 +#define ST_PRESS_1_DRDY_IRQ_MASK 0x04 +#define ST_PRESS_1_MULTIREAD_BIT true +#define ST_PRESS_1_TEMP_OFFSET 42500 + +static const struct iio_chan_spec st_press_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, + ST_PRESS_DEFAULT_OUT_XL_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_TEMP, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, + ST_TEMP_DEFAULT_OUT_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + +static const struct st_sensors st_press_sensors[] = { + { + .wai = ST_PRESS_1_WAI_EXP, + .sensors_supported = { + [0] = LPS331AP_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_channels, + .odr = { + .addr = ST_PRESS_1_ODR_ADDR, + .mask = ST_PRESS_1_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_1_PW_ADDR, + .mask = ST_PRESS_1_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = ST_PRESS_1_FS_ADDR, + .mask = ST_PRESS_1_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .value = ST_PRESS_1_FS_AVL_1260_VAL, + .gain = ST_PRESS_1_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_PRESS_1_BDU_ADDR, + .mask = ST_PRESS_1_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_1_DRDY_IRQ_ADDR, + .mask = ST_PRESS_1_DRDY_IRQ_MASK, + }, + .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, + .bootime = 2, + }, +}; + +static int st_press_read_axis_data(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, int *data) +{ + int err, num_byte = 0; + u8 outdata[ST_PRESS_BYTE_FOR_CHANNEL]; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + switch (ch->type) { + case IIO_PRESSURE: + num_byte = ST_PRESS_BYTE_FOR_CHANNEL; + break; + case IIO_TEMP: + num_byte = ST_TEMP_BYTE_FOR_CHANNEL; + break; + default: + err = -EINVAL; + goto read_error; + } + + err = pdata->tf->read_multiple_byte(&pdata->tb, pdata->dev, + ch->address, num_byte, + outdata, pdata->multiread_bit); + if (err < 0) + goto read_error; + + switch (ch->type) { + case IIO_PRESSURE: + *data = (s32)get_unaligned_le32(outdata); + break; + case IIO_TEMP: + *data = (s16)get_unaligned_le16(outdata); + break; + default: + err = -EINVAL; + goto read_error; + } + +read_error: + return err; +} + +static int st_press_read_info_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, int *val) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + mutex_lock(&indio_dev->mlock); + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + err = -EBUSY; + goto read_error; + } else { + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto read_error; + + msleep((pdata->sensor->bootime * 1000) / pdata->odr); + err = st_press_read_axis_data(indio_dev, ch, val); + if (err < 0) + goto read_error; + + *val = *val >> ch->scan_type.shift; + + err = st_sensors_set_enable(indio_dev, false); + } + mutex_unlock(&indio_dev->mlock); + + return err; + +read_error: + mutex_unlock(&indio_dev->mlock); + return err; +} + +static int st_press_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *ch, int *val, + int *val2, long mask) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = st_press_read_info_raw(indio_dev, ch, val); + if (err < 0) + goto read_error; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + + switch (ch->type) { + case IIO_PRESSURE: + *val2 = pdata->current_fullscale->gain; + break; + case IIO_TEMP: + *val2 = pdata->current_fullscale->gain2; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = 0; + + switch (ch->type) { + case IIO_TEMP: + *val2 = 42500000; + break; + default: + err = -EINVAL; + goto read_error; + } + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + +read_error: + return err; +} + +static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); +static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); +static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_press_scale_available); + +static struct attribute *st_press_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_press_scale_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + NULL, +}; + +static const struct attribute_group st_press_attribute_group = { + .attrs = st_press_attributes, +}; + +static const struct iio_info press_info = { + .driver_module = THIS_MODULE, + .attrs = &st_press_attribute_group, + .read_raw = &st_press_read_raw, +}; + +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_press_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, +}; +#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) +#else +#define ST_PRESS_TRIGGER_OPS NULL +#endif + +int st_press_common_probe(struct iio_dev *indio_dev) +{ + int err; + struct st_sensor_data *pdata = iio_priv(indio_dev); + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &press_info; + + err = st_sensors_check_device_support(indio_dev, + ARRAY_SIZE(st_press_sensors), st_press_sensors); + if (err < 0) + goto st_press_common_probe_error; + + pdata->get_buffer_element = &st_press_get_buffer_element; + pdata->multiread_bit = pdata->sensor->multi_read_bit; + indio_dev->channels = pdata->sensor->ch; + indio_dev->num_channels = ST_PRESS_NUMBER_ALL_CHANNELS; + + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) + &pdata->sensor->fs.fs_avl[0]; + pdata->odr = pdata->sensor->odr.odr_avl[0].hz; + + err = st_sensors_init_sensor(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + if (pdata->get_irq_data_ready(indio_dev) > 0) { + err = st_press_allocate_ring(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + err = st_sensors_allocate_trigger(indio_dev, + ST_PRESS_TRIGGER_OPS); + if (err < 0) + goto st_press_probe_trigger_error; + } + + err = iio_device_register(indio_dev); + if (err) + goto st_press_device_register_error; + + return err; + +st_press_device_register_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_sensors_deallocate_trigger(indio_dev); +st_press_probe_trigger_error: + if (pdata->get_irq_data_ready(indio_dev) > 0) + st_press_deallocate_ring(indio_dev); +st_press_common_probe_error: + return err; +} +EXPORT_SYMBOL(st_press_common_probe); + +void st_press_common_remove(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (pdata->get_irq_data_ready(indio_dev) > 0) { + st_sensors_deallocate_trigger(indio_dev); + st_press_deallocate_ring(indio_dev); + } + iio_device_free(indio_dev); +} +EXPORT_SYMBOL(st_press_common_remove); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c new file mode 100644 index 0000000..7cebcc7 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -0,0 +1,77 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_i2c.h> +#include "st_pressure.h" + +static int st_press_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &client->dev; + + st_sensors_i2c_configure(indio_dev, client, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_i2c_remove(struct i2c_client *client) +{ + st_press_common_remove(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, st_press_id_table); + +static struct i2c_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-i2c", + }, + .probe = st_press_i2c_probe, + .remove = st_press_i2c_remove, + .id_table = st_press_id_table, +}; +module_i2c_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c new file mode 100644 index 0000000..17a1490 --- /dev/null +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -0,0 +1,76 @@ +/* + * STMicroelectronics pressures driver + * + * Copyright 2013 STMicroelectronics Inc. + * + * Denis Ciocca <denis.ciocca@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/common/st_sensors_spi.h> +#include "st_pressure.h" + +static int st_press_spi_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct st_sensor_data *pdata; + int err; + + indio_dev = iio_device_alloc(sizeof(*pdata)); + if (indio_dev == NULL) { + err = -ENOMEM; + goto iio_device_alloc_error; + } + + pdata = iio_priv(indio_dev); + pdata->dev = &spi->dev; + + st_sensors_spi_configure(indio_dev, spi, pdata); + + err = st_press_common_probe(indio_dev); + if (err < 0) + goto st_press_common_probe_error; + + return 0; + +st_press_common_probe_error: + iio_device_free(indio_dev); +iio_device_alloc_error: + return err; +} + +static int st_press_spi_remove(struct spi_device *spi) +{ + st_press_common_remove(spi_get_drvdata(spi)); + + return 0; +} + +static const struct spi_device_id st_press_id_table[] = { + { LPS331AP_PRESS_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, st_press_id_table); + +static struct spi_driver st_press_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "st-press-spi", + }, + .probe = st_press_spi_probe, + .remove = st_press_spi_remove, + .id_table = st_press_id_table, +}; +module_spi_driver(st_press_driver); + +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); +MODULE_LICENSE("GPL v2"); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-15 8:44 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA @ 2013-05-17 15:00 ` Jacek Anaszewski 2013-05-17 16:09 ` Denis CIOCCA 2013-05-18 21:06 ` Jonathan Cameron 1 sibling, 1 reply; 15+ messages in thread From: Jacek Anaszewski @ 2013-05-17 15:00 UTC (permalink / raw) To: linux-iio Cc: public-jic23-DgEjT+Ai2ygdnm+yROfE0A, public-linux-iio-u79uwXL29TY76Z2rM5mHXA, public-lars-Qo5EllUWu/uELgA04lAiVw On 05/15/2013 10:44 AM, Denis CIOCCA wrote: > This patch adds a generic pressure driver for STMicroelectronics > pressures, currently it supports: LPS331AP. > > Signed-off-by: Denis Ciocca<denis.ciocca@st.com> Hi Denis, I have tested your driver with Samsung Exynos4x12 PQ/M0 board and in general it works fine, except of one issue. Triggers can be used only when INT1 interrupt source is exploited. On the test board I am using there is INT2 interrupt source routed to the CPU, and I had to change ST_PRESS_1_DRDY_IRQ_MASK constant defined in the st_pressure_core.c file to 0x20, to instruct the device to to generate the 'data ready' interrupts on the INT2 pin. I think that information about used interrupt source should be passed through platform_data and/or of_tree. For the of_tree there is ready solution available in my patch for this barometer. Thanks, Jacek ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-17 15:00 ` Jacek Anaszewski @ 2013-05-17 16:09 ` Denis CIOCCA 0 siblings, 0 replies; 15+ messages in thread From: Denis CIOCCA @ 2013-05-17 16:09 UTC (permalink / raw) To: Jacek Anaszewski Cc: linux-iio@vger.kernel.org, public-jic23-DgEjT+Ai2ygdnm+yROfE0A@plane.gmane.org, public-linux-iio-u79uwXL29TY76Z2rM5mHXA@plane.gmane.org, public-lars-Qo5EllUWu/uELgA04lAiVw@plane.gmane.org Hi Jacek, > I have tested your driver with Samsung Exynos4x12 PQ/M0 board and in > general it works fine, except of one issue. ok good news. > Triggers can be used only when INT1 interrupt source is exploited. Yes you have right. Now all ST mems use INT1 as data-ready generator! > I think that information about used interrupt source should be passed > through platform_data and/or of_tree. For the of_tree there is ready > solution available in my patch for this barometer. I think the best solution is a new patch to fix this issue for all ST mems. I can do it in next days... Thanks, Denis ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-15 8:44 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2013-05-17 15:00 ` Jacek Anaszewski @ 2013-05-18 21:06 ` Jonathan Cameron 2013-05-20 7:51 ` Denis CIOCCA 1 sibling, 1 reply; 15+ messages in thread From: Jonathan Cameron @ 2013-05-18 21:06 UTC (permalink / raw) To: Denis CIOCCA; +Cc: linux-iio, lars, j.anaszewski On 05/15/2013 09:44 AM, Denis CIOCCA wrote: > This patch adds a generic pressure driver for STMicroelectronics > pressures, currently it supports: LPS331AP. > > Signed-off-by: Denis Ciocca <denis.ciocca@st.com> One utter nitpick inline (blank lines between the stub functions). Otherwise I'm happy with this up to the changes due to the previous patch. Now going forward I'd of course like to see everyone happy with the resulting driver. Denis do you have plans to implement the threshold events that were in the other driver proposal? Other than the request from Jacek to handle the other interrupt line choice I think that is all that is missing from here that was present there? (Of course you two will probably have a better idea of the differences) Jonathan > --- > drivers/iio/Kconfig | 1 + > drivers/iio/Makefile | 1 + > drivers/iio/pressure/Kconfig | 35 +++ > drivers/iio/pressure/Makefile | 10 + > drivers/iio/pressure/st_pressure.h | 47 ++++ > drivers/iio/pressure/st_pressure_buffer.c | 115 ++++++++++ > drivers/iio/pressure/st_pressure_core.c | 349 +++++++++++++++++++++++++++++ > drivers/iio/pressure/st_pressure_i2c.c | 77 +++++++ > drivers/iio/pressure/st_pressure_spi.c | 76 +++++++ > 9 files changed, 711 insertions(+) > create mode 100644 drivers/iio/pressure/Kconfig > create mode 100644 drivers/iio/pressure/Makefile > create mode 100644 drivers/iio/pressure/st_pressure.h > create mode 100644 drivers/iio/pressure/st_pressure_buffer.c > create mode 100644 drivers/iio/pressure/st_pressure_core.c > create mode 100644 drivers/iio/pressure/st_pressure_i2c.c > create mode 100644 drivers/iio/pressure/st_pressure_spi.c > > diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig > index b2f963b..b45b070 100644 > --- a/drivers/iio/Kconfig > +++ b/drivers/iio/Kconfig > @@ -70,5 +70,6 @@ source "drivers/iio/gyro/Kconfig" > source "drivers/iio/imu/Kconfig" > source "drivers/iio/light/Kconfig" > source "drivers/iio/magnetometer/Kconfig" > +source "drivers/iio/pressure/Kconfig" > > endif # IIO > diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile > index a0e8cdd..5ee89f3 100644 > --- a/drivers/iio/Makefile > +++ b/drivers/iio/Makefile > @@ -21,3 +21,4 @@ obj-y += frequency/ > obj-y += imu/ > obj-y += light/ > obj-y += magnetometer/ > +obj-y += pressure/ > diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig > new file mode 100644 > index 0000000..9427f01 > --- /dev/null > +++ b/drivers/iio/pressure/Kconfig > @@ -0,0 +1,35 @@ > +# > +# Pressure drivers > +# > +menu "Pressure Sensors" > + > +config IIO_ST_PRESS > + tristate "STMicroelectronics pressures Driver" > + depends on (I2C || SPI_MASTER) && SYSFS > + select IIO_ST_SENSORS_CORE > + select IIO_ST_PRESS_I2C if (I2C) > + select IIO_ST_PRESS_SPI if (SPI_MASTER) > + select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) > + help > + Say yes here to build support for STMicroelectronics pressures: > + LPS331AP. > + > + This driver can also be built as a module. If so, will be created > + these modules: > + - st_pressure (core functions for the driver [it is mandatory]); > + - st_pressure_i2c (necessary for the I2C devices [optional*]); > + - st_pressure_spi (necessary for the SPI devices [optional*]); > + > + (*) one of these is necessary to do something. > + > +config IIO_ST_PRESS_I2C > + tristate > + depends on IIO_ST_PRESS > + depends on IIO_ST_SENSORS_I2C > + > +config IIO_ST_PRESS_SPI > + tristate > + depends on IIO_ST_PRESS > + depends on IIO_ST_SENSORS_SPI > + > +endmenu > diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile > new file mode 100644 > index 0000000..d4bb33e > --- /dev/null > +++ b/drivers/iio/pressure/Makefile > @@ -0,0 +1,10 @@ > +# > +# Makefile for industrial I/O pressure drivers > +# > + > +obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o > +st_pressure-y := st_pressure_core.o > +st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o > + > +obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o > +obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o > diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h > new file mode 100644 > index 0000000..d817387 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure.h > @@ -0,0 +1,47 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * v. 1.0.0 > + * Licensed under the GPL-2. > + */ > + > +#ifndef ST_PRESS_H > +#define ST_PRESS_H > + > +#include <linux/types.h> > +#include <linux/iio/common/st_sensors.h> > + > +#define LPS331AP_PRESS_DEV_NAME "lps331ap" > + > +#define ST_PRESS_BYTE_FOR_CHANNEL 3 > +#define ST_TEMP_BYTE_FOR_CHANNEL 2 > + > +int st_press_common_probe(struct iio_dev *indio_dev); > +void st_press_common_remove(struct iio_dev *indio_dev); > + > +#ifdef CONFIG_IIO_BUFFER > +int st_press_allocate_ring(struct iio_dev *indio_dev); > +void st_press_deallocate_ring(struct iio_dev *indio_dev); > +int st_press_trig_set_state(struct iio_trigger *trig, bool state); > +int st_press_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); > +#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) > +#else /* CONFIG_IIO_BUFFER */ > +static inline int st_press_allocate_ring(struct iio_dev *indio_dev) > +{ > + return 0; > +} > +static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) > +{ > +} line breaks between functions (even stub ones ;) > +static int st_press_get_buffer_element(struct iio_dev *indio_dev, > + u8 *buf) > +{ > + return 0; > +} > +#define ST_PRESS_TRIGGER_SET_STATE NULL > +#endif /* CONFIG_IIO_BUFFER */ > + > +#endif /* ST_PRESS_H */ > diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c > new file mode 100644 > index 0000000..db9753d > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_buffer.c > @@ -0,0 +1,115 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/stat.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <linux/delay.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/buffer.h> > +#include <linux/iio/trigger_consumer.h> > +#include <linux/iio/triggered_buffer.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include "st_pressure.h" > + > +int st_press_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) > +{ > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + return pdata->tf->read_multiple_byte(&pdata->tb, pdata->dev, > + indio_dev->channels[ST_SENSORS_SCAN_X].address, > + ST_PRESS_BYTE_FOR_CHANNEL, buf, pdata->multiread_bit); > +} > +EXPORT_SYMBOL(st_press_get_buffer_element); > + > +int st_press_trig_set_state(struct iio_trigger *trig, bool state) > +{ > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > + > + return st_sensors_set_dataready_irq(indio_dev, state); > +} > + > +static int st_press_buffer_preenable(struct iio_dev *indio_dev) > +{ > + int err; > + > + err = st_sensors_set_enable(indio_dev, true); > + if (err < 0) > + goto st_press_set_enable_error; > + > + err = iio_sw_buffer_preenable(indio_dev); > + > +st_press_set_enable_error: > + return err; > +} > + > +static int st_press_buffer_postenable(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); > + if (pdata->buffer_data == NULL) { > + err = -ENOMEM; > + goto allocate_memory_error; > + } > + > + err = iio_triggered_buffer_postenable(indio_dev); > + if (err < 0) > + goto st_press_buffer_postenable_error; > + > + return err; > + > +st_press_buffer_postenable_error: > + kfree(pdata->buffer_data); > +allocate_memory_error: > + return err; > +} > + > +static int st_press_buffer_predisable(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + err = iio_triggered_buffer_predisable(indio_dev); > + if (err < 0) > + goto st_press_buffer_predisable_error; > + > + err = st_sensors_set_enable(indio_dev, false); > + > +st_press_buffer_predisable_error: > + kfree(pdata->buffer_data); > + return err; > +} > + > +static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { > + .preenable = &st_press_buffer_preenable, > + .postenable = &st_press_buffer_postenable, > + .predisable = &st_press_buffer_predisable, > +}; > + > +int st_press_allocate_ring(struct iio_dev *indio_dev) > +{ > + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, > + &st_sensors_trigger_handler, &st_press_buffer_setup_ops); > +} > + > +void st_press_deallocate_ring(struct iio_dev *indio_dev) > +{ > + iio_triggered_buffer_cleanup(indio_dev); > +} > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c > new file mode 100644 > index 0000000..ae5703f > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_core.c > @@ -0,0 +1,349 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/errno.h> > +#include <linux/types.h> > +#include <linux/mutex.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <linux/gpio.h> > +#include <linux/irq.h> > +#include <linux/delay.h> > +#include <linux/iio/iio.h> > +#include <linux/iio/sysfs.h> > +#include <linux/iio/trigger.h> > +#include <linux/iio/buffer.h> > +#include <asm/unaligned.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include "st_pressure.h" > + > +#define ST_PRESS_MBAR_TO_KPASCAL(x) (x * 10) > +#define ST_PRESS_NUMBER_ALL_CHANNELS 3 > + > +/* DEFAULT VALUE FOR SENSORS */ > +#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 > +#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b > + > +/* FULLSCALE */ > +#define ST_PRESS_FS_AVL_1260MB 1260 > + > +/* CUSTOM VALUES FOR SENSOR 1 */ > +#define ST_PRESS_1_WAI_EXP 0xbb > +#define ST_PRESS_1_ODR_ADDR 0x20 > +#define ST_PRESS_1_ODR_MASK 0x70 > +#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 > +#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 > +#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 > +#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 > +#define ST_PRESS_1_PW_ADDR 0x20 > +#define ST_PRESS_1_PW_MASK 0x80 > +#define ST_PRESS_1_FS_ADDR 0x23 > +#define ST_PRESS_1_FS_MASK 0x30 > +#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 > +#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_MBAR_TO_KPASCAL(244141) > +#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000 > +#define ST_PRESS_1_BDU_ADDR 0x20 > +#define ST_PRESS_1_BDU_MASK 0x04 > +#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 > +#define ST_PRESS_1_DRDY_IRQ_MASK 0x04 > +#define ST_PRESS_1_MULTIREAD_BIT true > +#define ST_PRESS_1_TEMP_OFFSET 42500 > + > +static const struct iio_chan_spec st_press_channels[] = { > + ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, > + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), > + ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, > + ST_PRESS_DEFAULT_OUT_XL_ADDR), > + ST_SENSORS_LSM_CHANNELS(IIO_TEMP, > + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | > + BIT(IIO_CHAN_INFO_OFFSET), > + -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, > + ST_TEMP_DEFAULT_OUT_L_ADDR), > + IIO_CHAN_SOFT_TIMESTAMP(1) > +}; > + > +static const struct st_sensors st_press_sensors[] = { > + { > + .wai = ST_PRESS_1_WAI_EXP, > + .sensors_supported = { > + [0] = LPS331AP_PRESS_DEV_NAME, > + }, > + .ch = (struct iio_chan_spec *)st_press_channels, > + .odr = { > + .addr = ST_PRESS_1_ODR_ADDR, > + .mask = ST_PRESS_1_ODR_MASK, > + .odr_avl = { > + { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, > + { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, > + { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, > + { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, > + }, > + }, > + .pw = { > + .addr = ST_PRESS_1_PW_ADDR, > + .mask = ST_PRESS_1_PW_MASK, > + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, > + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, > + }, > + .fs = { > + .addr = ST_PRESS_1_FS_ADDR, > + .mask = ST_PRESS_1_FS_MASK, > + .fs_avl = { > + [0] = { > + .num = ST_PRESS_FS_AVL_1260MB, > + .value = ST_PRESS_1_FS_AVL_1260_VAL, > + .gain = ST_PRESS_1_FS_AVL_1260_GAIN, > + .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, > + }, > + }, > + }, > + .bdu = { > + .addr = ST_PRESS_1_BDU_ADDR, > + .mask = ST_PRESS_1_BDU_MASK, > + }, > + .drdy_irq = { > + .addr = ST_PRESS_1_DRDY_IRQ_ADDR, > + .mask = ST_PRESS_1_DRDY_IRQ_MASK, > + }, > + .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, > + .bootime = 2, > + }, > +}; > + > +static int st_press_read_axis_data(struct iio_dev *indio_dev, > + struct iio_chan_spec const *ch, int *data) > +{ > + int err, num_byte = 0; > + u8 outdata[ST_PRESS_BYTE_FOR_CHANNEL]; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + switch (ch->type) { > + case IIO_PRESSURE: > + num_byte = ST_PRESS_BYTE_FOR_CHANNEL; > + break; > + case IIO_TEMP: > + num_byte = ST_TEMP_BYTE_FOR_CHANNEL; > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > + err = pdata->tf->read_multiple_byte(&pdata->tb, pdata->dev, > + ch->address, num_byte, > + outdata, pdata->multiread_bit); > + if (err < 0) > + goto read_error; > + > + switch (ch->type) { > + case IIO_PRESSURE: > + *data = (s32)get_unaligned_le32(outdata); > + break; > + case IIO_TEMP: > + *data = (s16)get_unaligned_le16(outdata); > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > +read_error: > + return err; > +} > + > +static int st_press_read_info_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *ch, int *val) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + mutex_lock(&indio_dev->mlock); > + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { > + err = -EBUSY; > + goto read_error; > + } else { > + err = st_sensors_set_enable(indio_dev, true); > + if (err < 0) > + goto read_error; > + > + msleep((pdata->sensor->bootime * 1000) / pdata->odr); > + err = st_press_read_axis_data(indio_dev, ch, val); > + if (err < 0) > + goto read_error; > + > + *val = *val >> ch->scan_type.shift; > + > + err = st_sensors_set_enable(indio_dev, false); > + } > + mutex_unlock(&indio_dev->mlock); > + > + return err; > + > +read_error: > + mutex_unlock(&indio_dev->mlock); > + return err; > +} > + > +static int st_press_read_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *ch, int *val, > + int *val2, long mask) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + switch (mask) { > + case IIO_CHAN_INFO_RAW: > + err = st_press_read_info_raw(indio_dev, ch, val); > + if (err < 0) > + goto read_error; > + > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_SCALE: > + *val = 0; > + > + switch (ch->type) { > + case IIO_PRESSURE: > + *val2 = pdata->current_fullscale->gain; > + break; > + case IIO_TEMP: > + *val2 = pdata->current_fullscale->gain2; > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > + return IIO_VAL_INT_PLUS_NANO; > + case IIO_CHAN_INFO_OFFSET: > + *val = 0; > + > + switch (ch->type) { > + case IIO_TEMP: > + *val2 = 42500000; > + break; > + default: > + err = -EINVAL; > + goto read_error; > + } > + > + return IIO_VAL_INT_PLUS_MICRO; > + default: > + return -EINVAL; > + } > + > +read_error: > + return err; > +} > + > +static ST_SENSOR_DEV_ATTR_SAMP_FREQ(); > +static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); > +static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_press_scale_available); > + > +static struct attribute *st_press_attributes[] = { > + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, > + &iio_dev_attr_in_press_scale_available.dev_attr.attr, > + &iio_dev_attr_sampling_frequency.dev_attr.attr, > + NULL, > +}; > + > +static const struct attribute_group st_press_attribute_group = { > + .attrs = st_press_attributes, > +}; > + > +static const struct iio_info press_info = { > + .driver_module = THIS_MODULE, > + .attrs = &st_press_attribute_group, > + .read_raw = &st_press_read_raw, > +}; > + > +#ifdef CONFIG_IIO_TRIGGER > +static const struct iio_trigger_ops st_press_trigger_ops = { > + .owner = THIS_MODULE, > + .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, > +}; > +#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) > +#else > +#define ST_PRESS_TRIGGER_OPS NULL > +#endif > + > +int st_press_common_probe(struct iio_dev *indio_dev) > +{ > + int err; > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->info = &press_info; > + > + err = st_sensors_check_device_support(indio_dev, > + ARRAY_SIZE(st_press_sensors), st_press_sensors); > + if (err < 0) > + goto st_press_common_probe_error; > + > + pdata->get_buffer_element = &st_press_get_buffer_element; > + pdata->multiread_bit = pdata->sensor->multi_read_bit; > + indio_dev->channels = pdata->sensor->ch; > + indio_dev->num_channels = ST_PRESS_NUMBER_ALL_CHANNELS; > + > + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) > + &pdata->sensor->fs.fs_avl[0]; > + pdata->odr = pdata->sensor->odr.odr_avl[0].hz; > + > + err = st_sensors_init_sensor(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + if (pdata->get_irq_data_ready(indio_dev) > 0) { > + err = st_press_allocate_ring(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + err = st_sensors_allocate_trigger(indio_dev, > + ST_PRESS_TRIGGER_OPS); > + if (err < 0) > + goto st_press_probe_trigger_error; > + } > + > + err = iio_device_register(indio_dev); > + if (err) > + goto st_press_device_register_error; > + > + return err; > + > +st_press_device_register_error: > + if (pdata->get_irq_data_ready(indio_dev) > 0) > + st_sensors_deallocate_trigger(indio_dev); > +st_press_probe_trigger_error: > + if (pdata->get_irq_data_ready(indio_dev) > 0) > + st_press_deallocate_ring(indio_dev); > +st_press_common_probe_error: > + return err; > +} > +EXPORT_SYMBOL(st_press_common_probe); > + > +void st_press_common_remove(struct iio_dev *indio_dev) > +{ > + struct st_sensor_data *pdata = iio_priv(indio_dev); > + > + iio_device_unregister(indio_dev); > + if (pdata->get_irq_data_ready(indio_dev) > 0) { > + st_sensors_deallocate_trigger(indio_dev); > + st_press_deallocate_ring(indio_dev); > + } > + iio_device_free(indio_dev); > +} > +EXPORT_SYMBOL(st_press_common_remove); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c > new file mode 100644 > index 0000000..7cebcc7 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_i2c.c > @@ -0,0 +1,77 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/i2c.h> > +#include <linux/iio/iio.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include <linux/iio/common/st_sensors_i2c.h> > +#include "st_pressure.h" > + > +static int st_press_i2c_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct iio_dev *indio_dev; > + struct st_sensor_data *pdata; > + int err; > + > + indio_dev = iio_device_alloc(sizeof(*pdata)); > + if (indio_dev == NULL) { > + err = -ENOMEM; > + goto iio_device_alloc_error; > + } > + > + pdata = iio_priv(indio_dev); > + pdata->dev = &client->dev; > + > + st_sensors_i2c_configure(indio_dev, client, pdata); > + > + err = st_press_common_probe(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + return 0; > + > +st_press_common_probe_error: > + iio_device_free(indio_dev); > +iio_device_alloc_error: > + return err; > +} > + > +static int st_press_i2c_remove(struct i2c_client *client) > +{ > + st_press_common_remove(i2c_get_clientdata(client)); > + > + return 0; > +} > + > +static const struct i2c_device_id st_press_id_table[] = { > + { LPS331AP_PRESS_DEV_NAME }, > + {}, > +}; > +MODULE_DEVICE_TABLE(i2c, st_press_id_table); > + > +static struct i2c_driver st_press_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "st-press-i2c", > + }, > + .probe = st_press_i2c_probe, > + .remove = st_press_i2c_remove, > + .id_table = st_press_id_table, > +}; > +module_i2c_driver(st_press_driver); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c > new file mode 100644 > index 0000000..17a1490 > --- /dev/null > +++ b/drivers/iio/pressure/st_pressure_spi.c > @@ -0,0 +1,76 @@ > +/* > + * STMicroelectronics pressures driver > + * > + * Copyright 2013 STMicroelectronics Inc. > + * > + * Denis Ciocca <denis.ciocca@st.com> > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/spi/spi.h> > +#include <linux/iio/iio.h> > + > +#include <linux/iio/common/st_sensors.h> > +#include <linux/iio/common/st_sensors_spi.h> > +#include "st_pressure.h" > + > +static int st_press_spi_probe(struct spi_device *spi) > +{ > + struct iio_dev *indio_dev; > + struct st_sensor_data *pdata; > + int err; > + > + indio_dev = iio_device_alloc(sizeof(*pdata)); > + if (indio_dev == NULL) { > + err = -ENOMEM; > + goto iio_device_alloc_error; > + } > + > + pdata = iio_priv(indio_dev); > + pdata->dev = &spi->dev; > + > + st_sensors_spi_configure(indio_dev, spi, pdata); > + > + err = st_press_common_probe(indio_dev); > + if (err < 0) > + goto st_press_common_probe_error; > + > + return 0; > + > +st_press_common_probe_error: > + iio_device_free(indio_dev); > +iio_device_alloc_error: > + return err; > +} > + > +static int st_press_spi_remove(struct spi_device *spi) > +{ > + st_press_common_remove(spi_get_drvdata(spi)); > + > + return 0; > +} > + > +static const struct spi_device_id st_press_id_table[] = { > + { LPS331AP_PRESS_DEV_NAME }, > + {}, > +}; > +MODULE_DEVICE_TABLE(spi, st_press_id_table); > + > +static struct spi_driver st_press_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "st-press-spi", > + }, > + .probe = st_press_spi_probe, > + .remove = st_press_spi_remove, > + .id_table = st_press_id_table, > +}; > +module_spi_driver(st_press_driver); > + > +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); > +MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); > +MODULE_LICENSE("GPL v2"); > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-18 21:06 ` Jonathan Cameron @ 2013-05-20 7:51 ` Denis CIOCCA 2013-05-20 9:47 ` Jacek Anaszewski 0 siblings, 1 reply; 15+ messages in thread From: Denis CIOCCA @ 2013-05-20 7:51 UTC (permalink / raw) To: Jonathan Cameron Cc: linux-iio@vger.kernel.org, lars@metafoo.de, j.anaszewski@samsung.com Hi Jonathan, > Now going forward I'd of course like to see everyone happy with the > resulting driver. Denis do you have plans to implement the threshold > events that were in the other driver proposal? Now I'm very full but in the future I have plans to support the threshold events, I'm very happy if Jacek will help me! ;) > Other than the request > from Jacek to handle the other interrupt line choice I think that is > all that is missing from here that was present there? > (Of course you two will probably have a better idea of the differences) For the interrupt lines, I'm working to support in all ST drivers the choice of interrupt line. Thanks, Denis ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-20 7:51 ` Denis CIOCCA @ 2013-05-20 9:47 ` Jacek Anaszewski 2013-05-22 21:27 ` Jonathan Cameron 0 siblings, 1 reply; 15+ messages in thread From: Jacek Anaszewski @ 2013-05-20 9:47 UTC (permalink / raw) To: linux-iio Cc: Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org, j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org On 05/20/2013 09:51 AM, Denis CIOCCA wrote: > Hi Jonathan, > >> Now going forward I'd of course like to see everyone happy with the >> resulting driver. Denis do you have plans to implement the threshold >> events that were in the other driver proposal? > Now I'm very full but in the future I have plans to support the threshold > events, I'm very happy if Jacek will help me! ;) Hi Jonathan, Denis, The threshold events weren't supported in my driver proposal - the events were related only to the 'data ready' interrupts. I've been playing with threshold interrupts during development, but I didn't find the device reliable by minimal threshold levels. I've lately devised a procedure of testing greater pressure differences and I will test it within few weeks, as currently I am working on another driver. Thanks, Jacek ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-20 9:47 ` Jacek Anaszewski @ 2013-05-22 21:27 ` Jonathan Cameron 2013-05-22 21:29 ` Jonathan Cameron 0 siblings, 1 reply; 15+ messages in thread From: Jonathan Cameron @ 2013-05-22 21:27 UTC (permalink / raw) To: Jacek Anaszewski Cc: linux-iio, Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org, j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org On 05/20/2013 10:47 AM, Jacek Anaszewski wrote: > On 05/20/2013 09:51 AM, Denis CIOCCA wrote: >> Hi Jonathan, >> >>> Now going forward I'd of course like to see everyone happy with the >>> resulting driver. Denis do you have plans to implement the threshold >>> events that were in the other driver proposal? >> Now I'm very full but in the future I have plans to support the threshold >> events, I'm very happy if Jacek will help me! ;) > > Hi Jonathan, Denis, > > The threshold events weren't supported in my driver proposal - the events were related only to the 'data ready' > interrupts. I've been > playing with threshold interrupts during development, but I didn't > find the device reliable by minimal threshold levels. Oops, I missed that you were 'abusing' these entirely in review. > I've lately > devised a procedure of testing greater pressure differences and > I will test it within few weeks, as currently I am working on > another driver. Given the driver simplicity (as it's adding to the existing drivers that are well tested) I'm going to assume it works fine for now and merge it based on review. Do shout if it doesn't of course or if you have any improvements to suggest. I'd definitely like to see full event support for the threshold interrupts in these parts (which will be needed to finally kill off the my lis3l02dq driver :) Been trying to get rid of that one for years.). Jonathan > > Thanks, > Jacek > > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver 2013-05-22 21:27 ` Jonathan Cameron @ 2013-05-22 21:29 ` Jonathan Cameron 0 siblings, 0 replies; 15+ messages in thread From: Jonathan Cameron @ 2013-05-22 21:29 UTC (permalink / raw) To: Jacek Anaszewski Cc: linux-iio, Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org, j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org On 05/22/2013 10:27 PM, Jonathan Cameron wrote: > On 05/20/2013 10:47 AM, Jacek Anaszewski wrote: >> On 05/20/2013 09:51 AM, Denis CIOCCA wrote: >>> Hi Jonathan, >>> >>>> Now going forward I'd of course like to see everyone happy with the >>>> resulting driver. Denis do you have plans to implement the threshold >>>> events that were in the other driver proposal? >>> Now I'm very full but in the future I have plans to support the threshold >>> events, I'm very happy if Jacek will help me! ;) >> >> Hi Jonathan, Denis, >> >> The threshold events weren't supported in my driver proposal - the events were related only to the 'data ready' >> interrupts. I've been >> playing with threshold interrupts during development, but I didn't >> find the device reliable by minimal threshold levels. > Oops, I missed that you were 'abusing' these entirely in review. > >> I've lately >> devised a procedure of testing greater pressure differences and >> I will test it within few weeks, as currently I am working on >> another driver. > Given the driver simplicity (as it's adding to the existing drivers that > are well tested) I'm going to assume it works fine for now > and merge it based on review. Do shout if it doesn't of course > or if you have any improvements to suggest. Actually no I'm not. I'd completely forgotten that I wasn't happy with some of the patches during review. Over to Denis to post a new version or convince me the review comments were wrong ;) > > I'd definitely like to see full event support for the threshold interrupts > in these parts (which will be needed to finally kill off the my lis3l02dq > driver :) Been trying to get rid of that one for years.). > > Jonathan >> >> Thanks, >> Jacek >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-iio" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2013-06-04 18:03 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-06-03 14:58 STMicroelectronics series of patches to support pressure sensors Denis CIOCCA 2013-06-03 14:58 ` [PATCH 1/3] iio:common: ST_SENSORS_LSM_CHANNELS macro changed Denis CIOCCA 2013-06-03 14:58 ` [PATCH 2/3] iio:common: Removed stuff macros, added num_data_channels on st_sensors struct and added support on one-shot sysfs reads to 3 byte channel Denis CIOCCA 2013-06-04 18:03 ` Jonathan Cameron 2013-06-03 14:58 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2013-06-04 18:03 ` Jonathan Cameron -- strict thread matches above, loose matches on Subject: below -- 2013-05-24 14:25 Support pressure sensors Denis CIOCCA 2013-05-24 14:25 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2013-05-15 8:44 STMicroelectronics pressure sensors driver Denis CIOCCA 2013-05-15 8:44 ` [PATCH 3/3] iio:pressure: Add STMicroelectronics pressures driver Denis CIOCCA 2013-05-17 15:00 ` Jacek Anaszewski 2013-05-17 16:09 ` Denis CIOCCA 2013-05-18 21:06 ` Jonathan Cameron 2013-05-20 7:51 ` Denis CIOCCA 2013-05-20 9:47 ` Jacek Anaszewski 2013-05-22 21:27 ` Jonathan Cameron 2013-05-22 21:29 ` Jonathan Cameron
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).