xref: /linux/drivers/iio/pressure/ms5611_i2c.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
16cfdb150STomasz Duszynski // SPDX-License-Identifier: GPL-2.0
2c0644160STomasz Duszynski /*
3c0644160STomasz Duszynski  * MS5611 pressure and temperature sensor driver (I2C bus)
4c0644160STomasz Duszynski  *
5c0644160STomasz Duszynski  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6c0644160STomasz Duszynski  *
7c0644160STomasz Duszynski  * 7-bit I2C slave addresses:
8c0644160STomasz Duszynski  *
9c0644160STomasz Duszynski  * 0x77 (CSB pin low)
10c0644160STomasz Duszynski  * 0x76 (CSB pin high)
11c0644160STomasz Duszynski  *
12c0644160STomasz Duszynski  */
13c0644160STomasz Duszynski 
14c0644160STomasz Duszynski #include <linux/delay.h>
15c0644160STomasz Duszynski #include <linux/i2c.h>
16c0644160STomasz Duszynski #include <linux/module.h>
170e624706SJonathan Cameron #include <linux/mod_devicetable.h>
18c0644160STomasz Duszynski 
1900d5e7b2SAndy Shevchenko #include <asm/unaligned.h>
2000d5e7b2SAndy Shevchenko 
21c0644160STomasz Duszynski #include "ms5611.h"
22c0644160STomasz Duszynski 
ms5611_i2c_reset(struct ms5611_state * st)23dc19fa63SLars-Peter Clausen static int ms5611_i2c_reset(struct ms5611_state *st)
24c0644160STomasz Duszynski {
25c0644160STomasz Duszynski 	return i2c_smbus_write_byte(st->client, MS5611_RESET);
26c0644160STomasz Duszynski }
27c0644160STomasz Duszynski 
ms5611_i2c_read_prom_word(struct ms5611_state * st,int index,u16 * word)28dc19fa63SLars-Peter Clausen static int ms5611_i2c_read_prom_word(struct ms5611_state *st, int index,
29dc19fa63SLars-Peter Clausen 				     u16 *word)
30c0644160STomasz Duszynski {
31c0644160STomasz Duszynski 	int ret;
32c0644160STomasz Duszynski 
33c0644160STomasz Duszynski 	ret = i2c_smbus_read_word_swapped(st->client,
34c0644160STomasz Duszynski 			MS5611_READ_PROM_WORD + (index << 1));
35c0644160STomasz Duszynski 	if (ret < 0)
36c0644160STomasz Duszynski 		return ret;
37c0644160STomasz Duszynski 
38c0644160STomasz Duszynski 	*word = ret;
39c0644160STomasz Duszynski 
40c0644160STomasz Duszynski 	return 0;
41c0644160STomasz Duszynski }
42c0644160STomasz Duszynski 
ms5611_i2c_read_adc(struct ms5611_state * st,s32 * val)43c0644160STomasz Duszynski static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val)
44c0644160STomasz Duszynski {
45c0644160STomasz Duszynski 	int ret;
46c0644160STomasz Duszynski 	u8 buf[3];
47c0644160STomasz Duszynski 
48c0644160STomasz Duszynski 	ret = i2c_smbus_read_i2c_block_data(st->client, MS5611_READ_ADC,
49c0644160STomasz Duszynski 					    3, buf);
50c0644160STomasz Duszynski 	if (ret < 0)
51c0644160STomasz Duszynski 		return ret;
52c0644160STomasz Duszynski 
5300d5e7b2SAndy Shevchenko 	*val = get_unaligned_be24(&buf[0]);
54c0644160STomasz Duszynski 
55c0644160STomasz Duszynski 	return 0;
56c0644160STomasz Duszynski }
57c0644160STomasz Duszynski 
ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state * st,s32 * temp,s32 * pressure)58dc19fa63SLars-Peter Clausen static int ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state *st,
59c0644160STomasz Duszynski 						 s32 *temp, s32 *pressure)
60c0644160STomasz Duszynski {
61c0644160STomasz Duszynski 	int ret;
62033691a9SGregor Boirie 	const struct ms5611_osr *osr = st->temp_osr;
63c0644160STomasz Duszynski 
64033691a9SGregor Boirie 	ret = i2c_smbus_write_byte(st->client, osr->cmd);
65c0644160STomasz Duszynski 	if (ret < 0)
66c0644160STomasz Duszynski 		return ret;
67c0644160STomasz Duszynski 
68033691a9SGregor Boirie 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
69c0644160STomasz Duszynski 	ret = ms5611_i2c_read_adc(st, temp);
70c0644160STomasz Duszynski 	if (ret < 0)
71c0644160STomasz Duszynski 		return ret;
72c0644160STomasz Duszynski 
73033691a9SGregor Boirie 	osr = st->pressure_osr;
74033691a9SGregor Boirie 	ret = i2c_smbus_write_byte(st->client, osr->cmd);
75c0644160STomasz Duszynski 	if (ret < 0)
76c0644160STomasz Duszynski 		return ret;
77c0644160STomasz Duszynski 
78033691a9SGregor Boirie 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
79c0644160STomasz Duszynski 	return ms5611_i2c_read_adc(st, pressure);
80c0644160STomasz Duszynski }
81c0644160STomasz Duszynski 
ms5611_i2c_probe(struct i2c_client * client)82eba7dcb6SUwe Kleine-König static int ms5611_i2c_probe(struct i2c_client *client)
83c0644160STomasz Duszynski {
84eba7dcb6SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
85c0644160STomasz Duszynski 	struct ms5611_state *st;
86c0644160STomasz Duszynski 	struct iio_dev *indio_dev;
87c0644160STomasz Duszynski 
88c0644160STomasz Duszynski 	if (!i2c_check_functionality(client->adapter,
89c0644160STomasz Duszynski 				     I2C_FUNC_SMBUS_WRITE_BYTE |
90c0644160STomasz Duszynski 				     I2C_FUNC_SMBUS_READ_WORD_DATA |
91c0644160STomasz Duszynski 				     I2C_FUNC_SMBUS_READ_I2C_BLOCK))
92f8d9d3b4SMatt Ranostay 		return -EOPNOTSUPP;
93c0644160STomasz Duszynski 
94c0644160STomasz Duszynski 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
95c0644160STomasz Duszynski 	if (!indio_dev)
96c0644160STomasz Duszynski 		return -ENOMEM;
97c0644160STomasz Duszynski 
98c0644160STomasz Duszynski 	st = iio_priv(indio_dev);
99713bbb4eSDaniel Baluta 	i2c_set_clientdata(client, indio_dev);
100c0644160STomasz Duszynski 	st->reset = ms5611_i2c_reset;
101c0644160STomasz Duszynski 	st->read_prom_word = ms5611_i2c_read_prom_word;
102c0644160STomasz Duszynski 	st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
103c0644160STomasz Duszynski 	st->client = client;
104c0644160STomasz Duszynski 
105eac635ebSGrégor Boirie 	return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data);
106c0644160STomasz Duszynski }
107c0644160STomasz Duszynski 
1087a948c5eSGrégor Boirie static const struct of_device_id ms5611_i2c_matches[] = {
1097a948c5eSGrégor Boirie 	{ .compatible = "meas,ms5611" },
1107a948c5eSGrégor Boirie 	{ .compatible = "meas,ms5607" },
1117a948c5eSGrégor Boirie 	{ }
1127a948c5eSGrégor Boirie };
1137a948c5eSGrégor Boirie MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
1147a948c5eSGrégor Boirie 
115c0644160STomasz Duszynski static const struct i2c_device_id ms5611_id[] = {
1169690d81aSTomasz Duszynski 	{ "ms5611", MS5611 },
1179690d81aSTomasz Duszynski 	{ "ms5607", MS5607 },
118c0644160STomasz Duszynski 	{ }
119c0644160STomasz Duszynski };
120c0644160STomasz Duszynski MODULE_DEVICE_TABLE(i2c, ms5611_id);
121c0644160STomasz Duszynski 
122c0644160STomasz Duszynski static struct i2c_driver ms5611_driver = {
123c0644160STomasz Duszynski 	.driver = {
124c0644160STomasz Duszynski 		.name = "ms5611",
1250e624706SJonathan Cameron 		.of_match_table = ms5611_i2c_matches,
126c0644160STomasz Duszynski 	},
127c0644160STomasz Duszynski 	.id_table = ms5611_id,
128*7cf15f42SUwe Kleine-König 	.probe = ms5611_i2c_probe,
129c0644160STomasz Duszynski };
130c0644160STomasz Duszynski module_i2c_driver(ms5611_driver);
131c0644160STomasz Duszynski 
132c0644160STomasz Duszynski MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
133c0644160STomasz Duszynski MODULE_DESCRIPTION("MS5611 i2c driver");
134c0644160STomasz Duszynski MODULE_LICENSE("GPL v2");
1351980d4a1SJonathan Cameron MODULE_IMPORT_NS(IIO_MS5611);
136