brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 71ded2e Raw
347 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mpl3115.c - Support for Freescale MPL3115A2 pressure/temperature sensor4 *5 * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net>6 *7 * (7-bit I2C slave address 0x60)8 *9 * TODO: FIFO buffer, altimeter mode, oversampling, continuous mode,10 * interrupts, user offset correction, raw mode11 */12 13#include <linux/module.h>14#include <linux/i2c.h>15#include <linux/iio/iio.h>16#include <linux/iio/sysfs.h>17#include <linux/iio/trigger_consumer.h>18#include <linux/iio/buffer.h>19#include <linux/iio/triggered_buffer.h>20#include <linux/delay.h>21 22#define MPL3115_STATUS 0x0023#define MPL3115_OUT_PRESS 0x01 /* MSB first, 20 bit */24#define MPL3115_OUT_TEMP 0x04 /* MSB first, 12 bit */25#define MPL3115_WHO_AM_I 0x0c26#define MPL3115_CTRL_REG1 0x2627 28#define MPL3115_DEVICE_ID 0xc429 30#define MPL3115_STATUS_PRESS_RDY BIT(2)31#define MPL3115_STATUS_TEMP_RDY BIT(1)32 33#define MPL3115_CTRL_RESET BIT(2) /* software reset */34#define MPL3115_CTRL_OST BIT(1) /* initiate measurement */35#define MPL3115_CTRL_ACTIVE BIT(0) /* continuous measurement */36#define MPL3115_CTRL_OS_258MS (BIT(5) | BIT(4)) /* 64x oversampling */37 38struct mpl3115_data {39	struct i2c_client *client;40	struct mutex lock;41	u8 ctrl_reg1;42};43 44static int mpl3115_request(struct mpl3115_data *data)45{46	int ret, tries = 15;47 48	/* trigger measurement */49	ret = i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1,50		data->ctrl_reg1 | MPL3115_CTRL_OST);51	if (ret < 0)52		return ret;53 54	while (tries-- > 0) {55		ret = i2c_smbus_read_byte_data(data->client, MPL3115_CTRL_REG1);56		if (ret < 0)57			return ret;58		/* wait for data ready, i.e. OST cleared */59		if (!(ret & MPL3115_CTRL_OST))60			break;61		msleep(20);62	}63 64	if (tries < 0) {65		dev_err(&data->client->dev, "data not ready\n");66		return -EIO;67	}68 69	return 0;70}71 72static int mpl3115_read_raw(struct iio_dev *indio_dev,73			    struct iio_chan_spec const *chan,74			    int *val, int *val2, long mask)75{76	struct mpl3115_data *data = iio_priv(indio_dev);77	int ret;78 79	switch (mask) {80	case IIO_CHAN_INFO_RAW:81		ret = iio_device_claim_direct_mode(indio_dev);82		if (ret)83			return ret;84 85		switch (chan->type) {86		case IIO_PRESSURE: { /* in 0.25 pascal / LSB */87			__be32 tmp = 0;88 89			mutex_lock(&data->lock);90			ret = mpl3115_request(data);91			if (ret < 0) {92				mutex_unlock(&data->lock);93				break;94			}95			ret = i2c_smbus_read_i2c_block_data(data->client,96				MPL3115_OUT_PRESS, 3, (u8 *) &tmp);97			mutex_unlock(&data->lock);98			if (ret < 0)99				break;100			*val = be32_to_cpu(tmp) >> chan->scan_type.shift;101			ret = IIO_VAL_INT;102			break;103		}104		case IIO_TEMP: { /* in 0.0625 celsius / LSB */105			__be16 tmp;106 107			mutex_lock(&data->lock);108			ret = mpl3115_request(data);109			if (ret < 0) {110				mutex_unlock(&data->lock);111				break;112			}113			ret = i2c_smbus_read_i2c_block_data(data->client,114				MPL3115_OUT_TEMP, 2, (u8 *) &tmp);115			mutex_unlock(&data->lock);116			if (ret < 0)117				break;118			*val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift,119					     chan->scan_type.realbits - 1);120			ret = IIO_VAL_INT;121			break;122		}123		default:124			ret = -EINVAL;125			break;126		}127 128		iio_device_release_direct_mode(indio_dev);129		return ret;130 131	case IIO_CHAN_INFO_SCALE:132		switch (chan->type) {133		case IIO_PRESSURE:134			*val = 0;135			*val2 = 250; /* want kilopascal */136			return IIO_VAL_INT_PLUS_MICRO;137		case IIO_TEMP:138			*val = 0;139			*val2 = 62500;140			return IIO_VAL_INT_PLUS_MICRO;141		default:142			return -EINVAL;143		}144	}145	return -EINVAL;146}147 148static irqreturn_t mpl3115_trigger_handler(int irq, void *p)149{150	struct iio_poll_func *pf = p;151	struct iio_dev *indio_dev = pf->indio_dev;152	struct mpl3115_data *data = iio_priv(indio_dev);153	/*154	 * 32-bit channel + 16-bit channel + padding + ts155	 * Note that it is possible for only one of the first 2156	 * channels to be enabled. If that happens, the first element157	 * of the buffer may be either 16 or 32-bits.  As such we cannot158	 * use a simple structure definition to express this data layout.159	 */160	u8 buffer[16] __aligned(8);161	int ret, pos = 0;162 163	mutex_lock(&data->lock);164	ret = mpl3115_request(data);165	if (ret < 0) {166		mutex_unlock(&data->lock);167		goto done;168	}169 170	memset(buffer, 0, sizeof(buffer));171	if (test_bit(0, indio_dev->active_scan_mask)) {172		ret = i2c_smbus_read_i2c_block_data(data->client,173			MPL3115_OUT_PRESS, 3, &buffer[pos]);174		if (ret < 0) {175			mutex_unlock(&data->lock);176			goto done;177		}178		pos += 4;179	}180 181	if (test_bit(1, indio_dev->active_scan_mask)) {182		ret = i2c_smbus_read_i2c_block_data(data->client,183			MPL3115_OUT_TEMP, 2, &buffer[pos]);184		if (ret < 0) {185			mutex_unlock(&data->lock);186			goto done;187		}188	}189	mutex_unlock(&data->lock);190 191	iio_push_to_buffers_with_timestamp(indio_dev, buffer,192		iio_get_time_ns(indio_dev));193 194done:195	iio_trigger_notify_done(indio_dev->trig);196	return IRQ_HANDLED;197}198 199static const struct iio_chan_spec mpl3115_channels[] = {200	{201		.type = IIO_PRESSURE,202		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),203		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),204		.scan_index = 0,205		.scan_type = {206			.sign = 'u',207			.realbits = 20,208			.storagebits = 32,209			.shift = 12,210			.endianness = IIO_BE,211		}212	},213	{214		.type = IIO_TEMP,215		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),216		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),217		.scan_index = 1,218		.scan_type = {219			.sign = 's',220			.realbits = 12,221			.storagebits = 16,222			.shift = 4,223			.endianness = IIO_BE,224		}225	},226	IIO_CHAN_SOFT_TIMESTAMP(2),227};228 229static const struct iio_info mpl3115_info = {230	.read_raw = &mpl3115_read_raw,231};232 233static int mpl3115_probe(struct i2c_client *client)234{235	const struct i2c_device_id *id = i2c_client_get_device_id(client);236	struct mpl3115_data *data;237	struct iio_dev *indio_dev;238	int ret;239 240	ret = i2c_smbus_read_byte_data(client, MPL3115_WHO_AM_I);241	if (ret < 0)242		return ret;243	if (ret != MPL3115_DEVICE_ID)244		return -ENODEV;245 246	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));247	if (!indio_dev)248		return -ENOMEM;249 250	data = iio_priv(indio_dev);251	data->client = client;252	mutex_init(&data->lock);253 254	i2c_set_clientdata(client, indio_dev);255	indio_dev->info = &mpl3115_info;256	indio_dev->name = id->name;257	indio_dev->modes = INDIO_DIRECT_MODE;258	indio_dev->channels = mpl3115_channels;259	indio_dev->num_channels = ARRAY_SIZE(mpl3115_channels);260 261	/* software reset, I2C transfer is aborted (fails) */262	i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1,263		MPL3115_CTRL_RESET);264	msleep(50);265 266	data->ctrl_reg1 = MPL3115_CTRL_OS_258MS;267	ret = i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1,268		data->ctrl_reg1);269	if (ret < 0)270		return ret;271 272	ret = iio_triggered_buffer_setup(indio_dev, NULL,273		mpl3115_trigger_handler, NULL);274	if (ret < 0)275		return ret;276 277	ret = iio_device_register(indio_dev);278	if (ret < 0)279		goto buffer_cleanup;280	return 0;281 282buffer_cleanup:283	iio_triggered_buffer_cleanup(indio_dev);284	return ret;285}286 287static int mpl3115_standby(struct mpl3115_data *data)288{289	return i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1,290		data->ctrl_reg1 & ~MPL3115_CTRL_ACTIVE);291}292 293static void mpl3115_remove(struct i2c_client *client)294{295	struct iio_dev *indio_dev = i2c_get_clientdata(client);296 297	iio_device_unregister(indio_dev);298	iio_triggered_buffer_cleanup(indio_dev);299	mpl3115_standby(iio_priv(indio_dev));300}301 302static int mpl3115_suspend(struct device *dev)303{304	return mpl3115_standby(iio_priv(i2c_get_clientdata(305		to_i2c_client(dev))));306}307 308static int mpl3115_resume(struct device *dev)309{310	struct mpl3115_data *data = iio_priv(i2c_get_clientdata(311		to_i2c_client(dev)));312 313	return i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1,314		data->ctrl_reg1);315}316 317static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend,318				mpl3115_resume);319 320static const struct i2c_device_id mpl3115_id[] = {321	{ "mpl3115" },322	{ }323};324MODULE_DEVICE_TABLE(i2c, mpl3115_id);325 326static const struct of_device_id mpl3115_of_match[] = {327	{ .compatible = "fsl,mpl3115" },328	{ }329};330MODULE_DEVICE_TABLE(of, mpl3115_of_match);331 332static struct i2c_driver mpl3115_driver = {333	.driver = {334		.name	= "mpl3115",335		.of_match_table = mpl3115_of_match,336		.pm	= pm_sleep_ptr(&mpl3115_pm_ops),337	},338	.probe = mpl3115_probe,339	.remove = mpl3115_remove,340	.id_table = mpl3115_id,341};342module_i2c_driver(mpl3115_driver);343 344MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");345MODULE_DESCRIPTION("Freescale MPL3115 pressure/temperature driver");346MODULE_LICENSE("GPL");347