Contiki 2.5
cc1020.c
Go to the documentation of this file.
1 /*
2  * Copyright 2006, Freie Universitaet Berlin. All rights reserved.
3  *
4  * These sources were developed at the Freie Universitaet Berlin, Computer
5  * Systems and Telematics group.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * - Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * - Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * - Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * This software is provided by FUB and the contributors on an "as is"
22  * basis, without any representations or warranties of any kind, express
23  * or implied including, but not limited to, representations or
24  * warranties of non-infringement, merchantability or fitness for a
25  * particular purpose. In no event shall FUB or contributors be liable
26  * for any direct, indirect, incidental, special, exemplary, or
27  * consequential damages (including, but not limited to, procurement of
28  * substitute goods or services; loss of use, data, or profits; or
29  * business interruption) however caused and on any theory of liability,
30  * whether in contract, strict liability, or tort (including negligence
31  * or otherwise) arising in any way out of the use of this software,
32  * even if advised of the possibility of such damage.
33  *
34  * This implementation was originally developed by the CST group at the FUB.
35  */
36 
37 /**
38  * \file cc1020.c
39  * \author FUB ScatterWeb Developers, Michael Baar, Nicolas Tsiftes
40  **/
41 
42 #include <stdio.h>
43 #include <string.h>
44 #include <signal.h>
45 
46 #include "contiki.h"
47 #include "contiki-msb430.h"
48 #include "cc1020-internal.h"
49 #include "cc1020.h"
50 #include "lib/random.h"
51 #include "lib/crc16.h"
52 #include "net/rime/rimestats.h"
53 #include "dev/dma.h"
54 #include "sys/energest.h"
55 
56 #define DEBUG 0
57 #if DEBUG
58 #include <stdio.h>
59 #define PRINTF(...) printf(__VA_ARGS__)
60 #else
61 #define PRINTF(...)
62 #endif
63 
64 #define SEND_TIMEOUT 10
65 
66 static int cc1020_calibrate(void);
67 static int cc1020_setupTX(int);
68 static int cc1020_setupRX(int);
69 static void cc1020_setupPD(void);
70 static void cc1020_wakeupTX(int);
71 static void cc1020_wakeupRX(int);
72 static uint8_t cc1020_read_reg(uint8_t addr);
73 static void cc1020_write_reg(uint8_t addr, uint8_t adata);
74 static void cc1020_load_config(const uint8_t *);
75 static void cc1020_reset(void);
76 
77 static const uint8_t syncword[SYNCWORD_SIZE] = {0xD3, 0x91};
78 
79 /* current mode of cc1020 chip */
80 static volatile enum cc1020_state cc1020_state = CC1020_OFF;
81 static volatile uint8_t cc1020_rxbuf[HDR_SIZE + CC1020_BUFFERSIZE];
82 static uint8_t cc1020_txbuf[PREAMBLE_SIZE + SYNCWORD_SIZE + HDR_SIZE +
83  CC1020_BUFFERSIZE + TAIL_SIZE];
84 
85 /* number of bytes in receive and transmit buffers respectively. */
86 static uint8_t cc1020_rxlen;
87 static uint8_t cc1020_txlen;
88 
89 /* received signal strength indicator reading for last received packet */
90 static volatile uint8_t rssi;
91 
92 /* callback when a packet has been received */
93 static uint8_t cc1020_pa_power = PA_POWER;
94 
95 static volatile char dma_done;
96 
97 /* Radio driver AAPI functions. */
98 static int cc1020_init(void);
99 static int cc1020_prepare(const void *payload, unsigned short payload_len);
100 static int cc1020_transmit(unsigned short transmit_len);
101 static int cc1020_send(const void *payload, unsigned short payload_len);
102 static int cc1020_read(void *buf, unsigned short buf_len);
103 static int cc1020_channel_clear(void);
104 static int cc1020_receiving_packet(void);
105 static int cc1020_pending_packet(void);
106 static int cc1020_on(void);
107 static int cc1020_off(void);
108 
109 const struct radio_driver cc1020_driver =
110  {
111  cc1020_init,
112  cc1020_prepare,
113  cc1020_transmit,
114  cc1020_send,
115  cc1020_read,
116  cc1020_channel_clear,
117  cc1020_receiving_packet,
118  cc1020_pending_packet,
119  cc1020_on,
120  cc1020_off
121  };
122 
123 #define MS_DELAY(x) clock_delay(354 * (x))
124 
125 PROCESS(cc1020_receiver_process, "CC1020 receiver");
126 
127 static void
128 dma_callback(void)
129 {
130  dma_done = 1;
131 }
132 
133 static void
134 reset_receiver(void)
135 {
136  /* reset receiver */
137  cc1020_rxlen = 0;
138 
139  if((cc1020_state & CC1020_TURN_OFF) && (cc1020_txlen == 0)) {
140  cc1020_off();
141  } else {
142  CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING);
143  cc1020_set_rx();
144  ENABLE_RX_IRQ();
145  }
146 }
147 
148 static int
149 cc1020_init(void)
150 {
151  cc1020_setupPD();
152  cc1020_reset();
153  cc1020_load_config(cc1020_config_19200);
154 
155  /* init tx buffer with preamble + syncword */
156  memset(cc1020_txbuf, PREAMBLE, PREAMBLE_SIZE);
157  cc1020_txbuf[PREAMBLE_SIZE] = syncword[0];
158  cc1020_txbuf[PREAMBLE_SIZE + 1] = syncword[1];
159 
160  /* calibrate receiver */
161  cc1020_wakeupRX(RX_CURRENT);
162  if(!cc1020_calibrate()) {
163  PRINTF("cc1020: rx calibration failed\n");
164  return -1;
165  }
166 
167  /* calibrate transmitter */
168  cc1020_wakeupTX(TX_CURRENT);
169  if(!cc1020_calibrate()) {
170  PRINTF("cc1020: tx calibration failed\n");
171  return -1;
172  }
173 
174  /* power down */
175  cc1020_setupPD();
176 
177  process_start(&cc1020_receiver_process, NULL);
178  dma_subscribe(0, dma_callback);
179 
180  return 0;
181 }
182 
183 void
184 cc1020_set_rx(void)
185 {
186  int s;
187 
188  s = splhigh();
189 
190  /* Reset SEL for P3[1-3] (CC DIO, DIO, DCLK) and P3[4-5] (Camera Rx+Tx) */
191  P3SEL &= ~0x3E;
192  IFG1 &= ~(UTXIE0 | URXIE0); /* Clear interrupt flags */
193  ME1 &= ~(UTXE0 | URXE0); /* Disable Uart0 Tx + Rx */
194  UCTL0 = SWRST; /* U0 into reset state. */
195  UCTL0 |= CHAR | SYNC; /* 8-bit character, SPI, Slave mode */
196 
197  /* CKPH works also, but not CKPH+CKPL or none of them!! */
198  UTCTL0 = CKPL | STC;
199  URCTL0 = 0x00;
200  UBR00 = 0x00; /* No baudrate divider */
201  UBR10 = 0x00; /* settings for a spi */
202  UMCTL0 = 0x00; /* slave. */
203  ME1 |= URXE0; /* Enable USART0 RXD, disabling does not yield any powersavings */
204  P3SEL |= 0x0A; /* Select rx line and clk */
205  UCTL0 &= ~SWRST; /* Clear reset bit */
206  splx(s);
207 
208  /* configure driver */
209  cc1020_rxlen = 0; /* receive buffer position to start */
210  CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING); /* driver state to receive mode */
211 
212  /* configure radio */
213  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
214  cc1020_wakeupRX(RX_CURRENT);
215  cc1020_setupRX(RX_CURRENT);
216  LNA_POWER_ON(); /* enable amplifier */
217 
218  /* activate */
219  IE1 |= URXIE0; /* enable interrupt */
220 }
221 
222 void
223 cc1020_set_tx(void)
224 {
225  int s;
226 
227  /* configure radio rx */
228  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
229  LNA_POWER_OFF(); /* power down LNA */
230  s = splhigh();
231  DISABLE_RX_IRQ();
232  P3SEL &= ~0x02; /* Ensure Rx line is off */
233  splx(s);
234 
235  /* configure radio tx */
236  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
237  cc1020_wakeupTX(TX_CURRENT);
238  cc1020_setupTX(TX_CURRENT);
239  P3SEL |= 0x0C; /* select Tx line and clk */
240  U0CTL |= SWRST; /* UART to reset mode */
241  IFG1 &= ~UTXIFG0; /* Reset IFG. */
242 
243  /* configure driver */
244  CC1020_SET_OPSTATE(CC1020_TX);
245 }
246 
247 void
248 cc1020_set_power(uint8_t pa_power)
249 {
250  cc1020_pa_power = pa_power;
251 }
252 
253 static int
254 cc1020_prepare(const void *payload, unsigned short payload_len)
255 {
256  return -1;
257 }
258 
259 static int
260 cc1020_transmit(unsigned short transmit_len)
261 {
262  return 0;
263 }
264 
265 static int
266 cc1020_send(const void *buf, unsigned short len)
267 {
268  int normal_header = HDR_SIZE + len;
269  uint16_t rxcrc = 0xffff; /* For checksum purposes */
270  rtimer_clock_t timeout_time;
271 
272  timeout_time = RTIMER_NOW() + RTIMER_SECOND / 1000 * SEND_TIMEOUT;
273  while(cc1020_state & CC1020_RX_RECEIVING) {
274  if(RTIMER_CLOCK_LT(timeout_time, RTIMER_NOW())) {
275  PRINTF("cc1020: transmission blocked by reception in progress\n");
276  return RADIO_TX_ERR;
277  }
278  }
279 
280  if(cc1020_state == CC1020_OFF) {
281  return RADIO_TX_ERR;
282  }
283 
284  if(len > CC1020_BUFFERSIZE) {
285  return RADIO_TX_ERR;
286  }
287 
288  /* The preamble and the sync word are already in buffer. */
289  cc1020_txlen = PREAMBLE_SIZE + SYNCWORD_SIZE;
290 
291  /* header */
292  cc1020_txbuf[cc1020_txlen++] = 0x00;
293  cc1020_txbuf[cc1020_txlen++] = normal_header + CRC_SIZE;
294 
295  /* Adding the checksum on header and data */
296  rxcrc = crc16_add(normal_header & 0xff, rxcrc);
297  rxcrc = crc16_add((normal_header >> 8) & 0xff, rxcrc);
298 
299  rxcrc = crc16_data(buf, len, rxcrc);
300 
301  /* data to send */
302  memcpy((char *)cc1020_txbuf + cc1020_txlen, buf, len);
303  cc1020_txlen += len;
304 
305  /* Send checksum */
306  cc1020_txbuf[cc1020_txlen++] = rxcrc >> 8;
307  cc1020_txbuf[cc1020_txlen++] = rxcrc & 0xff;
308 
309  /* suffix */
310  cc1020_txbuf[cc1020_txlen++] = TAIL;
311  cc1020_txbuf[cc1020_txlen++] = TAIL;
312 
313  /* Switch to transceive mode. */
314  cc1020_set_tx();
315 
316  /* Initiate radio transfer. */
317  dma_done = 0;
318  dma_transfer((unsigned char *)&TXBUF0, cc1020_txbuf, cc1020_txlen);
319  while(!dma_done);
320 
321  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
322  RIMESTATS_ADD(lltx);
323 
324  /* clean up */
325  cc1020_txlen = 0;
326  if(cc1020_state & CC1020_TURN_OFF) {
327  cc1020_off();
328  } else {
329  cc1020_set_rx();
330  }
331 
332  return RADIO_TX_OK;
333 }
334 
335 static int
336 cc1020_read(void *buf, unsigned short size)
337 {
338  unsigned len;
339 
340  if(cc1020_rxlen <= HDR_SIZE) {
341  return 0;
342  }
343 
344  len = cc1020_rxlen - HDR_SIZE;
345  if(len > size) {
346  RIMESTATS_ADD(toolong);
347  return -1;
348  }
349 
350  memcpy(buf, (char *)cc1020_rxbuf + HDR_SIZE, len);
351  RIMESTATS_ADD(llrx);
352  reset_receiver();
353 
354  return len;
355 }
356 
357 static int
358 cc1020_channel_clear(void)
359 {
360  return (cc1020_read_reg(CC1020_STATUS) & CARRIER_SENSE);
361 }
362 
363 static int
364 cc1020_receiving_packet(void)
365 {
366  return cc1020_state & CC1020_RX_RECEIVING;
367 }
368 
369 static int
370 cc1020_pending_packet(void)
371 {
372  return cc1020_state & CC1020_RX_PROCESSING;
373 }
374 
375 int
376 cc1020_on(void)
377 {
378  if(cc1020_state == CC1020_OFF) {
379  cc1020_set_rx();
380  } else if(cc1020_state & CC1020_TURN_OFF) {
381  cc1020_state &= ~CC1020_TURN_OFF;
382  cc1020_set_rx();
383  }
384 
385  return 1;
386 }
387 
388 int
389 cc1020_off(void)
390 {
391  int s;
392 
393  if(cc1020_state != CC1020_OFF) {
394  if(cc1020_state & CC1020_RX_SEARCHING) {
395  /* Discard the current read buffer when the radio is shutting down. */
396  cc1020_rxlen = 0;
397 
398  LNA_POWER_OFF(); /* power down lna */
399  s = splhigh();
400  DISABLE_RX_IRQ();
401  cc1020_state = CC1020_OFF;
402  splx(s);
403  cc1020_setupPD(); /* power down radio */
404  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
405  cc1020_state = CC1020_OFF;
406  } else {
407  cc1020_state |= CC1020_TURN_OFF;
408  }
409  }
410  return 1;
411 }
412 
413 uint8_t
414 cc1020_get_rssi(void)
415 {
416  return (cc1020_read_reg(CC1020_RSS) & 0x7F);
417 }
418 
419 uint8_t
420 cc1020_get_packet_rssi(void)
421 {
422  return rssi;
423 }
424 
425 PROCESS_THREAD(cc1020_receiver_process, ev, data)
426 {
427  int len;
428 
429  PROCESS_BEGIN();
430 
431  while(1) {
432  ev = PROCESS_EVENT_NONE;
433  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
434 
435  /* Verify the checksum. */
436  uint16_t expected_crc = 0xffff;
437  uint16_t actual_crc;
438 
439  actual_crc = (cc1020_rxbuf[cc1020_rxlen - CRC_SIZE] << 8) |
440  cc1020_rxbuf[cc1020_rxlen - CRC_SIZE + 1];
441  cc1020_rxlen -= CRC_SIZE;
442 
443  expected_crc = crc16_add(cc1020_rxlen & 0xff, expected_crc);
444  expected_crc = crc16_add((cc1020_rxlen >> 8) & 0xff, expected_crc);
445  expected_crc = crc16_data((char *)&cc1020_rxbuf[HDR_SIZE],
446  cc1020_rxlen - HDR_SIZE, expected_crc);
447 
448  if(expected_crc == actual_crc) {
449  len = cc1020_read(packetbuf_dataptr(), PACKETBUF_SIZE);
451  NETSTACK_RDC.input();
452  } else {
453  RIMESTATS_ADD(badcrc);
454  reset_receiver();
455  }
456  }
457 
458  PROCESS_END();
459 }
460 
461 interrupt(UART0RX_VECTOR) cc1020_rxhandler(void)
462 {
463  static signed char syncbs;
464  static union {
465  struct {
466  uint8_t b2;
467  uint8_t b1;
468  uint8_t b4;
469  uint8_t b3;
470  };
471  struct {
472  uint16_t i1;
473  uint16_t i2;
474  };
475  } shiftbuf;
476  static unsigned char pktlen;
477 
478  if(cc1020_state & CC1020_RX_SEARCHING) {
479  shiftbuf.b1 = shiftbuf.b2;
480  shiftbuf.b2 = shiftbuf.b3;
481  shiftbuf.b3 = shiftbuf.b4;
482  shiftbuf.b4 = RXBUF0;
483  if(shiftbuf.i1 == 0xAAD3 && shiftbuf.b3 == 0x91) {
484  /* 0 AA D3 91 00 | FF 00 | */
485  syncbs = 0;
486  cc1020_rxbuf[cc1020_rxlen++] = shiftbuf.b4;
487  } else if(shiftbuf.i1 == 0x5569 && shiftbuf.i2 == 0xC880) {
488  /* 1 55 69 C8 80 | 7F 80 | */
489  syncbs = -1;
490  } else if(shiftbuf.i1 == 0xAAB4 && shiftbuf.i2 == 0xE440) {
491  /* 2 AA B4 E4 40 | 3F C0 | */
492  syncbs = -2;
493  } else if(shiftbuf.i1 == 0x555A && shiftbuf.i2 == 0x7220) {
494  /* 3 55 5A 72 20 | 1F E0 | */
495  syncbs = -3;
496  } else if(shiftbuf.i1 == 0xAAAD && shiftbuf.i2 == 0x3910) {
497  /* 4 AA AD 39 10 | 0F F0 | */
498  syncbs = -4;
499  } else if(shiftbuf.i1 == 0x5556 && shiftbuf.i2 == 0x9C88) {
500  /* 5 55 56 9C 88 | 07 F8 | */
501  syncbs = +3;
502  } else if(shiftbuf.i1 == 0xAAAB && shiftbuf.i2 == 0x4E44) {
503  /* 6 AA AB 4E 44 | 03 FC | */
504  syncbs = +2;
505  } else if(shiftbuf.i1 == 0x5555 && shiftbuf.i2 == 0xA722) {
506  /* 7 55 55 A7 22 | 01 FE | */
507  syncbs = +1;
508  } else {
509  return;
510  }
511  rssi = cc1020_get_rssi();
512  CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_RECEIVING);
513  } else if(cc1020_state & CC1020_RX_RECEIVING) {
514  if(syncbs == 0) {
515  cc1020_rxbuf[cc1020_rxlen] = RXBUF0;
516  } else {
517  shiftbuf.b3 = shiftbuf.b4;
518  shiftbuf.b4 = RXBUF0;
519  if(syncbs < 0) {
520  shiftbuf.i1 = shiftbuf.i2 << -syncbs;
521  cc1020_rxbuf[cc1020_rxlen] = shiftbuf.b1;
522  } else {
523  shiftbuf.i1 = shiftbuf.i2 >> syncbs;
524  cc1020_rxbuf[cc1020_rxlen] = shiftbuf.b2;
525  }
526  }
527 
528  cc1020_rxlen++;
529 
530  if(cc1020_rxlen == HDR_SIZE) {
531  pktlen = ((struct cc1020_header *)cc1020_rxbuf)->length;
532  if(pktlen == 0 || pktlen > sizeof (cc1020_rxbuf)) {
533  cc1020_rxlen = 0;
534  CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING);
535  }
536  } else if(cc1020_rxlen > HDR_SIZE) {
537  if(cc1020_rxlen == pktlen) {
538  /* Disable interrupts while processing the packet. */
539  DISABLE_RX_IRQ();
540  CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_PROCESSING);
541  _BIC_SR_IRQ(LPM3_bits);
542  process_poll(&cc1020_receiver_process);
543  }
544  }
545  }
546 }
547 
548 static void
549 cc1020_write_reg(uint8_t addr, uint8_t adata)
550 {
551  unsigned int i;
552  uint8_t data;
553 
554  data = addr << 1;
555  PSEL_ON;
556 
557  /* Send address bits */
558  for(i = 0; i < 7; i++) {
559  PCLK_LOW;
560  if(data & 0x80) {
561  PDI_HIGH;
562  } else {
563  PDI_LOW;
564  }
565  data = data << 1;
566  PCLK_HIGH;
567  nop();
568  }
569 
570  /* Send read/write bit */
571  /* Ignore bit in data, always use 1 */
572  PCLK_LOW;
573  PDI_HIGH;
574  PCLK_HIGH;
575  nop();
576  data = adata;
577 
578  /* Send data bits */
579  for(i = 0; i < 8; i++) {
580  PCLK_LOW;
581  if(data & 0x80) {
582  PDI_HIGH;
583  } else {
584  PDI_LOW;
585  }
586  data = data << 1;
587  PCLK_HIGH;
588  nop();
589  }
590 
591  PCLK_LOW;
592  PSEL_OFF;
593 }
594 
595 static uint8_t
596 cc1020_read_reg(uint8_t addr)
597 {
598  unsigned int i;
599  uint8_t data;
600 
601  data = addr << 1;
602  PSEL_ON;
603 
604  /* Send address bits */
605  for(i = 0; i < 7; i++) {
606  PCLK_LOW;
607  if(data & 0x80) {
608  PDI_HIGH;
609  } else {
610  PDI_LOW;
611  }
612  data = data << 1;
613  PCLK_HIGH;
614  nop();
615  }
616 
617  /* Send read/write bit */
618  /* Ignore bit in data, always use 0 */
619  PCLK_LOW;
620  PDI_LOW;
621  PCLK_HIGH;
622  nop();
623  PCLK_LOW;
624 
625  /* Receive data bits */
626  for(i = 0; i < 8; i++) {
627  nop();
628  PCLK_HIGH;
629  nop();
630  data = data << 1;
631  if(PDO) {
632  data++;
633  }
634  PCLK_LOW;
635  }
636 
637  PSEL_OFF;
638 
639  return data;
640 }
641 
642 static void
643 cc1020_load_config(const uint8_t * config)
644 {
645  int i;
646 
647  for(i = 0; i < 0x28; i++)
648  cc1020_write_reg(i, config[i]);
649 }
650 
651 static void
652 cc1020_reset(void)
653 {
654  /* Reset CC1020 */
655  cc1020_write_reg(CC1020_MAIN, 0x0FU & ~0x01U);
656 
657  /* Bring CC1020 out of reset */
658  cc1020_write_reg(CC1020_MAIN, 0x1F);
659 }
660 
661 static int
662 cc1020_calibrate(void)
663 {
664  unsigned int timeout_cnt;
665 
666  /* Turn off PA to avoid spurs during calibration in TX mode */
667  cc1020_write_reg(CC1020_PA_POWER, 0x00);
668 
669  /* Start calibration */
670  cc1020_write_reg(CC1020_CALIBRATE, 0xB5);
671  while((cc1020_read_reg(CC1020_STATUS) & CAL_COMPLETE) == 0);
672 
673  /* Monitor lock */
674  for(timeout_cnt = LOCK_TIMEOUT; timeout_cnt > 0; timeout_cnt--) {
675  if(cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS) {
676  break;
677  }
678  }
679 
680  /* Restore PA_POWER */
681  cc1020_write_reg(CC1020_PA_POWER, cc1020_pa_power);
682 
683  /* Return state of LOCK_CONTINUOUS bit */
684  return (cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS) == LOCK_CONTINUOUS;
685 }
686 
687 static int
688 cc1020_lock(void)
689 {
690  char lock_status;
691  int i;
692 
693  /* Monitor LOCK, lasts 420 - 510 cycles @ 4505600 = 93 us - 113 us */
694  for(i = LOCK_TIMEOUT; i > 0; i--) {
695  lock_status = cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS;
696  if(lock_status) {
697  break;
698  }
699  }
700 
701  if(lock_status == LOCK_CONTINUOUS) {
702  return LOCK_OK;
703  }
704 
705  return cc1020_calibrate() ? LOCK_RECAL_OK : LOCK_NOK;
706 }
707 
708 static int
709 cc1020_setupRX(int analog)
710 {
711  char lock_status;
712 
713  /* Switch into RX, switch to freq. reg A */
714  cc1020_write_reg(CC1020_MAIN, 0x01);
715  lock_status = cc1020_lock();
716 
717  /* Switch RX part of CC1020 on */
718  cc1020_write_reg(CC1020_INTERFACE, 0x02);
719 
720  /* Return LOCK status to application */
721  return lock_status;
722 }
723 
724 static int
725 cc1020_setupTX(int analog)
726 {
727  char lock_status;
728 
729  /* Switch into TX, switch to freq. reg B */
730  cc1020_write_reg(CC1020_MAIN, 0xC1);
731  lock_status = cc1020_lock();
732 
733  /* Restore PA_POWER */
734  cc1020_write_reg(CC1020_PA_POWER, cc1020_pa_power);
735 
736  /* Turn OFF DCLK squelch in TX */
737  cc1020_write_reg(CC1020_INTERFACE, 0x01);
738 
739  /* Return LOCK status to application */
740  return lock_status;
741 }
742 
743 static void
744 cc1020_setupPD(void)
745 {
746  /*
747  * Power down components and reset all registers except MAIN
748  * to their default values.
749  */
750  cc1020_write_reg(CC1020_MAIN,
751  RESET_N | BIAS_PD | FS_PD | XOSC_PD | PD_MODE_1);
752 
753  /* Turn off the power amplifier. */
754  cc1020_write_reg(CC1020_PA_POWER, 0x00);
755 
756  cc1020_write_reg(CC1020_POWERDOWN, 0x1F);
757 }
758 
759 static void
760 cc1020_wakeupRX(int analog)
761 {
762  /* Turn on crystal oscillator core. */
763  cc1020_write_reg(CC1020_MAIN, 0x1B);
764 
765  /* Setup bias current adjustment. */
766  cc1020_write_reg(CC1020_ANALOG, analog);
767 
768  /*
769  * Wait for the crystal oscillator to stabilize.
770  * This typically takes 2-5 ms.
771  */
772  MS_DELAY(5);
773 
774  /* Turn on bias generator. */
775  cc1020_write_reg(CC1020_MAIN, 0x19);
776 
777  /* Turn on frequency synthesizer. */
778  cc1020_write_reg(CC1020_MAIN, 0x11);
779 }
780 
781 static void
782 cc1020_wakeupTX(int analog)
783 {
784  /* Turn on crystal oscillator core. */
785  cc1020_write_reg(CC1020_MAIN, 0xDB);
786 
787  /* Setup bias current adjustment. */
788  cc1020_write_reg(CC1020_ANALOG, analog);
789 
790  /*
791  * Wait for the crystal oscillator to stabilize.
792  * This typically takes 2-5 ms.
793  */
794  MS_DELAY(5);
795 
796  /* Turn on bias generator. */
797  cc1020_write_reg(CC1020_MAIN, 0xD9);
798 
799  /* Turn on frequency synthesizer. */
800  MS_DELAY(1);
801  cc1020_write_reg(CC1020_MAIN, 0xD1);
802 }
803