diff options
author | Tomasz Duszynski <tduszyns@gmail.com> | 2015-03-14 16:29:31 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-03-15 07:47:46 -0400 |
commit | c0644160a8b5e56b3c3896d77ac3d50d41fa9336 (patch) | |
tree | 9cd8486122d69d05455b20b7e831758e55917514 | |
parent | 8b0544263761adbc7308f6910cdcc0d601782cb1 (diff) |
iio: pressure: add support for MS5611 pressure and temperature sensor
Add support for Measurement Specialities MS5611 pressure
and temperature sensor.
Signed-off-by: Tomasz Duszynski <tduszyns@gmail.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/pressure/Kconfig | 27 | ||||
-rw-r--r-- | drivers/iio/pressure/Makefile | 3 | ||||
-rw-r--r-- | drivers/iio/pressure/ms5611.h | 44 | ||||
-rw-r--r-- | drivers/iio/pressure/ms5611_core.c | 215 | ||||
-rw-r--r-- | drivers/iio/pressure/ms5611_i2c.c | 128 | ||||
-rw-r--r-- | drivers/iio/pressure/ms5611_spi.c | 127 |
6 files changed, 544 insertions, 0 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index a3be53792072..fa6295041947 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig | |||
@@ -52,6 +52,33 @@ config MPL3115 | |||
52 | To compile this driver as a module, choose M here: the module | 52 | To compile this driver as a module, choose M here: the module |
53 | will be called mpl3115. | 53 | will be called mpl3115. |
54 | 54 | ||
55 | config MS5611 | ||
56 | tristate "Measurement Specialities MS5611 pressure sensor driver" | ||
57 | help | ||
58 | Say Y here to build support for the Measurement Specialities | ||
59 | MS5611 pressure and temperature sensor. | ||
60 | |||
61 | To compile this driver as a module, choose M here: the module will | ||
62 | be called ms5611_core. | ||
63 | |||
64 | config MS5611_I2C | ||
65 | tristate "support I2C bus connection" | ||
66 | depends on I2C && MS5611 | ||
67 | help | ||
68 | Say Y here to build I2C bus support for MS5611. | ||
69 | |||
70 | To compile this driver as a module, choose M here: the module will | ||
71 | be called ms5611_i2c. | ||
72 | |||
73 | config MS5611_SPI | ||
74 | tristate "support SPI bus connection" | ||
75 | depends on SPI_MASTER && MS5611 | ||
76 | help | ||
77 | Say Y here to build SPI bus support for MS5611. | ||
78 | |||
79 | To compile this driver as a module, choose M here: the module will | ||
80 | be called ms5611_spi. | ||
81 | |||
55 | config IIO_ST_PRESS | 82 | config IIO_ST_PRESS |
56 | tristate "STMicroelectronics pressure sensor Driver" | 83 | tristate "STMicroelectronics pressure sensor Driver" |
57 | depends on (I2C || SPI_MASTER) && SYSFS | 84 | depends on (I2C || SPI_MASTER) && SYSFS |
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 88011f2ae00e..a4f98f8d90ed 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile | |||
@@ -7,6 +7,9 @@ obj-$(CONFIG_BMP280) += bmp280.o | |||
7 | obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o | 7 | obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o |
8 | obj-$(CONFIG_MPL115) += mpl115.o | 8 | obj-$(CONFIG_MPL115) += mpl115.o |
9 | obj-$(CONFIG_MPL3115) += mpl3115.o | 9 | obj-$(CONFIG_MPL3115) += mpl3115.o |
10 | obj-$(CONFIG_MS5611) += ms5611_core.o | ||
11 | obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o | ||
12 | obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o | ||
10 | obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o | 13 | obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o |
11 | st_pressure-y := st_pressure_core.o | 14 | st_pressure-y := st_pressure_core.o |
12 | st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o | 15 | st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o |
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h new file mode 100644 index 000000000000..099c6cdea43f --- /dev/null +++ b/drivers/iio/pressure/ms5611.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * MS5611 pressure and temperature sensor driver | ||
3 | * | ||
4 | * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _MS5611_H | ||
13 | #define _MS5611_H | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/iio/iio.h> | ||
17 | #include <linux/mutex.h> | ||
18 | |||
19 | #define MS5611_RESET 0x1e | ||
20 | #define MS5611_READ_ADC 0x00 | ||
21 | #define MS5611_READ_PROM_WORD 0xA0 | ||
22 | #define MS5611_START_TEMP_CONV 0x58 | ||
23 | #define MS5611_START_PRESSURE_CONV 0x48 | ||
24 | |||
25 | #define MS5611_CONV_TIME_MIN 9040 | ||
26 | #define MS5611_CONV_TIME_MAX 10000 | ||
27 | |||
28 | #define MS5611_PROM_WORDS_NB 8 | ||
29 | |||
30 | struct ms5611_state { | ||
31 | void *client; | ||
32 | struct mutex lock; | ||
33 | |||
34 | int (*reset)(struct device *dev); | ||
35 | int (*read_prom_word)(struct device *dev, int index, u16 *word); | ||
36 | int (*read_adc_temp_and_pressure)(struct device *dev, | ||
37 | s32 *temp, s32 *pressure); | ||
38 | |||
39 | u16 prom[MS5611_PROM_WORDS_NB]; | ||
40 | }; | ||
41 | |||
42 | int ms5611_probe(struct iio_dev *indio_dev, struct device *dev); | ||
43 | |||
44 | #endif /* _MS5611_H */ | ||
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c new file mode 100644 index 000000000000..e42c8531d9b3 --- /dev/null +++ b/drivers/iio/pressure/ms5611_core.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * MS5611 pressure and temperature sensor driver | ||
3 | * | ||
4 | * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Data sheet: | ||
11 | * http://www.meas-spec.com/downloads/MS5611-01BA03.pdf | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/iio/iio.h> | ||
17 | #include <linux/delay.h> | ||
18 | |||
19 | #include "ms5611.h" | ||
20 | |||
21 | static bool ms5611_prom_is_valid(u16 *prom, size_t len) | ||
22 | { | ||
23 | int i, j; | ||
24 | uint16_t crc = 0, crc_orig = prom[7] & 0x000F; | ||
25 | |||
26 | prom[7] &= 0xFF00; | ||
27 | |||
28 | for (i = 0; i < len * 2; i++) { | ||
29 | if (i % 2 == 1) | ||
30 | crc ^= prom[i >> 1] & 0x00FF; | ||
31 | else | ||
32 | crc ^= prom[i >> 1] >> 8; | ||
33 | |||
34 | for (j = 0; j < 8; j++) { | ||
35 | if (crc & 0x8000) | ||
36 | crc = (crc << 1) ^ 0x3000; | ||
37 | else | ||
38 | crc <<= 1; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | crc = (crc >> 12) & 0x000F; | ||
43 | |||
44 | return crc_orig != 0x0000 && crc == crc_orig; | ||
45 | } | ||
46 | |||
47 | static int ms5611_read_prom(struct iio_dev *indio_dev) | ||
48 | { | ||
49 | int ret, i; | ||
50 | struct ms5611_state *st = iio_priv(indio_dev); | ||
51 | |||
52 | for (i = 0; i < MS5611_PROM_WORDS_NB; i++) { | ||
53 | ret = st->read_prom_word(&indio_dev->dev, i, &st->prom[i]); | ||
54 | if (ret < 0) { | ||
55 | dev_err(&indio_dev->dev, | ||
56 | "failed to read prom at %d\n", i); | ||
57 | return ret; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) { | ||
62 | dev_err(&indio_dev->dev, "PROM integrity check failed\n"); | ||
63 | return -ENODEV; | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev, | ||
70 | s32 *temp, s32 *pressure) | ||
71 | { | ||
72 | int ret; | ||
73 | s32 t, p; | ||
74 | s64 off, sens, dt; | ||
75 | struct ms5611_state *st = iio_priv(indio_dev); | ||
76 | |||
77 | ret = st->read_adc_temp_and_pressure(&indio_dev->dev, &t, &p); | ||
78 | if (ret < 0) { | ||
79 | dev_err(&indio_dev->dev, | ||
80 | "failed to read temperature and pressure\n"); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | dt = t - (st->prom[5] << 8); | ||
85 | off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7); | ||
86 | sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8); | ||
87 | |||
88 | t = 2000 + ((st->prom[6] * dt) >> 23); | ||
89 | if (t < 2000) { | ||
90 | s64 off2, sens2, t2; | ||
91 | |||
92 | t2 = (dt * dt) >> 31; | ||
93 | off2 = (5 * (t - 2000) * (t - 2000)) >> 1; | ||
94 | sens2 = off2 >> 1; | ||
95 | |||
96 | if (t < -1500) { | ||
97 | s64 tmp = (t + 1500) * (t + 1500); | ||
98 | |||
99 | off2 += 7 * tmp; | ||
100 | sens2 += (11 * tmp) >> 1; | ||
101 | } | ||
102 | |||
103 | t -= t2; | ||
104 | off -= off2; | ||
105 | sens -= sens2; | ||
106 | } | ||
107 | |||
108 | *temp = t; | ||
109 | *pressure = (((p * sens) >> 21) - off) >> 15; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int ms5611_reset(struct iio_dev *indio_dev) | ||
115 | { | ||
116 | int ret; | ||
117 | struct ms5611_state *st = iio_priv(indio_dev); | ||
118 | |||
119 | ret = st->reset(&indio_dev->dev); | ||
120 | if (ret < 0) { | ||
121 | dev_err(&indio_dev->dev, "failed to reset device\n"); | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | usleep_range(3000, 4000); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int ms5611_read_raw(struct iio_dev *indio_dev, | ||
131 | struct iio_chan_spec const *chan, | ||
132 | int *val, int *val2, long mask) | ||
133 | { | ||
134 | int ret; | ||
135 | s32 temp, pressure; | ||
136 | struct ms5611_state *st = iio_priv(indio_dev); | ||
137 | |||
138 | switch (mask) { | ||
139 | case IIO_CHAN_INFO_PROCESSED: | ||
140 | mutex_lock(&st->lock); | ||
141 | ret = ms5611_read_temp_and_pressure(indio_dev, | ||
142 | &temp, &pressure); | ||
143 | mutex_unlock(&st->lock); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | switch (chan->type) { | ||
148 | case IIO_TEMP: | ||
149 | *val = temp * 10; | ||
150 | return IIO_VAL_INT; | ||
151 | case IIO_PRESSURE: | ||
152 | *val = pressure / 1000; | ||
153 | *val2 = (pressure % 1000) * 1000; | ||
154 | return IIO_VAL_INT_PLUS_MICRO; | ||
155 | default: | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | static const struct iio_chan_spec ms5611_channels[] = { | ||
164 | { | ||
165 | .type = IIO_PRESSURE, | ||
166 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | | ||
167 | BIT(IIO_CHAN_INFO_SCALE) | ||
168 | }, | ||
169 | { | ||
170 | .type = IIO_TEMP, | ||
171 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | | ||
172 | BIT(IIO_CHAN_INFO_SCALE) | ||
173 | } | ||
174 | }; | ||
175 | |||
176 | static const struct iio_info ms5611_info = { | ||
177 | .read_raw = &ms5611_read_raw, | ||
178 | .driver_module = THIS_MODULE, | ||
179 | }; | ||
180 | |||
181 | static int ms5611_init(struct iio_dev *indio_dev) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | ret = ms5611_reset(indio_dev); | ||
186 | if (ret < 0) | ||
187 | return ret; | ||
188 | |||
189 | return ms5611_read_prom(indio_dev); | ||
190 | } | ||
191 | |||
192 | int ms5611_probe(struct iio_dev *indio_dev, struct device *dev) | ||
193 | { | ||
194 | int ret; | ||
195 | struct ms5611_state *st = iio_priv(indio_dev); | ||
196 | |||
197 | mutex_init(&st->lock); | ||
198 | indio_dev->dev.parent = dev; | ||
199 | indio_dev->name = dev->driver->name; | ||
200 | indio_dev->info = &ms5611_info; | ||
201 | indio_dev->channels = ms5611_channels; | ||
202 | indio_dev->num_channels = ARRAY_SIZE(ms5611_channels); | ||
203 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
204 | |||
205 | ret = ms5611_init(indio_dev); | ||
206 | if (ret < 0) | ||
207 | return ret; | ||
208 | |||
209 | return devm_iio_device_register(dev, indio_dev); | ||
210 | } | ||
211 | EXPORT_SYMBOL(ms5611_probe); | ||
212 | |||
213 | MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); | ||
214 | MODULE_DESCRIPTION("MS5611 core driver"); | ||
215 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c new file mode 100644 index 000000000000..748fd9acaad8 --- /dev/null +++ b/drivers/iio/pressure/ms5611_i2c.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * MS5611 pressure and temperature sensor driver (I2C bus) | ||
3 | * | ||
4 | * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * 7-bit I2C slave addresses: | ||
11 | * | ||
12 | * 0x77 (CSB pin low) | ||
13 | * 0x76 (CSB pin high) | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/module.h> | ||
20 | |||
21 | #include "ms5611.h" | ||
22 | |||
23 | static int ms5611_i2c_reset(struct device *dev) | ||
24 | { | ||
25 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
26 | |||
27 | return i2c_smbus_write_byte(st->client, MS5611_RESET); | ||
28 | } | ||
29 | |||
30 | static int ms5611_i2c_read_prom_word(struct device *dev, int index, u16 *word) | ||
31 | { | ||
32 | int ret; | ||
33 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
34 | |||
35 | ret = i2c_smbus_read_word_swapped(st->client, | ||
36 | MS5611_READ_PROM_WORD + (index << 1)); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | |||
40 | *word = ret; | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val) | ||
46 | { | ||
47 | int ret; | ||
48 | u8 buf[3]; | ||
49 | |||
50 | ret = i2c_smbus_read_i2c_block_data(st->client, MS5611_READ_ADC, | ||
51 | 3, buf); | ||
52 | if (ret < 0) | ||
53 | return ret; | ||
54 | |||
55 | *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev, | ||
61 | s32 *temp, s32 *pressure) | ||
62 | { | ||
63 | int ret; | ||
64 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
65 | |||
66 | ret = i2c_smbus_write_byte(st->client, MS5611_START_TEMP_CONV); | ||
67 | if (ret < 0) | ||
68 | return ret; | ||
69 | |||
70 | usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); | ||
71 | |||
72 | ret = ms5611_i2c_read_adc(st, temp); | ||
73 | if (ret < 0) | ||
74 | return ret; | ||
75 | |||
76 | ret = i2c_smbus_write_byte(st->client, MS5611_START_PRESSURE_CONV); | ||
77 | if (ret < 0) | ||
78 | return ret; | ||
79 | |||
80 | usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); | ||
81 | |||
82 | return ms5611_i2c_read_adc(st, pressure); | ||
83 | } | ||
84 | |||
85 | static int ms5611_i2c_probe(struct i2c_client *client, | ||
86 | const struct i2c_device_id *id) | ||
87 | { | ||
88 | struct ms5611_state *st; | ||
89 | struct iio_dev *indio_dev; | ||
90 | |||
91 | if (!i2c_check_functionality(client->adapter, | ||
92 | I2C_FUNC_SMBUS_WRITE_BYTE | | ||
93 | I2C_FUNC_SMBUS_READ_WORD_DATA | | ||
94 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) | ||
95 | return -ENODEV; | ||
96 | |||
97 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); | ||
98 | if (!indio_dev) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | st = iio_priv(indio_dev); | ||
102 | st->reset = ms5611_i2c_reset; | ||
103 | st->read_prom_word = ms5611_i2c_read_prom_word; | ||
104 | st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure; | ||
105 | st->client = client; | ||
106 | |||
107 | return ms5611_probe(indio_dev, &client->dev); | ||
108 | } | ||
109 | |||
110 | static const struct i2c_device_id ms5611_id[] = { | ||
111 | { "ms5611", 0 }, | ||
112 | { } | ||
113 | }; | ||
114 | MODULE_DEVICE_TABLE(i2c, ms5611_id); | ||
115 | |||
116 | static struct i2c_driver ms5611_driver = { | ||
117 | .driver = { | ||
118 | .name = "ms5611", | ||
119 | .owner = THIS_MODULE, | ||
120 | }, | ||
121 | .id_table = ms5611_id, | ||
122 | .probe = ms5611_i2c_probe, | ||
123 | }; | ||
124 | module_i2c_driver(ms5611_driver); | ||
125 | |||
126 | MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); | ||
127 | MODULE_DESCRIPTION("MS5611 i2c driver"); | ||
128 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c new file mode 100644 index 000000000000..976726fd4e6c --- /dev/null +++ b/drivers/iio/pressure/ms5611_spi.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * MS5611 pressure and temperature sensor driver (SPI bus) | ||
3 | * | ||
4 | * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | |||
16 | #include "ms5611.h" | ||
17 | |||
18 | static int ms5611_spi_reset(struct device *dev) | ||
19 | { | ||
20 | u8 cmd = MS5611_RESET; | ||
21 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
22 | |||
23 | return spi_write_then_read(st->client, &cmd, 1, NULL, 0); | ||
24 | } | ||
25 | |||
26 | static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word) | ||
27 | { | ||
28 | int ret; | ||
29 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
30 | |||
31 | ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1)); | ||
32 | if (ret < 0) | ||
33 | return ret; | ||
34 | |||
35 | *word = ret; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int ms5611_spi_read_adc(struct device *dev, s32 *val) | ||
41 | { | ||
42 | int ret; | ||
43 | u8 buf[3] = { MS5611_READ_ADC }; | ||
44 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
45 | |||
46 | ret = spi_write_then_read(st->client, buf, 1, buf, 3); | ||
47 | if (ret < 0) | ||
48 | return ret; | ||
49 | |||
50 | *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev, | ||
56 | s32 *temp, s32 *pressure) | ||
57 | { | ||
58 | u8 cmd; | ||
59 | int ret; | ||
60 | struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); | ||
61 | |||
62 | cmd = MS5611_START_TEMP_CONV; | ||
63 | ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | |||
67 | usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); | ||
68 | |||
69 | ret = ms5611_spi_read_adc(dev, temp); | ||
70 | if (ret < 0) | ||
71 | return ret; | ||
72 | |||
73 | cmd = MS5611_START_PRESSURE_CONV; | ||
74 | ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); | ||
79 | |||
80 | return ms5611_spi_read_adc(dev, pressure); | ||
81 | } | ||
82 | |||
83 | static int ms5611_spi_probe(struct spi_device *spi) | ||
84 | { | ||
85 | int ret; | ||
86 | struct ms5611_state *st; | ||
87 | struct iio_dev *indio_dev; | ||
88 | |||
89 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | ||
90 | if (!indio_dev) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | spi->mode = SPI_MODE_0; | ||
94 | spi->max_speed_hz = 20000000; | ||
95 | spi->bits_per_word = 8; | ||
96 | ret = spi_setup(spi); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | st = iio_priv(indio_dev); | ||
101 | st->reset = ms5611_spi_reset; | ||
102 | st->read_prom_word = ms5611_spi_read_prom_word; | ||
103 | st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure; | ||
104 | st->client = spi; | ||
105 | |||
106 | return ms5611_probe(indio_dev, &spi->dev); | ||
107 | } | ||
108 | |||
109 | static const struct spi_device_id ms5611_id[] = { | ||
110 | { "ms5611", 0 }, | ||
111 | { } | ||
112 | }; | ||
113 | MODULE_DEVICE_TABLE(spi, ms5611_id); | ||
114 | |||
115 | static struct spi_driver ms5611_driver = { | ||
116 | .driver = { | ||
117 | .name = "ms5611", | ||
118 | .owner = THIS_MODULE, | ||
119 | }, | ||
120 | .id_table = ms5611_id, | ||
121 | .probe = ms5611_spi_probe, | ||
122 | }; | ||
123 | module_spi_driver(ms5611_driver); | ||
124 | |||
125 | MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); | ||
126 | MODULE_DESCRIPTION("MS5611 spi driver"); | ||
127 | MODULE_LICENSE("GPL v2"); | ||