xref: /openbmc/linux/drivers/iio/pressure/ms5611_spi.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
16cfdb150STomasz Duszynski // SPDX-License-Identifier: GPL-2.0
2c0644160STomasz Duszynski /*
3c0644160STomasz Duszynski  * MS5611 pressure and temperature sensor driver (SPI bus)
4c0644160STomasz Duszynski  *
5c0644160STomasz Duszynski  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6c0644160STomasz Duszynski  *
7c0644160STomasz Duszynski  */
8c0644160STomasz Duszynski 
9c0644160STomasz Duszynski #include <linux/delay.h>
10c0644160STomasz Duszynski #include <linux/module.h>
11c0644160STomasz Duszynski #include <linux/spi/spi.h>
120e624706SJonathan Cameron #include <linux/mod_devicetable.h>
13c0644160STomasz Duszynski 
1400d5e7b2SAndy Shevchenko #include <asm/unaligned.h>
1500d5e7b2SAndy Shevchenko 
16c0644160STomasz Duszynski #include "ms5611.h"
17c0644160STomasz Duszynski 
ms5611_spi_reset(struct ms5611_state * st)18dc19fa63SLars-Peter Clausen static int ms5611_spi_reset(struct ms5611_state *st)
19c0644160STomasz Duszynski {
20c0644160STomasz Duszynski 	u8 cmd = MS5611_RESET;
21c0644160STomasz Duszynski 
22c0644160STomasz Duszynski 	return spi_write_then_read(st->client, &cmd, 1, NULL, 0);
23c0644160STomasz Duszynski }
24c0644160STomasz Duszynski 
ms5611_spi_read_prom_word(struct ms5611_state * st,int index,u16 * word)25dc19fa63SLars-Peter Clausen static int ms5611_spi_read_prom_word(struct ms5611_state *st, int index,
26dc19fa63SLars-Peter Clausen 				     u16 *word)
27c0644160STomasz Duszynski {
28c0644160STomasz Duszynski 	int ret;
29c0644160STomasz Duszynski 
30c0644160STomasz Duszynski 	ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1));
31c0644160STomasz Duszynski 	if (ret < 0)
32c0644160STomasz Duszynski 		return ret;
33c0644160STomasz Duszynski 
34c0644160STomasz Duszynski 	*word = ret;
35c0644160STomasz Duszynski 
36c0644160STomasz Duszynski 	return 0;
37c0644160STomasz Duszynski }
38c0644160STomasz Duszynski 
ms5611_spi_read_adc(struct ms5611_state * st,s32 * val)39dc19fa63SLars-Peter Clausen static int ms5611_spi_read_adc(struct ms5611_state *st, s32 *val)
40c0644160STomasz Duszynski {
41c0644160STomasz Duszynski 	int ret;
42c0644160STomasz Duszynski 	u8 buf[3] = { MS5611_READ_ADC };
43c0644160STomasz Duszynski 
44c0644160STomasz Duszynski 	ret = spi_write_then_read(st->client, buf, 1, buf, 3);
45c0644160STomasz Duszynski 	if (ret < 0)
46c0644160STomasz Duszynski 		return ret;
47c0644160STomasz Duszynski 
4800d5e7b2SAndy Shevchenko 	*val = get_unaligned_be24(&buf[0]);
49c0644160STomasz Duszynski 
50c0644160STomasz Duszynski 	return 0;
51c0644160STomasz Duszynski }
52c0644160STomasz Duszynski 
ms5611_spi_read_adc_temp_and_pressure(struct ms5611_state * st,s32 * temp,s32 * pressure)53dc19fa63SLars-Peter Clausen static int ms5611_spi_read_adc_temp_and_pressure(struct ms5611_state *st,
54c0644160STomasz Duszynski 						 s32 *temp, s32 *pressure)
55c0644160STomasz Duszynski {
56c0644160STomasz Duszynski 	int ret;
57033691a9SGregor Boirie 	const struct ms5611_osr *osr = st->temp_osr;
58c0644160STomasz Duszynski 
59033691a9SGregor Boirie 	/*
60033691a9SGregor Boirie 	 * Warning: &osr->cmd MUST be aligned on a word boundary since used as
61033691a9SGregor Boirie 	 * 2nd argument (void*) of spi_write_then_read.
62033691a9SGregor Boirie 	 */
63033691a9SGregor Boirie 	ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
64c0644160STomasz Duszynski 	if (ret < 0)
65c0644160STomasz Duszynski 		return ret;
66c0644160STomasz Duszynski 
67033691a9SGregor Boirie 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
68dc19fa63SLars-Peter Clausen 	ret = ms5611_spi_read_adc(st, temp);
69c0644160STomasz Duszynski 	if (ret < 0)
70c0644160STomasz Duszynski 		return ret;
71c0644160STomasz Duszynski 
72033691a9SGregor Boirie 	osr = st->pressure_osr;
73033691a9SGregor Boirie 	ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
74c0644160STomasz Duszynski 	if (ret < 0)
75c0644160STomasz Duszynski 		return ret;
76c0644160STomasz Duszynski 
77033691a9SGregor Boirie 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
78dc19fa63SLars-Peter Clausen 	return ms5611_spi_read_adc(st, pressure);
79c0644160STomasz Duszynski }
80c0644160STomasz Duszynski 
ms5611_spi_probe(struct spi_device * spi)81c0644160STomasz Duszynski static int ms5611_spi_probe(struct spi_device *spi)
82c0644160STomasz Duszynski {
83c0644160STomasz Duszynski 	int ret;
84c0644160STomasz Duszynski 	struct ms5611_state *st;
85c0644160STomasz Duszynski 	struct iio_dev *indio_dev;
86c0644160STomasz Duszynski 
87c0644160STomasz Duszynski 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
88c0644160STomasz Duszynski 	if (!indio_dev)
89c0644160STomasz Duszynski 		return -ENOMEM;
90c0644160STomasz Duszynski 
91713bbb4eSDaniel Baluta 	spi_set_drvdata(spi, indio_dev);
92713bbb4eSDaniel Baluta 
93c0644160STomasz Duszynski 	spi->mode = SPI_MODE_0;
94*741cec30SMitja Spes 	spi->max_speed_hz = min(spi->max_speed_hz, 20000000U);
95c0644160STomasz Duszynski 	spi->bits_per_word = 8;
96c0644160STomasz Duszynski 	ret = spi_setup(spi);
97c0644160STomasz Duszynski 	if (ret < 0)
98c0644160STomasz Duszynski 		return ret;
99c0644160STomasz Duszynski 
100c0644160STomasz Duszynski 	st = iio_priv(indio_dev);
101c0644160STomasz Duszynski 	st->reset = ms5611_spi_reset;
102c0644160STomasz Duszynski 	st->read_prom_word = ms5611_spi_read_prom_word;
103c0644160STomasz Duszynski 	st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure;
104c0644160STomasz Duszynski 	st->client = spi;
105c0644160STomasz Duszynski 
106eac635ebSGrégor Boirie 	return ms5611_probe(indio_dev, &spi->dev, spi_get_device_id(spi)->name,
1079690d81aSTomasz Duszynski 			    spi_get_device_id(spi)->driver_data);
108c0644160STomasz Duszynski }
109c0644160STomasz Duszynski 
1107a948c5eSGrégor Boirie static const struct of_device_id ms5611_spi_matches[] = {
1117a948c5eSGrégor Boirie 	{ .compatible = "meas,ms5611" },
1127a948c5eSGrégor Boirie 	{ .compatible = "meas,ms5607" },
1137a948c5eSGrégor Boirie 	{ }
1147a948c5eSGrégor Boirie };
1157a948c5eSGrégor Boirie MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
1167a948c5eSGrégor Boirie 
117c0644160STomasz Duszynski static const struct spi_device_id ms5611_id[] = {
1189690d81aSTomasz Duszynski 	{ "ms5611", MS5611 },
1199690d81aSTomasz Duszynski 	{ "ms5607", MS5607 },
120c0644160STomasz Duszynski 	{ }
121c0644160STomasz Duszynski };
122c0644160STomasz Duszynski MODULE_DEVICE_TABLE(spi, ms5611_id);
123c0644160STomasz Duszynski 
124c0644160STomasz Duszynski static struct spi_driver ms5611_driver = {
125c0644160STomasz Duszynski 	.driver = {
126c0644160STomasz Duszynski 		.name = "ms5611",
1270e624706SJonathan Cameron 		.of_match_table = ms5611_spi_matches
128c0644160STomasz Duszynski 	},
129c0644160STomasz Duszynski 	.id_table = ms5611_id,
130c0644160STomasz Duszynski 	.probe = ms5611_spi_probe,
131c0644160STomasz Duszynski };
132c0644160STomasz Duszynski module_spi_driver(ms5611_driver);
133c0644160STomasz Duszynski 
134c0644160STomasz Duszynski MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
135c0644160STomasz Duszynski MODULE_DESCRIPTION("MS5611 spi driver");
136c0644160STomasz Duszynski MODULE_LICENSE("GPL v2");
1371980d4a1SJonathan Cameron MODULE_IMPORT_NS(IIO_MS5611);
138