1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * mpl115.c - Support for Freescale MPL115A pressure/temperature sensor 4 * 5 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 6 * 7 * TODO: synchronization with system suspend 8 */ 9 10 #include <linux/module.h> 11 #include <linux/iio/iio.h> 12 #include <linux/delay.h> 13 #include <linux/gpio/consumer.h> 14 15 #include "mpl115.h" 16 17 #define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */ 18 #define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */ 19 #define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */ 20 #define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */ 21 #define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */ 22 #define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */ 23 #define MPL115_CONVERT 0x12 /* convert temperature and pressure */ 24 25 struct mpl115_data { 26 struct device *dev; 27 struct mutex lock; 28 s16 a0; 29 s16 b1, b2; 30 s16 c12; 31 struct gpio_desc *shutdown; 32 const struct mpl115_ops *ops; 33 }; 34 35 static int mpl115_request(struct mpl115_data *data) 36 { 37 int ret = data->ops->write(data->dev, MPL115_CONVERT, 0); 38 39 if (ret < 0) 40 return ret; 41 42 usleep_range(3000, 4000); 43 44 return 0; 45 } 46 47 static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2) 48 { 49 int ret; 50 u16 padc, tadc; 51 int a1, y1, pcomp; 52 unsigned kpa; 53 54 mutex_lock(&data->lock); 55 ret = mpl115_request(data); 56 if (ret < 0) 57 goto done; 58 59 ret = data->ops->read(data->dev, MPL115_PADC); 60 if (ret < 0) 61 goto done; 62 padc = ret >> 6; 63 64 ret = data->ops->read(data->dev, MPL115_TADC); 65 if (ret < 0) 66 goto done; 67 tadc = ret >> 6; 68 69 /* see Freescale AN3785 */ 70 a1 = data->b1 + ((data->c12 * tadc) >> 11); 71 y1 = (data->a0 << 10) + a1 * padc; 72 73 /* compensated pressure with 4 fractional bits */ 74 pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9; 75 76 kpa = pcomp * (115 - 50) / 1023 + (50 << 4); 77 *val = kpa >> 4; 78 *val2 = (kpa & 15) * (1000000 >> 4); 79 done: 80 mutex_unlock(&data->lock); 81 return ret; 82 } 83 84 static int mpl115_read_temp(struct mpl115_data *data) 85 { 86 int ret; 87 88 mutex_lock(&data->lock); 89 ret = mpl115_request(data); 90 if (ret < 0) 91 goto done; 92 ret = data->ops->read(data->dev, MPL115_TADC); 93 done: 94 mutex_unlock(&data->lock); 95 return ret; 96 } 97 98 static int mpl115_read_raw(struct iio_dev *indio_dev, 99 struct iio_chan_spec const *chan, 100 int *val, int *val2, long mask) 101 { 102 struct mpl115_data *data = iio_priv(indio_dev); 103 int ret; 104 105 switch (mask) { 106 case IIO_CHAN_INFO_PROCESSED: 107 pm_runtime_get_sync(data->dev); 108 ret = mpl115_comp_pressure(data, val, val2); 109 if (ret < 0) 110 return ret; 111 pm_runtime_mark_last_busy(data->dev); 112 pm_runtime_put_autosuspend(data->dev); 113 114 return IIO_VAL_INT_PLUS_MICRO; 115 case IIO_CHAN_INFO_RAW: 116 pm_runtime_get_sync(data->dev); 117 /* temperature -5.35 C / LSB, 472 LSB is 25 C */ 118 ret = mpl115_read_temp(data); 119 if (ret < 0) 120 return ret; 121 pm_runtime_mark_last_busy(data->dev); 122 pm_runtime_put_autosuspend(data->dev); 123 *val = ret >> 6; 124 125 return IIO_VAL_INT; 126 case IIO_CHAN_INFO_OFFSET: 127 *val = -605; 128 *val2 = 750000; 129 return IIO_VAL_INT_PLUS_MICRO; 130 case IIO_CHAN_INFO_SCALE: 131 *val = -186; 132 *val2 = 915888; 133 return IIO_VAL_INT_PLUS_MICRO; 134 } 135 return -EINVAL; 136 } 137 138 static const struct iio_chan_spec mpl115_channels[] = { 139 { 140 .type = IIO_PRESSURE, 141 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 142 }, 143 { 144 .type = IIO_TEMP, 145 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 146 .info_mask_shared_by_type = 147 BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), 148 }, 149 }; 150 151 static const struct iio_info mpl115_info = { 152 .read_raw = &mpl115_read_raw, 153 }; 154 155 int mpl115_probe(struct device *dev, const char *name, 156 const struct mpl115_ops *ops) 157 { 158 struct mpl115_data *data; 159 struct iio_dev *indio_dev; 160 int ret; 161 162 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 163 if (!indio_dev) 164 return -ENOMEM; 165 166 data = iio_priv(indio_dev); 167 data->dev = dev; 168 data->ops = ops; 169 mutex_init(&data->lock); 170 171 indio_dev->info = &mpl115_info; 172 indio_dev->name = name; 173 indio_dev->modes = INDIO_DIRECT_MODE; 174 indio_dev->channels = mpl115_channels; 175 indio_dev->num_channels = ARRAY_SIZE(mpl115_channels); 176 177 ret = data->ops->init(data->dev); 178 if (ret) 179 return ret; 180 181 dev_set_drvdata(dev, indio_dev); 182 183 ret = data->ops->read(data->dev, MPL115_A0); 184 if (ret < 0) 185 return ret; 186 data->a0 = ret; 187 ret = data->ops->read(data->dev, MPL115_B1); 188 if (ret < 0) 189 return ret; 190 data->b1 = ret; 191 ret = data->ops->read(data->dev, MPL115_B2); 192 if (ret < 0) 193 return ret; 194 data->b2 = ret; 195 ret = data->ops->read(data->dev, MPL115_C12); 196 if (ret < 0) 197 return ret; 198 data->c12 = ret; 199 200 data->shutdown = devm_gpiod_get_optional(dev, "shutdown", 201 GPIOD_OUT_LOW); 202 if (IS_ERR(data->shutdown)) 203 return dev_err_probe(dev, PTR_ERR(data->shutdown), 204 "cannot get shutdown gpio\n"); 205 206 if (data->shutdown) { 207 /* Enable runtime PM */ 208 pm_runtime_get_noresume(dev); 209 pm_runtime_set_active(dev); 210 pm_runtime_enable(dev); 211 212 /* 213 * As the device takes 3 ms to come up with a fresh 214 * reading after power-on and 5 ms to actually power-on, 215 * do not shut it down unnecessarily. Set autosuspend to 216 * 2000 ms. 217 */ 218 pm_runtime_set_autosuspend_delay(dev, 2000); 219 pm_runtime_use_autosuspend(dev); 220 pm_runtime_put(dev); 221 222 dev_dbg(dev, "low-power mode enabled"); 223 } else 224 dev_dbg(dev, "low-power mode disabled"); 225 226 return devm_iio_device_register(dev, indio_dev); 227 } 228 EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115); 229 230 static int mpl115_runtime_suspend(struct device *dev) 231 { 232 struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 233 234 gpiod_set_value(data->shutdown, 1); 235 236 return 0; 237 } 238 239 static int mpl115_runtime_resume(struct device *dev) 240 { 241 struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 242 243 gpiod_set_value(data->shutdown, 0); 244 usleep_range(5000, 6000); 245 246 return 0; 247 } 248 249 EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend, 250 mpl115_runtime_resume, NULL, IIO_MPL115); 251 252 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 253 MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); 254 MODULE_LICENSE("GPL"); 255