xref: /openbmc/linux/drivers/iio/pressure/mpl115.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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