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"); 212