| // SPDX-License-Identifier: GPL-2.0-only | 
 | /* | 
 |  * Freescale MPL115A1 pressure/temperature sensor | 
 |  * | 
 |  * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com> | 
 |  * | 
 |  * Datasheet: http://www.nxp.com/files/sensors/doc/data_sheet/MPL115A1.pdf | 
 |  */ | 
 |  | 
 | #include <linux/module.h> | 
 | #include <linux/spi/spi.h> | 
 |  | 
 | #include "mpl115.h" | 
 |  | 
 | #define MPL115_SPI_WRITE(address)	((address) << 1) | 
 | #define MPL115_SPI_READ(address)	(0x80 | (address) << 1) | 
 |  | 
 | struct mpl115_spi_buf { | 
 | 	u8 tx[4]; | 
 | 	u8 rx[4]; | 
 | }; | 
 |  | 
 | static int mpl115_spi_init(struct device *dev) | 
 | { | 
 | 	struct spi_device *spi = to_spi_device(dev); | 
 | 	struct mpl115_spi_buf *buf; | 
 |  | 
 | 	buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL); | 
 | 	if (!buf) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	spi_set_drvdata(spi, buf); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int mpl115_spi_read(struct device *dev, u8 address) | 
 | { | 
 | 	struct spi_device *spi = to_spi_device(dev); | 
 | 	struct mpl115_spi_buf *buf = spi_get_drvdata(spi); | 
 | 	struct spi_transfer xfer = { | 
 | 		.tx_buf = buf->tx, | 
 | 		.rx_buf = buf->rx, | 
 | 		.len = 4, | 
 | 	}; | 
 | 	int ret; | 
 |  | 
 | 	buf->tx[0] = MPL115_SPI_READ(address); | 
 | 	buf->tx[2] = MPL115_SPI_READ(address + 1); | 
 |  | 
 | 	ret = spi_sync_transfer(spi, &xfer, 1); | 
 | 	if (ret) | 
 | 		return ret; | 
 |  | 
 | 	return (buf->rx[1] << 8) | buf->rx[3]; | 
 | } | 
 |  | 
 | static int mpl115_spi_write(struct device *dev, u8 address, u8 value) | 
 | { | 
 | 	struct spi_device *spi = to_spi_device(dev); | 
 | 	struct mpl115_spi_buf *buf = spi_get_drvdata(spi); | 
 | 	struct spi_transfer xfer = { | 
 | 		.tx_buf = buf->tx, | 
 | 		.len = 2, | 
 | 	}; | 
 |  | 
 | 	buf->tx[0] = MPL115_SPI_WRITE(address); | 
 | 	buf->tx[1] = value; | 
 |  | 
 | 	return spi_sync_transfer(spi, &xfer, 1); | 
 | } | 
 |  | 
 | static const struct mpl115_ops mpl115_spi_ops = { | 
 | 	.init = mpl115_spi_init, | 
 | 	.read = mpl115_spi_read, | 
 | 	.write = mpl115_spi_write, | 
 | }; | 
 |  | 
 | static int mpl115_spi_probe(struct spi_device *spi) | 
 | { | 
 | 	const struct spi_device_id *id = spi_get_device_id(spi); | 
 |  | 
 | 	return mpl115_probe(&spi->dev, id->name, &mpl115_spi_ops); | 
 | } | 
 |  | 
 | static const struct spi_device_id mpl115_spi_ids[] = { | 
 | 	{ "mpl115", 0 }, | 
 | 	{} | 
 | }; | 
 | MODULE_DEVICE_TABLE(spi, mpl115_spi_ids); | 
 |  | 
 | static struct spi_driver mpl115_spi_driver = { | 
 | 	.driver = { | 
 | 		.name   = "mpl115", | 
 | 	}, | 
 | 	.probe = mpl115_spi_probe, | 
 | 	.id_table = mpl115_spi_ids, | 
 | }; | 
 | module_spi_driver(mpl115_spi_driver); | 
 |  | 
 | MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>"); | 
 | MODULE_DESCRIPTION("Freescale MPL115A1 pressure/temperature driver"); | 
 | MODULE_LICENSE("GPL"); |