1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Honeywell TruStability HSC Series pressure/temperature sensor |
4 | * |
5 | * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> |
6 | * |
7 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf |
8 | */ |
9 | |
10 | #include <linux/array_size.h> |
11 | #include <linux/bitfield.h> |
12 | #include <linux/bits.h> |
13 | #include <linux/cleanup.h> |
14 | #include <linux/init.h> |
15 | #include <linux/math64.h> |
16 | #include <linux/mod_devicetable.h> |
17 | #include <linux/module.h> |
18 | #include <linux/printk.h> |
19 | #include <linux/property.h> |
20 | #include <linux/regulator/consumer.h> |
21 | #include <linux/string.h> |
22 | #include <linux/types.h> |
23 | #include <linux/units.h> |
24 | |
25 | #include <linux/iio/buffer.h> |
26 | #include <linux/iio/iio.h> |
27 | #include <linux/iio/sysfs.h> |
28 | #include <linux/iio/trigger_consumer.h> |
29 | #include <linux/iio/triggered_buffer.h> |
30 | |
31 | #include <asm/unaligned.h> |
32 | |
33 | #include "hsc030pa.h" |
34 | |
35 | /* |
36 | * HSC_PRESSURE_TRIPLET_LEN - length for the string that defines the |
37 | * pressure range, measurement unit and type as per the part nomenclature. |
38 | * Consult honeywell,pressure-triplet in the bindings file for details. |
39 | */ |
40 | #define HSC_PRESSURE_TRIPLET_LEN 6 |
41 | #define HSC_STATUS_MASK GENMASK(7, 6) |
42 | #define HSC_TEMPERATURE_MASK GENMASK(15, 5) |
43 | #define HSC_PRESSURE_MASK GENMASK(29, 16) |
44 | |
45 | struct hsc_func_spec { |
46 | u32 output_min; |
47 | u32 output_max; |
48 | }; |
49 | |
50 | /* |
51 | * function A: 10% - 90% of 2^14 |
52 | * function B: 5% - 95% of 2^14 |
53 | * function C: 5% - 85% of 2^14 |
54 | * function F: 4% - 94% of 2^14 |
55 | */ |
56 | static const struct hsc_func_spec hsc_func_spec[] = { |
57 | [HSC_FUNCTION_A] = { .output_min = 1638, .output_max = 14746 }, |
58 | [HSC_FUNCTION_B] = { .output_min = 819, .output_max = 15565 }, |
59 | [HSC_FUNCTION_C] = { .output_min = 819, .output_max = 13926 }, |
60 | [HSC_FUNCTION_F] = { .output_min = 655, .output_max = 15401 }, |
61 | }; |
62 | |
63 | enum hsc_variants { |
64 | HSC001BA = 0x00, HSC1_6BA = 0x01, HSC2_5BA = 0x02, HSC004BA = 0x03, |
65 | HSC006BA = 0x04, HSC010BA = 0x05, HSC1_6MD = 0x06, HSC2_5MD = 0x07, |
66 | HSC004MD = 0x08, HSC006MD = 0x09, HSC010MD = 0x0a, HSC016MD = 0x0b, |
67 | HSC025MD = 0x0c, HSC040MD = 0x0d, HSC060MD = 0x0e, HSC100MD = 0x0f, |
68 | HSC160MD = 0x10, HSC250MD = 0x11, HSC400MD = 0x12, HSC600MD = 0x13, |
69 | HSC001BD = 0x14, HSC1_6BD = 0x15, HSC2_5BD = 0x16, HSC004BD = 0x17, |
70 | HSC2_5MG = 0x18, HSC004MG = 0x19, HSC006MG = 0x1a, HSC010MG = 0x1b, |
71 | HSC016MG = 0x1c, HSC025MG = 0x1d, HSC040MG = 0x1e, HSC060MG = 0x1f, |
72 | HSC100MG = 0x20, HSC160MG = 0x21, HSC250MG = 0x22, HSC400MG = 0x23, |
73 | HSC600MG = 0x24, HSC001BG = 0x25, HSC1_6BG = 0x26, HSC2_5BG = 0x27, |
74 | HSC004BG = 0x28, HSC006BG = 0x29, HSC010BG = 0x2a, HSC100KA = 0x2b, |
75 | HSC160KA = 0x2c, HSC250KA = 0x2d, HSC400KA = 0x2e, HSC600KA = 0x2f, |
76 | HSC001GA = 0x30, HSC160LD = 0x31, HSC250LD = 0x32, HSC400LD = 0x33, |
77 | HSC600LD = 0x34, HSC001KD = 0x35, HSC1_6KD = 0x36, HSC2_5KD = 0x37, |
78 | HSC004KD = 0x38, HSC006KD = 0x39, HSC010KD = 0x3a, HSC016KD = 0x3b, |
79 | HSC025KD = 0x3c, HSC040KD = 0x3d, HSC060KD = 0x3e, HSC100KD = 0x3f, |
80 | HSC160KD = 0x40, HSC250KD = 0x41, HSC400KD = 0x42, HSC250LG = 0x43, |
81 | HSC400LG = 0x44, HSC600LG = 0x45, HSC001KG = 0x46, HSC1_6KG = 0x47, |
82 | HSC2_5KG = 0x48, HSC004KG = 0x49, HSC006KG = 0x4a, HSC010KG = 0x4b, |
83 | HSC016KG = 0x4c, HSC025KG = 0x4d, HSC040KG = 0x4e, HSC060KG = 0x4f, |
84 | HSC100KG = 0x50, HSC160KG = 0x51, HSC250KG = 0x52, HSC400KG = 0x53, |
85 | HSC600KG = 0x54, HSC001GG = 0x55, HSC015PA = 0x56, HSC030PA = 0x57, |
86 | HSC060PA = 0x58, HSC100PA = 0x59, HSC150PA = 0x5a, HSC0_5ND = 0x5b, |
87 | HSC001ND = 0x5c, HSC002ND = 0x5d, HSC004ND = 0x5e, HSC005ND = 0x5f, |
88 | HSC010ND = 0x60, HSC020ND = 0x61, HSC030ND = 0x62, HSC001PD = 0x63, |
89 | HSC005PD = 0x64, HSC015PD = 0x65, HSC030PD = 0x66, HSC060PD = 0x67, |
90 | HSC001NG = 0x68, HSC002NG = 0x69, HSC004NG = 0x6a, HSC005NG = 0x6b, |
91 | HSC010NG = 0x6c, HSC020NG = 0x6d, HSC030NG = 0x6e, HSC001PG = 0x6f, |
92 | HSC005PG = 0x70, HSC015PG = 0x71, HSC030PG = 0x72, HSC060PG = 0x73, |
93 | HSC100PG = 0x74, HSC150PG = 0x75, HSC_VARIANTS_MAX |
94 | }; |
95 | |
96 | static const char * const hsc_triplet_variants[HSC_VARIANTS_MAX] = { |
97 | [HSC001BA] = "001BA" , [HSC1_6BA] = "1.6BA" , [HSC2_5BA] = "2.5BA" , |
98 | [HSC004BA] = "004BA" , [HSC006BA] = "006BA" , [HSC010BA] = "010BA" , |
99 | [HSC1_6MD] = "1.6MD" , [HSC2_5MD] = "2.5MD" , [HSC004MD] = "004MD" , |
100 | [HSC006MD] = "006MD" , [HSC010MD] = "010MD" , [HSC016MD] = "016MD" , |
101 | [HSC025MD] = "025MD" , [HSC040MD] = "040MD" , [HSC060MD] = "060MD" , |
102 | [HSC100MD] = "100MD" , [HSC160MD] = "160MD" , [HSC250MD] = "250MD" , |
103 | [HSC400MD] = "400MD" , [HSC600MD] = "600MD" , [HSC001BD] = "001BD" , |
104 | [HSC1_6BD] = "1.6BD" , [HSC2_5BD] = "2.5BD" , [HSC004BD] = "004BD" , |
105 | [HSC2_5MG] = "2.5MG" , [HSC004MG] = "004MG" , [HSC006MG] = "006MG" , |
106 | [HSC010MG] = "010MG" , [HSC016MG] = "016MG" , [HSC025MG] = "025MG" , |
107 | [HSC040MG] = "040MG" , [HSC060MG] = "060MG" , [HSC100MG] = "100MG" , |
108 | [HSC160MG] = "160MG" , [HSC250MG] = "250MG" , [HSC400MG] = "400MG" , |
109 | [HSC600MG] = "600MG" , [HSC001BG] = "001BG" , [HSC1_6BG] = "1.6BG" , |
110 | [HSC2_5BG] = "2.5BG" , [HSC004BG] = "004BG" , [HSC006BG] = "006BG" , |
111 | [HSC010BG] = "010BG" , [HSC100KA] = "100KA" , [HSC160KA] = "160KA" , |
112 | [HSC250KA] = "250KA" , [HSC400KA] = "400KA" , [HSC600KA] = "600KA" , |
113 | [HSC001GA] = "001GA" , [HSC160LD] = "160LD" , [HSC250LD] = "250LD" , |
114 | [HSC400LD] = "400LD" , [HSC600LD] = "600LD" , [HSC001KD] = "001KD" , |
115 | [HSC1_6KD] = "1.6KD" , [HSC2_5KD] = "2.5KD" , [HSC004KD] = "004KD" , |
116 | [HSC006KD] = "006KD" , [HSC010KD] = "010KD" , [HSC016KD] = "016KD" , |
117 | [HSC025KD] = "025KD" , [HSC040KD] = "040KD" , [HSC060KD] = "060KD" , |
118 | [HSC100KD] = "100KD" , [HSC160KD] = "160KD" , [HSC250KD] = "250KD" , |
119 | [HSC400KD] = "400KD" , [HSC250LG] = "250LG" , [HSC400LG] = "400LG" , |
120 | [HSC600LG] = "600LG" , [HSC001KG] = "001KG" , [HSC1_6KG] = "1.6KG" , |
121 | [HSC2_5KG] = "2.5KG" , [HSC004KG] = "004KG" , [HSC006KG] = "006KG" , |
122 | [HSC010KG] = "010KG" , [HSC016KG] = "016KG" , [HSC025KG] = "025KG" , |
123 | [HSC040KG] = "040KG" , [HSC060KG] = "060KG" , [HSC100KG] = "100KG" , |
124 | [HSC160KG] = "160KG" , [HSC250KG] = "250KG" , [HSC400KG] = "400KG" , |
125 | [HSC600KG] = "600KG" , [HSC001GG] = "001GG" , [HSC015PA] = "015PA" , |
126 | [HSC030PA] = "030PA" , [HSC060PA] = "060PA" , [HSC100PA] = "100PA" , |
127 | [HSC150PA] = "150PA" , [HSC0_5ND] = "0.5ND" , [HSC001ND] = "001ND" , |
128 | [HSC002ND] = "002ND" , [HSC004ND] = "004ND" , [HSC005ND] = "005ND" , |
129 | [HSC010ND] = "010ND" , [HSC020ND] = "020ND" , [HSC030ND] = "030ND" , |
130 | [HSC001PD] = "001PD" , [HSC005PD] = "005PD" , [HSC015PD] = "015PD" , |
131 | [HSC030PD] = "030PD" , [HSC060PD] = "060PD" , [HSC001NG] = "001NG" , |
132 | [HSC002NG] = "002NG" , [HSC004NG] = "004NG" , [HSC005NG] = "005NG" , |
133 | [HSC010NG] = "010NG" , [HSC020NG] = "020NG" , [HSC030NG] = "030NG" , |
134 | [HSC001PG] = "001PG" , [HSC005PG] = "005PG" , [HSC015PG] = "015PG" , |
135 | [HSC030PG] = "030PG" , [HSC060PG] = "060PG" , [HSC100PG] = "100PG" , |
136 | [HSC150PG] = "150PG" , |
137 | }; |
138 | |
139 | /** |
140 | * struct hsc_range_config - list of pressure ranges based on nomenclature |
141 | * @pmin: lowest pressure that can be measured |
142 | * @pmax: highest pressure that can be measured |
143 | */ |
144 | struct hsc_range_config { |
145 | const s32 pmin; |
146 | const s32 pmax; |
147 | }; |
148 | |
149 | /* All min max limits have been converted to pascals */ |
150 | static const struct hsc_range_config hsc_range_config[HSC_VARIANTS_MAX] = { |
151 | [HSC001BA] = { .pmin = 0, .pmax = 100000 }, |
152 | [HSC1_6BA] = { .pmin = 0, .pmax = 160000 }, |
153 | [HSC2_5BA] = { .pmin = 0, .pmax = 250000 }, |
154 | [HSC004BA] = { .pmin = 0, .pmax = 400000 }, |
155 | [HSC006BA] = { .pmin = 0, .pmax = 600000 }, |
156 | [HSC010BA] = { .pmin = 0, .pmax = 1000000 }, |
157 | [HSC1_6MD] = { .pmin = -160, .pmax = 160 }, |
158 | [HSC2_5MD] = { .pmin = -250, .pmax = 250 }, |
159 | [HSC004MD] = { .pmin = -400, .pmax = 400 }, |
160 | [HSC006MD] = { .pmin = -600, .pmax = 600 }, |
161 | [HSC010MD] = { .pmin = -1000, .pmax = 1000 }, |
162 | [HSC016MD] = { .pmin = -1600, .pmax = 1600 }, |
163 | [HSC025MD] = { .pmin = -2500, .pmax = 2500 }, |
164 | [HSC040MD] = { .pmin = -4000, .pmax = 4000 }, |
165 | [HSC060MD] = { .pmin = -6000, .pmax = 6000 }, |
166 | [HSC100MD] = { .pmin = -10000, .pmax = 10000 }, |
167 | [HSC160MD] = { .pmin = -16000, .pmax = 16000 }, |
168 | [HSC250MD] = { .pmin = -25000, .pmax = 25000 }, |
169 | [HSC400MD] = { .pmin = -40000, .pmax = 40000 }, |
170 | [HSC600MD] = { .pmin = -60000, .pmax = 60000 }, |
171 | [HSC001BD] = { .pmin = -100000, .pmax = 100000 }, |
172 | [HSC1_6BD] = { .pmin = -160000, .pmax = 160000 }, |
173 | [HSC2_5BD] = { .pmin = -250000, .pmax = 250000 }, |
174 | [HSC004BD] = { .pmin = -400000, .pmax = 400000 }, |
175 | [HSC2_5MG] = { .pmin = 0, .pmax = 250 }, |
176 | [HSC004MG] = { .pmin = 0, .pmax = 400 }, |
177 | [HSC006MG] = { .pmin = 0, .pmax = 600 }, |
178 | [HSC010MG] = { .pmin = 0, .pmax = 1000 }, |
179 | [HSC016MG] = { .pmin = 0, .pmax = 1600 }, |
180 | [HSC025MG] = { .pmin = 0, .pmax = 2500 }, |
181 | [HSC040MG] = { .pmin = 0, .pmax = 4000 }, |
182 | [HSC060MG] = { .pmin = 0, .pmax = 6000 }, |
183 | [HSC100MG] = { .pmin = 0, .pmax = 10000 }, |
184 | [HSC160MG] = { .pmin = 0, .pmax = 16000 }, |
185 | [HSC250MG] = { .pmin = 0, .pmax = 25000 }, |
186 | [HSC400MG] = { .pmin = 0, .pmax = 40000 }, |
187 | [HSC600MG] = { .pmin = 0, .pmax = 60000 }, |
188 | [HSC001BG] = { .pmin = 0, .pmax = 100000 }, |
189 | [HSC1_6BG] = { .pmin = 0, .pmax = 160000 }, |
190 | [HSC2_5BG] = { .pmin = 0, .pmax = 250000 }, |
191 | [HSC004BG] = { .pmin = 0, .pmax = 400000 }, |
192 | [HSC006BG] = { .pmin = 0, .pmax = 600000 }, |
193 | [HSC010BG] = { .pmin = 0, .pmax = 1000000 }, |
194 | [HSC100KA] = { .pmin = 0, .pmax = 100000 }, |
195 | [HSC160KA] = { .pmin = 0, .pmax = 160000 }, |
196 | [HSC250KA] = { .pmin = 0, .pmax = 250000 }, |
197 | [HSC400KA] = { .pmin = 0, .pmax = 400000 }, |
198 | [HSC600KA] = { .pmin = 0, .pmax = 600000 }, |
199 | [HSC001GA] = { .pmin = 0, .pmax = 1000000 }, |
200 | [HSC160LD] = { .pmin = -160, .pmax = 160 }, |
201 | [HSC250LD] = { .pmin = -250, .pmax = 250 }, |
202 | [HSC400LD] = { .pmin = -400, .pmax = 400 }, |
203 | [HSC600LD] = { .pmin = -600, .pmax = 600 }, |
204 | [HSC001KD] = { .pmin = -1000, .pmax = 1000 }, |
205 | [HSC1_6KD] = { .pmin = -1600, .pmax = 1600 }, |
206 | [HSC2_5KD] = { .pmin = -2500, .pmax = 2500 }, |
207 | [HSC004KD] = { .pmin = -4000, .pmax = 4000 }, |
208 | [HSC006KD] = { .pmin = -6000, .pmax = 6000 }, |
209 | [HSC010KD] = { .pmin = -10000, .pmax = 10000 }, |
210 | [HSC016KD] = { .pmin = -16000, .pmax = 16000 }, |
211 | [HSC025KD] = { .pmin = -25000, .pmax = 25000 }, |
212 | [HSC040KD] = { .pmin = -40000, .pmax = 40000 }, |
213 | [HSC060KD] = { .pmin = -60000, .pmax = 60000 }, |
214 | [HSC100KD] = { .pmin = -100000, .pmax = 100000 }, |
215 | [HSC160KD] = { .pmin = -160000, .pmax = 160000 }, |
216 | [HSC250KD] = { .pmin = -250000, .pmax = 250000 }, |
217 | [HSC400KD] = { .pmin = -400000, .pmax = 400000 }, |
218 | [HSC250LG] = { .pmin = 0, .pmax = 250 }, |
219 | [HSC400LG] = { .pmin = 0, .pmax = 400 }, |
220 | [HSC600LG] = { .pmin = 0, .pmax = 600 }, |
221 | [HSC001KG] = { .pmin = 0, .pmax = 1000 }, |
222 | [HSC1_6KG] = { .pmin = 0, .pmax = 1600 }, |
223 | [HSC2_5KG] = { .pmin = 0, .pmax = 2500 }, |
224 | [HSC004KG] = { .pmin = 0, .pmax = 4000 }, |
225 | [HSC006KG] = { .pmin = 0, .pmax = 6000 }, |
226 | [HSC010KG] = { .pmin = 0, .pmax = 10000 }, |
227 | [HSC016KG] = { .pmin = 0, .pmax = 16000 }, |
228 | [HSC025KG] = { .pmin = 0, .pmax = 25000 }, |
229 | [HSC040KG] = { .pmin = 0, .pmax = 40000 }, |
230 | [HSC060KG] = { .pmin = 0, .pmax = 60000 }, |
231 | [HSC100KG] = { .pmin = 0, .pmax = 100000 }, |
232 | [HSC160KG] = { .pmin = 0, .pmax = 160000 }, |
233 | [HSC250KG] = { .pmin = 0, .pmax = 250000 }, |
234 | [HSC400KG] = { .pmin = 0, .pmax = 400000 }, |
235 | [HSC600KG] = { .pmin = 0, .pmax = 600000 }, |
236 | [HSC001GG] = { .pmin = 0, .pmax = 1000000 }, |
237 | [HSC015PA] = { .pmin = 0, .pmax = 103421 }, |
238 | [HSC030PA] = { .pmin = 0, .pmax = 206843 }, |
239 | [HSC060PA] = { .pmin = 0, .pmax = 413685 }, |
240 | [HSC100PA] = { .pmin = 0, .pmax = 689476 }, |
241 | [HSC150PA] = { .pmin = 0, .pmax = 1034214 }, |
242 | [HSC0_5ND] = { .pmin = -125, .pmax = 125 }, |
243 | [HSC001ND] = { .pmin = -249, .pmax = 249 }, |
244 | [HSC002ND] = { .pmin = -498, .pmax = 498 }, |
245 | [HSC004ND] = { .pmin = -996, .pmax = 996 }, |
246 | [HSC005ND] = { .pmin = -1245, .pmax = 1245 }, |
247 | [HSC010ND] = { .pmin = -2491, .pmax = 2491 }, |
248 | [HSC020ND] = { .pmin = -4982, .pmax = 4982 }, |
249 | [HSC030ND] = { .pmin = -7473, .pmax = 7473 }, |
250 | [HSC001PD] = { .pmin = -6895, .pmax = 6895 }, |
251 | [HSC005PD] = { .pmin = -34474, .pmax = 34474 }, |
252 | [HSC015PD] = { .pmin = -103421, .pmax = 103421 }, |
253 | [HSC030PD] = { .pmin = -206843, .pmax = 206843 }, |
254 | [HSC060PD] = { .pmin = -413685, .pmax = 413685 }, |
255 | [HSC001NG] = { .pmin = 0, .pmax = 249 }, |
256 | [HSC002NG] = { .pmin = 0, .pmax = 498 }, |
257 | [HSC004NG] = { .pmin = 0, .pmax = 996 }, |
258 | [HSC005NG] = { .pmin = 0, .pmax = 1245 }, |
259 | [HSC010NG] = { .pmin = 0, .pmax = 2491 }, |
260 | [HSC020NG] = { .pmin = 0, .pmax = 4982 }, |
261 | [HSC030NG] = { .pmin = 0, .pmax = 7473 }, |
262 | [HSC001PG] = { .pmin = 0, .pmax = 6895 }, |
263 | [HSC005PG] = { .pmin = 0, .pmax = 34474 }, |
264 | [HSC015PG] = { .pmin = 0, .pmax = 103421 }, |
265 | [HSC030PG] = { .pmin = 0, .pmax = 206843 }, |
266 | [HSC060PG] = { .pmin = 0, .pmax = 413685 }, |
267 | [HSC100PG] = { .pmin = 0, .pmax = 689476 }, |
268 | [HSC150PG] = { .pmin = 0, .pmax = 1034214 }, |
269 | }; |
270 | |
271 | /** |
272 | * hsc_measurement_is_valid() - validate last conversion via status bits |
273 | * @data: structure containing instantiated sensor data |
274 | * Return: true only if both status bits are zero |
275 | * |
276 | * the two MSB from the first transfered byte contain a status code |
277 | * 00 - normal operation, valid data |
278 | * 01 - device in factory programming mode |
279 | * 10 - stale data |
280 | * 11 - diagnostic condition |
281 | */ |
282 | static bool hsc_measurement_is_valid(struct hsc_data *data) |
283 | { |
284 | return !(data->buffer[0] & HSC_STATUS_MASK); |
285 | } |
286 | |
287 | static int hsc_get_measurement(struct hsc_data *data) |
288 | { |
289 | const struct hsc_chip_data *chip = data->chip; |
290 | int ret; |
291 | |
292 | ret = data->recv_cb(data); |
293 | if (ret < 0) |
294 | return ret; |
295 | |
296 | data->is_valid = chip->valid(data); |
297 | if (!data->is_valid) |
298 | return -EAGAIN; |
299 | |
300 | return 0; |
301 | } |
302 | |
303 | static irqreturn_t hsc_trigger_handler(int irq, void *private) |
304 | { |
305 | struct iio_poll_func *pf = private; |
306 | struct iio_dev *indio_dev = pf->indio_dev; |
307 | struct hsc_data *data = iio_priv(indio_dev); |
308 | int ret; |
309 | |
310 | ret = hsc_get_measurement(data); |
311 | if (ret) |
312 | goto error; |
313 | |
314 | memcpy(&data->scan.chan[0], &data->buffer[0], 2); |
315 | memcpy(&data->scan.chan[1], &data->buffer[2], 2); |
316 | |
317 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
318 | timestamp: iio_get_time_ns(indio_dev)); |
319 | |
320 | error: |
321 | iio_trigger_notify_done(trig: indio_dev->trig); |
322 | |
323 | return IRQ_HANDLED; |
324 | } |
325 | |
326 | /* |
327 | * IIO ABI expects |
328 | * value = (conv + offset) * scale |
329 | * |
330 | * datasheet provides the following formula for determining the temperature |
331 | * temp[C] = conv * a + b |
332 | * where a = 200/2047; b = -50 |
333 | * |
334 | * temp[C] = (conv + (b/a)) * a * (1000) |
335 | * => |
336 | * scale = a * 1000 = .097703957 * 1000 = 97.703957 |
337 | * offset = b/a = -50 / .097703957 = -50000000 / 97704 |
338 | * |
339 | * based on the datasheet |
340 | * pressure = (conv - Omin) * Q + Pmin = |
341 | * ((conv - Omin) + Pmin/Q) * Q |
342 | * => |
343 | * scale = Q = (Pmax - Pmin) / (Omax - Omin) |
344 | * offset = Pmin/Q - Omin = Pmin * (Omax - Omin) / (Pmax - Pmin) - Omin |
345 | */ |
346 | static int hsc_read_raw(struct iio_dev *indio_dev, |
347 | struct iio_chan_spec const *channel, int *val, |
348 | int *val2, long mask) |
349 | { |
350 | struct hsc_data *data = iio_priv(indio_dev); |
351 | int ret; |
352 | u32 recvd; |
353 | |
354 | switch (mask) { |
355 | case IIO_CHAN_INFO_RAW: |
356 | ret = hsc_get_measurement(data); |
357 | if (ret) |
358 | return ret; |
359 | |
360 | recvd = get_unaligned_be32(p: data->buffer); |
361 | switch (channel->type) { |
362 | case IIO_PRESSURE: |
363 | *val = FIELD_GET(HSC_PRESSURE_MASK, recvd); |
364 | return IIO_VAL_INT; |
365 | case IIO_TEMP: |
366 | *val = FIELD_GET(HSC_TEMPERATURE_MASK, recvd); |
367 | return IIO_VAL_INT; |
368 | default: |
369 | return -EINVAL; |
370 | } |
371 | |
372 | case IIO_CHAN_INFO_SCALE: |
373 | switch (channel->type) { |
374 | case IIO_TEMP: |
375 | *val = 97; |
376 | *val2 = 703957; |
377 | return IIO_VAL_INT_PLUS_MICRO; |
378 | case IIO_PRESSURE: |
379 | *val = data->p_scale; |
380 | *val2 = data->p_scale_dec; |
381 | return IIO_VAL_INT_PLUS_NANO; |
382 | default: |
383 | return -EINVAL; |
384 | } |
385 | |
386 | case IIO_CHAN_INFO_OFFSET: |
387 | switch (channel->type) { |
388 | case IIO_TEMP: |
389 | *val = -50000000; |
390 | *val2 = 97704; |
391 | return IIO_VAL_FRACTIONAL; |
392 | case IIO_PRESSURE: |
393 | *val = data->p_offset; |
394 | *val2 = data->p_offset_dec; |
395 | return IIO_VAL_INT_PLUS_MICRO; |
396 | default: |
397 | return -EINVAL; |
398 | } |
399 | |
400 | default: |
401 | return -EINVAL; |
402 | } |
403 | } |
404 | |
405 | static const struct iio_chan_spec hsc_channels[] = { |
406 | { |
407 | .type = IIO_PRESSURE, |
408 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
409 | BIT(IIO_CHAN_INFO_SCALE) | |
410 | BIT(IIO_CHAN_INFO_OFFSET), |
411 | .scan_index = 0, |
412 | .scan_type = { |
413 | .sign = 'u', |
414 | .realbits = 14, |
415 | .storagebits = 16, |
416 | .endianness = IIO_BE, |
417 | }, |
418 | }, |
419 | { |
420 | .type = IIO_TEMP, |
421 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
422 | BIT(IIO_CHAN_INFO_SCALE) | |
423 | BIT(IIO_CHAN_INFO_OFFSET), |
424 | .scan_index = 1, |
425 | .scan_type = { |
426 | .sign = 'u', |
427 | .realbits = 11, |
428 | .storagebits = 16, |
429 | .shift = 5, |
430 | .endianness = IIO_BE, |
431 | }, |
432 | }, |
433 | IIO_CHAN_SOFT_TIMESTAMP(2), |
434 | }; |
435 | |
436 | static const struct iio_info hsc_info = { |
437 | .read_raw = hsc_read_raw, |
438 | }; |
439 | |
440 | static const struct hsc_chip_data hsc_chip = { |
441 | .valid = hsc_measurement_is_valid, |
442 | .channels = hsc_channels, |
443 | .num_channels = ARRAY_SIZE(hsc_channels), |
444 | }; |
445 | |
446 | int hsc_common_probe(struct device *dev, hsc_recv_fn recv) |
447 | { |
448 | struct hsc_data *hsc; |
449 | struct iio_dev *indio_dev; |
450 | const char *triplet; |
451 | s64 tmp; |
452 | int ret; |
453 | |
454 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*hsc)); |
455 | if (!indio_dev) |
456 | return -ENOMEM; |
457 | |
458 | hsc = iio_priv(indio_dev); |
459 | |
460 | hsc->chip = &hsc_chip; |
461 | hsc->recv_cb = recv; |
462 | hsc->dev = dev; |
463 | |
464 | ret = device_property_read_u32(dev, propname: "honeywell,transfer-function" , |
465 | val: &hsc->function); |
466 | if (ret) |
467 | return dev_err_probe(dev, err: ret, |
468 | fmt: "honeywell,transfer-function could not be read\n" ); |
469 | if (hsc->function > HSC_FUNCTION_F) |
470 | return dev_err_probe(dev, err: -EINVAL, |
471 | fmt: "honeywell,transfer-function %d invalid\n" , |
472 | hsc->function); |
473 | |
474 | ret = device_property_read_string(dev, propname: "honeywell,pressure-triplet" , |
475 | val: &triplet); |
476 | if (ret) |
477 | return dev_err_probe(dev, err: ret, |
478 | fmt: "honeywell,pressure-triplet could not be read\n" ); |
479 | |
480 | if (str_has_prefix(str: triplet, prefix: "NA" )) { |
481 | ret = device_property_read_u32(dev, propname: "honeywell,pmin-pascal" , |
482 | val: &hsc->pmin); |
483 | if (ret) |
484 | return dev_err_probe(dev, err: ret, |
485 | fmt: "honeywell,pmin-pascal could not be read\n" ); |
486 | |
487 | ret = device_property_read_u32(dev, propname: "honeywell,pmax-pascal" , |
488 | val: &hsc->pmax); |
489 | if (ret) |
490 | return dev_err_probe(dev, err: ret, |
491 | fmt: "honeywell,pmax-pascal could not be read\n" ); |
492 | } else { |
493 | ret = device_property_match_property_string(dev, |
494 | propname: "honeywell,pressure-triplet" , |
495 | array: hsc_triplet_variants, |
496 | n: HSC_VARIANTS_MAX); |
497 | if (ret < 0) |
498 | return dev_err_probe(dev, err: -EINVAL, |
499 | fmt: "honeywell,pressure-triplet is invalid\n" ); |
500 | |
501 | hsc->pmin = hsc_range_config[ret].pmin; |
502 | hsc->pmax = hsc_range_config[ret].pmax; |
503 | } |
504 | |
505 | if (hsc->pmin >= hsc->pmax) |
506 | return dev_err_probe(dev, err: -EINVAL, |
507 | fmt: "pressure limits are invalid\n" ); |
508 | |
509 | ret = devm_regulator_get_enable(dev, id: "vdd" ); |
510 | if (ret) |
511 | return dev_err_probe(dev, err: ret, fmt: "can't get vdd supply\n" ); |
512 | |
513 | hsc->outmin = hsc_func_spec[hsc->function].output_min; |
514 | hsc->outmax = hsc_func_spec[hsc->function].output_max; |
515 | |
516 | tmp = div_s64(dividend: ((s64)(hsc->pmax - hsc->pmin)) * MICRO, |
517 | divisor: hsc->outmax - hsc->outmin); |
518 | hsc->p_scale = div_s64_rem(dividend: tmp, NANO, remainder: &hsc->p_scale_dec); |
519 | tmp = div_s64(dividend: ((s64)hsc->pmin * (s64)(hsc->outmax - hsc->outmin)) * MICRO, |
520 | divisor: hsc->pmax - hsc->pmin); |
521 | tmp -= (s64)hsc->outmin * MICRO; |
522 | hsc->p_offset = div_s64_rem(dividend: tmp, MICRO, remainder: &hsc->p_offset_dec); |
523 | |
524 | indio_dev->name = "hsc030pa" ; |
525 | indio_dev->modes = INDIO_DIRECT_MODE; |
526 | indio_dev->info = &hsc_info; |
527 | indio_dev->channels = hsc->chip->channels; |
528 | indio_dev->num_channels = hsc->chip->num_channels; |
529 | |
530 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, |
531 | hsc_trigger_handler, NULL); |
532 | if (ret) |
533 | return ret; |
534 | |
535 | return devm_iio_device_register(dev, indio_dev); |
536 | } |
537 | EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA); |
538 | |
539 | MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>" ); |
540 | MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor core driver" ); |
541 | MODULE_LICENSE("GPL" ); |
542 | |