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_put_autosuspend(data->dev); 112 113 return IIO_VAL_INT_PLUS_MICRO; 114 case IIO_CHAN_INFO_RAW: 115 pm_runtime_get_sync(data->dev); 116 /* temperature -5.35 C / LSB, 472 LSB is 25 C */ 117 ret = mpl115_read_temp(data); 118 if (ret < 0) 119 return ret; 120 pm_runtime_put_autosuspend(data->dev); 121 *val = ret >> 6; 122 123 return IIO_VAL_INT; 124 case IIO_CHAN_INFO_OFFSET: 125 *val = -605; 126 *val2 = 750000; 127 return IIO_VAL_INT_PLUS_MICRO; 128 case IIO_CHAN_INFO_SCALE: 129 *val = -186; 130 *val2 = 915888; 131 return IIO_VAL_INT_PLUS_MICRO; 132 } 133 return -EINVAL; 134 } 135 136 static const struct iio_chan_spec mpl115_channels[] = { 137 { 138 .type = IIO_PRESSURE, 139 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 140 }, 141 { 142 .type = IIO_TEMP, 143 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 144 .info_mask_shared_by_type = 145 BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), 146 }, 147 }; 148 149 static const struct iio_info mpl115_info = { 150 .read_raw = &mpl115_read_raw, 151 }; 152 153 int mpl115_probe(struct device *dev, const char *name, 154 const struct mpl115_ops *ops) 155 { 156 struct mpl115_data *data; 157 struct iio_dev *indio_dev; 158 int ret; 159 160 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 161 if (!indio_dev) 162 return -ENOMEM; 163 164 data = iio_priv(indio_dev); 165 data->dev = dev; 166 data->ops = ops; 167 mutex_init(&data->lock); 168 169 indio_dev->info = &mpl115_info; 170 indio_dev->name = name; 171 indio_dev->modes = INDIO_DIRECT_MODE; 172 indio_dev->channels = mpl115_channels; 173 indio_dev->num_channels = ARRAY_SIZE(mpl115_channels); 174 175 ret = data->ops->init(data->dev); 176 if (ret) 177 return ret; 178 179 dev_set_drvdata(dev, indio_dev); 180 181 ret = data->ops->read(data->dev, MPL115_A0); 182 if (ret < 0) 183 return ret; 184 data->a0 = ret; 185 ret = data->ops->read(data->dev, MPL115_B1); 186 if (ret < 0) 187 return ret; 188 data->b1 = ret; 189 ret = data->ops->read(data->dev, MPL115_B2); 190 if (ret < 0) 191 return ret; 192 data->b2 = ret; 193 ret = data->ops->read(data->dev, MPL115_C12); 194 if (ret < 0) 195 return ret; 196 data->c12 = ret; 197 198 data->shutdown = devm_gpiod_get_optional(dev, "shutdown", 199 GPIOD_OUT_LOW); 200 if (IS_ERR(data->shutdown)) 201 return dev_err_probe(dev, PTR_ERR(data->shutdown), 202 "cannot get shutdown gpio\n"); 203 204 if (data->shutdown) { 205 /* Enable runtime PM */ 206 pm_runtime_get_noresume(dev); 207 pm_runtime_set_active(dev); 208 pm_runtime_enable(dev); 209 210 /* 211 * As the device takes 3 ms to come up with a fresh 212 * reading after power-on and 5 ms to actually power-on, 213 * do not shut it down unnecessarily. Set autosuspend to 214 * 2000 ms. 215 */ 216 pm_runtime_set_autosuspend_delay(dev, 2000); 217 pm_runtime_use_autosuspend(dev); 218 pm_runtime_put(dev); 219 220 dev_dbg(dev, "low-power mode enabled"); 221 } else 222 dev_dbg(dev, "low-power mode disabled"); 223 224 return devm_iio_device_register(dev, indio_dev); 225 } 226 EXPORT_SYMBOL_NS_GPL(mpl115_probe, "IIO_MPL115"); 227 228 static int mpl115_runtime_suspend(struct device *dev) 229 { 230 struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 231 232 gpiod_set_value(data->shutdown, 1); 233 234 return 0; 235 } 236 237 static int mpl115_runtime_resume(struct device *dev) 238 { 239 struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 240 241 gpiod_set_value(data->shutdown, 0); 242 usleep_range(5000, 6000); 243 244 return 0; 245 } 246 247 EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend, 248 mpl115_runtime_resume, NULL, IIO_MPL115); 249 250 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 251 MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); 252 MODULE_LICENSE("GPL"); 253