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