brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 02ea38c Raw
255 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mpl115.c - Support for Freescale MPL115A pressure/temperature sensor4 *5 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>6 *7 * TODO: synchronization with system suspend8 */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 25struct 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 35static 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 47static 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);79done:80	mutex_unlock(&data->lock);81	return ret;82}83 84static 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);93done:94	mutex_unlock(&data->lock);95	return ret;96}97 98static 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 138static 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 151static const struct iio_info mpl115_info = {152	.read_raw = &mpl115_read_raw,153};154 155int 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 fresh214		 * reading after power-on and 5 ms to actually power-on,215		 * do not shut it down unnecessarily. Set autosuspend to216		 * 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	} else224		dev_dbg(dev, "low-power mode disabled");225 226	return devm_iio_device_register(dev, indio_dev);227}228EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115);229 230static 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 239static 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 249EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend,250			  mpl115_runtime_resume, NULL, IIO_MPL115);251 252MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");253MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");254MODULE_LICENSE("GPL");255