136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23017d90eSPeter Meerwald /*
3c984b9cbSAkinobu Mita * mpl115.c - Support for Freescale MPL115A pressure/temperature sensor
43017d90eSPeter Meerwald *
53017d90eSPeter Meerwald * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
63017d90eSPeter Meerwald *
7*0c3a3335SRajat Khandelwal * TODO: synchronization with system suspend
83017d90eSPeter Meerwald */
93017d90eSPeter Meerwald
103017d90eSPeter Meerwald #include <linux/module.h>
113017d90eSPeter Meerwald #include <linux/iio/iio.h>
123017d90eSPeter Meerwald #include <linux/delay.h>
13*0c3a3335SRajat Khandelwal #include <linux/gpio/consumer.h>
143017d90eSPeter Meerwald
15c984b9cbSAkinobu Mita #include "mpl115.h"
16c984b9cbSAkinobu Mita
173017d90eSPeter Meerwald #define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */
183017d90eSPeter Meerwald #define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */
193017d90eSPeter Meerwald #define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */
203017d90eSPeter Meerwald #define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */
213017d90eSPeter Meerwald #define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */
223017d90eSPeter Meerwald #define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */
233017d90eSPeter Meerwald #define MPL115_CONVERT 0x12 /* convert temperature and pressure */
243017d90eSPeter Meerwald
253017d90eSPeter Meerwald struct mpl115_data {
26c984b9cbSAkinobu Mita struct device *dev;
273017d90eSPeter Meerwald struct mutex lock;
283017d90eSPeter Meerwald s16 a0;
293017d90eSPeter Meerwald s16 b1, b2;
303017d90eSPeter Meerwald s16 c12;
31*0c3a3335SRajat Khandelwal struct gpio_desc *shutdown;
32c984b9cbSAkinobu Mita const struct mpl115_ops *ops;
333017d90eSPeter Meerwald };
343017d90eSPeter Meerwald
mpl115_request(struct mpl115_data * data)353017d90eSPeter Meerwald static int mpl115_request(struct mpl115_data *data)
363017d90eSPeter Meerwald {
37c984b9cbSAkinobu Mita int ret = data->ops->write(data->dev, MPL115_CONVERT, 0);
38c984b9cbSAkinobu Mita
393017d90eSPeter Meerwald if (ret < 0)
403017d90eSPeter Meerwald return ret;
413017d90eSPeter Meerwald
423017d90eSPeter Meerwald usleep_range(3000, 4000);
433017d90eSPeter Meerwald
443017d90eSPeter Meerwald return 0;
453017d90eSPeter Meerwald }
463017d90eSPeter Meerwald
mpl115_comp_pressure(struct mpl115_data * data,int * val,int * val2)473017d90eSPeter Meerwald static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2)
483017d90eSPeter Meerwald {
493017d90eSPeter Meerwald int ret;
503017d90eSPeter Meerwald u16 padc, tadc;
513017d90eSPeter Meerwald int a1, y1, pcomp;
523017d90eSPeter Meerwald unsigned kpa;
533017d90eSPeter Meerwald
543017d90eSPeter Meerwald mutex_lock(&data->lock);
553017d90eSPeter Meerwald ret = mpl115_request(data);
563017d90eSPeter Meerwald if (ret < 0)
573017d90eSPeter Meerwald goto done;
583017d90eSPeter Meerwald
59c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_PADC);
603017d90eSPeter Meerwald if (ret < 0)
613017d90eSPeter Meerwald goto done;
623017d90eSPeter Meerwald padc = ret >> 6;
633017d90eSPeter Meerwald
64c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_TADC);
653017d90eSPeter Meerwald if (ret < 0)
663017d90eSPeter Meerwald goto done;
673017d90eSPeter Meerwald tadc = ret >> 6;
683017d90eSPeter Meerwald
693017d90eSPeter Meerwald /* see Freescale AN3785 */
703017d90eSPeter Meerwald a1 = data->b1 + ((data->c12 * tadc) >> 11);
713017d90eSPeter Meerwald y1 = (data->a0 << 10) + a1 * padc;
723017d90eSPeter Meerwald
733017d90eSPeter Meerwald /* compensated pressure with 4 fractional bits */
743017d90eSPeter Meerwald pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9;
753017d90eSPeter Meerwald
763017d90eSPeter Meerwald kpa = pcomp * (115 - 50) / 1023 + (50 << 4);
773017d90eSPeter Meerwald *val = kpa >> 4;
783017d90eSPeter Meerwald *val2 = (kpa & 15) * (1000000 >> 4);
793017d90eSPeter Meerwald done:
803017d90eSPeter Meerwald mutex_unlock(&data->lock);
813017d90eSPeter Meerwald return ret;
823017d90eSPeter Meerwald }
833017d90eSPeter Meerwald
mpl115_read_temp(struct mpl115_data * data)843017d90eSPeter Meerwald static int mpl115_read_temp(struct mpl115_data *data)
853017d90eSPeter Meerwald {
863017d90eSPeter Meerwald int ret;
873017d90eSPeter Meerwald
883017d90eSPeter Meerwald mutex_lock(&data->lock);
893017d90eSPeter Meerwald ret = mpl115_request(data);
903017d90eSPeter Meerwald if (ret < 0)
913017d90eSPeter Meerwald goto done;
92c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_TADC);
933017d90eSPeter Meerwald done:
943017d90eSPeter Meerwald mutex_unlock(&data->lock);
953017d90eSPeter Meerwald return ret;
963017d90eSPeter Meerwald }
973017d90eSPeter Meerwald
mpl115_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)983017d90eSPeter Meerwald static int mpl115_read_raw(struct iio_dev *indio_dev,
993017d90eSPeter Meerwald struct iio_chan_spec const *chan,
1003017d90eSPeter Meerwald int *val, int *val2, long mask)
1013017d90eSPeter Meerwald {
1023017d90eSPeter Meerwald struct mpl115_data *data = iio_priv(indio_dev);
1033017d90eSPeter Meerwald int ret;
1043017d90eSPeter Meerwald
1053017d90eSPeter Meerwald switch (mask) {
1063017d90eSPeter Meerwald case IIO_CHAN_INFO_PROCESSED:
107*0c3a3335SRajat Khandelwal pm_runtime_get_sync(data->dev);
1083017d90eSPeter Meerwald ret = mpl115_comp_pressure(data, val, val2);
1093017d90eSPeter Meerwald if (ret < 0)
1103017d90eSPeter Meerwald return ret;
111*0c3a3335SRajat Khandelwal pm_runtime_mark_last_busy(data->dev);
112*0c3a3335SRajat Khandelwal pm_runtime_put_autosuspend(data->dev);
113*0c3a3335SRajat Khandelwal
1143017d90eSPeter Meerwald return IIO_VAL_INT_PLUS_MICRO;
1153017d90eSPeter Meerwald case IIO_CHAN_INFO_RAW:
116*0c3a3335SRajat Khandelwal pm_runtime_get_sync(data->dev);
1173017d90eSPeter Meerwald /* temperature -5.35 C / LSB, 472 LSB is 25 C */
1183017d90eSPeter Meerwald ret = mpl115_read_temp(data);
1193017d90eSPeter Meerwald if (ret < 0)
1203017d90eSPeter Meerwald return ret;
121*0c3a3335SRajat Khandelwal pm_runtime_mark_last_busy(data->dev);
122*0c3a3335SRajat Khandelwal pm_runtime_put_autosuspend(data->dev);
1233017d90eSPeter Meerwald *val = ret >> 6;
124*0c3a3335SRajat Khandelwal
1253017d90eSPeter Meerwald return IIO_VAL_INT;
1263017d90eSPeter Meerwald case IIO_CHAN_INFO_OFFSET:
127431386e7SAkinobu Mita *val = -605;
1283017d90eSPeter Meerwald *val2 = 750000;
1293017d90eSPeter Meerwald return IIO_VAL_INT_PLUS_MICRO;
1303017d90eSPeter Meerwald case IIO_CHAN_INFO_SCALE:
1313017d90eSPeter Meerwald *val = -186;
1323017d90eSPeter Meerwald *val2 = 915888;
1333017d90eSPeter Meerwald return IIO_VAL_INT_PLUS_MICRO;
1343017d90eSPeter Meerwald }
1353017d90eSPeter Meerwald return -EINVAL;
1363017d90eSPeter Meerwald }
1373017d90eSPeter Meerwald
1383017d90eSPeter Meerwald static const struct iio_chan_spec mpl115_channels[] = {
1393017d90eSPeter Meerwald {
1403017d90eSPeter Meerwald .type = IIO_PRESSURE,
1413017d90eSPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
1423017d90eSPeter Meerwald },
1433017d90eSPeter Meerwald {
1443017d90eSPeter Meerwald .type = IIO_TEMP,
1453017d90eSPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1466a6e1d56SPeter Rosin .info_mask_shared_by_type =
1473017d90eSPeter Meerwald BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
1483017d90eSPeter Meerwald },
1493017d90eSPeter Meerwald };
1503017d90eSPeter Meerwald
1513017d90eSPeter Meerwald static const struct iio_info mpl115_info = {
1523017d90eSPeter Meerwald .read_raw = &mpl115_read_raw,
1533017d90eSPeter Meerwald };
1543017d90eSPeter Meerwald
mpl115_probe(struct device * dev,const char * name,const struct mpl115_ops * ops)155c984b9cbSAkinobu Mita int mpl115_probe(struct device *dev, const char *name,
156c984b9cbSAkinobu Mita const struct mpl115_ops *ops)
1573017d90eSPeter Meerwald {
1583017d90eSPeter Meerwald struct mpl115_data *data;
1593017d90eSPeter Meerwald struct iio_dev *indio_dev;
1603017d90eSPeter Meerwald int ret;
1613017d90eSPeter Meerwald
162c984b9cbSAkinobu Mita indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
1633017d90eSPeter Meerwald if (!indio_dev)
1643017d90eSPeter Meerwald return -ENOMEM;
1653017d90eSPeter Meerwald
1663017d90eSPeter Meerwald data = iio_priv(indio_dev);
167c984b9cbSAkinobu Mita data->dev = dev;
168c984b9cbSAkinobu Mita data->ops = ops;
1693017d90eSPeter Meerwald mutex_init(&data->lock);
1703017d90eSPeter Meerwald
1713017d90eSPeter Meerwald indio_dev->info = &mpl115_info;
172c984b9cbSAkinobu Mita indio_dev->name = name;
1733017d90eSPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE;
1743017d90eSPeter Meerwald indio_dev->channels = mpl115_channels;
1753017d90eSPeter Meerwald indio_dev->num_channels = ARRAY_SIZE(mpl115_channels);
1763017d90eSPeter Meerwald
177c984b9cbSAkinobu Mita ret = data->ops->init(data->dev);
178c984b9cbSAkinobu Mita if (ret)
179c984b9cbSAkinobu Mita return ret;
180c984b9cbSAkinobu Mita
181*0c3a3335SRajat Khandelwal dev_set_drvdata(dev, indio_dev);
182*0c3a3335SRajat Khandelwal
183c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_A0);
1843017d90eSPeter Meerwald if (ret < 0)
1853017d90eSPeter Meerwald return ret;
1863017d90eSPeter Meerwald data->a0 = ret;
187c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_B1);
1883017d90eSPeter Meerwald if (ret < 0)
1893017d90eSPeter Meerwald return ret;
1903017d90eSPeter Meerwald data->b1 = ret;
191c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_B2);
1923017d90eSPeter Meerwald if (ret < 0)
1933017d90eSPeter Meerwald return ret;
1943017d90eSPeter Meerwald data->b2 = ret;
195c984b9cbSAkinobu Mita ret = data->ops->read(data->dev, MPL115_C12);
1963017d90eSPeter Meerwald if (ret < 0)
1973017d90eSPeter Meerwald return ret;
1983017d90eSPeter Meerwald data->c12 = ret;
1993017d90eSPeter Meerwald
200*0c3a3335SRajat Khandelwal data->shutdown = devm_gpiod_get_optional(dev, "shutdown",
201*0c3a3335SRajat Khandelwal GPIOD_OUT_LOW);
202*0c3a3335SRajat Khandelwal if (IS_ERR(data->shutdown))
203*0c3a3335SRajat Khandelwal return dev_err_probe(dev, PTR_ERR(data->shutdown),
204*0c3a3335SRajat Khandelwal "cannot get shutdown gpio\n");
205*0c3a3335SRajat Khandelwal
206*0c3a3335SRajat Khandelwal if (data->shutdown) {
207*0c3a3335SRajat Khandelwal /* Enable runtime PM */
208*0c3a3335SRajat Khandelwal pm_runtime_get_noresume(dev);
209*0c3a3335SRajat Khandelwal pm_runtime_set_active(dev);
210*0c3a3335SRajat Khandelwal pm_runtime_enable(dev);
211*0c3a3335SRajat Khandelwal
212*0c3a3335SRajat Khandelwal /*
213*0c3a3335SRajat Khandelwal * As the device takes 3 ms to come up with a fresh
214*0c3a3335SRajat Khandelwal * reading after power-on and 5 ms to actually power-on,
215*0c3a3335SRajat Khandelwal * do not shut it down unnecessarily. Set autosuspend to
216*0c3a3335SRajat Khandelwal * 2000 ms.
217*0c3a3335SRajat Khandelwal */
218*0c3a3335SRajat Khandelwal pm_runtime_set_autosuspend_delay(dev, 2000);
219*0c3a3335SRajat Khandelwal pm_runtime_use_autosuspend(dev);
220*0c3a3335SRajat Khandelwal pm_runtime_put(dev);
221*0c3a3335SRajat Khandelwal
222*0c3a3335SRajat Khandelwal dev_dbg(dev, "low-power mode enabled");
223*0c3a3335SRajat Khandelwal } else
224*0c3a3335SRajat Khandelwal dev_dbg(dev, "low-power mode disabled");
225*0c3a3335SRajat Khandelwal
226c984b9cbSAkinobu Mita return devm_iio_device_register(dev, indio_dev);
2273017d90eSPeter Meerwald }
228c7c848b0SJonathan Cameron EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115);
2293017d90eSPeter Meerwald
mpl115_runtime_suspend(struct device * dev)230*0c3a3335SRajat Khandelwal static int mpl115_runtime_suspend(struct device *dev)
231*0c3a3335SRajat Khandelwal {
232*0c3a3335SRajat Khandelwal struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
233*0c3a3335SRajat Khandelwal
234*0c3a3335SRajat Khandelwal gpiod_set_value(data->shutdown, 1);
235*0c3a3335SRajat Khandelwal
236*0c3a3335SRajat Khandelwal return 0;
237*0c3a3335SRajat Khandelwal }
238*0c3a3335SRajat Khandelwal
mpl115_runtime_resume(struct device * dev)239*0c3a3335SRajat Khandelwal static int mpl115_runtime_resume(struct device *dev)
240*0c3a3335SRajat Khandelwal {
241*0c3a3335SRajat Khandelwal struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
242*0c3a3335SRajat Khandelwal
243*0c3a3335SRajat Khandelwal gpiod_set_value(data->shutdown, 0);
244*0c3a3335SRajat Khandelwal usleep_range(5000, 6000);
245*0c3a3335SRajat Khandelwal
246*0c3a3335SRajat Khandelwal return 0;
247*0c3a3335SRajat Khandelwal }
248*0c3a3335SRajat Khandelwal
249*0c3a3335SRajat Khandelwal EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend,
250*0c3a3335SRajat Khandelwal mpl115_runtime_resume, NULL, IIO_MPL115);
251*0c3a3335SRajat Khandelwal
2523017d90eSPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
2533017d90eSPeter Meerwald MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
2543017d90eSPeter Meerwald MODULE_LICENSE("GPL");
255