1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * abstraction of the spi interface of HopeRf rf69 radio module |
4 | * |
5 | * Copyright (C) 2016 Wolf-Entwicklungen |
6 | * Marcus Wolf <linux@wolf-entwicklungen.de> |
7 | */ |
8 | |
9 | #include <linux/types.h> |
10 | #include <linux/spi/spi.h> |
11 | #include <linux/units.h> |
12 | |
13 | #include "rf69.h" |
14 | #include "rf69_registers.h" |
15 | |
16 | #define F_OSC (32 * HZ_PER_MHZ) |
17 | |
18 | /*-------------------------------------------------------------------------*/ |
19 | |
20 | u8 rf69_read_reg(struct spi_device *spi, u8 addr) |
21 | { |
22 | return spi_w8r8(spi, cmd: addr); |
23 | } |
24 | |
25 | static int rf69_write_reg(struct spi_device *spi, u8 addr, u8 value) |
26 | { |
27 | char buffer[2]; |
28 | |
29 | buffer[0] = addr | WRITE_BIT; |
30 | buffer[1] = value; |
31 | |
32 | return spi_write(spi, buf: &buffer, ARRAY_SIZE(buffer)); |
33 | } |
34 | |
35 | /*-------------------------------------------------------------------------*/ |
36 | |
37 | static int rf69_set_bit(struct spi_device *spi, u8 reg, u8 mask) |
38 | { |
39 | u8 tmp; |
40 | |
41 | tmp = rf69_read_reg(spi, addr: reg); |
42 | tmp = tmp | mask; |
43 | return rf69_write_reg(spi, addr: reg, value: tmp); |
44 | } |
45 | |
46 | static int rf69_clear_bit(struct spi_device *spi, u8 reg, u8 mask) |
47 | { |
48 | u8 tmp; |
49 | |
50 | tmp = rf69_read_reg(spi, addr: reg); |
51 | tmp = tmp & ~mask; |
52 | return rf69_write_reg(spi, addr: reg, value: tmp); |
53 | } |
54 | |
55 | static inline int rf69_read_mod_write(struct spi_device *spi, u8 reg, |
56 | u8 mask, u8 value) |
57 | { |
58 | u8 tmp; |
59 | |
60 | tmp = rf69_read_reg(spi, addr: reg); |
61 | tmp = (tmp & ~mask) | value; |
62 | return rf69_write_reg(spi, addr: reg, value: tmp); |
63 | } |
64 | |
65 | /*-------------------------------------------------------------------------*/ |
66 | |
67 | int rf69_get_version(struct spi_device *spi) |
68 | { |
69 | return rf69_read_reg(spi, REG_VERSION); |
70 | } |
71 | |
72 | int rf69_set_mode(struct spi_device *spi, enum mode mode) |
73 | { |
74 | static const u8 mode_map[] = { |
75 | [transmit] = OPMODE_MODE_TRANSMIT, |
76 | [receive] = OPMODE_MODE_RECEIVE, |
77 | [synthesizer] = OPMODE_MODE_SYNTHESIZER, |
78 | [standby] = OPMODE_MODE_STANDBY, |
79 | [mode_sleep] = OPMODE_MODE_SLEEP, |
80 | }; |
81 | |
82 | if (unlikely(mode >= ARRAY_SIZE(mode_map))) { |
83 | dev_dbg(&spi->dev, "set: illegal mode %u\n" , mode); |
84 | return -EINVAL; |
85 | } |
86 | |
87 | return rf69_read_mod_write(spi, REG_OPMODE, MASK_OPMODE_MODE, |
88 | value: mode_map[mode]); |
89 | |
90 | /* |
91 | * we are using packet mode, so this check is not really needed |
92 | * but waiting for mode ready is necessary when going from sleep |
93 | * because the FIFO may not be immediately available from previous mode |
94 | * while (_mode == RF69_MODE_SLEEP && (READ_REG(REG_IRQFLAGS1) & |
95 | RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady |
96 | */ |
97 | } |
98 | |
99 | int rf69_set_data_mode(struct spi_device *spi, u8 data_mode) |
100 | { |
101 | return rf69_read_mod_write(spi, REG_DATAMODUL, MASK_DATAMODUL_MODE, |
102 | value: data_mode); |
103 | } |
104 | |
105 | int rf69_set_modulation(struct spi_device *spi, enum modulation modulation) |
106 | { |
107 | static const u8 modulation_map[] = { |
108 | [OOK] = DATAMODUL_MODULATION_TYPE_OOK, |
109 | [FSK] = DATAMODUL_MODULATION_TYPE_FSK, |
110 | }; |
111 | |
112 | if (unlikely(modulation >= ARRAY_SIZE(modulation_map))) { |
113 | dev_dbg(&spi->dev, "set: illegal modulation %u\n" , modulation); |
114 | return -EINVAL; |
115 | } |
116 | |
117 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
118 | MASK_DATAMODUL_MODULATION_TYPE, |
119 | value: modulation_map[modulation]); |
120 | } |
121 | |
122 | static enum modulation rf69_get_modulation(struct spi_device *spi) |
123 | { |
124 | u8 modulation_reg; |
125 | |
126 | modulation_reg = rf69_read_reg(spi, REG_DATAMODUL); |
127 | |
128 | switch (modulation_reg & MASK_DATAMODUL_MODULATION_TYPE) { |
129 | case DATAMODUL_MODULATION_TYPE_OOK: |
130 | return OOK; |
131 | case DATAMODUL_MODULATION_TYPE_FSK: |
132 | return FSK; |
133 | default: |
134 | return UNDEF; |
135 | } |
136 | } |
137 | |
138 | int rf69_set_modulation_shaping(struct spi_device *spi, |
139 | enum mod_shaping mod_shaping) |
140 | { |
141 | switch (rf69_get_modulation(spi)) { |
142 | case FSK: |
143 | switch (mod_shaping) { |
144 | case SHAPING_OFF: |
145 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
146 | MASK_DATAMODUL_MODULATION_SHAPE, |
147 | DATAMODUL_MODULATION_SHAPE_NONE); |
148 | case SHAPING_1_0: |
149 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
150 | MASK_DATAMODUL_MODULATION_SHAPE, |
151 | DATAMODUL_MODULATION_SHAPE_1_0); |
152 | case SHAPING_0_5: |
153 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
154 | MASK_DATAMODUL_MODULATION_SHAPE, |
155 | DATAMODUL_MODULATION_SHAPE_0_5); |
156 | case SHAPING_0_3: |
157 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
158 | MASK_DATAMODUL_MODULATION_SHAPE, |
159 | DATAMODUL_MODULATION_SHAPE_0_3); |
160 | default: |
161 | dev_dbg(&spi->dev, "set: illegal mod shaping for FSK %u\n" , mod_shaping); |
162 | return -EINVAL; |
163 | } |
164 | case OOK: |
165 | switch (mod_shaping) { |
166 | case SHAPING_OFF: |
167 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
168 | MASK_DATAMODUL_MODULATION_SHAPE, |
169 | DATAMODUL_MODULATION_SHAPE_NONE); |
170 | case SHAPING_BR: |
171 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
172 | MASK_DATAMODUL_MODULATION_SHAPE, |
173 | DATAMODUL_MODULATION_SHAPE_BR); |
174 | case SHAPING_2BR: |
175 | return rf69_read_mod_write(spi, REG_DATAMODUL, |
176 | MASK_DATAMODUL_MODULATION_SHAPE, |
177 | DATAMODUL_MODULATION_SHAPE_2BR); |
178 | default: |
179 | dev_dbg(&spi->dev, "set: illegal mod shaping for OOK %u\n" , mod_shaping); |
180 | return -EINVAL; |
181 | } |
182 | default: |
183 | dev_dbg(&spi->dev, "set: modulation undefined\n" ); |
184 | return -EINVAL; |
185 | } |
186 | } |
187 | |
188 | int rf69_set_bit_rate(struct spi_device *spi, u16 bit_rate) |
189 | { |
190 | int retval; |
191 | u32 bit_rate_reg; |
192 | u8 msb; |
193 | u8 lsb; |
194 | enum modulation mod; |
195 | |
196 | // check if modulation is configured |
197 | mod = rf69_get_modulation(spi); |
198 | if (mod == UNDEF) { |
199 | dev_dbg(&spi->dev, "setBitRate: modulation is undefined\n" ); |
200 | return -EINVAL; |
201 | } |
202 | |
203 | // check input value |
204 | if (bit_rate < 1200 || (mod == OOK && bit_rate > 32768)) { |
205 | dev_dbg(&spi->dev, "setBitRate: illegal input param\n" ); |
206 | return -EINVAL; |
207 | } |
208 | |
209 | // calculate reg settings |
210 | bit_rate_reg = (F_OSC / bit_rate); |
211 | |
212 | msb = (bit_rate_reg & 0xff00) >> 8; |
213 | lsb = (bit_rate_reg & 0xff); |
214 | |
215 | // transmit to RF 69 |
216 | retval = rf69_write_reg(spi, REG_BITRATE_MSB, value: msb); |
217 | if (retval) |
218 | return retval; |
219 | retval = rf69_write_reg(spi, REG_BITRATE_LSB, value: lsb); |
220 | if (retval) |
221 | return retval; |
222 | |
223 | return 0; |
224 | } |
225 | |
226 | int rf69_set_deviation(struct spi_device *spi, u32 deviation) |
227 | { |
228 | int retval; |
229 | u64 f_reg; |
230 | u64 f_step; |
231 | u32 bit_rate_reg; |
232 | u32 bit_rate; |
233 | u8 msb; |
234 | u8 lsb; |
235 | u64 factor = 1000000; // to improve precision of calculation |
236 | |
237 | // calculate bit rate |
238 | bit_rate_reg = rf69_read_reg(spi, REG_BITRATE_MSB) << 8; |
239 | bit_rate_reg |= rf69_read_reg(spi, REG_BITRATE_LSB); |
240 | bit_rate = F_OSC / bit_rate_reg; |
241 | |
242 | /* |
243 | * frequency deviation must exceed 600 Hz but not exceed |
244 | * 500kHz when taking bitrate dependency into consideration |
245 | * to ensure proper modulation |
246 | */ |
247 | if (deviation < 600 || (deviation + (bit_rate / 2)) > 500000) { |
248 | dev_dbg(&spi->dev, |
249 | "set_deviation: illegal input param: %u\n" , deviation); |
250 | return -EINVAL; |
251 | } |
252 | |
253 | // calculat f step |
254 | f_step = F_OSC * factor; |
255 | do_div(f_step, 524288); // 524288 = 2^19 |
256 | |
257 | // calculate register settings |
258 | f_reg = deviation * factor; |
259 | do_div(f_reg, f_step); |
260 | |
261 | msb = (f_reg & 0xff00) >> 8; |
262 | lsb = (f_reg & 0xff); |
263 | |
264 | // check msb |
265 | if (msb & ~FDEVMASB_MASK) { |
266 | dev_dbg(&spi->dev, "set_deviation: err in calc of msb\n" ); |
267 | return -EINVAL; |
268 | } |
269 | |
270 | // write to chip |
271 | retval = rf69_write_reg(spi, REG_FDEV_MSB, value: msb); |
272 | if (retval) |
273 | return retval; |
274 | retval = rf69_write_reg(spi, REG_FDEV_LSB, value: lsb); |
275 | if (retval) |
276 | return retval; |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | int rf69_set_frequency(struct spi_device *spi, u32 frequency) |
282 | { |
283 | int retval; |
284 | u32 f_max; |
285 | u64 f_reg; |
286 | u64 f_step; |
287 | u8 msb; |
288 | u8 mid; |
289 | u8 lsb; |
290 | u64 factor = 1000000; // to improve precision of calculation |
291 | |
292 | // calculat f step |
293 | f_step = F_OSC * factor; |
294 | do_div(f_step, 524288); // 524288 = 2^19 |
295 | |
296 | // check input value |
297 | f_max = div_u64(dividend: f_step * 8388608, divisor: factor); |
298 | if (frequency > f_max) { |
299 | dev_dbg(&spi->dev, "setFrequency: illegal input param\n" ); |
300 | return -EINVAL; |
301 | } |
302 | |
303 | // calculate reg settings |
304 | f_reg = frequency * factor; |
305 | do_div(f_reg, f_step); |
306 | |
307 | msb = (f_reg & 0xff0000) >> 16; |
308 | mid = (f_reg & 0xff00) >> 8; |
309 | lsb = (f_reg & 0xff); |
310 | |
311 | // write to chip |
312 | retval = rf69_write_reg(spi, REG_FRF_MSB, value: msb); |
313 | if (retval) |
314 | return retval; |
315 | retval = rf69_write_reg(spi, REG_FRF_MID, value: mid); |
316 | if (retval) |
317 | return retval; |
318 | retval = rf69_write_reg(spi, REG_FRF_LSB, value: lsb); |
319 | if (retval) |
320 | return retval; |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | int rf69_enable_amplifier(struct spi_device *spi, u8 amplifier_mask) |
326 | { |
327 | return rf69_set_bit(spi, REG_PALEVEL, mask: amplifier_mask); |
328 | } |
329 | |
330 | int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask) |
331 | { |
332 | return rf69_clear_bit(spi, REG_PALEVEL, mask: amplifier_mask); |
333 | } |
334 | |
335 | int rf69_set_output_power_level(struct spi_device *spi, u8 power_level) |
336 | { |
337 | u8 pa_level, ocp, test_pa1, test_pa2; |
338 | bool pa0, pa1, pa2, high_power; |
339 | u8 min_power_level; |
340 | |
341 | // check register pa_level |
342 | pa_level = rf69_read_reg(spi, REG_PALEVEL); |
343 | pa0 = pa_level & MASK_PALEVEL_PA0; |
344 | pa1 = pa_level & MASK_PALEVEL_PA1; |
345 | pa2 = pa_level & MASK_PALEVEL_PA2; |
346 | |
347 | // check high power mode |
348 | ocp = rf69_read_reg(spi, REG_OCP); |
349 | test_pa1 = rf69_read_reg(spi, REG_TESTPA1); |
350 | test_pa2 = rf69_read_reg(spi, REG_TESTPA2); |
351 | high_power = (ocp == 0x0f) && (test_pa1 == 0x5d) && (test_pa2 == 0x7c); |
352 | |
353 | if (pa0 && !pa1 && !pa2) { |
354 | power_level += 18; |
355 | min_power_level = 0; |
356 | } else if (!pa0 && pa1 && !pa2) { |
357 | power_level += 18; |
358 | min_power_level = 16; |
359 | } else if (!pa0 && pa1 && pa2) { |
360 | if (high_power) |
361 | power_level += 11; |
362 | else |
363 | power_level += 14; |
364 | min_power_level = 16; |
365 | } else { |
366 | goto failed; |
367 | } |
368 | |
369 | // check input value |
370 | if (power_level > 0x1f) |
371 | goto failed; |
372 | |
373 | if (power_level < min_power_level) |
374 | goto failed; |
375 | |
376 | // write value |
377 | return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, |
378 | value: power_level); |
379 | failed: |
380 | dev_dbg(&spi->dev, "set: illegal power level %u\n" , power_level); |
381 | return -EINVAL; |
382 | } |
383 | |
384 | int rf69_set_pa_ramp(struct spi_device *spi, enum pa_ramp pa_ramp) |
385 | { |
386 | static const u8 pa_ramp_map[] = { |
387 | [ramp3400] = PARAMP_3400, |
388 | [ramp2000] = PARAMP_2000, |
389 | [ramp1000] = PARAMP_1000, |
390 | [ramp500] = PARAMP_500, |
391 | [ramp250] = PARAMP_250, |
392 | [ramp125] = PARAMP_125, |
393 | [ramp100] = PARAMP_100, |
394 | [ramp62] = PARAMP_62, |
395 | [ramp50] = PARAMP_50, |
396 | [ramp40] = PARAMP_40, |
397 | [ramp31] = PARAMP_31, |
398 | [ramp25] = PARAMP_25, |
399 | [ramp20] = PARAMP_20, |
400 | [ramp15] = PARAMP_15, |
401 | [ramp10] = PARAMP_10, |
402 | }; |
403 | |
404 | if (unlikely(pa_ramp >= ARRAY_SIZE(pa_ramp_map))) { |
405 | dev_dbg(&spi->dev, "set: illegal pa_ramp %u\n" , pa_ramp); |
406 | return -EINVAL; |
407 | } |
408 | |
409 | return rf69_write_reg(spi, REG_PARAMP, value: pa_ramp_map[pa_ramp]); |
410 | } |
411 | |
412 | int rf69_set_antenna_impedance(struct spi_device *spi, |
413 | enum antenna_impedance antenna_impedance) |
414 | { |
415 | switch (antenna_impedance) { |
416 | case fifty_ohm: |
417 | return rf69_clear_bit(spi, REG_LNA, MASK_LNA_ZIN); |
418 | case two_hundred_ohm: |
419 | return rf69_set_bit(spi, REG_LNA, MASK_LNA_ZIN); |
420 | default: |
421 | dev_dbg(&spi->dev, "set: illegal antenna impedance %u\n" , antenna_impedance); |
422 | return -EINVAL; |
423 | } |
424 | } |
425 | |
426 | int rf69_set_lna_gain(struct spi_device *spi, enum lna_gain lna_gain) |
427 | { |
428 | static const u8 lna_gain_map[] = { |
429 | [automatic] = LNA_GAIN_AUTO, |
430 | [max] = LNA_GAIN_MAX, |
431 | [max_minus_6] = LNA_GAIN_MAX_MINUS_6, |
432 | [max_minus_12] = LNA_GAIN_MAX_MINUS_12, |
433 | [max_minus_24] = LNA_GAIN_MAX_MINUS_24, |
434 | [max_minus_36] = LNA_GAIN_MAX_MINUS_36, |
435 | [max_minus_48] = LNA_GAIN_MAX_MINUS_48, |
436 | }; |
437 | |
438 | if (unlikely(lna_gain >= ARRAY_SIZE(lna_gain_map))) { |
439 | dev_dbg(&spi->dev, "set: illegal lna gain %u\n" , lna_gain); |
440 | return -EINVAL; |
441 | } |
442 | |
443 | return rf69_read_mod_write(spi, REG_LNA, MASK_LNA_GAIN, |
444 | value: lna_gain_map[lna_gain]); |
445 | } |
446 | |
447 | static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, |
448 | enum mantisse mantisse, u8 exponent) |
449 | { |
450 | u8 bandwidth; |
451 | |
452 | // check value for mantisse and exponent |
453 | if (exponent > 7) { |
454 | dev_dbg(&spi->dev, "set: illegal bandwidth exponent %u\n" , exponent); |
455 | return -EINVAL; |
456 | } |
457 | |
458 | if (mantisse != mantisse16 && |
459 | mantisse != mantisse20 && |
460 | mantisse != mantisse24) { |
461 | dev_dbg(&spi->dev, "set: illegal bandwidth mantisse %u\n" , mantisse); |
462 | return -EINVAL; |
463 | } |
464 | |
465 | // read old value |
466 | bandwidth = rf69_read_reg(spi, addr: reg); |
467 | |
468 | // "delete" mantisse and exponent = just keep the DCC setting |
469 | bandwidth = bandwidth & MASK_BW_DCC_FREQ; |
470 | |
471 | // add new mantisse |
472 | switch (mantisse) { |
473 | case mantisse16: |
474 | bandwidth = bandwidth | BW_MANT_16; |
475 | break; |
476 | case mantisse20: |
477 | bandwidth = bandwidth | BW_MANT_20; |
478 | break; |
479 | case mantisse24: |
480 | bandwidth = bandwidth | BW_MANT_24; |
481 | break; |
482 | } |
483 | |
484 | // add new exponent |
485 | bandwidth = bandwidth | exponent; |
486 | |
487 | // write back |
488 | return rf69_write_reg(spi, addr: reg, value: bandwidth); |
489 | } |
490 | |
491 | int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, |
492 | u8 exponent) |
493 | { |
494 | return rf69_set_bandwidth_intern(spi, REG_RXBW, mantisse, exponent); |
495 | } |
496 | |
497 | int rf69_set_bandwidth_during_afc(struct spi_device *spi, |
498 | enum mantisse mantisse, |
499 | u8 exponent) |
500 | { |
501 | return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent); |
502 | } |
503 | |
504 | int rf69_set_ook_threshold_dec(struct spi_device *spi, |
505 | enum threshold_decrement threshold_decrement) |
506 | { |
507 | static const u8 td_map[] = { |
508 | [dec_every8th] = OOKPEAK_THRESHDEC_EVERY_8TH, |
509 | [dec_every4th] = OOKPEAK_THRESHDEC_EVERY_4TH, |
510 | [dec_every2nd] = OOKPEAK_THRESHDEC_EVERY_2ND, |
511 | [dec_once] = OOKPEAK_THRESHDEC_ONCE, |
512 | [dec_twice] = OOKPEAK_THRESHDEC_TWICE, |
513 | [dec_4times] = OOKPEAK_THRESHDEC_4_TIMES, |
514 | [dec_8times] = OOKPEAK_THRESHDEC_8_TIMES, |
515 | [dec_16times] = OOKPEAK_THRESHDEC_16_TIMES, |
516 | }; |
517 | |
518 | if (unlikely(threshold_decrement >= ARRAY_SIZE(td_map))) { |
519 | dev_dbg(&spi->dev, "set: illegal OOK threshold decrement %u\n" , |
520 | threshold_decrement); |
521 | return -EINVAL; |
522 | } |
523 | |
524 | return rf69_read_mod_write(spi, REG_OOKPEAK, MASK_OOKPEAK_THRESDEC, |
525 | value: td_map[threshold_decrement]); |
526 | } |
527 | |
528 | int rf69_set_dio_mapping(struct spi_device *spi, u8 dio_number, u8 value) |
529 | { |
530 | u8 mask; |
531 | u8 shift; |
532 | u8 dio_addr; |
533 | u8 dio_value; |
534 | |
535 | switch (dio_number) { |
536 | case 0: |
537 | mask = MASK_DIO0; |
538 | shift = SHIFT_DIO0; |
539 | dio_addr = REG_DIOMAPPING1; |
540 | break; |
541 | case 1: |
542 | mask = MASK_DIO1; |
543 | shift = SHIFT_DIO1; |
544 | dio_addr = REG_DIOMAPPING1; |
545 | break; |
546 | case 2: |
547 | mask = MASK_DIO2; |
548 | shift = SHIFT_DIO2; |
549 | dio_addr = REG_DIOMAPPING1; |
550 | break; |
551 | case 3: |
552 | mask = MASK_DIO3; |
553 | shift = SHIFT_DIO3; |
554 | dio_addr = REG_DIOMAPPING1; |
555 | break; |
556 | case 4: |
557 | mask = MASK_DIO4; |
558 | shift = SHIFT_DIO4; |
559 | dio_addr = REG_DIOMAPPING2; |
560 | break; |
561 | case 5: |
562 | mask = MASK_DIO5; |
563 | shift = SHIFT_DIO5; |
564 | dio_addr = REG_DIOMAPPING2; |
565 | break; |
566 | default: |
567 | dev_dbg(&spi->dev, "set: illegal dio number %u\n" , dio_number); |
568 | return -EINVAL; |
569 | } |
570 | |
571 | // read reg |
572 | dio_value = rf69_read_reg(spi, addr: dio_addr); |
573 | // delete old value |
574 | dio_value = dio_value & ~mask; |
575 | // add new value |
576 | dio_value = dio_value | value << shift; |
577 | // write back |
578 | return rf69_write_reg(spi, addr: dio_addr, value: dio_value); |
579 | } |
580 | |
581 | int (struct spi_device *spi, u8 threshold) |
582 | { |
583 | /* no value check needed - u8 exactly matches register size */ |
584 | |
585 | return rf69_write_reg(spi, REG_RSSITHRESH, value: threshold); |
586 | } |
587 | |
588 | int rf69_set_preamble_length(struct spi_device *spi, u16 preamble_length) |
589 | { |
590 | int retval; |
591 | u8 msb, lsb; |
592 | |
593 | /* no value check needed - u16 exactly matches register size */ |
594 | |
595 | /* calculate reg settings */ |
596 | msb = (preamble_length & 0xff00) >> 8; |
597 | lsb = (preamble_length & 0xff); |
598 | |
599 | /* transmit to chip */ |
600 | retval = rf69_write_reg(spi, REG_PREAMBLE_MSB, value: msb); |
601 | if (retval) |
602 | return retval; |
603 | return rf69_write_reg(spi, REG_PREAMBLE_LSB, value: lsb); |
604 | } |
605 | |
606 | int rf69_enable_sync(struct spi_device *spi) |
607 | { |
608 | return rf69_set_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_ON); |
609 | } |
610 | |
611 | int rf69_disable_sync(struct spi_device *spi) |
612 | { |
613 | return rf69_clear_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_ON); |
614 | } |
615 | |
616 | int rf69_set_fifo_fill_condition(struct spi_device *spi, |
617 | enum fifo_fill_condition fifo_fill_condition) |
618 | { |
619 | switch (fifo_fill_condition) { |
620 | case always: |
621 | return rf69_set_bit(spi, REG_SYNC_CONFIG, |
622 | MASK_SYNC_CONFIG_FIFO_FILL_CONDITION); |
623 | case after_sync_interrupt: |
624 | return rf69_clear_bit(spi, REG_SYNC_CONFIG, |
625 | MASK_SYNC_CONFIG_FIFO_FILL_CONDITION); |
626 | default: |
627 | dev_dbg(&spi->dev, "set: illegal fifo fill condition %u\n" , fifo_fill_condition); |
628 | return -EINVAL; |
629 | } |
630 | } |
631 | |
632 | int rf69_set_sync_size(struct spi_device *spi, u8 sync_size) |
633 | { |
634 | // check input value |
635 | if (sync_size > 0x07) { |
636 | dev_dbg(&spi->dev, "set: illegal sync size %u\n" , sync_size); |
637 | return -EINVAL; |
638 | } |
639 | |
640 | // write value |
641 | return rf69_read_mod_write(spi, REG_SYNC_CONFIG, |
642 | MASK_SYNC_CONFIG_SYNC_SIZE, |
643 | value: (sync_size << 3)); |
644 | } |
645 | |
646 | int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8]) |
647 | { |
648 | int retval = 0; |
649 | |
650 | retval += rf69_write_reg(spi, REG_SYNCVALUE1, value: sync_values[0]); |
651 | retval += rf69_write_reg(spi, REG_SYNCVALUE2, value: sync_values[1]); |
652 | retval += rf69_write_reg(spi, REG_SYNCVALUE3, value: sync_values[2]); |
653 | retval += rf69_write_reg(spi, REG_SYNCVALUE4, value: sync_values[3]); |
654 | retval += rf69_write_reg(spi, REG_SYNCVALUE5, value: sync_values[4]); |
655 | retval += rf69_write_reg(spi, REG_SYNCVALUE6, value: sync_values[5]); |
656 | retval += rf69_write_reg(spi, REG_SYNCVALUE7, value: sync_values[6]); |
657 | retval += rf69_write_reg(spi, REG_SYNCVALUE8, value: sync_values[7]); |
658 | |
659 | return retval; |
660 | } |
661 | |
662 | int rf69_set_packet_format(struct spi_device *spi, |
663 | enum packet_format packet_format) |
664 | { |
665 | switch (packet_format) { |
666 | case packet_length_var: |
667 | return rf69_set_bit(spi, REG_PACKETCONFIG1, |
668 | MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE); |
669 | case packet_length_fix: |
670 | return rf69_clear_bit(spi, REG_PACKETCONFIG1, |
671 | MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE); |
672 | default: |
673 | dev_dbg(&spi->dev, "set: illegal packet format %u\n" , packet_format); |
674 | return -EINVAL; |
675 | } |
676 | } |
677 | |
678 | int rf69_enable_crc(struct spi_device *spi) |
679 | { |
680 | return rf69_set_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_CRC_ON); |
681 | } |
682 | |
683 | int rf69_disable_crc(struct spi_device *spi) |
684 | { |
685 | return rf69_clear_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_CRC_ON); |
686 | } |
687 | |
688 | int rf69_set_address_filtering(struct spi_device *spi, |
689 | enum address_filtering address_filtering) |
690 | { |
691 | static const u8 af_map[] = { |
692 | [filtering_off] = PACKETCONFIG1_ADDRESSFILTERING_OFF, |
693 | [node_address] = PACKETCONFIG1_ADDRESSFILTERING_NODE, |
694 | [node_or_broadcast_address] = |
695 | PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST, |
696 | }; |
697 | |
698 | if (unlikely(address_filtering >= ARRAY_SIZE(af_map))) { |
699 | dev_dbg(&spi->dev, "set: illegal address filtering %u\n" , address_filtering); |
700 | return -EINVAL; |
701 | } |
702 | |
703 | return rf69_read_mod_write(spi, REG_PACKETCONFIG1, |
704 | MASK_PACKETCONFIG1_ADDRESSFILTERING, |
705 | value: af_map[address_filtering]); |
706 | } |
707 | |
708 | int rf69_set_payload_length(struct spi_device *spi, u8 payload_length) |
709 | { |
710 | return rf69_write_reg(spi, REG_PAYLOAD_LENGTH, value: payload_length); |
711 | } |
712 | |
713 | int rf69_set_node_address(struct spi_device *spi, u8 node_address) |
714 | { |
715 | return rf69_write_reg(spi, REG_NODEADRS, value: node_address); |
716 | } |
717 | |
718 | int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcast_address) |
719 | { |
720 | return rf69_write_reg(spi, REG_BROADCASTADRS, value: broadcast_address); |
721 | } |
722 | |
723 | int rf69_set_tx_start_condition(struct spi_device *spi, |
724 | enum tx_start_condition tx_start_condition) |
725 | { |
726 | switch (tx_start_condition) { |
727 | case fifo_level: |
728 | return rf69_clear_bit(spi, REG_FIFO_THRESH, |
729 | MASK_FIFO_THRESH_TXSTART); |
730 | case fifo_not_empty: |
731 | return rf69_set_bit(spi, REG_FIFO_THRESH, |
732 | MASK_FIFO_THRESH_TXSTART); |
733 | default: |
734 | dev_dbg(&spi->dev, "set: illegal tx start condition %u\n" , tx_start_condition); |
735 | return -EINVAL; |
736 | } |
737 | } |
738 | |
739 | int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold) |
740 | { |
741 | int retval; |
742 | |
743 | /* check input value */ |
744 | if (threshold & ~MASK_FIFO_THRESH_VALUE) { |
745 | dev_dbg(&spi->dev, "set: illegal fifo threshold %u\n" , threshold); |
746 | return -EINVAL; |
747 | } |
748 | |
749 | /* write value */ |
750 | retval = rf69_read_mod_write(spi, REG_FIFO_THRESH, |
751 | MASK_FIFO_THRESH_VALUE, |
752 | value: threshold); |
753 | if (retval) |
754 | return retval; |
755 | |
756 | /* |
757 | * access the fifo to activate new threshold |
758 | * retval (mis-) used as buffer here |
759 | */ |
760 | return rf69_read_fifo(spi, buffer: (u8 *)&retval, size: 1); |
761 | } |
762 | |
763 | int rf69_set_dagc(struct spi_device *spi, enum dagc dagc) |
764 | { |
765 | static const u8 dagc_map[] = { |
766 | [normal_mode] = DAGC_NORMAL, |
767 | [improve] = DAGC_IMPROVED_LOWBETA0, |
768 | [improve_for_low_modulation_index] = DAGC_IMPROVED_LOWBETA1, |
769 | }; |
770 | |
771 | if (unlikely(dagc >= ARRAY_SIZE(dagc_map))) { |
772 | dev_dbg(&spi->dev, "set: illegal dagc %u\n" , dagc); |
773 | return -EINVAL; |
774 | } |
775 | |
776 | return rf69_write_reg(spi, REG_TESTDAGC, value: dagc_map[dagc]); |
777 | } |
778 | |
779 | /*-------------------------------------------------------------------------*/ |
780 | |
781 | int rf69_read_fifo(struct spi_device *spi, u8 *buffer, unsigned int size) |
782 | { |
783 | int i; |
784 | struct spi_transfer transfer; |
785 | u8 local_buffer[FIFO_SIZE + 1] = {}; |
786 | int retval; |
787 | |
788 | if (size > FIFO_SIZE) { |
789 | dev_dbg(&spi->dev, |
790 | "read fifo: passed in buffer bigger then internal buffer\n" ); |
791 | return -EMSGSIZE; |
792 | } |
793 | |
794 | /* prepare a bidirectional transfer */ |
795 | local_buffer[0] = REG_FIFO; |
796 | memset(&transfer, 0, sizeof(transfer)); |
797 | transfer.tx_buf = local_buffer; |
798 | transfer.rx_buf = local_buffer; |
799 | transfer.len = size + 1; |
800 | |
801 | retval = spi_sync_transfer(spi, xfers: &transfer, num_xfers: 1); |
802 | |
803 | /* print content read from fifo for debugging purposes */ |
804 | for (i = 0; i < size; i++) |
805 | dev_dbg(&spi->dev, "%d - 0x%x\n" , i, local_buffer[i + 1]); |
806 | |
807 | memcpy(buffer, &local_buffer[1], size); |
808 | |
809 | return retval; |
810 | } |
811 | |
812 | int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size) |
813 | { |
814 | int i; |
815 | u8 local_buffer[FIFO_SIZE + 1]; |
816 | |
817 | if (size > FIFO_SIZE) { |
818 | dev_dbg(&spi->dev, |
819 | "write fifo: passed in buffer bigger then internal buffer\n" ); |
820 | return -EMSGSIZE; |
821 | } |
822 | |
823 | local_buffer[0] = REG_FIFO | WRITE_BIT; |
824 | memcpy(&local_buffer[1], buffer, size); |
825 | |
826 | /* print content written from fifo for debugging purposes */ |
827 | for (i = 0; i < size; i++) |
828 | dev_dbg(&spi->dev, "%d - 0x%x\n" , i, buffer[i]); |
829 | |
830 | return spi_write(spi, buf: local_buffer, len: size + 1); |
831 | } |
832 | |
833 | |