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

Configure Feed

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

iio: Add Freescale MPL115A2 pressure / temperature sensor driver

I2C-controlled sensor with 10-bit pressure and temperature measurement

datasheet: http://cache.freescale.com/files/sensors/doc/data_sheet/MPL3115A2.pdf

v2:
* use devm_iio_device_register()

Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Peter Meerwald and committed by
Jonathan Cameron
3017d90e 0828eddc

+222
+10
drivers/iio/pressure/Kconfig
··· 19 19 To compile this driver as a module, choose M here: the module 20 20 will be called hid-sensor-press. 21 21 22 + config MPL115 23 + tristate "Freescale MPL115A2 pressure sensor driver" 24 + depends on I2C 25 + help 26 + Say yes here to build support for the Freescale MPL115A2 27 + pressure sensor connected via I2C. 28 + 29 + To compile this driver as a module, choose M here: the module 30 + will be called mpl115. 31 + 22 32 config MPL3115 23 33 tristate "Freescale MPL3115A2 pressure sensor driver" 24 34 depends on I2C
+1
drivers/iio/pressure/Makefile
··· 4 4 5 5 # When adding new entries keep the list in alphabetical order 6 6 obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o 7 + obj-$(CONFIG_MPL115) += mpl115.o 7 8 obj-$(CONFIG_MPL3115) += mpl3115.o 8 9 obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o 9 10 st_pressure-y := st_pressure_core.o
+211
drivers/iio/pressure/mpl115.c
··· 1 + /* 2 + * mpl115.c - Support for Freescale MPL115A2 pressure/temperature sensor 3 + * 4 + * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 5 + * 6 + * This file is subject to the terms and conditions of version 2 of 7 + * the GNU General Public License. See the file COPYING in the main 8 + * directory of this archive for more details. 9 + * 10 + * (7-bit I2C slave address 0x60) 11 + * 12 + * TODO: shutdown pin 13 + * 14 + */ 15 + 16 + #include <linux/module.h> 17 + #include <linux/i2c.h> 18 + #include <linux/iio/iio.h> 19 + #include <linux/delay.h> 20 + 21 + #define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */ 22 + #define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */ 23 + #define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */ 24 + #define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */ 25 + #define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */ 26 + #define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */ 27 + #define MPL115_CONVERT 0x12 /* convert temperature and pressure */ 28 + 29 + struct mpl115_data { 30 + struct i2c_client *client; 31 + struct mutex lock; 32 + s16 a0; 33 + s16 b1, b2; 34 + s16 c12; 35 + }; 36 + 37 + static int mpl115_request(struct mpl115_data *data) 38 + { 39 + int ret = i2c_smbus_write_byte_data(data->client, MPL115_CONVERT, 0); 40 + if (ret < 0) 41 + return ret; 42 + 43 + usleep_range(3000, 4000); 44 + 45 + return 0; 46 + } 47 + 48 + static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2) 49 + { 50 + int ret; 51 + u16 padc, tadc; 52 + int a1, y1, pcomp; 53 + unsigned kpa; 54 + 55 + mutex_lock(&data->lock); 56 + ret = mpl115_request(data); 57 + if (ret < 0) 58 + goto done; 59 + 60 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_PADC); 61 + if (ret < 0) 62 + goto done; 63 + padc = ret >> 6; 64 + 65 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC); 66 + if (ret < 0) 67 + goto done; 68 + tadc = ret >> 6; 69 + 70 + /* see Freescale AN3785 */ 71 + a1 = data->b1 + ((data->c12 * tadc) >> 11); 72 + y1 = (data->a0 << 10) + a1 * padc; 73 + 74 + /* compensated pressure with 4 fractional bits */ 75 + pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9; 76 + 77 + kpa = pcomp * (115 - 50) / 1023 + (50 << 4); 78 + *val = kpa >> 4; 79 + *val2 = (kpa & 15) * (1000000 >> 4); 80 + done: 81 + mutex_unlock(&data->lock); 82 + return ret; 83 + } 84 + 85 + static int mpl115_read_temp(struct mpl115_data *data) 86 + { 87 + int ret; 88 + 89 + mutex_lock(&data->lock); 90 + ret = mpl115_request(data); 91 + if (ret < 0) 92 + goto done; 93 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC); 94 + done: 95 + mutex_unlock(&data->lock); 96 + return ret; 97 + } 98 + 99 + static int mpl115_read_raw(struct iio_dev *indio_dev, 100 + struct iio_chan_spec const *chan, 101 + int *val, int *val2, long mask) 102 + { 103 + struct mpl115_data *data = iio_priv(indio_dev); 104 + int ret; 105 + 106 + switch (mask) { 107 + case IIO_CHAN_INFO_PROCESSED: 108 + ret = mpl115_comp_pressure(data, val, val2); 109 + if (ret < 0) 110 + return ret; 111 + return IIO_VAL_INT_PLUS_MICRO; 112 + case IIO_CHAN_INFO_RAW: 113 + /* temperature -5.35 C / LSB, 472 LSB is 25 C */ 114 + ret = mpl115_read_temp(data); 115 + if (ret < 0) 116 + return ret; 117 + *val = ret >> 6; 118 + return IIO_VAL_INT; 119 + case IIO_CHAN_INFO_OFFSET: 120 + *val = 605; 121 + *val2 = 750000; 122 + return IIO_VAL_INT_PLUS_MICRO; 123 + case IIO_CHAN_INFO_SCALE: 124 + *val = -186; 125 + *val2 = 915888; 126 + return IIO_VAL_INT_PLUS_MICRO; 127 + } 128 + return -EINVAL; 129 + } 130 + 131 + static const struct iio_chan_spec mpl115_channels[] = { 132 + { 133 + .type = IIO_PRESSURE, 134 + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 135 + }, 136 + { 137 + .type = IIO_TEMP, 138 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 139 + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), 140 + }, 141 + }; 142 + 143 + static const struct iio_info mpl115_info = { 144 + .read_raw = &mpl115_read_raw, 145 + .driver_module = THIS_MODULE, 146 + }; 147 + 148 + static int mpl115_probe(struct i2c_client *client, 149 + const struct i2c_device_id *id) 150 + { 151 + struct mpl115_data *data; 152 + struct iio_dev *indio_dev; 153 + int ret; 154 + 155 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 156 + return -ENODEV; 157 + 158 + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 159 + if (!indio_dev) 160 + return -ENOMEM; 161 + 162 + data = iio_priv(indio_dev); 163 + data->client = client; 164 + mutex_init(&data->lock); 165 + 166 + i2c_set_clientdata(client, indio_dev); 167 + indio_dev->info = &mpl115_info; 168 + indio_dev->name = id->name; 169 + indio_dev->dev.parent = &client->dev; 170 + indio_dev->modes = INDIO_DIRECT_MODE; 171 + indio_dev->channels = mpl115_channels; 172 + indio_dev->num_channels = ARRAY_SIZE(mpl115_channels); 173 + 174 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_A0); 175 + if (ret < 0) 176 + return ret; 177 + data->a0 = ret; 178 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_B1); 179 + if (ret < 0) 180 + return ret; 181 + data->b1 = ret; 182 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_B2); 183 + if (ret < 0) 184 + return ret; 185 + data->b2 = ret; 186 + ret = i2c_smbus_read_word_swapped(data->client, MPL115_C12); 187 + if (ret < 0) 188 + return ret; 189 + data->c12 = ret; 190 + 191 + return devm_iio_device_register(&client->dev, indio_dev); 192 + } 193 + 194 + static const struct i2c_device_id mpl115_id[] = { 195 + { "mpl115", 0 }, 196 + { } 197 + }; 198 + MODULE_DEVICE_TABLE(i2c, mpl115_id); 199 + 200 + static struct i2c_driver mpl115_driver = { 201 + .driver = { 202 + .name = "mpl115", 203 + }, 204 + .probe = mpl115_probe, 205 + .id_table = mpl115_id, 206 + }; 207 + module_i2c_driver(mpl115_driver); 208 + 209 + MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 210 + MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); 211 + MODULE_LICENSE("GPL");